diff calypso/tpinterf.c @ 4:deeeef558279

fcsim-calypso-be put together
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 14 Mar 2021 05:07:34 +0000
parents
children b25d4dfe5798
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calypso/tpinterf.c	Sun Mar 14 05:07:34 2021 +0000
@@ -0,0 +1,190 @@
+/*
+ * This code is based on loadtools/tpinterf.c from FC host tools,
+ * modified for our different application of interfacing between
+ * simagent below and fc-simtool above.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern int errno;
+
+extern int target_fd;
+
+/* definition matches target-utils/libcommon/cmdentry.c */
+#define	MAXCMD	527
+
+/*
+ * static buffer between tpinterf_make_cmd and tpinterf_send_cmd
+ *
+ * We store the command with an ending \r\n so we can use it for
+ * matching the received echo as well, hence the sizing of the
+ * buffer.
+ */
+static char cmdbuf[MAXCMD+2];
+static int cmdlen;
+
+static int
+arg_chars_valid(arg)
+	char *arg;
+{
+	char *cp;
+
+	for (cp = arg; *cp; cp++)
+		if (*cp < ' ' || *cp > '~')
+			return(0);
+	return(1);
+}
+
+/*
+ * This function takes a command for the target in argv form and
+ * converts it to a space-separated continuous string which can be
+ * passed as tty "keyboard" input to the target, enforcing length
+ * and character validity limits in the process.  The output is
+ * stored in an internal static buffer for subsequent
+ * tpinterf_send_cmd().
+ *
+ * Return value: 0 if everything OK, or -1 if some constraint is
+ * violated.
+ */
+tpinterf_make_cmd(argv)
+	char **argv;
+{
+	int arglen;
+	char **ap, *dp;
+
+	dp = cmdbuf;
+	cmdlen = 0;
+	for (ap = argv; *ap; ap++) {
+		arglen = strlen(*ap);
+		if (ap != argv)
+			arglen++;	/* separating space */
+		if (arglen > MAXCMD - cmdlen)
+			return(-1);
+		if (!arg_chars_valid(*ap))
+			return(-1);
+		if (ap != argv)
+			*dp++ = ' ';
+		strcpy(dp, *ap);
+		dp += strlen(*ap);
+		cmdlen += arglen;
+	}
+	*dp++ = '\r';
+	*dp = '\n';
+	return(0);
+}
+
+/*
+ * This function sends the previously-constructed command to the target,
+ * and collects the expected echo.
+ *
+ * Return value: 0 if successful, -1 on errors (timeout or wrong response)
+ */
+tpinterf_send_cmd()
+{
+	char echobuf[MAXCMD+2];
+	fd_set fds;
+	struct timeval tv;
+	int rcvd, cc;
+
+	write(target_fd, cmdbuf, cmdlen + 1);
+	for (rcvd = 0; rcvd < cmdlen + 2; ) {
+		FD_ZERO(&fds);
+		FD_SET(target_fd, &fds);
+		tv.tv_sec = 1;
+		tv.tv_usec = 0;
+		cc = select(target_fd+1, &fds, NULL, NULL, &tv);
+		if (cc < 0) {
+			if (errno == EINTR)
+				continue;
+			printf("back end error: failed select\n");
+			return(-1);
+		}
+		if (cc < 1) {
+			printf(
+			"back end error: timeout waiting for command echo\n");
+			return(-1);
+		}
+		cc = read(target_fd, echobuf + rcvd, cmdlen + 2 - rcvd);
+		if (cc <= 0) {
+			printf(
+		"back end error: failed read after successful select\n");
+			return(-1);
+		}
+		rcvd += cc;
+	}
+	if (bcmp(echobuf, cmdbuf, cmdlen + 2)) {
+		printf("back end error: command echo mismatch\n");
+		return(-1);
+	} else
+		return(0);
+}
+
+/*
+ * This functions reads the serial output from the target until a
+ * '=' prompt is received.  All intermediate output is passed to
+ * stdout, with some hacks specific to this SIM interface back end.
+ */
+tpinterf_pass_output(timeout)
+{
+	char buf[1024], *cp;
+	fd_set fds;
+	struct timeval tv;
+	int cc, newline = 1, termflag = 0;
+	unsigned goodchar;
+
+	for (goodchar = 0; ; ) {
+		FD_ZERO(&fds);
+		FD_SET(target_fd, &fds);
+		tv.tv_sec = timeout;
+		tv.tv_usec = 0;
+		cc = select(target_fd+1, &fds, NULL, NULL, &tv);
+		if (cc < 0) {
+			if (errno == EINTR)
+				continue;
+			printf("back end error: failed select\n");
+			return(-1);
+		}
+		if (cc < 1) {
+			printf(
+		"back end error: timeout waiting for simagent response\n");
+			return(-1);
+		}
+		cc = read(target_fd, buf + goodchar, sizeof(buf) - goodchar);
+		if (cc <= 0) {
+			printf(
+		"back end error: failed read after successful select\n");
+			return(-1);
+		}
+		for (cp = buf + goodchar; cc; cp++) {
+			cc--;
+			if (*cp == '=' && newline && !cc)
+				break;
+			if (*cp == '\n') {
+				newline = 1;
+				termflag = 1;
+				continue;
+			}
+			newline = 0;
+			if (*cp == '\r')
+				termflag = 1;
+			if (!termflag)
+				goodchar++;
+			if (goodchar >= 516)
+				termflag = 1;
+		}
+	}
+	if (!goodchar) {
+		printf("back end error: empty output from simagent\n");
+		return(-1);
+	}
+	buf[goodchar] = '\0';
+	puts(buf);
+	return(0);
+}