mdcart

annotate src/main.c @ 1:c8d3d23ccd1f

works
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 12 Mar 2017 23:43:21 +0200
parents e6d499a8eb1d
children
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@0 3 #include <string.h>
nuclear@0 4 #include <stdint.h>
nuclear@0 5 #include <errno.h>
nuclear@0 6 #include <assert.h>
nuclear@0 7 #include <unistd.h>
nuclear@0 8 #include <fcntl.h>
nuclear@0 9 #include <termios.h>
nuclear@1 10 #include <sys/stat.h>
nuclear@0 11
nuclear@0 12 enum {
nuclear@0 13 OP_NONE,
nuclear@0 14 OP_WRITE,
nuclear@0 15 OP_READ,
nuclear@0 16 OP_RESET
nuclear@0 17 };
nuclear@0 18
nuclear@0 19 int op_write(FILE *dev, FILE *fp);
nuclear@0 20 int op_read(FILE *dev, FILE *fp);
nuclear@0 21 int op_reset(FILE *dev);
nuclear@0 22 int parse_args(int argc, char **argv);
nuclear@1 23 void print_progress(int p);
nuclear@0 24
nuclear@0 25 int op, verify = 0;
nuclear@0 26 const char *devname = "/dev/ttyUSB0";
nuclear@0 27 char *fname = 0;
nuclear@0 28 uint32_t start_addr;
nuclear@0 29 int read_size = 128 * 1024;
nuclear@1 30 int quiet;
nuclear@0 31
nuclear@0 32 int main(int argc, char **argv)
nuclear@0 33 {
nuclear@0 34 FILE *fp, *devfp;
nuclear@0 35 int dev;
nuclear@0 36 struct termios term;
nuclear@0 37
nuclear@0 38 if(parse_args(argc, argv) == -1) {
nuclear@0 39 return 1;
nuclear@0 40 }
nuclear@0 41
nuclear@0 42 if((dev = open(devname, O_RDWR)) == -1) {
nuclear@0 43 fprintf(stderr, "failed to open device %s: %s\n", devname, strerror(errno));
nuclear@0 44 return 1;
nuclear@0 45 }
nuclear@0 46 if(tcgetattr(dev, &term) == -1) {
nuclear@0 47 fprintf(stderr, "failed to get terminal attributes for %s: %s\n", devname, strerror(errno));
nuclear@0 48 return 1;
nuclear@0 49 }
nuclear@0 50 term.c_cflag = CS8 | CLOCAL;
nuclear@0 51 term.c_iflag &= ~(IXON | IXOFF);
nuclear@0 52 term.c_lflag = 0;
nuclear@0 53
nuclear@1 54 cfsetispeed(&term, B115200);
nuclear@1 55 cfsetospeed(&term, B115200);
nuclear@0 56
nuclear@0 57 if(tcsetattr(dev, TCSANOW, &term) == -1) {
nuclear@0 58 fprintf(stderr, "failed to set terminal attributes for %s: %s\n", devname, strerror(errno));
nuclear@0 59 return 1;
nuclear@0 60 }
nuclear@0 61
nuclear@0 62 if(!(devfp = fdopen(dev, "r+"))) {
nuclear@0 63 perror("failed to attach I/O stream to the device file\n");
nuclear@0 64 return 1;
nuclear@0 65 }
nuclear@0 66 setvbuf(devfp, 0, _IONBF, 0);
nuclear@0 67
nuclear@0 68 if(fname && !(fp = fopen(fname, op == OP_READ ? "w" : "r"))) {
nuclear@0 69 fprintf(stderr, "failed to open %s: %s\n", fname, strerror(errno));
nuclear@0 70 return 1;
nuclear@0 71 }
nuclear@0 72
nuclear@0 73 switch(op) {
nuclear@0 74 case OP_WRITE:
nuclear@0 75 if(op_write(devfp, fp) == -1) {
nuclear@0 76 fprintf(stderr, "write failed\n");
nuclear@0 77 return 1;
nuclear@0 78 }
nuclear@0 79 break;
nuclear@0 80
nuclear@0 81 case OP_READ:
nuclear@0 82 if(op_read(devfp, fp) == -1) {
nuclear@0 83 fprintf(stderr, "read failed\n");
nuclear@0 84 return 1;
nuclear@0 85 }
nuclear@0 86 break;
nuclear@0 87
nuclear@0 88 case OP_RESET:
nuclear@0 89 if(op_reset(devfp) == -1) {
nuclear@0 90 fprintf(stderr, "reset failed\n");
nuclear@0 91 return 1;
nuclear@0 92 }
nuclear@0 93 break;
nuclear@0 94
nuclear@0 95 default:
nuclear@0 96 break;
nuclear@0 97 }
nuclear@0 98
nuclear@0 99 fclose(devfp);
nuclear@0 100 close(dev);
nuclear@0 101 if(fp) {
nuclear@0 102 fclose(fp);
nuclear@0 103 }
nuclear@0 104 return 0;
nuclear@0 105 }
nuclear@0 106
nuclear@1 107 #define RET_IF_FAIL(x) if(!fgets(buf, sizeof buf, dev) || buf[0] != 'O') return x
nuclear@1 108 /*#define RET_IF_FAIL(x) \
nuclear@1 109 do { \
nuclear@1 110 if(!fgets(buf, sizeof buf, dev)) return x; \
nuclear@1 111 printf("--> %s", buf); \
nuclear@1 112 if(buf[0] != 'O') return x; \
nuclear@1 113 } while(0)
nuclear@1 114 */
nuclear@0 115
nuclear@0 116 int op_write(FILE *dev, FILE *fp)
nuclear@0 117 {
nuclear@0 118 char buf[128];
nuclear@1 119 int c, prev_progr = -1, written = 0;
nuclear@1 120 struct stat st;
nuclear@1 121
nuclear@1 122 fstat(fileno(fp), &st);
nuclear@0 123
nuclear@0 124 fprintf(dev, "p\n");
nuclear@0 125 RET_IF_FAIL(-1);
nuclear@0 126 fprintf(dev, "a%d\n", start_addr);
nuclear@0 127 RET_IF_FAIL(-1);
nuclear@0 128
nuclear@1 129 if(!quiet) {
nuclear@1 130 printf("writing %d bytes starting from %xh\n", (int)st.st_size, start_addr);
nuclear@1 131 }
nuclear@1 132
nuclear@0 133 while((c = fgetc(fp)) != -1) {
nuclear@1 134 int p;
nuclear@0 135 fprintf(dev, "w%d\n", c);
nuclear@0 136 RET_IF_FAIL(-1);
nuclear@1 137
nuclear@1 138 if(!quiet) {
nuclear@1 139 p = 100 * ++written / st.st_size;
nuclear@1 140 if(p != prev_progr) {
nuclear@1 141 prev_progr = p;
nuclear@1 142 print_progress(p);
nuclear@1 143 }
nuclear@1 144 }
nuclear@1 145 }
nuclear@1 146 if(!quiet) {
nuclear@1 147 putchar('\n');
nuclear@1 148 }
nuclear@1 149
nuclear@1 150 if(verify) {
nuclear@1 151 int verified = 0;
nuclear@1 152
nuclear@1 153 rewind(fp);
nuclear@1 154 fprintf(dev, "a%d\n", start_addr);
nuclear@1 155 RET_IF_FAIL(-1);
nuclear@1 156
nuclear@1 157 if(!quiet) {
nuclear@1 158 printf("verifying %d bytes starting from %xh\n", (int)st.st_size, start_addr);
nuclear@1 159 }
nuclear@1 160
nuclear@1 161 while((c = fgetc(fp)) != -1) {
nuclear@1 162 int p, val;
nuclear@1 163 fprintf(dev, "r\n");
nuclear@1 164
nuclear@1 165 if(!fgets(buf, sizeof buf, dev) || buf[0] != 'O') {
nuclear@1 166 fprintf(stderr, "\rread error after %d bytes\n", verified);
nuclear@1 167 break;
nuclear@1 168 }
nuclear@1 169
nuclear@1 170 if((val = atoi(buf + 3)) != c) { /* skip 'O', 'K', ' ' */
nuclear@1 171 fprintf(stderr, "\rverification error at byte %d\n", verified);
nuclear@1 172 fprintf(stderr, "expected %d (%xh), got %d (%xh)\n", c, c, val, val);
nuclear@1 173 break;
nuclear@1 174 }
nuclear@1 175
nuclear@1 176 if(!quiet) {
nuclear@1 177 p = 100 * ++verified / st.st_size;
nuclear@1 178 if(p != prev_progr) {
nuclear@1 179 prev_progr = p;
nuclear@1 180 print_progress(p);
nuclear@1 181 }
nuclear@1 182 }
nuclear@1 183 }
nuclear@1 184 if(!quiet) {
nuclear@1 185 putchar('\n');
nuclear@1 186 }
nuclear@0 187 }
nuclear@0 188
nuclear@0 189 fprintf(dev, "b\n");
nuclear@0 190 RET_IF_FAIL(-1);
nuclear@0 191 return 0;
nuclear@0 192 }
nuclear@0 193
nuclear@0 194 int op_read(FILE *dev, FILE *fp)
nuclear@0 195 {
nuclear@0 196 char buf[128];
nuclear@1 197 int i, val, prev_progr = -1;
nuclear@0 198
nuclear@0 199 fprintf(dev, "p\n");
nuclear@0 200 RET_IF_FAIL(-1);
nuclear@0 201 fprintf(dev, "a%d\n", start_addr);
nuclear@0 202 RET_IF_FAIL(-1);
nuclear@0 203
nuclear@1 204 if(!quiet) {
nuclear@1 205 printf("reading %d bytes starting from %xh\n", read_size, start_addr);
nuclear@1 206 }
nuclear@1 207
nuclear@0 208 for(i=0; i<read_size; i++) {
nuclear@1 209 int p;
nuclear@0 210 fprintf(dev, "r\n");
nuclear@0 211 if(!fgets(buf, sizeof buf, dev) || buf[0] != 'O') {
nuclear@0 212 fprintf(stderr, "read error after %d bytes\n", i);
nuclear@0 213 break;
nuclear@0 214 }
nuclear@1 215
nuclear@0 216 val = atoi(buf + 3); /* skip 'O', 'K', ' ' */
nuclear@0 217 fputc(val, fp);
nuclear@1 218
nuclear@1 219 if(!quiet) {
nuclear@1 220 p = 100 * i / read_size;
nuclear@1 221 if(p != prev_progr) {
nuclear@1 222 prev_progr = p;
nuclear@1 223 print_progress(p);
nuclear@1 224 }
nuclear@1 225 }
nuclear@1 226 }
nuclear@1 227 if(!quiet) {
nuclear@1 228 putchar('\n');
nuclear@0 229 }
nuclear@0 230
nuclear@0 231 fprintf(dev, "b\n");
nuclear@0 232 RET_IF_FAIL(-1);
nuclear@0 233 return 0;
nuclear@0 234 }
nuclear@0 235
nuclear@0 236 int op_reset(FILE *dev)
nuclear@0 237 {
nuclear@0 238 char buf[128];
nuclear@0 239 fprintf(dev, "p\n");
nuclear@0 240 RET_IF_FAIL(-1);
nuclear@0 241 fprintf(dev, "b\n");
nuclear@0 242 RET_IF_FAIL(-1);
nuclear@0 243 return 0;
nuclear@0 244 }
nuclear@0 245
nuclear@0 246 int parse_args(int argc, char **argv)
nuclear@0 247 {
nuclear@0 248 int i;
nuclear@0 249
nuclear@0 250 for(i=1; i<argc; i++) {
nuclear@0 251 if(strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "-write") == 0) {
nuclear@0 252 op = OP_WRITE;
nuclear@0 253 if(!(fname = argv[++i])) {
nuclear@0 254 fprintf(stderr, "%s must be followed by a filename\n", argv[i - 1]);
nuclear@0 255 return -1;
nuclear@0 256 }
nuclear@0 257
nuclear@0 258 } else if(strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "-read") == 0) {
nuclear@0 259 op = OP_READ;
nuclear@0 260 if(!(fname = argv[++i])) {
nuclear@0 261 fprintf(stderr, "%s must be followed by a filename\n", argv[i - 1]);
nuclear@0 262 return -1;
nuclear@0 263 }
nuclear@0 264
nuclear@0 265 } else if(strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "-addr") == 0) {
nuclear@0 266 char *endp;
nuclear@0 267 if(!argv[++i] || ((start_addr = strtol(argv[i], &endp, 0)), endp == argv[i])) {
nuclear@0 268 fprintf(stderr, "%s must be followed by an address\n", argv[i - 1]);
nuclear@0 269 return -1;
nuclear@0 270 }
nuclear@0 271
nuclear@0 272 } else if(strcmp(argv[i], "-R") == 0 || strcmp(argv[i], "-reset") == 0) {
nuclear@0 273 op = OP_RESET;
nuclear@0 274
nuclear@0 275 } else if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-size") == 0) {
nuclear@0 276 char *endp;
nuclear@0 277 if(!argv[++i] || ((read_size = strtol(argv[i], &endp, 0)), endp == argv[i])) {
nuclear@0 278 fprintf(stderr, "%s must be followed by a size in bytes\n", argv[i - 1]);
nuclear@0 279 return -1;
nuclear@0 280 }
nuclear@0 281
nuclear@0 282 } else if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "-verify") == 0) {
nuclear@0 283 verify = 1;
nuclear@0 284
nuclear@0 285 } else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "-device") == 0) {
nuclear@0 286 devname = argv[++i];
nuclear@0 287
nuclear@1 288 } else if(strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "-quiet") == 0) {
nuclear@1 289 quiet = 1;
nuclear@1 290
nuclear@0 291 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
nuclear@0 292 printf("Usage: %s [options]\n", argv[0]);
nuclear@0 293 printf("Options:\n");
nuclear@0 294 printf(" -w|-write <filename>\n");
nuclear@0 295 printf(" -r|-read <filename>\n");
nuclear@0 296 printf(" -a|-addr <address>: start address for read/write operations\n");
nuclear@0 297 printf(" -R|-reset: reboot machine\n");
nuclear@0 298 printf(" -v|-verify: do verification after writing\n");
nuclear@0 299 printf(" -s|-size: read size in bytes\n");
nuclear@1 300 printf(" -q|-quiet: don't print anything to stdout\n");
nuclear@0 301 printf(" -d|-device <device file>: serial device (eg /dev/ttyUSB0)\n");
nuclear@0 302 printf(" -h|-help: print usage and exit\n");
nuclear@0 303 return 0;
nuclear@0 304
nuclear@0 305 } else {
nuclear@0 306 fprintf(stderr, "invalid argument: %s\n", argv[i]);
nuclear@0 307 return -1;
nuclear@0 308 }
nuclear@0 309 }
nuclear@0 310
nuclear@0 311 if(!op) {
nuclear@0 312 fprintf(stderr, "you must specify an operation\n");
nuclear@0 313 return -1;
nuclear@0 314 }
nuclear@0 315 return 0;
nuclear@0 316 }
nuclear@1 317
nuclear@1 318 void print_progress(int p)
nuclear@1 319 {
nuclear@1 320 int i, num = p / 2;
nuclear@1 321 printf("\rprogress: [");
nuclear@1 322 for(i=0; i<50; i++) {
nuclear@1 323 if(i == num) {
nuclear@1 324 putchar('>');
nuclear@1 325 } else {
nuclear@1 326 putchar(i < num ? '=' : ' ');
nuclear@1 327 }
nuclear@1 328 }
nuclear@1 329 printf("] %3d%%", p);
nuclear@1 330 fflush(stdout);
nuclear@1 331 }