@@ -7,3 +7,4 @@ | |||
/slatest | |||
/stripfc | |||
/bin2c | |||
/exec |
@@ -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 $@ | |||
@@ -1,5 +1,18 @@ | |||
#include <stdlib.h> | |||
#include <unistd.h> | |||
#include <termios.h> | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
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); | |||
} | |||
} | |||
@@ -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); | |||
@@ -0,0 +1,38 @@ | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include <fcntl.h> | |||
#include <unistd.h> | |||
#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; | |||
} | |||
@@ -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; | |||