/* upload.c - send data to the sh1wh board by Matt Debergalis */ /*** implements sh1wh upload protocol, described below: the binary format is as follows, byte by byte: ...0xFF SZ3 SZ2 SZ1 SZ0 0x00 0xFF 0x00 0xFF [D0 ... DN] 0x00 0xDE 0xAD 0x00 explanations: ...0xFF is the first byte we care about. all other bytes until 0xFF is sent are ignored (this helps insure ASCII garbage gets flushed from all FIFOs before send begins). SZ3-SZ0 is the size of the binary file data sequence, given MSB first. The SZ bytes makes up a 32-bit number = 4 GBytes, which is as large as the entire SH-1 address space. Famous last words: 4 GBytes should be plenty. 0xFF 0x00 0xFF 0x00 -- preamble sequence. D0-DN -- data, where N is the number represented in the SZ field. One byte of data uploaded gives an SZ = 0 (D0 - D0), 1024 bytes is SZ = 1023. 0x00 0xDE 0xAD 0x00 -- postamble sequence. This lets us know if we skipped any bytes, or if we overran or miscounted somehow. It's not foolproof, but its useful for reference. An error message is kicked out to the serial port if any errors are encountered in the download process. ***/ #include #include #include #include #include #include #include #include static int baud = 38400; static char *serial_device = "/dev/ttyS0"; static int serial_fd; extern char *optarg; extern int optind; void setup_serial(void); void usage(char *); int main(int argc, char *argv[]) { struct stat sb; unsigned char buf[512]; int f; int len; int size; char *file; char *progname; char c; /* parse command line */ progname = argv[0]; while ((c = getopt(argc, argv, "b:p:")) != -1) { switch (c) { case 'b': baud = atoi(optarg); printf("baud: %d\n", baud); break; case 'p': serial_device = strdup(optarg); break; default: usage(progname); } } argc -= optind; argv += optind; if (argc == 1) file = strdup(argv[0]); else usage(progname); /* configure serial connection */ setup_serial(); /* load in file */ f = open(file, O_RDONLY); if (f == -1) { fprintf(stderr, "missing input file %s\n", file); exit(1); } fstat(f, &sb); size = sb.st_size ; /* send preamble */ buf[0] = 0xff; buf[1] = size >> 24; buf[2] = (size >> 16) & 0xff; buf[3] = (size >> 8) & 0xff; buf[4] = size & 0xff; buf[5] = 0xff; buf[6] = 0x00; buf[7] = 0xff; buf[8] = 0x00; write(serial_fd, buf, 9); /* send file */ while ((len = read(f, buf, 512))) write(serial_fd, buf, len); /* send postamble */ buf[0] = 0x00; buf[1] = 0xDE; buf[2] = 0xAD; buf[3] = 0x00; write(serial_fd, buf, 4); close(f); close(serial_fd); return 0; } void setup_serial(void) { struct termios term; /* open the port */ serial_fd=open(serial_device, O_WRONLY); if (serial_fd == -1) { fprintf(stderr, "unable to open %s\n", serial_device); exit(1); } /* if writing to a file, don't frob terminal settings */ if (isatty(serial_fd)) { /* get, modify, and save terminal characteristics */ tcgetattr(serial_fd, &term); term.c_cflag=CS8; /* 8N1 */ term.c_cflag |= (CREAD | /* enable receiver */ HUPCL | /* lower modem lines on last close */ CLOCAL); /* ignore modem status lines */ term.c_oflag = 0; /* turn off all output processing */ term.c_iflag = IGNBRK | IGNPAR; /* ignore break, parity errors also no flow control since XON, XOFF unset */ term.c_lflag = 0; /* turn off canonical mode, sig generation, echo */ /* set baud both ways */ cfsetispeed(&term, baud); cfsetospeed(&term, baud); /* set attribs */ tcsetattr(serial_fd, TCSANOW, &term); } } void usage(char *progname) { printf("usage: %s [-p device] [-b baudrate] infile\n", progname); exit(1); }