10 enum { FMT_BIN, FMT_IHEX, FMT_SREC };
12 int send_bin(FILE *infile, int dev);
13 int send_ihex(FILE *infile, int dev);
14 int send_srec(FILE *infile, int dev);
15 void print_usage(const char *argv0);
21 int main(int argc, char **argv)
25 const char *serdev = "/dev/ttyACM0";
26 const char *fname = 0;
28 int (*send)(FILE*, int) = send_bin;
30 for(i=1; i<argc; i++) {
31 if(argv[i][0] == '-') {
36 fprintf(stderr, "-d must be followed by a device file\n");
43 if(strcmp(argv[++i], "bin") == 0) {
45 } else if(strcmp(argv[i], "ihex") == 0 || strcmp(argv[i], "hex") == 0) {
47 } else if(strcmp(argv[i], "srec") == 0) {
50 fprintf(stderr, "invalid input format: %s\n", argv[i]);
56 base_addr = strtol(argv[++i], &endp, 0);
58 fprintf(stderr, "-a must be followed by a base address offset\n");
68 fprintf(stderr, "invalid option: %s\n", argv[i]);
73 fprintf(stderr, "invalid option: %s\n", argv[i]);
79 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
88 if(!(infile = fopen(fname, "rb"))) {
89 fprintf(stderr, "failed to open input file: %s: %s\n", fname, strerror(errno));
96 if((sdev = open(serdev, O_RDWR | O_NOCTTY)) == -1) {
97 fprintf(stderr, "failed to connect to devrom board (%s): %s\n", serdev, strerror(errno));
100 tcgetattr(sdev, &term);
105 term.c_cc[VTIME] = 0;
107 term.c_cflag = CLOCAL | CREAD | CS8 | HUPCL;
108 term.c_iflag = IGNBRK | IGNPAR;
110 cfsetispeed(&term, B38400);
111 cfsetospeed(&term, B38400);
113 if(tcsetattr(sdev, TCSANOW, &term) < 0) {
114 fprintf(stderr, "failed to set terminal attributes\n");
118 if(send(infile, sdev) == -1) {
126 int read_line(int fd, char *buf, int bufsz)
129 bufsz--; /* leave space for the terminator */
132 if((num = read(fd, buf, bufsz)) <= 0) {
136 for(i=0; i<num; i++) {
137 if(*buf == '\r' || *buf == '\n') {
151 int read_status(int dev)
155 if(read_line(dev, buf, sizeof buf) == -1) {
156 fprintf(stderr, "failed to read status\n");
161 if(memcmp(buf, "ERR", 3) == 0) {
162 fprintf(stderr, "error:%s\n", buf + 3);
168 int cmd(int dev, const char *cmd)
170 write(dev, cmd, strlen(cmd));
171 if(read_status(dev) != 0) {
177 int cmd_addr(int dev, int addr)
180 sprintf(buf, "a %d\n", addr);
181 return cmd(dev, buf);
184 int cmd_write(int dev, int val)
188 if(val < 0 || val >= 256) {
189 fprintf(stderr, "cmd_write: invalid byte value: %d\n", val);
193 sprintf(buf, "w %d\n", val);
194 return cmd(dev, buf);
197 int send_bin(FILE *infile, int dev)
200 long count = 0, fsz = -1;
202 if(fseek(infile, 0, SEEK_END) != -1) {
207 if(cmd(dev, "p\n") == -1 || cmd_addr(dev, 0) == -1) {
211 while((c = fgetc(infile)) != -1) {
212 if(cmd_write(dev, c) == -1) {
217 printf("\r%ld/%ld ", ++count, fsz);
224 if(fsz > 0) putchar('\n');
229 long hexval(const char *s, int digits)
234 for(i=0; i<digits; i++) {
241 val |= *s - 'a' + 10;
242 } else if(*s >= 'A') {
243 val |= *s - 'A' + 10;
252 const char *substr(const char *s, int len)
259 if(!(tmp = malloc(len + 1))) {
260 perror("failed to allocate substring buffer");
281 int send_ihex(FILE *infile, int dev)
283 char line[512], *ptr;
284 int res = -1, count, addr, type, val;
285 int cur_addr = -1, offs = 0;
287 if(cmd(dev, "p\n") == -1) {
291 while(fgets(line, sizeof line, infile)) {
292 if(line[0] != ':') continue;
296 if((count = hexval(ptr, 2)) == -1) {
297 fprintf(stderr, "ihex: invalid count field: %s\n", substr(ptr, 2));
301 if((addr = hexval(ptr, 4)) == -1) {
302 fprintf(stderr, "ihex: invalid address field: %s\n", substr(ptr, 4));
306 if((type = hexval(ptr, 2)) == -1 || type > 5) {
307 fprintf(stderr, "ihex: invalid type field: %s\n", substr(ptr, 2));
314 addr += base_addr + offs;
315 if(cur_addr != addr) {
317 if(cmd_addr(dev, addr) == -1) {
324 if((val = hexval(ptr, 2)) == -1) {
325 fprintf(stderr, "ihex: invalid value: %s\n", substr(ptr, 2));
328 if(cmd_write(dev, val) == -1) {
340 if((val = hexval(ptr, 4)) == -1) {
341 fprintf(stderr, "ihex: invalid extended segment address: %s\n", substr(ptr, 4));
349 if((val = hexval(ptr, 8)) == -1) {
350 fprintf(stderr, "ihex: invalid extended linear address: %s\n", substr(ptr, 8));
369 int send_srec(FILE *infile, int dev)
371 fprintf(stderr, "TODO: SREC format not implemented yet\n");
375 void print_usage(const char *argv0)
377 printf("Usage: %s [options] [input file]\n", argv0);
378 printf("If no input file is specified, defaults to reading standard input\n");
379 printf("Options:\n");
380 printf(" -d <device file> devrom board USB serial port (default: /dev/ttyACM0)\n");
381 printf(" -f <input format> format of the input file [bin/ihex/srec] (default: bin)\n");
382 printf(" -a <base address> address offset (default: 0)\n");
383 printf(" -h print usage and exit\n");