From 509972b08c2b10460ec155e27b70ee78c2f6f8f2 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Mon, 13 Apr 2020 10:25:27 -0400 Subject: [PATCH] tools: add exec and convert ./upload to Forth --- tools/.gitignore | 1 + tools/Makefile | 4 ++- tools/common.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- tools/common.h | 3 +++ tools/exec.c | 38 +++++++++++++++++++++++++++ tools/upload.c | 20 +++++++++----- 6 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 tools/exec.c diff --git a/tools/.gitignore b/tools/.gitignore index bcca6b1..0d7da18 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -7,3 +7,4 @@ /slatest /stripfc /bin2c +/exec diff --git a/tools/Makefile b/tools/Makefile index a676406..65d0343 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -7,9 +7,10 @@ PINGPONG_TGT = pingpong SLATEST_TGT = slatest STRIPFC_TGT = stripfc BIN2C_TGT = bin2c +EXEC_TGT = exec TARGETS = $(MEMDUMP_TGT) $(BLKDUMP_TGT) $(UPLOAD_TGT) $(FONTCOMPILE_TGT) \ $(TTYSAFE_TGT) $(PINGPONG_TGT) $(SLATEST_TGT) $(STRIPFC_TGT) \ - $(BIN2C_TGT) + $(BIN2C_TGT) $(EXEC_TGT) OBJS = common.o all: $(TARGETS) @@ -27,6 +28,7 @@ $(PINGPONG_TGT): $(PINGPONG_TGT).c $(SLATEST_TGT): $(SLATEST_TGT).c $(STRIPFC_TGT): $(STRIPFC_TGT).c $(BIN2C_TGT): $(BIN2C_TGT).c +$(EXEC_TGT): $(EXEC_TGT).c $(TARGETS): $(OBJS) $(CC) $(CFLAGS) $@.c $(OBJS) -o $@ diff --git a/tools/common.c b/tools/common.c index 32f4b1d..82824a7 100644 --- a/tools/common.c +++ b/tools/common.c @@ -1,5 +1,18 @@ #include #include +#include +#include +#include +#include + +void mread(int fd, char *s, int count) +{ + while (count) { + while (read(fd, s, 1) == 0); + s++; + count--; + } +} void sendcmd(int fd, char *cmd) { @@ -12,8 +25,8 @@ void sendcmd(int fd, char *cmd) // it breathe, it can choke. usleep(1000); } - write(fd, "\n", 1); - read(fd, &junk, 2); // sends back \r\n + write(fd, "\r", 1); + mread(fd, junk, 2); // sends back \r\n usleep(1000); } @@ -22,5 +35,66 @@ void sendcmdp(int fd, char *cmd) { char junk[2]; sendcmd(fd, cmd); - read(fd, &junk, 2); + mread(fd, junk, 2); } + +// from https://stackoverflow.com/a/6947758 +// discussion from https://stackoverflow.com/a/26006680 is interesting, +// but we don't want POSIX compliance. + +int set_interface_attribs(int fd, int speed, int parity) +{ + struct termios tty; + if (tcgetattr (fd, &tty) != 0) { + fprintf(stderr, "error %d from tcgetattr", errno); + return -1; + } + + if (speed) { + cfsetospeed (&tty, speed); + cfsetispeed (&tty, speed); + } + + tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars + // disable IGNBRK for mismatched speed tests; otherwise receive break + // as \000 chars + tty.c_iflag &= ~IGNBRK; // disable break processing + tty.c_lflag = 0; // no signaling chars, no echo, + // no canonical processing + tty.c_oflag = 0; // no remapping, no delays + tty.c_cc[VMIN] = 0; // read doesn't block + tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout + + tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl + + tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls, + // enable reading + tty.c_cflag &= ~(PARENB | PARODD); // shut off parity + tty.c_cflag |= parity; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CRTSCTS; + + if (tcsetattr (fd, TCSANOW, &tty) != 0) { + fprintf(stderr, "error %d from tcsetattr", errno); + return -1; + } + return 0; +} + +void set_blocking(int fd, int should_block) +{ + struct termios tty; + memset(&tty, 0, sizeof tty); + if (tcgetattr (fd, &tty) != 0) { + fprintf(stderr, "error %d from tggetattr", errno); + return; + } + + tty.c_cc[VMIN] = should_block ? 1 : 0; + tty.c_cc[VTIME] = 1; // 0.1 seconds read timeout + + if (tcsetattr (fd, TCSANOW, &tty) != 0) { + fprintf(stderr, "error %d setting term attributes", errno); + } +} + diff --git a/tools/common.h b/tools/common.h index 4504a88..ea36a15 100644 --- a/tools/common.h +++ b/tools/common.h @@ -1,3 +1,6 @@ void sendcmd(int fd, char *cmd); void sendcmdp(int fd, char *cmd); +void mread(int fd, char *s, int count); +int set_interface_attribs(int fd, int speed, int parity); +void set_blocking(int fd, int should_block); diff --git a/tools/exec.c b/tools/exec.c new file mode 100644 index 0000000..5fae28d --- /dev/null +++ b/tools/exec.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +#include "common.h" + +/* Execute code from stdin on the target machine. + */ + +int main(int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: ./exec device\n"); + return 1; + } + int fd = open(argv[1], O_RDWR|O_NOCTTY|O_SYNC); + if (fd < 0) { + fprintf(stderr, "Could not open %s\n", argv[1]); + return 1; + } + set_interface_attribs(fd, 0, 0); + set_blocking(fd, 0); + int c = getchar(); + while (c != EOF) { + if (c == '\n') c = '\r'; + write(fd, &c, 1); + while (read(fd, &c, 1) == 1) { + putchar(c); + fflush(stdout); + } + c = getchar(); + } + printf("Done!\n"); + return 0; +} + + diff --git a/tools/upload.c b/tools/upload.c index bd6252a..fb60935 100644 --- a/tools/upload.c +++ b/tools/upload.c @@ -5,7 +5,7 @@ #include "common.h" -/* Push specified file to specified device running the BASIC shell and verify +/* Push specified file to specified device running Forth and verify * that the sent contents is correct. */ @@ -35,11 +35,17 @@ int main(int argc, char **argv) return 1; } rewind(fp); - int fd = open(argv[1], O_RDWR|O_NOCTTY); + int fd = open(argv[1], O_RDWR|O_NOCTTY|O_SYNC); + if (fd < 0) { + fprintf(stderr, "Could not open %s\n", argv[1]); + return 1; + } + set_interface_attribs(fd, 0, 0); + set_blocking(fd, 1); char s[0x40]; - sprintf(s, "m=0x%04x", memptr); - sendcmdp(fd, s); - sprintf(s, "while m<0x%04x getc:puth a:poke m a:m=m+1", memptr+bytecount); + sprintf(s, + ": _ 0x%04x 0x%04x DO KEY DUP .x I C! LOOP ; _", + memptr+bytecount, memptr); sendcmd(fd, s); int returncode = 0; @@ -49,7 +55,7 @@ int main(int argc, char **argv) unsigned char c = s[0]; write(fd, &c, 1); usleep(1000); // let it breathe - read(fd, s, 2); // read hex pair + mread(fd, s, 2); // read hex pair s[2] = 0; // null terminate unsigned char c2 = strtol(s, NULL, 16); if (c != c2) { @@ -60,6 +66,8 @@ int main(int argc, char **argv) returncode = 1; } } + mread(fd, s, 2); // "> " prompt + sendcmdp(fd, "FORGET _"); printf("Done!\n"); fclose(fp); return returncode;