mdcart

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