diff uptools/atcmd/atinterf.c @ 348:64dcbabd48ca

uptools/atcmd framework started
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 04 Feb 2018 18:38:20 +0000
parents
children 9ffaeb6fea1a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uptools/atcmd/atinterf.c	Sun Feb 04 18:38:20 2018 +0000
@@ -0,0 +1,214 @@
+/*
+ * This module implements the interface functions to the AT command phone or
+ * modem to be used by the rest of the FreeCalypso User Phone tools suite.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include "../../rvinterf/include/exitcodes.h"
+
+static char atinterf_pathname[] = "/opt/freecalypso/bin/fcup-atinterf";
+static char rvtat_pathname[] = "/opt/freecalypso/bin/fcup-rvtat";
+static char shell_pathname[] = "/bin/sh";
+
+char *target_ttyport, *target_baud, *external_prog;
+int rvtat_mode, no_target_mode;
+static char *backend_prog, *backend_argv[6];
+
+FILE *cpipeF, *rpipeF;
+char at_response[514];
+
+atinterf_cmdline_opt(opt)
+{
+	extern char *optarg;
+
+	switch (opt) {
+	case 'B':
+		target_baud = optarg;
+		return(1);
+	case 'n':
+		no_target_mode = 1;
+		return(1);
+	case 'p':
+		target_ttyport = optarg;
+		return(1);
+	case 'R':
+		rvtat_mode = 1;
+		return(1);
+	case 'X':
+		external_prog = optarg;
+		return(1);
+	}
+	return(0);
+}
+
+static void
+preen_port_baud_config()
+{
+	if (!target_ttyport && target_baud) {
+		fprintf(stderr, "error: -B option invalid without -p\n");
+		exit(ERROR_USAGE);
+	}
+	if (rvtat_mode)
+		return;
+	if (!target_ttyport) {
+		target_ttyport = getenv("FC_GSM_DEVICE");
+		if (!target_ttyport) {
+			fprintf(stderr,
+				"error: no FC GSM device target specified\n");
+			exit(ERROR_USAGE);
+		}
+	}
+	if (!target_baud)
+		target_baud = "115200";
+}
+
+static void
+setup_be_native_at()
+{
+	backend_prog = atinterf_pathname;
+	backend_argv[0] = "fcup-atinterf";
+	backend_argv[1] = target_ttyport;
+	backend_argv[2] = target_baud;
+	backend_argv[3] = 0;
+}
+
+static void
+setup_be_rvtat()
+{
+	char **ap;
+
+	backend_prog = rvtat_pathname;
+	ap = backend_argv;
+	*ap++ = "fcup-rvtat";
+	if (target_ttyport) {
+		*ap++ = "-p";
+		*ap++ = target_ttyport;
+	}
+	if (target_baud) {
+		*ap++ = "-B";
+		*ap++ = target_baud;
+	}
+	*ap = 0;
+}
+
+static void
+setup_be_external()
+{
+	backend_prog = shell_pathname;
+	backend_argv[0] = "sh";
+	backend_argv[1] = "-c";
+	backend_argv[2] = external_prog;
+	backend_argv[3] = 0;
+}
+
+atinterf_init()
+{
+	int cpipe[2], rpipe[2], rc;
+
+	if (!no_target_mode)
+		return(0);
+	if (external_prog)
+		setup_be_external();
+	else {
+		preen_port_baud_config();
+		if (rvtat_mode)
+			setup_be_rvtat();
+		else
+			setup_be_native_at();
+	}
+	if (pipe(cpipe) < 0 || pipe(rpipe) < 0) {
+		perror("pipe");
+		exit(ERROR_UNIX);
+	}
+	rc = vfork();
+	if (rc < 0) {
+		perror("vfork for launching back end");
+		exit(ERROR_UNIX);
+	}
+	if (!rc) {
+		/* we are in the child - prepare to exec the BE */
+		dup2(cpipe[0], 0);
+		dup2(rpipe[1], 1);
+		close(cpipe[0]);
+		close(cpipe[1]);
+		close(rpipe[0]);
+		close(rpipe[1]);
+		/* do the exec */
+		execv(backend_prog, backend_argv);
+		perror(backend_prog);
+		_exit(1);
+	}
+	close(cpipe[0]);
+	close(rpipe[1]);
+	cpipeF = fdopen(cpipe[1], "w");
+	if (!cpipeF) {
+		perror("fdopen");
+		exit(ERROR_UNIX);
+	}
+	rpipeF = fdopen(rpipe[0], "r");
+	if (!rpipeF) {
+		perror("fdopen");
+		exit(ERROR_UNIX);
+	}
+	return(0);
+}
+
+atinterf_exec_cmd(command, message, callback)
+	char *command, *message;
+	void (*callback)();
+{
+	char *nl;
+
+	if (message) {
+		fputs("c+m\n", cpipeF);
+		fprintf(cpipeF, "%s\n", command);
+		fprintf(cpipeF, "%s\n", message);
+	} else
+		fprintf(cpipeF, "%s\n", command);
+	fflush(cpipeF);
+	for (;;) {
+		if (!fgets(at_response, sizeof at_response, rpipeF)) {
+			fprintf(stderr,
+				"error reading AT response from back end\n");
+			exit(ERROR_RVINTERF);
+		}
+		nl = index(at_response, '\n');
+		if (!nl) {
+			fprintf(stderr,
+		"error: back end response is too long or unterminated\n");
+			exit(ERROR_RVINTERF);
+		}
+		*nl = '\0';
+		switch (at_response[0]) {
+		case 'E':
+			fprintf(stderr, "error from back end: %s\n",
+				at_response + 1);
+			exit(ERROR_RVINTERF);
+		case 'F':
+			return(0);
+		case 'I':
+			if (callback)
+				callback();
+			continue;
+		}
+		fprintf(stderr, "error: invalid response from back end\n");
+		exit(ERROR_RVINTERF);
+	}
+}
+
+atinterf_exec_cmd_needok(command, message, callback)
+	char *command, *message;
+	void (*callback)();
+{
+	atinterf_exec_cmd(command, message, callback);
+	if (strcmp(at_response+1, "OK")) {
+		fprintf(stderr, "AT error: %s\n", at_response+1);
+		exit(ERROR_TARGET);
+	}
+	return(0);
+}