1 /*********************************************************************
2  *
3  *   LPC ISP Commands
4  *
5  *
6  * Written by Nathael Pajani <nathael.pajani@nathael.net>
7  *
8  * This programm is released under the terms of the GNU GPLv3 licence
9  * as can be found on the GNU website : <http://www.gnu.org/licenses/>
10  *
11  *********************************************************************/
14 #include <stdlib.h> /* strtoul */
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <unistd.h>
18 #include <string.h> /* strncmp */
19 #include <ctype.h>
20 #include <errno.h>
22 #include <unistd.h> /* for open, close */
23 #include <fcntl.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
27 #include "isp_utils.h"
29 extern int trace_on;
32 /* Max should be 1270 for read memory, a little bit more for writes */
33 #define SERIAL_BUFSIZE  1300
34 #define REP_BUFSIZE 100
36 #define SYNCHRO_START "?"
37 #define SYNCHRO  "Synchronized\r\n"
38 #define SYNCHRO_OK "OK\r\n"
39 #define DATA_BLOCK_OK "OK\r\n"
40 #define DATA_BLOCK_RESEND "RESEND\r\n"
41 #define SYNCHRO_ECHO_OFF "A 0\r\n"
43 #define ISP_ABORT "\e"  /* Not handled */
45 #define UNLOCK "U 23130\r\n"
46 #define READ_UID "N\r\n"
47 #define READ_PART_ID "J\r\n"
48 #define READ_BOOT_VERSION "K\r\n"
50 #define LINE_DATA_LENGTH 45
51 #define LINES_PER_BLOCK 20
52 #define MAX_DATA_BLOCK_SIZE (LINES_PER_BLOCK * LINE_DATA_LENGTH) /* 900 */
53 #define MAX_BYTES_PER_LINE (1 + ((LINE_DATA_LENGTH / 3) * 4) + 2) /* "line length" (1) + 60 + \r\n */
55 #if (SERIAL_BUFSIZE < (MAX_BYTES_PER_LINE * LINES_PER_BLOCK + 10 + 2)) /* uuencoded data + checksum + \r\n */
56 #error "SERIAL_BUFSIZE too small"
57 #endif
59 /* Order in this table is important */
60 char* error_codes[] = {
61         "CMD_SUCCESS",
62         "INVALID_COMMAND",
63         "SRC_ADDR_ERROR",
64         "DST_ADDR_ERROR",
65         "SRC_ADDR_NOT_MAPPED",
66         "DST_ADDR_NOT_MAPPED",
67         "COUNT_ERROR",
68         "INVALID_SECTOR",
69         "SECTOR_NOT_BLANK",
70         "SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION",
71         "COMPARE_ERROR",
72         "BUSY",
73         "PARAM_ERROR",
74         "ADDR_ERROR",
75         "ADDR_NOT_MAPPED",
76         "CMD_LOCKED",
77         "INVALID_CODE",
78         "INVALID_BAUD_RATE",
79         "INVALID_STOP_BIT",
80         "CODE_READ_PROTECTION_ENABLED",
81 };
83 static int isp_ret_code(char* buf, char** endptr, int quiet)
84 {
85         unsigned int ret = 0;
86         ret = strtoul(buf, endptr, 10);
87         /* FIXME : Find how return code are sent (binary or ASCII) */
88         if (quiet != 1) {
89                 if (ret > (sizeof(error_codes)/sizeof(char*))) {
90                         printf("Received unknown error code '%u' !\n", ret);
91                 } else if ((ret != 0) || trace_on) {
92                         printf("Received error code '%u': %s\n", ret, error_codes[ret]);
93                 }
94         }
95         return ret;
96 }
99 /* Connect or reconnect to the target.
100  * crystal_freq is in KHz
101  * Return positive or NULL value when connection is OK, or negative value otherwise.
102  */
103 int isp_connect(unsigned int crystal_freq, int quiet)
105         char buf[REP_BUFSIZE];
106         char freq[10];
108         snprintf(freq, 8, "%d\r\n", crystal_freq);
110         /* Send synchronize request */
111         if (isp_serial_write(SYNCHRO_START, strlen(SYNCHRO_START)) != strlen(SYNCHRO_START)) {
112                 printf("Unable to send synchronize request.\n");
113                 return -5;
114         }
115         /* Wait for answer */
116         if (isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO)) < 0) {
117                 printf("Error reading synchronize answer.\n");
118                 return -4;
119         }
120         /* Check answer, and acknowledge if OK */
121         if (strncmp(SYNCHRO, buf, strlen(SYNCHRO)) == 0) {
122                 isp_serial_write(SYNCHRO, strlen(SYNCHRO));
123         } else {
124                 if (quiet != 1) {
125                         printf("Unable to synchronize, no synchro received.\n");
126                 }
127                 return -3;
128         }
129         /* Empty read buffer (echo is on) */
130         isp_serial_empty_buffer();
131         /* Read reply (OK) */
132         isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO_OK));
133         if (strncmp(SYNCHRO_OK, buf, strlen(SYNCHRO_OK)) != 0) {
134                 printf("Unable to synchronize, synchro not acknowledged.\n");
135                 return -2;
136         }
138         /* Documentation says we should send crystal frequency .. sending anything is OK */
139         isp_serial_write(freq, strlen(freq));
140         /* Empty read buffer (echo is on) */
141         isp_serial_empty_buffer();
142         /* Read reply (OK) */
143         isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO_OK));
144         if (strncmp(SYNCHRO_OK, buf, strlen(SYNCHRO_OK)) != 0) {
145                 printf("Unable to synchronize, crystal frequency not acknowledged.\n");
146                 return -2;
147         }
149         /* Turn off echo */
150         isp_serial_write(SYNCHRO_ECHO_OFF, strlen(SYNCHRO_ECHO_OFF));
151         /* Empty read buffer (echo still on) */
152         isp_serial_empty_buffer();
153         /* Read eror code for command */
154         isp_serial_read(buf, REP_BUFSIZE, 3);
156         /* Leave it even in quiet mode, so the user knows something is going on */
157         printf("Device session openned.\n");
159         return 1;
162 int isp_send_cmd_no_args(char* cmd_name, char* cmd, int quiet)
164         char buf[5];
165         int ret = 0, len = 0;
167         /* Send request */
168         if (isp_serial_write(cmd, strlen(cmd)) != (int)strlen(cmd)) {
169                 printf("Unable to send %s request.\n", cmd_name);
170                 return -5;
171         }
172         /* Wait for answer */
173         usleep( 5000 );
174         len = isp_serial_read(buf, 3, 3);
175         if (len <= 0) {
176                 printf("Error reading %s acknowledge.\n", cmd_name);
177                 return -4;
178         }
179         ret = isp_ret_code(buf, NULL, quiet);
180         return ret;
183 int isp_cmd_unlock(int quiet)
185         int ret = 0;
187         ret = isp_send_cmd_no_args("unlock", UNLOCK, quiet);
188         if (ret != 0) {
189                 printf("Unlock error.\n");
190                 return -1;
191         }
192         if (quiet == 0) {
193                 printf("Device memory protection unlocked.\n");
194         }
196         return 0;
199 int isp_cmd_read_uid(void)
201         char buf[REP_BUFSIZE];
202         char* tmp = NULL;
203         int i = 0, ret = 0, len = 0;
204         unsigned long int uid[4];
206         ret = isp_send_cmd_no_args("read-uid", READ_UID, 0);
207         if (ret != 0) {
208                 printf("Read UID error.\n");
209                 return ret;
210         }
211         len = isp_serial_read(buf, REP_BUFSIZE, 50);
212         if (len <= 0) {
213                 printf("Error reading uid.\n");
214                 return -2;
215         }
216         tmp = buf;
217         for (i=0; i<4; i++) {
218                 static char* endptr = NULL;
219                 uid[i] = strtoul(tmp, &endptr, 10);
220                 tmp = endptr;
221         }
222         printf("UID: 0x%08lx - 0x%08lx - 0x%08lx - 0x%08lx\n", uid[0], uid[1], uid[2], uid[3]);
224         return 0;
227 int isp_cmd_part_id(int quiet)
229         char buf[REP_BUFSIZE];
230         int ret = 0, len = 0;
231         unsigned long int part_id = 0;
233         ret = isp_send_cmd_no_args("read-part-id", READ_PART_ID, quiet);
234         if (ret != 0) {
235                 if (quiet != 1) {
236                         printf("Read part ID error.\n");
237                 }
238                 return ret;
239         }
240         len = isp_serial_read(buf, REP_BUFSIZE, 15);
241         if (len <= 0) {
242                 printf("Error reading part ID.\n");
243                 return -2;
244         }
245         /* FIXME : some part IDs are on two 32bits values */
246         part_id = strtoul(buf, NULL, 10);
247         if (quiet == 0) {
248                 printf("Part ID is 0x%08lx\n", part_id);
249         }
251         return part_id;
254 int isp_cmd_boot_version(void)
256         char buf[REP_BUFSIZE];
257         int ret = 0, len = 0;
258         char* tmp = NULL;
259         unsigned int ver[2];
261         ret = isp_send_cmd_no_args("read-boot-version", READ_BOOT_VERSION, 0);
262         if (ret != 0) {
263                 printf("Read boot version error.\n");
264                 return ret;
265         }
266         len = isp_serial_read(buf, REP_BUFSIZE, 20);
267         if (len <= 0) {
268                 printf("Error reading boot version.\n");
269                 return -2;
270         }
271         ver[0] = strtoul(buf, &tmp, 10);
272         ver[1] = strtoul(tmp, NULL, 10);
273         printf("Boot code version is %u.%u\n", ver[1], ver[0]);
275         return 0;
278 int isp_send_cmd_two_args(char* cmd_name, char cmd, unsigned int arg1, unsigned int arg2)
280         char buf[REP_BUFSIZE];
281         int ret = 0, len = 0;
283         /* Create read-memory request */
284         len = snprintf(buf, REP_BUFSIZE, "%c %u %u\r\n", cmd, arg1, arg2);
285         if (len > REP_BUFSIZE) {
286                 len = REP_BUFSIZE; /* This should not happen if REP_BUFSIZE is 32 or more ... */
287         }
289         /* Send request */
290         if (isp_serial_write(buf, len) != len) {
291                 printf("Unable to send %s request.\n", cmd_name);
292                 return -5;
293         }
294         /* Wait for answer */
295         usleep( 5000 );
296         len = isp_serial_read(buf, 3, 3);
297         if (len <= 0) {
298                 printf("Error reading %s acknowledge.\n", cmd_name);
299                 return -4;
300         }
301         ret = isp_ret_code(buf, NULL, 0);
302         return ret;
305 static int get_remaining_blocksize(unsigned int count, unsigned int actual_count, char* dir, unsigned int i)
307         unsigned int blocksize = 0;
308         unsigned int remain = count - actual_count;
310         if (remain >= MAX_DATA_BLOCK_SIZE) {
311                 blocksize = (MAX_BYTES_PER_LINE * LINES_PER_BLOCK);
312                 if (trace_on) {
313                         printf("%s block %d (%d line(s)).\n", dir, i, LINES_PER_BLOCK);
314                 }
315         } else {
316                 unsigned int nb_last_lines = (remain / LINE_DATA_LENGTH);
317                 if (remain % LINE_DATA_LENGTH) {
318                         nb_last_lines += 1;
319                 }
320                 /* 4 bytes transmitted for each 3 data bytes */
321                 blocksize = ((remain / 3) * 4);
322                 if (remain % 3) {
323                         blocksize += 4;
324                 }
325                 /* Add one byte per line for the starting "length character" and two bytes per
326                  * line for the ending "\r\n" */
327                 blocksize += (3 * nb_last_lines);
328                 if (trace_on) {
329                         printf("%s block %d of size %u (%d line(s)).\n", dir, i, blocksize, nb_last_lines);
330                 }
331         }
332         return blocksize;
335 /* Compute the number of blocks of the transmitted data. */
336 static int get_nb_blocks(unsigned int count, char* dir)
338         unsigned int lines = 0;
339         unsigned int blocks = 0;
341         /* See section 21.4.3 of LPC11xx user's manual (UM10398) */
342         lines = (count / LINE_DATA_LENGTH);
343         if (count % LINE_DATA_LENGTH) {
344                 lines += 1;
345         }
346         blocks = (lines / LINES_PER_BLOCK);
347         if (lines % LINES_PER_BLOCK) {
348                 blocks += 1;
349         }
350         if (trace_on) {
351                 printf("%s %d block(s) (%d line(s)).\n", dir, blocks, lines);
352         }
354         return blocks;
357 static unsigned int calc_checksum(unsigned char* data, unsigned int size)
359         unsigned int i = 0;
360         unsigned int checksum = 0;
362         for (i=0; i<size; i++) {
363                 checksum += data[i];
364         }
365         return checksum;
368 /*
369  * perform read-memory operation
370  * read 'count' bytes from 'addr' to 'data' buffer
371  */
372 int isp_read_memory(char* data, uint32_t addr, unsigned int count)
374         /* Serial communication */
375         char buf[SERIAL_BUFSIZE];
376         int ret = 0, len = 0;
377         /* Reply handling */
378         unsigned int blocks = 0;
379         unsigned int total_bytes_received = 0; /* actual count of bytes received */
380         unsigned int i = 0;
382         /* Send command */
383         ret = isp_send_cmd_two_args("read-memory", 'R', addr, count);
384         if (ret != 0) {
385                 printf("Error when trying to read %u bytes of memory at address 0x%08x.\n", count, addr);
386                 return ret;
387         }
389         /* Now, find the number of blocks of the reply. */
390         blocks = get_nb_blocks(count, "Reading");
392         /* Receive and decode the data */
393         for (i=0; i<blocks; i++) {
394                 unsigned int blocksize = 0, decoded_size = 0;
395                 unsigned int received_checksum = 0, computed_checksum = 0;
396                 static int resend_request_for_block = 0;
398                 /* First compute the next block size */
399                 blocksize = get_remaining_blocksize(count, total_bytes_received, "Reading", i);
400                 /* Read the uuencoded data */
401                 len = isp_serial_read(buf, SERIAL_BUFSIZE, blocksize);
402                 if (len <= 0) {
403                         printf("Error reading memory.\n");
404                         ret = -6;
405                         break;
406                 }
407                 usleep( 1000 );
408                 /* Now read the checksum, maybe not yet received */
409                 len += isp_serial_read((buf + len), (SERIAL_BUFSIZE - len), ((len > (int)blocksize) ? 0 : 3));
410                 if (len < 0) { /* Length may be null, as we may already have received everything */
411                         printf("Error reading memory (checksum part).\n");
412                         ret = -5;
413                         break;
414                 }
415                 /* Decode. This must be done before sending acknowledge because we must
416                  * compute the checksum */
417                 decoded_size = isp_uu_decode((data + total_bytes_received), buf, blocksize);
418                 received_checksum = strtoul((buf + blocksize), NULL, 10);
419                 computed_checksum = calc_checksum((unsigned char*)(data + total_bytes_received), decoded_size);
420                 if (trace_on) {
421                         printf("Decoded Data :\n");
422                         isp_dump((unsigned char*)(data + total_bytes_received), decoded_size);
423                 }
424                 if (computed_checksum == received_checksum) {
425                         resend_request_for_block = 0; /* reset resend request counter */
426                         if (trace_on) {
427                                 printf("Reading of blocks %u OK, contained %u bytes\n", i, decoded_size);
428                         }
429                         /* Acknowledge data */
430                         if (isp_serial_write(DATA_BLOCK_OK, strlen(DATA_BLOCK_OK)) != strlen(DATA_BLOCK_OK)) {
431                                 printf("Unable to send acknowledge.\n");
432                                 ret = -4;
433                                 break;
434                         }
435                         /* Add data length to sum of received data */
436                         total_bytes_received += decoded_size;
437                 } else {
438                         resend_request_for_block++;
439                         if (trace_on) {
440                                 printf("Checksum error for block %u (received %u, computed %u) error number: %d.\n",
441                                                 i, received_checksum, computed_checksum, resend_request_for_block);
442                         }
443                         if (resend_request_for_block > 3) {
444                                 printf("Block %d still wrong after 3 attempts, aborting.\n", i);
445                                 ret = -2;
446                                 break;
447                         }
448                         /* Back to previous block */
449                         i--;
450                         /* Ask for resend */
451                         if (isp_serial_write(DATA_BLOCK_RESEND, strlen(DATA_BLOCK_RESEND)) != strlen(DATA_BLOCK_RESEND)) {
452                                 printf("Unable to send resend request.\n");
453                                 ret = -1;
454                                 break;
455                         }
456                 }
457         }
459         return total_bytes_received;
463 /*
464  * perform write-to-ram operation
465  * send 'count' bytes from 'data' to 'addr' in RAM
466  */
467 int isp_send_buf_to_ram(char* data, unsigned long int addr, unsigned int count, unsigned int perform_uuencode)
469         /* Serial communication */
470         int ret = 0, len = 0;
471         /* Reply handling */
472         unsigned int blocks = 0;
473         unsigned int total_bytes_sent = 0;
474         unsigned int i = 0;
476         /* Send write-to-ram request */
477         ret = isp_send_cmd_two_args("write-to-ram", 'W', addr, count);
478         if (ret != 0) {
479                 printf("Error when trying to start write procedure to address 0x%08lx.\n", addr);
480                 return -8;
481         }
483         /* Now, find the number of blocks of data to send. */
484         blocks = get_nb_blocks(count, "Sending");
486         /* Encode and send the data */
487         for (i=0; i<blocks; i++) {
488                 char buf[SERIAL_BUFSIZE]; /* Store encoded data, to be sent to the microcontroller */
489                 char repbuf[REP_BUFSIZE];
490                 unsigned int datasize = 0, encoded_size = 0;
491                 unsigned int computed_checksum = 0;
492                 static int resend_requested_for_block = 0;
494                 /* First compute the next block size */
495                 datasize = (count - total_bytes_sent);
496                 if (datasize >= MAX_DATA_BLOCK_SIZE) {
497                         datasize = MAX_DATA_BLOCK_SIZE;
498                 }
499                 if (perform_uuencode == 0) {
500                         if (isp_serial_write(data + total_bytes_sent, datasize) != (int)datasize) {
501                                 printf("Error sending raw binary data.\n");
502                                 ret = -7;
503                                 break;
504                         } else {
505                                 /* No checks required */
506                                 return ret;
507                         }
508                 }
510                 /* uuencode data */
511                 encoded_size = isp_uu_encode(buf, data + total_bytes_sent, datasize);
512                 /* Add checksum */
513                 computed_checksum = calc_checksum((unsigned char*)(data + total_bytes_sent), datasize);
514                 encoded_size += snprintf((buf + encoded_size), 12, "%u\r\n", computed_checksum);
515                 if (trace_on) {
516                         printf("Encoded Data :\n");
517                         isp_dump((unsigned char*)buf, encoded_size);
518                 }
519                 if (isp_serial_write(buf, encoded_size) != (int)encoded_size) {
520                         printf("Error sending uuencoded data.\n");
521                         ret = -6;
522                         break;
523                 }
525                 usleep( 20000 );
526                 len = isp_serial_read(repbuf, REP_BUFSIZE, 4);
527                 if (len <= 0) {
528                         printf("Error reading write acknowledge.\n");
529                         return -5;
530                 }
531                 if (strncmp(DATA_BLOCK_OK, repbuf, strlen(DATA_BLOCK_OK)) == 0) {
532                         total_bytes_sent += datasize;
533                         resend_requested_for_block = 0; /* reset resend request counter */
534                         if (trace_on) {
535                                 printf("Block %d sent.\n", i);
536                         }
537                 } else {
538                         resend_requested_for_block++;
539                         if (trace_on) {
540                                 printf("Checksum error for block %u, error number: %d.\n", i, resend_requested_for_block);
541                         }
542                         if (resend_requested_for_block >= 3) {
543                                 printf("Block %d still wrong after 3 attempts, aborting.\n", i);
544                                 ret = -2;
545                                 break;
546                         }
547                         /* Back to previous block */
548                         i--;
549                 }
550         }
552         return ret;
556 int isp_send_cmd_address(char cmd, uint32_t addr1, uint32_t addr2, uint32_t length, char* name)
558         char buf[SERIAL_BUFSIZE];
559         int ret = 0, len = 0;
560         char* tmp = NULL;
562         /* Create request */
563         len = snprintf(buf, SERIAL_BUFSIZE, "%c %u %u %u\r\n", cmd, addr1, addr2, length);
564         if (len > SERIAL_BUFSIZE) {
565                 len = SERIAL_BUFSIZE;
566         }
568         /* Send request */
569         if (isp_serial_write(buf, len) != len) {
570                 printf("Unable to send %s request.\n", name);
571                 return -5;
572         }
573         /* Wait for answer */
574         usleep( 5000 );
575         len = isp_serial_read(buf, 3, 3);
576         if (len <= 0) {
577                 printf("Error reading %s result.\n", name);
578                 return -4;
579         }
580         ret = isp_ret_code(buf, &tmp, 0);
581         return ret;
585 int isp_send_cmd_go(uint32_t addr, char mode)
587         char buf[SERIAL_BUFSIZE];
588         int ret = 0, len = 0;
590         if (addr < 0x200) {
591                 printf("Error: address must be 0x00000200 or greater for go command.\n");
592                 return -6;
593         }
594         if ((mode != 'T') && (mode != 'A')) {
595                 printf("Error: mode must be 'thumb' (T) or 'arm' (A) for go command.\n");
596                 return -5;
597         }
599         /* Create go request */
600         len = snprintf(buf, SERIAL_BUFSIZE, "G %u %c\r\n", addr, mode);
601         if (len > SERIAL_BUFSIZE) {
602                 len = SERIAL_BUFSIZE;
603         }
605         /* Send go request */
606         if (isp_serial_write(buf, len) != len) {
607                 printf("Unable to send go request.\n");
608                 return -4;
609         }
610         /* Wait for answer */
611         usleep( 5000 );
612         len = isp_serial_read(buf, SERIAL_BUFSIZE, 3);
613         if (len <= 0) {
614                 printf("Error reading go result.\n");
615                 return -3;
616         }
617         ret = isp_ret_code(buf, NULL, 0);
618         if (ret != 0) {
619                 printf("Error when trying to execute programm at 0x%08x in '%c' mode.\n", addr, mode);
620                 return -1;
621         }
623         return 0;
626 int isp_send_cmd_sectors(char* name, char cmd, int first_sector, int last_sector, int quiet)
628         char buf[SERIAL_BUFSIZE];
629         int ret = 0, len = 0;
631         if (last_sector < first_sector) {
632                 printf("Last sector must be after (or equal to) first sector for %s command.\n", name);
633                 return -6;
634         }
636         /* Create request */
637         len = snprintf(buf, SERIAL_BUFSIZE, "%c %u %u\r\n", cmd, first_sector, last_sector);
638         if (len > SERIAL_BUFSIZE) {
639                 len = SERIAL_BUFSIZE;
640         }
641         /* Send request */
642         if (isp_serial_write(buf, len) != len) {
643                 printf("Unable to send %s request.\n", name);
644                 return -5;
645         }
646         /* Wait for answer */
647         usleep( 5000 );
648         len = isp_serial_read(buf, 3, 3); /* Read at exactly 3 bytes, so caller can retreive info */
649         if (len <= 0) {
650                 printf("Error reading %s result.\n", name);
651                 return -4;
652         }
653         ret = isp_ret_code(buf, NULL, quiet);
655         return ret;