diff ffstools/tiaud/compile.c @ 240:2568a2a8a453

tiaud-compile program written
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 25 Aug 2017 23:36:07 +0000
parents
children 2abc086b13ed
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiaud/compile.c	Fri Aug 25 23:36:07 2017 +0000
@@ -0,0 +1,662 @@
+/*
+ * This utility compiles a TI audio mode config file from our ASCII source
+ * format into the binary for uploading into Calypso device FFS.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <endian.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "binstruct.h"
+
+struct audio_cfg_bin bin;
+
+char *infname;
+FILE *inf;
+int lineno;
+
+init_nonzero_defaults()
+{
+	bin.mic_bytes[0] = 3;
+	bin.mic_fir[0] = 0x4000;
+	bin.speaker_fir[0] = 0x4000;
+	bin.sidetone_gain = -5;
+}
+
+static long
+strtol_wrap(arg)
+	char *arg;
+{
+	char *endptr;
+	long ret;
+
+	ret = strtol(arg, &endptr, 0);
+	if (*endptr) {
+		fprintf(stderr, "%s line %d: \"%s\" is not a valid number\n",
+			infname, lineno, arg);
+		exit(1);
+	}
+	return(ret);
+}
+
+static void
+mic_gain_setting(args)
+	char *args;
+{
+	char *cp, *np;
+
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+			"%s line %d: mic gain setting requires an argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#') {
+		fprintf(stderr,
+		"%s line %d: mic gain setting takes only one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	bin.mic_bytes[0] = strtol_wrap(np);
+}
+
+static void
+mic_extra_gain_setting(args)
+	char *args;
+{
+	char *cp, *np;
+
+	if (bin.mic_mode != AUDIO_MICROPHONE_HANDFREE) {
+		fprintf(stderr,
+	"%s line %d: mic extra-gain setting is only valid in aux mode\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+		"%s line %d: mic extra-gain setting requires an argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#') {
+		fprintf(stderr,
+		"%s line %d: mic extra-gain setting takes only one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	bin.mic_bytes[1] = strtol_wrap(np);
+}
+
+static void
+mic_output_bias_setting(args)
+	char *args;
+{
+	char *cp, *np;
+	int idx;
+
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+		"%s line %d: mic output-bias setting requires an argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#') {
+		fprintf(stderr,
+		"%s line %d: mic output-bias setting takes only one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (bin.mic_mode != AUDIO_MICROPHONE_HANDFREE)
+		idx = 1;
+	else
+		idx = 2;
+	bin.mic_bytes[idx] = strtol_wrap(np);
+}
+
+static void
+mic_fir_setting(args)
+	char *args;
+{
+	char *cp, *np;
+	int idx, start_idx;
+
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+missing_arg:	fprintf(stderr,
+		"%s line %d: mic fir setting requires two or more arguments\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	start_idx = strtol_wrap(np);
+	if (start_idx < 0 || start_idx > 31) {
+		fprintf(stderr,
+		"%s line %d: FIR coefficient number must be between 0 and 31\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (idx = start_idx; ; idx++) {
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#') {
+			if (idx == start_idx)
+				goto missing_arg;
+			break;
+		}
+		if (idx > 31) {
+			fprintf(stderr,
+				"%s line %d: spill past FIR coefficient 31\n",
+				infname, lineno);
+			exit(1);
+		}
+		for (np = cp; *cp && !isspace(*cp); cp++)
+			;
+		if (*cp)
+			*cp++ = '\0';
+		bin.mic_fir[idx] = htole16(strtol_wrap(np));
+	}
+}
+
+static void
+mic_head_line(args)
+	char *args;
+{
+	char linebuf[512];
+	char *cp, *np;
+
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+			"%s line %d: mic setting requires a mode argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	if (!strcmp(np, "default"))
+		bin.mic_mode = AUDIO_MICROPHONE_HANDHELD;
+	else if (!strcmp(np, "aux"))
+		bin.mic_mode = AUDIO_MICROPHONE_HANDFREE;
+	else if (!strcmp(np, "headset"))
+		bin.mic_mode = AUDIO_MICROPHONE_HEADSET;
+	else {
+		fprintf(stderr, "%s line %d: unknown mic mode \"%s\"\n",
+			infname, lineno, np);
+		exit(1);
+	}
+	while (isspace(*cp))
+		cp++;
+	if (*cp == '\0' || *cp == '#')
+		return;
+	if (*cp != '{') {
+		fprintf(stderr,
+			"%s line %d: invalid syntax on the mic head line\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (;;) {
+		if (!fgets(linebuf, sizeof linebuf, inf)) {
+			fprintf(stderr, "%s: unexpected EOF in mic section\n",
+				infname);
+			exit(1);
+		}
+		lineno++;
+		for (cp = linebuf; isspace(*cp); cp++)
+			;
+		if (*cp == '\0' || *cp == '#')
+			continue;
+		for (np = cp; *cp && !isspace(*cp); cp++)
+			;
+		if (*cp)
+			*cp++ = '\0';
+		if (!strcmp(np, "gain"))
+			mic_gain_setting(cp);
+		else if (!strcmp(np, "extra-gain"))
+			mic_extra_gain_setting(cp);
+		else if (!strcmp(np, "output-bias"))
+			mic_output_bias_setting(cp);
+		else if (!strcmp(np, "fir"))
+			mic_fir_setting(cp);
+		else if (!strcmp(np, "}"))
+			break;
+		else {
+			fprintf(stderr,
+				"%s line %d: unknown mic setting \"%s\"\n",
+				infname, lineno, np);
+			exit(1);
+		}
+	}
+}
+
+static void
+speaker_gain_setting(args)
+	char *args;
+{
+	char *cp, *np;
+
+	if (bin.speaker_mode == AUDIO_SPEAKER_BUZZER) {
+		fprintf(stderr,
+	"%s line %d: speaker gain setting is not valid in buzzer mode\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+		"%s line %d: speaker gain setting requires an argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#') {
+		fprintf(stderr,
+		"%s line %d: speaker gain setting takes only one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	bin.speaker_bytes[0] = strtol_wrap(np);
+}
+
+static void
+speaker_audio_filter_setting(args)
+	char *args;
+{
+	char *cp, *np;
+
+	if (bin.speaker_mode == AUDIO_SPEAKER_BUZZER) {
+		fprintf(stderr,
+      "%s line %d: speaker audio-filter setting is not valid in buzzer mode\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+	"%s line %d: speaker audio-filter setting requires an argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#') {
+		fprintf(stderr,
+	"%s line %d: speaker audio-filter setting takes only one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	bin.speaker_bytes[1] = strtol_wrap(np);
+}
+
+static void
+speaker_fir_setting(args)
+	char *args;
+{
+	char *cp, *np;
+	int idx, start_idx;
+
+	if (bin.speaker_mode == AUDIO_SPEAKER_BUZZER) {
+		fprintf(stderr,
+		"%s line %d: speaker fir setting is not valid in buzzer mode\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+missing_arg:	fprintf(stderr,
+	"%s line %d: speaker fir setting requires two or more arguments\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	start_idx = strtol_wrap(np);
+	if (start_idx < 0 || start_idx > 31) {
+		fprintf(stderr,
+		"%s line %d: FIR coefficient number must be between 0 and 31\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (idx = start_idx; ; idx++) {
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#') {
+			if (idx == start_idx)
+				goto missing_arg;
+			break;
+		}
+		if (idx > 31) {
+			fprintf(stderr,
+				"%s line %d: spill past FIR coefficient 31\n",
+				infname, lineno);
+			exit(1);
+		}
+		for (np = cp; *cp && !isspace(*cp); cp++)
+			;
+		if (*cp)
+			*cp++ = '\0';
+		bin.speaker_fir[idx] = htole16(strtol_wrap(np));
+	}
+}
+
+static void
+speaker_activate_setting(args)
+	char *args;
+{
+	char *cp, *np;
+
+	if (bin.speaker_mode != AUDIO_SPEAKER_BUZZER) {
+		fprintf(stderr,
+	"%s line %d: speaker activate setting is only valid in buzzer mode\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+		"%s line %d: speaker activate setting requires an argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#') {
+		fprintf(stderr,
+	"%s line %d: speaker activate setting takes only one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	bin.speaker_bytes[0] = strtol_wrap(np);
+}
+
+static void
+speaker_head_line(args)
+	char *args;
+{
+	char linebuf[512];
+	char *cp, *np;
+
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+		"%s line %d: speaker setting requires a mode argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	if (!strcmp(np, "ear"))
+		bin.speaker_mode = AUDIO_SPEAKER_HANDHELD;
+	else if (!strcmp(np, "aux"))
+		bin.speaker_mode = AUDIO_SPEAKER_HANDFREE;
+	else if (!strcmp(np, "headset"))
+		bin.speaker_mode = AUDIO_SPEAKER_HEADSET;
+	else if (!strcmp(np, "buzzer"))
+		bin.speaker_mode = AUDIO_SPEAKER_BUZZER;
+	else if (!strcmp(np, "ear+aux"))
+		bin.speaker_mode = AUDIO_SPEAKER_HANDHELD_HANDFREE;
+	else {
+		fprintf(stderr, "%s line %d: unknown speaker mode \"%s\"\n",
+			infname, lineno, np);
+		exit(1);
+	}
+	while (isspace(*cp))
+		cp++;
+	if (*cp == '\0' || *cp == '#')
+		return;
+	if (*cp != '{') {
+		fprintf(stderr,
+			"%s line %d: invalid syntax on the speaker head line\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (;;) {
+		if (!fgets(linebuf, sizeof linebuf, inf)) {
+			fprintf(stderr,
+				"%s: unexpected EOF in speaker section\n",
+				infname);
+			exit(1);
+		}
+		lineno++;
+		for (cp = linebuf; isspace(*cp); cp++)
+			;
+		if (*cp == '\0' || *cp == '#')
+			continue;
+		for (np = cp; *cp && !isspace(*cp); cp++)
+			;
+		if (*cp)
+			*cp++ = '\0';
+		if (!strcmp(np, "gain"))
+			speaker_gain_setting(cp);
+		else if (!strcmp(np, "audio-filter"))
+			speaker_audio_filter_setting(cp);
+		else if (!strcmp(np, "fir"))
+			speaker_fir_setting(cp);
+		else if (!strcmp(np, "activate"))
+			speaker_activate_setting(cp);
+		else if (!strcmp(np, "}"))
+			break;
+		else {
+			fprintf(stderr,
+				"%s line %d: unknown speaker setting \"%s\"\n",
+				infname, lineno, np);
+			exit(1);
+		}
+	}
+}
+
+static void
+voice_path_setting(args)
+	char *args;
+{
+	char *cp, *np;
+
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+			"%s line %d: voice-path setting requires an argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#') {
+		fprintf(stderr,
+		"%s line %d: voice-path setting takes only one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	bin.voice_path = strtol_wrap(np);
+}
+
+static void
+sidetone_setting(args)
+	char *args;
+{
+	char *cp, *np;
+
+	for (cp = args; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+		fprintf(stderr,
+			"%s line %d: sidetone setting requires an argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#') {
+		fprintf(stderr,
+		"%s line %d: sidetone setting takes only one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	bin.sidetone_gain = strtol_wrap(np);
+}
+
+static void
+aec_setting(args)
+	char *args;
+{
+	char *cp, *np;
+	int n;
+
+	cp = args;
+	for (n = 0; n < 5; n++) {
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#') {
+argcount_err:		fprintf(stderr,
+				"%s line %d: aec setting takes 5 arguments\n",
+				infname, lineno);
+			exit(1);
+		}
+		for (np = cp; *cp && !isspace(*cp); cp++)
+			;
+		if (*cp)
+			*cp++ = '\0';
+		bin.aec_words[n] = htole16(strtol_wrap(np));
+	}
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#')
+		goto argcount_err;
+}
+
+read_input_main()
+{
+	char linebuf[512];
+	char *cp, *np;
+
+	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
+		for (cp = linebuf; isspace(*cp); cp++)
+			;
+		if (*cp == '\0' || *cp == '#')
+			continue;
+		for (np = cp; *cp && !isspace(*cp); cp++)
+			;
+		if (*cp)
+			*cp++ = '\0';
+		if (!strcmp(np, "voice-path"))
+			voice_path_setting(cp);
+		else if (!strcmp(np, "mic"))
+			mic_head_line(cp);
+		else if (!strcmp(np, "speaker"))
+			speaker_head_line(cp);
+		else if (!strcmp(np, "sidetone"))
+			sidetone_setting(cp);
+		else if (!strcmp(np, "aec"))
+			aec_setting(cp);
+		else {
+			fprintf(stderr,
+			"%s line %d: unknown top-level setting \"%s\"\n",
+				infname, lineno, np);
+			exit(1);
+		}
+	}
+}
+
+write_bin_output(filename)
+	char *filename;
+{
+	int fd;
+
+	fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+	if (fd < 0) {
+		perror(filename);
+		exit(1);
+	}
+	write(fd, &bin, sizeof bin);
+	close(fd);
+}
+
+main(argc, argv)
+	char **argv;
+{
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s infile outfile\n", argv[0]);
+		exit(1);
+	}
+	if (strcmp(argv[1], "-")) {
+		infname = argv[1];
+		inf = fopen(infname, "r");
+		if (!inf) {
+			perror(infname);
+			exit(1);
+		}
+	} else {
+		inf = stdin;
+		infname = "stdin";
+	}
+	init_nonzero_defaults();
+	read_input_main();
+	write_bin_output(argv[2]);
+	exit(0);
+}