]> rtime.felk.cvut.cz Git - sysless.git/blob - arch/arm/mach-lpc21xx/tools/tolpc/tolpc_fn.c
comproc_test is not compiled by default.
[sysless.git] / arch / arm / mach-lpc21xx / tools / tolpc / tolpc_fn.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <termios.h>
5 #include <sys/time.h>
6 #include <sys/types.h>
7 #include <sys/ioctl.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <stdarg.h>
11 #include "tolpc_fn.h"
12 #include "uuencode.h"
13
14 #define DEBUG 0
15 #define DEBUG_COUNT 0
16
17 //#define WITHOUT_CFSETSPEED
18
19 int tolpc_debug_level = 0;
20
21 #ifdef WITHOUT_CFSETSPEED
22
23 #include "baudrate.h"
24
25 /* Set both the input and output baud rates stored in *TERMIOS_P to SPEED.  */
26 int rs232_cfsetspeed (struct termios *termios_p, speed_t speed) {
27   size_t cnt;
28   
29   for (cnt = 0; cnt < sizeof(rs232_speeds) / sizeof(rs232_speeds[ 0 ]); ++cnt)
30     if (speed == rs232_speeds[ cnt ].internal) {
31       cfsetispeed (termios_p, speed);
32       cfsetospeed (termios_p, speed);
33       return 0;
34     } else if (speed == rs232_speeds[ cnt ].value) {
35       cfsetispeed (termios_p, rs232_speeds[ cnt ].internal);
36       cfsetospeed (termios_p, rs232_speeds[ cnt ].internal);
37       return 0;
38     }
39   
40   return -1;
41 }
42
43 #endif /* WITHOUT_CFSETSPEED */
44
45 #define FLOWC_XONXOFF 0x02
46 #define FLOWC_RTSCTS  0x01
47
48 int tolpc_verbose_level = 0;
49
50 void tolpc_verbose(int level, const char *fmt, ...)
51 {
52     va_list ap;
53
54     if (level <= tolpc_verbose_level) {
55         va_start(ap, fmt);
56         vfprintf(stderr, fmt, ap);
57         va_end(ap);
58         fflush(stdout);
59     }
60 }
61 #define verbose tolpc_verbose
62
63 /**
64  * Set right mode and speed for RS232 interface
65  * baud can be either speed in character per second or special Bxxxx constant
66  */
67 int setup_comm_dev(int dev, int baudrate, int flowc) {
68   struct termios term_attr;
69
70   if (tcgetattr(dev, &term_attr)) {
71     perror("setup_dev: tcgetattr");
72     return -1;
73   }
74   /* set immediate character input */
75   /*
76     ~ICANON -- do not wait for EOL at input,
77     ~ECHO -- do not echo characters locally
78   */
79   term_attr.c_lflag = 0;
80   term_attr.c_cc[VMIN] = 1;
81   term_attr.c_cc[VTIME] = 0;
82
83   /* input newlines: \r\n=>\n */
84   term_attr.c_iflag = IGNCR;
85   if (flowc & FLOWC_XONXOFF)
86     term_attr.c_iflag |= IXON | IXOFF;
87   if (flowc & FLOWC_RTSCTS)
88     term_attr.c_cflag |= CRTSCTS;
89   
90   term_attr.c_oflag = 0;
91
92   /* set right ispeed and ospeed */
93   #ifdef WITHOUT_CFSETSPEED
94   if (rs232_cfsetspeed(&term_attr, baudrate) < 0) {
95     fprintf(stderr, "Error in rs232_cfsetspeed\n");
96     return -1;
97   }
98   #else /* WITHOUT_CFSETSPEED */
99   if (cfsetspeed(&term_attr, baudrate) < 0) {
100     fprintf(stderr, "Error in cfsetspeed\n");
101     return -1;
102   }
103   #endif /* WITHOUT_CFSETSPEED */
104
105   if (tcsetattr(dev, TCSAFLUSH, &term_attr)) {
106     perror("setup_dev: tcsetattr");
107     return -1;
108   }
109
110   return 0;
111 }
112
113 /* * * * */
114
115 static const char *isp_response_code[] = {
116   "CMD_SUCCESS",
117   "INVALID_COMMAND",
118   "SRC_ADDR_ERROR: Source address is not on word boundary",
119   "DST_ADDR_ERROR: Destination address is not on a correct boundary",
120   "SRC_ADDR_NOT_MAPPED: Source address is not mapped in the memory map",
121   "DST_ADDR_NOT_MAPPED: Destination address is not mapped in the memory map",
122   "COUNT_ERROR: Byte count is not multiple of 4 or is not a permitted value",
123   "INVALID_SECTOR: Sector number is invalid or end sector number is "
124   " greater than start sector number.",
125   "SECTOR_NOT_BLANK",
126   "SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION:"
127   " Command to prepare sector for write operation was not executed",
128   "",
129   "",
130   "",
131   "",
132   "",
133   "",
134   "",
135   "",
136   "",
137   "",
138   "",
139   "",
140   "",
141 };
142
143 typedef enum _response_type_t {
144   NO_RESPONSE,
145   NUM_RESPONSE,
146   OK_RESPONSE
147 } resp_type_t;
148
149 int poll_input(FILE *stream, long tv_sec, long tv_usec) {
150   fd_set sel_set;
151   struct timeval timeout;
152   int sel, comm_dev = fileno(stream);
153
154   FD_ZERO(&sel_set);
155   FD_SET(comm_dev, &sel_set);
156   timeout.tv_sec = tv_sec;
157   timeout.tv_usec = tv_usec;
158   sel = select(comm_dev+1, &sel_set, NULL, NULL, &timeout);
159   if (sel == -1)
160     perror("poll_input: select");
161   return(sel);
162 }
163
164 int send_line(FILE *comm, resp_type_t response_type, char *line) {
165   char s[160];
166   int sel, resp;
167
168   /* send command */
169   /*
170     according to documentation, \n should be sufficient
171     -- works well with commands, but uuencoded data transmission
172     seems to not work well with it; so using \r\n instead
173   */
174   if (fprintf(comm, "%s\r\n", line) < 0) {
175     perror("send_line: fprintf");
176     return -1;
177   }
178
179   /* check echo, 1s timeout */
180   if ((sel = poll_input(comm, 1, 0)) < 1) {
181     if (sel == 0)
182       fprintf(stderr, "send_line: command echo timeout\n");
183     else
184       perror("send_line: select");
185     return(1);
186   }
187   fgets(s, sizeof(s), comm);
188   /*DEBUG*/printf(":%s", s);
189   if (strncmp(line, s, strlen(line))) {
190     fprintf(stderr, "send_line: \"%s\" command echo mismatch (\"%s\" received)\n", line, s);
191     return(1);
192   }
193
194   if (response_type == NO_RESPONSE)
195     return 0;
196
197   /* check response, 1s timeout */
198   if ((sel = poll_input(comm, 1, 0)) < 1) {
199     if (sel == 0)
200       fprintf(stderr, "send_line: \"%s\" command response timeout\n", line);
201     else
202       perror("send_line: select");
203     return(1);
204   }
205   fgets(s, sizeof(s), comm);
206   /*DEBUG*/printf(">%s", s);
207   if (response_type == OK_RESPONSE) {
208     /* textual response -- expecting "OK" */
209     resp = (strncmp(s, "OK", 2) != 0);
210     if (resp)
211       fprintf(stderr, "Received something else than \"OK\"\n");
212     return(resp);
213   }
214   else {
215     /* numeric response */
216     if (sscanf(s, "%d", &resp) == 0) {
217       fprintf(stderr, "Invalid (non-numeric) command response received\n");
218       return(-1);
219     }
220     if (resp)
221       fprintf(stderr, "Error response code %d\n", resp);
222     return(resp);
223   }
224 }
225
226 int send_line_fmt(FILE *comm, resp_type_t resp, const char *fmt, ...) {
227   char s[160];
228   va_list ap;
229
230   va_start(ap, fmt);
231   vsprintf(s, fmt, ap);
232   va_end(ap);
233   return send_line(comm, resp, s);
234 }
235
236 #define MAX_SYNC_QM_TRIES 240
237 int synchronize(FILE *comm, int crystal_freq) {
238   int n, sel;
239   char ch = '\0';
240   char sync_string[] = "Synchronized\n";
241   int sync_status = 0, sync_pos = 0, sync_len = strlen(sync_string);
242
243   printf("Synchronizing");
244   /* send '?'s and wait for response */
245   for (n = 0; n < MAX_SYNC_QM_TRIES; n++) {
246     /* if not receiving "Synchronized" response, send '?'s */
247     if (!sync_status) {
248       fputc('?', comm);
249       fflush(comm);
250     }
251
252     /* poll for input */
253     /* 0.1s is duration of 3 characters in 8N1 300b/s transfer */
254     sel = poll_input(comm, 0, 100000);
255     if (sel == -1) {
256       perror("synchronize: select");
257       return(1);
258     }
259
260     if (sel > 0) {
261       ch = fgetc(comm);
262       if (ch == sync_string[sync_pos]) {
263         if (sync_pos == 0)
264           sync_status = 1;
265         sync_pos++;
266         if (sync_pos == sync_len) {
267           printf("\n\"Synchronized\" received (recv. %d chars)\n", n);
268           break;
269         }
270       }
271       else {
272         sync_status = 0;
273         sync_pos = 0;
274       }
275     }
276     /* show progress */
277     if (!sync_status) {
278       putchar(sel ? ((ch == '?') ? '.' : 'x') : '_');
279       fflush(stdout);
280     }
281   }
282   if (n == MAX_SYNC_QM_TRIES) {
283     fprintf(stderr, "Didn't synchronize after %d tries.\n", n);
284     return(1);
285   }
286   /*
287    * here may be comm.dev mode switched back to ICANON...
288    */
289   /* respond to sync */
290   if (send_line(comm, OK_RESPONSE, "Synchronized"))
291     return(1);
292   printf("Synchronized, OK.\n");
293   /* send Xtal frequency */
294   printf("Sending crystal frequency: %d\n", crystal_freq);
295   //sprintf(s, "%d", crystal_freq);
296   if (send_line_fmt(comm, OK_RESPONSE, "%d", 7373)) //crystal_freq))
297     return 1;
298
299   return 0;
300 }
301
302 struct termios comm_attr_save;
303
304 void close_comm(FILE *comm) {
305   /* restore serial line settings */
306   tcsetattr(fileno(comm), TCSANOW, &comm_attr_save);
307   fclose(comm);
308 }
309
310 FILE *open_comm(char *device, int baudrate, int flowc) {
311   FILE *comm;
312   int comm_dev, line;
313
314   if ((comm = fopen(device, "r+")) == NULL) {
315     perror("open_comm: fopen");
316     return(NULL);
317   }
318   /* set stream as unbuffered */
319   setbuf(comm, NULL);
320
321   comm_dev = fileno(comm);
322   /* backup serial line settings */
323   if (tcgetattr(comm_dev, &comm_attr_save))
324     fprintf(stderr, "Warning: open_comm: can not get serial line settings by tcgetattr");
325   /* setup serial device parameters */
326   setup_comm_dev(comm_dev, baudrate, flowc);
327
328   /* initialize serial bootloader (on miniARM_DB board) */
329   ioctl (comm_dev, TIOCMGET, &line);
330   line |= TIOCM_DTR;
331   ioctl (comm_dev, TIOCMSET, &line);
332   usleep(1000*1000);
333   line &= ~TIOCM_DTR;
334   ioctl (comm_dev, TIOCMSET, &line);
335   usleep(100*1000);
336
337   return(comm);
338 }
339
340 /* * * * */
341
342 int write_ram(FILE *comm, unsigned start, unsigned length, char *data) {
343   char s[100];
344   int i, line, line_len;
345   unsigned count = length;
346   unsigned checksum;
347
348   sprintf(s, "W %u %u", start, length);
349   if (send_line(comm, NUM_RESPONSE, s))
350     return(1);
351   while (count > 0) {
352     checksum = 0;
353     for (line = 0; (line < 20) && (count > 0); line++) {
354       line_len = (count < 45) ? count : 45;
355       for (i = 0; i < line_len; i++)
356         checksum += (unsigned char)data[i];
357       uuencode_line(s, data, line_len);
358       count -= line_len;
359       data += line_len;
360       if (send_line(comm, NO_RESPONSE, s))
361         return(1);
362     }
363     sprintf(s, "%u", checksum);
364     if (send_line(comm, OK_RESPONSE, s))
365       return(1);
366   }
367   return 0;
368 }
369
370 /* * * * */
371
372 int tolpc_send_cmd(struct tolpc_env *env, char *fmt, ...) {
373   va_list ap;
374   char s[160];
375
376   if (env->comm_stream == NULL)
377     if (tolpc_open_target(env))
378       return -1;
379
380   va_start(ap, fmt);
381   vsprintf(s, fmt, ap);
382   va_end(ap);
383
384   return send_line(env->comm_stream, NUM_RESPONSE, s);
385 }
386
387 int tolpc_readline_to(struct tolpc_env *env, char *s, int size) {
388   fgets(s, size, env->comm_stream);
389   return 0;
390 }
391
392 int tolpc_open_target(struct tolpc_env *env) {
393   FILE *comm;
394
395   comm = open_comm(env->sdev, env->baud, FLOWC_XONXOFF);
396   if (comm == NULL)
397     return -1;
398   if (synchronize(comm, env->crystal))
399     return -1;
400
401   env->comm_stream = comm;
402   return 0;
403 }
404
405 int tolpc_write_ram(struct tolpc_env *env, unsigned int start, int length, unsigned char *data) {
406   return write_ram(env->comm_stream, start, length, data);
407 }
408
409 /* * */
410
411 int tolpc_unlock(struct tolpc_env *env) {
412   int ret;
413   ret = tolpc_send_cmd(env, "U 23130");
414   return ret;
415 }
416
417 int tolpc_go(struct tolpc_env *env, unsigned int start, char arm_mode)
418 {
419     int ret;
420
421     ret = tolpc_send_cmd(env, "G %u %c", start, arm_mode ? 'A' : 'T');
422     if (ret == 2)
423     {
424         verbose(1, "Timeout means the code is executed\n");
425         ret = 0;
426     }
427     return ret;
428 }
429
430 /**
431  * Reads part ID
432  * @param env
433  * @param part_id Where to store received part id.
434  * @param size Size of part_id.
435  * @return Zero on success, -1 on error.
436  */
437 int tolpc_partid(struct tolpc_env *env, char* part_id, int size)
438 {
439     int ret;
440
441     ret = tolpc_send_cmd(env, "J");
442     if (ret) return ret;
443
444     ret = tolpc_readline_to(env, part_id, size);
445     return ret == 0 ? 0 : -1;
446 }
447
448 /**
449  * Reads boot code version
450  * @param env
451  * @param ver Where to store received version.
452  * @param size Size of ver.
453  * @return Zero on success, -1 on error.
454  */
455 int tolpc_bootver(struct tolpc_env *env, char* ver, int size)
456 {
457     int ret;
458
459     ret = tolpc_send_cmd(env, "K");
460     if (ret) return ret;
461
462     ret = tolpc_readline_to(env, ver, size);
463     return ret == 0 ? 0 : -1;
464 }
465
466 /**
467  * Sets echo mode
468  * @param env
469  * @return Zero on success, 1 on bad response, -1 on communication error.
470  */
471 int tolpc_echo(struct tolpc_env *env, char on)
472 {
473 #if 0
474     int ret;
475     ret = tolpc_send_cmd(env, "A %c", on);
476     return ret;
477 #else
478     return 0;
479 #endif
480 }
481
482 int tolpc_break(struct tolpc_env *env)
483 {
484 #if 0
485     int fd;
486     int i;
487     char c = 0;
488
489     /* Open RS232 device */
490     if ((fd = open(env->sdev, O_RDWR | O_NONBLOCK)) == -1) {
491         printf("Error openning %s\n", env->sdev);
492         return -1;
493     }
494
495     if (rs232_setmode(fd, env->baud / 2, 0) < 0) {
496         close(fd);
497         return -1;
498     }
499
500     #if DEBUG
501     printf("Sending break chars \n");
502     #endif
503
504     for (i = 100;i--;)
505         write(fd, &c, 1);
506
507     close(fd);
508 #endif
509     return 1;
510 }