]> rtime.felk.cvut.cz Git - sysless.git/blob - arch/arm/mach-lpc21xx/tools/tolpc/tolpc_fn.c
cmdproc: Make backspace work even in sterm
[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], *p;
166   int sel, resp;
167   size_t size;
168
169   /* send command */
170   /*
171     according to documentation, \n should be sufficient
172     -- works well with commands, but uuencoded data transmission
173     seems to not work well with it; so using \r\n instead
174   */
175   if (fprintf(comm, "%s\r\n", line) < 0) {
176     perror("send_line: fprintf");
177     return -1;
178   }
179
180   /* check echo, 1s timeout */
181   if ((sel = poll_input(comm, 1, 0)) < 1) {
182     if (sel == 0)
183       fprintf(stderr, "send_line: command echo timeout\n");
184     else
185       perror("send_line: select");
186     return(1);
187   }
188   fgets(s, sizeof(s), comm);
189   /*DEBUG*/printf(":%s", s);
190   if (strncmp(line, s, strlen(line))) {
191     fprintf(stderr, "send_line: \"%s\" command echo mismatch (\"%s\" received)\n", line, s);
192     return(1);
193   }
194
195   if (response_type == NO_RESPONSE)
196     return 0;
197
198   p=s;
199   /* read with timout for every character (necessary for go command) */
200   do {
201     /* check response, 1s timeout */
202     if ((sel = poll_input(comm, 1, 0)) < 1) {
203       *p = '\0';
204       /*DEBUG*/printf(">%s", s);
205       fflush(stdout);
206       if (sel == 0) {
207         fprintf(stderr, "send_line: \"%s\" command response timeout\n", line);
208       }
209       else
210         perror("send_line: select");
211       return(1);
212     }
213     /* read one character */
214     size = fread(p, 1, 1, comm);
215     p++;
216   } while (*(p-1) != '\n');
217
218   *p = '\0';
219   /*DEBUG*/printf(">%s", s);
220
221   if (response_type == OK_RESPONSE) {
222     /* textual response -- expecting "OK" */
223     resp = (strncmp(s, "OK", 2) != 0);
224     if (resp)
225       fprintf(stderr, "Received something else than \"OK\"\n");
226     return(resp);
227   }
228   else {
229     /* numeric response */
230     if (sscanf(s, "%d", &resp) == 0) {
231       fprintf(stderr, "Invalid (non-numeric) command response received\n");
232       return(-1);
233     }
234     if (resp)
235       fprintf(stderr, "Error response code %d\n", resp);
236     return(resp);
237   }
238 }
239
240 int send_line_fmt(FILE *comm, resp_type_t resp, const char *fmt, ...) {
241   char s[160];
242   va_list ap;
243
244   va_start(ap, fmt);
245   vsprintf(s, fmt, ap);
246   va_end(ap);
247   return send_line(comm, resp, s);
248 }
249
250 #define MAX_SYNC_QM_TRIES 240
251 int synchronize(FILE *comm, int crystal_freq) {
252   int n, sel;
253   char ch = '\0';
254   char sync_string[] = "Synchronized\n";
255   int sync_status = 0, sync_pos = 0, sync_len = strlen(sync_string);
256
257   printf("Synchronizing");
258   /* send '?'s and wait for response */
259   for (n = 0; n < MAX_SYNC_QM_TRIES; n++) {
260     /* if not receiving "Synchronized" response, send '?'s */
261     if (!sync_status) {
262       fputc('?', comm);
263       fflush(comm);
264     }
265
266     /* poll for input */
267     /* 0.1s is duration of 3 characters in 8N1 300b/s transfer */
268     sel = poll_input(comm, 0, 100000);
269     if (sel == -1) {
270       perror("synchronize: select");
271       return(1);
272     }
273
274     if (sel > 0) {
275       ch = fgetc(comm);
276       if (ch == sync_string[sync_pos]) {
277         if (sync_pos == 0)
278           sync_status = 1;
279         sync_pos++;
280         if (sync_pos == sync_len) {
281           printf("\n\"Synchronized\" received (recv. %d chars)\n", n);
282           break;
283         }
284       }
285       else {
286         sync_status = 0;
287         sync_pos = 0;
288       }
289     }
290     /* show progress */
291     if (!sync_status) {
292       putchar(sel ? ((ch == '?') ? '.' : 'x') : '_');
293       fflush(stdout);
294     }
295   }
296   if (n == MAX_SYNC_QM_TRIES) {
297     fprintf(stderr, "Didn't synchronize after %d tries.\n", n);
298     return(1);
299   }
300   /*
301    * here may be comm.dev mode switched back to ICANON...
302    */
303   /* respond to sync */
304   if (send_line(comm, OK_RESPONSE, "Synchronized"))
305     return(1);
306   printf("Synchronized, OK.\n");
307   /* send Xtal frequency */
308   printf("Sending crystal frequency: %d\n", crystal_freq);
309   //sprintf(s, "%d", crystal_freq);
310   if (send_line_fmt(comm, OK_RESPONSE, "%d", 7373)) //crystal_freq))
311     return 1;
312
313   return 0;
314 }
315
316 struct termios comm_attr_save;
317
318 void close_comm(FILE *comm) {
319   /* restore serial line settings */
320   tcsetattr(fileno(comm), TCSANOW, &comm_attr_save);
321   fclose(comm);
322 }
323
324 FILE *open_comm(char *device, int baudrate, int flowc) {
325   FILE *comm;
326   int comm_dev, line;
327
328   /* TODO: Open the serial line the same way as lpc21isp. It seems
329    * that loading works even if there is terminal emulator attached to
330    * the same port. */
331   if ((comm = fopen(device, "r+")) == NULL) {
332     perror("open_comm: fopen");
333     return(NULL);
334   }
335   /* set stream as unbuffered */
336   setbuf(comm, NULL);
337
338   comm_dev = fileno(comm);
339   /* backup serial line settings */
340   if (tcgetattr(comm_dev, &comm_attr_save))
341     fprintf(stderr, "Warning: open_comm: can not get serial line settings by tcgetattr");
342   /* setup serial device parameters */
343   setup_comm_dev(comm_dev, baudrate, flowc);
344
345   /* initialize serial bootloader (on miniARM_DB board) */
346   ioctl (comm_dev, TIOCMGET, &line);
347   line |= TIOCM_DTR;
348   ioctl (comm_dev, TIOCMSET, &line);
349   usleep(1000*1000);
350   line &= ~TIOCM_DTR;
351   ioctl (comm_dev, TIOCMSET, &line);
352   usleep(100*1000);
353
354   return(comm);
355 }
356
357 /* * * * */
358
359 int write_ram(FILE *comm, unsigned start, unsigned length, char *data) {
360   char s[100];
361   int i, line, line_len;
362   unsigned count = length;
363   unsigned checksum;
364
365   sprintf(s, "W %u %u", start, length);
366   if (send_line(comm, NUM_RESPONSE, s))
367     return(1);
368   while (count > 0) {
369     checksum = 0;
370     for (line = 0; (line < 20) && (count > 0); line++) {
371       line_len = (count < 45) ? count : 45;
372       for (i = 0; i < line_len; i++)
373         checksum += (unsigned char)data[i];
374       uuencode_line(s, data, line_len);
375       count -= line_len;
376       data += line_len;
377       if (send_line(comm, NO_RESPONSE, s))
378         return(1);
379     }
380     sprintf(s, "%u", checksum);
381     if (send_line(comm, OK_RESPONSE, s))
382       return(1);
383   }
384   return 0;
385 }
386
387 /* * * * */
388
389 int tolpc_send_cmd(struct tolpc_env *env, char *fmt, ...) {
390   va_list ap;
391   char s[160];
392
393   if (env->comm_stream == NULL)
394     if (tolpc_open_target(env))
395       return -1;
396
397   va_start(ap, fmt);
398   vsprintf(s, fmt, ap);
399   va_end(ap);
400
401   return send_line(env->comm_stream, NUM_RESPONSE, s);
402 }
403
404 int tolpc_readline_to(struct tolpc_env *env, char *s, int size) {
405   fgets(s, size, env->comm_stream);
406   return 0;
407 }
408
409 int tolpc_open_target(struct tolpc_env *env) {
410   FILE *comm;
411
412   comm = open_comm(env->sdev, env->baud, FLOWC_XONXOFF);
413   if (comm == NULL)
414     return -1;
415   if (synchronize(comm, env->crystal))
416     return -1;
417
418   env->comm_stream = comm;
419   return 0;
420 }
421
422 int tolpc_write_ram(struct tolpc_env *env, unsigned int start, int length, unsigned char *data) {
423   return write_ram(env->comm_stream, start, length, data);
424 }
425
426 /* * */
427
428 int tolpc_unlock(struct tolpc_env *env) {
429   int ret;
430   ret = tolpc_send_cmd(env, "U 23130");
431   return ret;
432 }
433
434 int tolpc_go(struct tolpc_env *env, unsigned int start, char arm_mode)
435 {
436     int ret;
437
438     ret = tolpc_send_cmd(env, "G %u %c", start, arm_mode ? 'A' : 'T');
439     if (ret == 2)
440     {
441         verbose(1, "Timeout means the code is executed\n");
442         ret = 0;
443     }
444     return ret;
445 }
446
447 /**
448  * Reads part ID
449  * @param env
450  * @param part_id Where to store received part id.
451  * @param size Size of part_id.
452  * @return Zero on success, -1 on error.
453  */
454 int tolpc_partid(struct tolpc_env *env, char* part_id, int size)
455 {
456     int ret;
457
458     ret = tolpc_send_cmd(env, "J");
459     if (ret) return ret;
460
461     ret = tolpc_readline_to(env, part_id, size);
462     return ret == 0 ? 0 : -1;
463 }
464
465 /**
466  * Reads boot code version
467  * @param env
468  * @param ver Where to store received version.
469  * @param size Size of ver.
470  * @return Zero on success, -1 on error.
471  */
472 int tolpc_bootver(struct tolpc_env *env, char* ver, int size)
473 {
474     int ret;
475
476     ret = tolpc_send_cmd(env, "K");
477     if (ret) return ret;
478
479     ret = tolpc_readline_to(env, ver, size);
480     return ret == 0 ? 0 : -1;
481 }
482
483 /**
484  * Sets echo mode
485  * @param env
486  * @return Zero on success, 1 on bad response, -1 on communication error.
487  */
488 int tolpc_echo(struct tolpc_env *env, char on)
489 {
490 #if 0
491     int ret;
492     ret = tolpc_send_cmd(env, "A %c", on);
493     return ret;
494 #else
495     return 0;
496 #endif
497 }
498
499 int tolpc_break(struct tolpc_env *env)
500 {
501 #if 0
502     int fd;
503     int i;
504     char c = 0;
505
506     /* Open RS232 device */
507     if ((fd = open(env->sdev, O_RDWR | O_NONBLOCK)) == -1) {
508         printf("Error openning %s\n", env->sdev);
509         return -1;
510     }
511
512     if (rs232_setmode(fd, env->baud / 2, 0) < 0) {
513         close(fd);
514         return -1;
515     }
516
517     #if DEBUG
518     printf("Sending break chars \n");
519     #endif
520
521     for (i = 100;i--;)
522         write(fd, &c, 1);
523
524     close(fd);
525 #endif
526     return 1;
527 }