view calypso/tpinterf.c @ 7:b25d4dfe5798

fcsim-calypso-be actually works now
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 14 Mar 2021 05:33:51 +0000
parents deeeef558279
children
line wrap: on
line source

/*
 * 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, finish = 0;
	unsigned goodchar;

	for (goodchar = 0; !finish; ) {
		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) {
				finish = 1;
				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);
}