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 }
|