Adding file with commands for non-regretion testing.
[lpctools] / isp_commands.c
1 /*********************************************************************
2  *
3  *   LPC1114 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;
31 struct isp_command {
32         char* name;
33         int nb_args;
34         int (*handler)(int arg_count, char** args);
35 };
38 /* Max should be 1270 for read memory, a little bit more for writes */
39 #define SERIAL_BUFSIZE  1300
40 #define REP_BUFSIZE 100
42 #define SYNCHRO_START "?"
43 #define SYNCHRO  "Synchronized\r\n"
44 #define SYNCHRO_OK "OK\r\n"
45 #define DATA_BLOCK_OK "OK\r\n"
46 #define DATA_BLOCK_RESEND "RESEND\r\n"
47 #define SYNCHRO_ECHO_OFF "A 0\r\n"
49 #define ISP_ABORT "\e"  /* Not handled */
51 #define UNLOCK "U 23130\r\n"
52 #define READ_UID "N\r\n"
53 #define READ_PART_ID "J\r\n"
54 #define READ_BOOT_VERSION "K\r\n"
56 #define LINE_DATA_LENGTH 45
57 #define LINES_PER_BLOCK 20
58 #define MAX_DATA_BLOCK_SIZE (LINES_PER_BLOCK * LINE_DATA_LENGTH) /* 900 */
59 #define MAX_BYTES_PER_LINE (1 + ((LINE_DATA_LENGTH / 3) * 4) + 2) /* "line length" (1) + 60 + \r\n */
60 #define FILE_CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP)
62 #if (SERIAL_BUFSIZE < (MAX_BYTES_PER_LINE * LINES_PER_BLOCK + 10 + 2)) /* uuencoded data + checksum + \r\n */
63 #error "SERIAL_BUFSIZE too small"
64 #endif
66 #define RAM_MAX_SIZE (8 * 1024) /* 8 KB */
68 char* error_codes[] = {
69 #define CMD_SUCCESS 0
70         "CMD_SUCCESS",
71 #define INVALID_COMMAND 1
72         "INVALID_COMMAND",
73 #define SRC_ADDR_ERROR 2
74         "SRC_ADDR_ERROR",
75 #define DST_ADDR_ERROR 3
76         "DST_ADDR_ERROR",
77 #define SRC_ADDR_NOT_MAPPED 4
78         "SRC_ADDR_NOT_MAPPED",
79 #define DST_ADDR_NOT_MAPPED 5
80         "DST_ADDR_NOT_MAPPED",
81 #define COUNT_ERROR 6
82         "COUNT_ERROR",
83 #define INVALID_SECTOR 7
84         "INVALID_SECTOR",
85 #define SECTOR_NOT_BLANK 8
86         "SECTOR_NOT_BLANK",
87 #define SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 9
88         "SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION",
89 #define COMPARE_ERROR 10
90         "COMPARE_ERROR",
91 #define BUSY 11
92         "BUSY",
93 #define PARAM_ERROR 12
94         "PARAM_ERROR",
95 #define ADDR_ERROR 13
96         "ADDR_ERROR",
97 #define ADDR_NOT_MAPPED 14
98         "ADDR_NOT_MAPPED",
99 #define CMD_LOCKED 15
100         "CMD_LOCKED",
101 #define INVALID_CODE 16
102         "INVALID_CODE",
103 #define INVALID_BAUD_RATE 17
104         "INVALID_BAUD_RATE",
105 #define INVALID_STOP_BIT 18
106         "INVALID_STOP_BIT",
107 #define CODE_READ_PROTECTION_ENABLED 19
108         "CODE_READ_PROTECTION_ENABLED",
109 };
111 int isp_ret_code(char* buf, char** endptr)
113         unsigned int ret = 0;
114         ret = strtoul(buf, endptr, 10);
115         /* FIXME : Find how return code are sent (binary or ASCII) */
116         if (ret > (sizeof(error_codes)/sizeof(char*))) {
117                 printf("Received unknown error code '%u' !\n", ret);
118         } else if ((ret != 0) || trace_on) {
119                 printf("Received error code '%u': %s\n", ret, error_codes[ret]);
120         }
121         return ret;
125 /* Connect or reconnect to the target.
126  * Return positive or NULL value when connection is OK, or negative value otherwise.
127  */
128 int isp_connect(unsigned int crystal_freq)
130         char buf[REP_BUFSIZE];
131         char freq[10];
132         
133         snprintf(freq, 8, "%d\r\n", crystal_freq);
135         /* Send synchronize request */
136         if (isp_serial_write(SYNCHRO_START, strlen(SYNCHRO_START)) != strlen(SYNCHRO_START)) {
137                 printf("Unable to send synchronize request.\n");
138                 return -5;
139         }
140         /* Wait for answer */
141         if (isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO)) < 0) {
142                 printf("Error reading synchronize answer.\n");
143                 return -4;
144         }
145         /* Check answer, and acknowledge if OK */
146         if (strncmp(SYNCHRO, buf, strlen(SYNCHRO)) == 0) {
147                 isp_serial_write(SYNCHRO, strlen(SYNCHRO));
148         } else {
149                 printf("Unable to synchronize, no synchro received.\n");
150                 return -3;
151         }
152         /* Empty read buffer (echo is on) */
153         isp_serial_read(buf, strlen(SYNCHRO), strlen(SYNCHRO));
154         /* Read reply (OK) */
155         isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO_OK));
156         if (strncmp(SYNCHRO_OK, buf, strlen(SYNCHRO_OK)) != 0) {
157                 printf("Unable to synchronize, synchro not acknowledged.\n");
158                 return -2;
159         }
161         /* Documentation says we should send crystal frequency .. sending anything is OK */
162         isp_serial_write(freq, strlen(freq));
163         /* Empty read buffer (echo is on) */
164         isp_serial_read(buf, strlen(freq), strlen(freq));
165         /* Read reply (OK) */
166         isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO_OK));
167         if (strncmp(SYNCHRO_OK, buf, strlen(SYNCHRO_OK)) != 0) {
168                 printf("Unable to synchronize, crystal frequency not acknowledged.\n");
169                 return -2;
170         }
172         /* Turn off echo */
173         isp_serial_write(SYNCHRO_ECHO_OFF, strlen(SYNCHRO_ECHO_OFF));
174         /* Empty read buffer (echo still on) */
175         isp_serial_read(buf, strlen(SYNCHRO_ECHO_OFF), strlen(SYNCHRO_ECHO_OFF));
176         /* Read eror code for command */
177         isp_serial_read(buf, REP_BUFSIZE, 3);
179         printf("Device session openned.\n");
181         return 1;
184 int isp_send_cmd_no_args(char* cmd_name, char* cmd)
186         char buf[5];
187         int ret = 0, len = 0;
188         
189         /* Send request */
190         if (isp_serial_write(cmd, strlen(cmd)) != (int)strlen(cmd)) {
191                 printf("Unable to send %s request.\n", cmd_name);
192                 return -5;
193         }
194         /* Wait for answer */
195         usleep( 5000 );
196         len = isp_serial_read(buf, 3, 3);
197         if (len <= 0) {
198                 printf("Error reading %s acknowledge.\n", cmd_name);
199                 return -4;
200         }
201         ret = isp_ret_code(buf, NULL);
202         return ret;
205 int isp_cmd_unlock(int arg_count, char** args)
207         int ret = 0;
209         ret = isp_send_cmd_no_args("unlock", UNLOCK);
210         if (ret != 0) {
211                 printf("Unlock error.\n");
212                 return -1;
213         }
214         printf("Device memory protection unlocked.\n");
216         return 0;
219 int isp_cmd_read_uid(int arg_count, char** args)
221         char buf[REP_BUFSIZE];
222         char* tmp = NULL;
223         int i = 0, ret = 0, len = 0;
224         unsigned long int uid[4];
225         
226         ret = isp_send_cmd_no_args("read-uid", READ_UID);
227         if (ret != 0) {
228                 printf("Read UID error.\n");
229                 return ret;
230         }
231         len = isp_serial_read(buf, REP_BUFSIZE, 50);
232         if (len <= 0) {
233                 printf("Error reading uid.\n");
234                 return -2;
235         }
236         tmp = buf;
237         for (i=0; i<4; i++) {
238                 static char* endptr = NULL;
239                 uid[i] = strtoul(tmp, &endptr, 10);
240                 tmp = endptr;
241         }
242         printf("UID: 0x%08lx - 0x%08lx - 0x%08lx - 0x%08lx\n", uid[0], uid[1], uid[2], uid[3]);
244         return 0;
247 int isp_cmd_part_id(int arg_count, char** args)
249         char buf[REP_BUFSIZE];
250         int ret = 0, len = 0;
251         unsigned long int part_id = 0;
253         ret = isp_send_cmd_no_args("read-part-id", READ_PART_ID);
254         if (ret != 0) {
255                 printf("Read part ID error.\n");
256                 return ret;
257         }
258         len = isp_serial_read(buf, REP_BUFSIZE, 15);
259         if (len <= 0) {
260                 printf("Error reading part ID.\n");
261                 return -2;
262         }
263         /* FIXME : some part IDs are on two 32bits values */
264         part_id = strtoul(buf, NULL, 10);
265         printf("Part ID is 0x%08lx\n", part_id);
267         return 0;
270 int isp_cmd_boot_version(int arg_count, char** args)
272         char buf[REP_BUFSIZE];
273         int ret = 0, len = 0;
274         char* tmp = NULL;
275         unsigned int ver[2];
277         ret = isp_send_cmd_no_args("read-boot-version", READ_BOOT_VERSION);
278         if (ret != 0) {
279                 printf("Read boot version error.\n");
280                 return ret;
281         }
282         len = isp_serial_read(buf, REP_BUFSIZE, 20);
283         if (len <= 0) {
284                 printf("Error reading boot version.\n");
285                 return -2;
286         }
287         ver[0] = strtoul(buf, &tmp, 10);
288         ver[1] = strtoul(tmp, NULL, 10);
289         printf("Boot code version is %u.%u\n", ver[0], ver[1]);
291         return 0;
294 int isp_send_cmd_two_args(char* cmd_name, char cmd, unsigned int arg1, unsigned int arg2)
296         char buf[REP_BUFSIZE];
297         int ret = 0, len = 0;
299         /* Create read-memory request */
300         len = snprintf(buf, REP_BUFSIZE, "%c %u %u\r\n", cmd, arg1, arg2);
301         if (len > REP_BUFSIZE) {
302                 len = REP_BUFSIZE; /* This should not happen if REP_BUFSIZE is 32 or more ... */
303         }
305         /* Send request */
306         if (isp_serial_write(buf, len) != len) {
307                 printf("Unable to send %s request.\n", cmd_name);
308                 return -5;
309         }
310         /* Wait for answer */
311         usleep( 5000 );
312         len = isp_serial_read(buf, 3, 3);
313         if (len <= 0) {
314                 printf("Error reading %s acknowledge.\n", cmd_name);
315                 return -4;
316         }
317         ret = isp_ret_code(buf, NULL);
318         return ret;
321 int get_remaining_blocksize(unsigned int count, unsigned int actual_count, char* dir, unsigned int i)
323         unsigned int blocksize = 0;
324         unsigned int remain = count - actual_count;
326         if (remain >= MAX_DATA_BLOCK_SIZE) {
327                 blocksize = (MAX_BYTES_PER_LINE * LINES_PER_BLOCK);
328                 if (trace_on) {
329                         printf("%s block %d (%d line(s)).\n", dir, i, LINES_PER_BLOCK);
330                 }
331         } else {
332                 unsigned int nb_last_lines = (remain / LINE_DATA_LENGTH);
333                 if (remain % LINE_DATA_LENGTH) {
334                         nb_last_lines += 1;
335                 }
336                 /* 4 bytes transmitted for each 3 data bytes */
337                 blocksize = ((remain / 3) * 4);
338                 if (remain % 3) {
339                         blocksize += 4;
340                 }
341                 /* Add one byte per line for the starting "length character" and two bytes per
342                  * line for the ending "\r\n" */
343                 blocksize += (3 * nb_last_lines);
344                 if (trace_on) {
345                         printf("%s block %d of size %u (%d line(s)).\n", dir, i, blocksize, nb_last_lines);
346                 }
347         }
348         return blocksize;
351 /* Compute the number of blocks of the transmitted data. */
352 int get_nb_blocks(unsigned int count, char* dir)
354         unsigned int lines = 0;
355         unsigned int blocks = 0;
357         /* See section 21.4.3 of LPC11xx user's manual (UM10398) */
358         lines = (count / LINE_DATA_LENGTH);
359         if (count % LINE_DATA_LENGTH) {
360                 lines += 1;
361         }
362         blocks = (lines / LINES_PER_BLOCK);
363         if (lines % LINES_PER_BLOCK) {
364                 blocks += 1;
365         }
366         if (trace_on) {
367                 printf("%s %d block(s) (%d line(s)).\n", dir, blocks, lines);
368         }
370         return blocks;
373 unsigned int calc_checksum(unsigned char* data, unsigned int size)
375         unsigned int i = 0;
376         unsigned int checksum = 0;
378         for (i=0; i<size; i++) {
379                 checksum += data[i];
380         }
381         return checksum;
384 int isp_cmd_read_memory(int arg_count, char** args)
386         /* Serial communication */
387         char buf[SERIAL_BUFSIZE];
388         int ret = 0, len = 0;
389         /* Arguments */
390         unsigned long int addr = 0, count = 0;
391         char* out_file_name = NULL;
392         int out_fd = -1;
393         /* Reply handling */
394         unsigned int blocks = 0;
395         unsigned int total_bytes_received = 0; /* actual count of bytes received */
396         unsigned int i = 0;
398         /* Check read-memory arguments */
399         if (arg_count != 3) {
400                 printf("read-memory command needs address and count. Both must be multiple of 4.\n");
401                 return -12;
402         }
403         addr = strtoul(args[0], NULL, 0);
404         count = strtoul(args[1], NULL, 0);
405         if (trace_on) {
406                 printf("read-memory command called for 0x%08lx (%lu) bytes at address 0x%08lx.\n",
407                                 count, count, addr);
408         }
409         if ((addr & 0x03) || (count & 0x03)) {
410                 printf("Address and count must be multiple of 4 for read-memory command.\n");
411                 return -11;
412         }
413         out_file_name = args[2];
414         
415         /* Send command */
416         ret = isp_send_cmd_two_args("read-memory", 'R', addr, count);
417         if (ret != 0) {
418                 printf("Error when trying to read %lu bytes of memory at address 0x%08lx.\n", count, addr);
419                 return ret;
420         }
422         /* Now, find the number of blocks of the reply. */
423         blocks = get_nb_blocks(count, "Reading");
425         /* Open file for writing if output is not stdout */
426         if (strncmp(out_file_name, "-", strlen(out_file_name)) == 0) {
427                 out_fd = STDOUT_FILENO;
428         } else {
429                 out_fd = open(out_file_name, (O_WRONLY | O_CREAT | O_TRUNC), FILE_CREATE_MODE);
430                 if (out_fd <= 0) {
431                         perror("Unable to open or create file for writing");
432                         printf("Tried to open \"%s\".\n", out_file_name);
433                         return -7;
434                 }
435         }
436         
437         /* Receive and decode the data */
438         /* FIXME : Factorize ? */
439         for (i=0; i<blocks; i++) {
440                 char data[SERIAL_BUFSIZE];
441                 unsigned int blocksize = 0, decoded_size = 0;
442                 unsigned int received_checksum = 0, computed_checksum = 0;
443                 static int resend_request_for_block = 0;
445                 /* First compute the next block size */
446                 blocksize = get_remaining_blocksize(count, total_bytes_received, "Reading", i);
447                 /* Read the uuencoded data */
448                 len = isp_serial_read(buf, SERIAL_BUFSIZE, blocksize);
449                 if (len <= 0) {
450                         printf("Error reading memory.\n");
451                         ret = -6;
452                         break;
453                 }
454                 usleep( 1000 );
455                 /* Now read the checksum, maybe not yet received */
456                 len += isp_serial_read((buf + len), (SERIAL_BUFSIZE - len), ((len > (int)blocksize) ? 0 : 3));
457                 if (len < 0) { /* Length may be null, as we may already have received everything */
458                         printf("Error reading memory (checksum part).\n");
459                         ret = -5;
460                         break;
461                 }
462                 /* Decode. This must be done before sending acknowledge because we must
463                  * compute the checksum */
464                 decoded_size = isp_uu_decode(data, buf, blocksize);
465                 received_checksum = strtoul((buf + blocksize), NULL, 10);
466                 computed_checksum = calc_checksum((unsigned char*)data, decoded_size);
467                 if (trace_on) {
468                         printf("Decoded Data :\n");
469                         isp_dump((unsigned char*)data, decoded_size);
470                 }
471                 if (computed_checksum == received_checksum) {
472                         resend_request_for_block = 0; /* reset resend request counter */
473                         if (trace_on) {
474                                 printf("Reading of blocks %u OK, contained %u bytes\n", i, decoded_size);
475                         }
476                         /* Acknowledge data */
477                         if (isp_serial_write(DATA_BLOCK_OK, strlen(DATA_BLOCK_OK)) != strlen(DATA_BLOCK_OK)) {
478                                 printf("Unable to send acknowledge.\n");
479                                 ret = -4;
480                                 break;
481                         }
482                         /* Add data length to sum of received data */
483                         total_bytes_received += decoded_size;
484                         /* Write data to file */
485                         ret = write(out_fd, data, decoded_size);
486                         if (ret != (int)decoded_size) {
487                                 perror("File write error");
488                                 printf("Unable to write %u bytes of data to file \"%s\", returned %d !",
489                                                 decoded_size, out_file_name, ret);
490                                 ret = -3;
491                                 break;
492                         }
493                 } else {
494                         resend_request_for_block++;
495                         if (trace_on) {
496                                 printf("Checksum error for block %u (received %u, computed %u) error number: %d.\n",
497                                                 i, received_checksum, computed_checksum, resend_request_for_block);
498                         }
499                         if (resend_request_for_block > 3) {
500                                 printf("Block %d still wrong after 3 attempts, aborting.\n", i);
501                                 ret = -2;
502                                 break;
503                         }
504                         /* Back to previous block */
505                         i--;
506                         /* Ask for resend */
507                         if (isp_serial_write(DATA_BLOCK_RESEND, strlen(DATA_BLOCK_RESEND)) != strlen(DATA_BLOCK_RESEND)) {
508                                 printf("Unable to send resend request.\n");
509                                 ret = -1;
510                                 break;
511                         }
512                 }
513         }
514         /* Close file */
515         if (out_fd != STDOUT_FILENO) {
516                 close(out_fd);
517         }
519         return ret;
522 int isp_send_buf_to_ram(char* data, unsigned long int addr, unsigned int count)
524         /* Serial communication */
525         int ret = 0, len = 0;
526         /* Reply handling */
527         unsigned int blocks = 0;
528         unsigned int total_bytes_sent = 0;
529         unsigned int i = 0;
531         /* Send write-to-ram request */
532         ret = isp_send_cmd_two_args("write-to-ram", 'W', addr, count);
533         if (ret != 0) {
534                 printf("Error when trying to start write procedure to address 0x%08lx.\n", addr);
535                 return -8;
536         }
538         /* Now, find the number of blocks of data to send. */
539         blocks = get_nb_blocks(count, "Sending");
540         
541         /* Encode and send the data */
542         for (i=0; i<blocks; i++) {
543                 char buf[SERIAL_BUFSIZE]; /* Store encoded data, to be sent to the microcontroller */
544                 char repbuf[REP_BUFSIZE];
545                 unsigned int datasize = 0, encoded_size = 0;
546                 unsigned int computed_checksum = 0;
547                 static int resend_requested_for_block = 0;
549                 /* First compute the next block size */
550                 datasize = (count - total_bytes_sent);
551                 if (datasize >= MAX_DATA_BLOCK_SIZE) {
552                         datasize = MAX_DATA_BLOCK_SIZE;
553                 }
554                 /* uuencode data */
555                 encoded_size = isp_uu_encode(buf, data + total_bytes_sent, datasize);
556                 /* Add checksum */
557                 computed_checksum = calc_checksum((unsigned char*)(data + total_bytes_sent), datasize);
558                 encoded_size += snprintf((buf + encoded_size), 12, "%u\r\n", computed_checksum);
559                 if (trace_on) {
560                         printf("Encoded Data :\n");
561                         isp_dump((unsigned char*)buf, encoded_size);
562                 }
564                 if (isp_serial_write(buf, encoded_size) != (int)encoded_size) {
565                         printf("Error sending uuencoded data.\n");
566                         ret = -6;
567                         break;
568                 }
569                 usleep( 20000 );
570                 len = isp_serial_read(repbuf, REP_BUFSIZE, 4);
571                 if (len <= 0) {
572                         printf("Error reading write acknowledge.\n");
573                         return -5;
574                 }
575                 if (strncmp(DATA_BLOCK_OK, repbuf, strlen(DATA_BLOCK_OK)) == 0) {
576                         total_bytes_sent += datasize;
577                         resend_requested_for_block = 0; /* reset resend request counter */
578                         if (trace_on) {
579                                 printf("Block %d sent.\n", i);
580                         }
581                 } else {
582                         resend_requested_for_block++;
583                         if (trace_on) {
584                                 printf("Checksum error for block %u, error number: %d.\n", i, resend_requested_for_block);
585                         }
586                         if (resend_requested_for_block >= 3) {
587                                 printf("Block %d still wrong after 3 attempts, aborting.\n", i);
588                                 ret = -2;
589                                 break;
590                         }
591                         /* Back to previous block */
592                         i--;
593                 }
594         }
596         return ret;
599 int isp_cmd_write_to_ram(int arg_count, char** args)
601         /* Arguments */
602         unsigned long int addr = 0;
603         char* in_file_name = NULL;
604         int in_fd = -1;
605         char file_buff[RAM_MAX_SIZE];
606         unsigned int bytes_read = 0;
607         int ret = 0;
609         /* Check write-to-ram arguments */
610         if (arg_count != 2) {
611                 printf("write-to-ram command needs ram address. Must be multiple of 4.\n");
612                 return -15;
613         }
614         addr = strtoul(args[0], NULL, 0);
615         if (trace_on) {
616                 printf("write-to-ram command called, destination address in ram is 0x%08lx.\n", addr);
617         }
618         if (addr & 0x03) {
619                 printf("Address must be multiple of 4 for write-to-ram command.\n");
620                 return -14;
621         }
622         in_file_name = args[1];
624         /* Open file for reading if input is not stdin */
625         if (strncmp(in_file_name, "-", strlen(in_file_name)) == 0) {
626                 /* FIXME : set as non blocking ? */
627                 in_fd = STDIN_FILENO;
628         } else {
629                 in_fd = open(in_file_name, O_RDONLY | O_NONBLOCK);
630                 if (in_fd <= 0) {
631                         perror("Unable to open file for reading");
632                         printf("Tried to open \"%s\".\n", in_file_name);
633                         return -13;
634                 }
635         }
636         /* Read file content */
637         do {
638                 int nb = read(in_fd, &file_buff[bytes_read], (RAM_MAX_SIZE - bytes_read));
639                 if (nb < 0) {
640                         if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
641                                 usleep( 50 );
642                                 continue;
643                         }
644                         perror("Input file read error");
645                         if (in_fd != STDIN_FILENO) {
646                                 close(in_fd);
647                         }
648                         return -12;
649                 } else if (nb == 0) {
650                         /* End of file */
651                         break;
652                 }
653                 bytes_read += nb;
654         } while (bytes_read < RAM_MAX_SIZE);
655         if (in_fd != STDIN_FILENO) {
656                 close(in_fd);
657         }
658         if (trace_on) {
659                 printf("Read %d octet(s) from input file\n", bytes_read);
660         }
662         /* Pad data size to 4 */
663         if (bytes_read & 0x03) {
664                 bytes_read = (bytes_read & ~0x03) + 0x04;
665         }
667         /* And send to ram */
668         ret = isp_send_buf_to_ram(file_buff, addr, bytes_read);
670         return ret;
673 int isp_send_cmd_address(int arg_count, char** args, char* name, char cmd)
675         char buf[SERIAL_BUFSIZE];
676         int ret = 0, len = 0;
677         char* tmp = NULL;
678         /* Arguments */
679         unsigned long int addr1 = 0, addr2 = 0;
680         unsigned long int length = 0;
682         /* Check compare arguments */
683         if (arg_count != 3) {
684                 printf("%s command needs two addresses and byte count.\n", name);
685                 return -7;
686         }
687         addr1 = strtoul(args[0], NULL, 0);
688         addr2 = strtoul(args[1], NULL, 0);
689         length = strtoul(args[2], NULL, 0);
690         if (trace_on) {
691                 printf("%s command called for %lu bytes between addresses %lu and %lu.\n",
692                                 name, length, addr1, addr2);
693         }
694         switch (cmd) {
695                 case 'M':
696                         if ((addr1 & 0x03) || (addr2 & 0x03) || (length & 0x03)) {
697                                 printf("Error: addresses and count must be multiples of 4 for %s command.\n", name);
698                                 return -7;
699                         }
700                         break;
701                 case 'C':
702                         if ((addr1 & 0x00FF) || (addr2 & 0x03)) {
703                                 printf("Error: flash address must be on 256 bytes boundary, ram address on 4 bytes boundary.\n");
704                                 return -8;
705                         }
706                         /* According to section 21.5.7 of LPC11xx user's manual (UM10398), number of bytes
707                          * written should be 256 | 512 | 1024 | 4096 */
708                         len = ((length >> 8) & 0x01) + ((length >> 9) & 0x01);
709                         len += ((length >> 10) & 0x01) + ((length >> 12) & 0x01);
710                         if (len != 1) {
711                                 printf("Error: bytes count must be one of 256 | 512 | 1024 | 4096\n");
712                                 return -7;
713                         }
714                         break;
715                 default:
716                         printf("Error: unsupported command code: '%c'\n", cmd);
717                         return -6;
718         }
720         /* Create compare request */
721         len = snprintf(buf, SERIAL_BUFSIZE, "%c %lu %lu %lu\r\n", cmd, addr1, addr2, length);
722         if (len > SERIAL_BUFSIZE) {
723                 len = SERIAL_BUFSIZE;
724         }
726         /* Send compare request */
727         if (isp_serial_write(buf, len) != len) {
728                 printf("Unable to send %s request.\n", name);
729                 return -5;
730         }
731         /* Wait for answer */
732         usleep( 5000 );
733         len = isp_serial_read(buf, 3, 3);
734         if (len <= 0) {
735                 printf("Error reading %s result.\n", name);
736                 return -4;
737         }
738         ret = isp_ret_code(buf, &tmp);
739         return ret;
742 int isp_cmd_compare(int arg_count, char** args)
744         char buf[SERIAL_BUFSIZE];
745         int ret = 0, len = 0;
746         unsigned long int offset = 0;
747         
748         ret = isp_send_cmd_address(arg_count, args, "compare", 'M');
749         switch (ret) {
750                 case CMD_SUCCESS:
751                         printf("Source and destination data are equal.\n");
752                         break;
753                 case COMPARE_ERROR:
754                         /* read remaining data */
755                         usleep( 2000 );
756                         len = isp_serial_read(buf, SERIAL_BUFSIZE, 3);
757                         if (len <= 0) {
758                                 printf("Error reading blank-check result.\n");
759                                 return -3;
760                         }
761                         offset = strtoul(buf, NULL, 10);
762                         printf("First mismatch occured at offset 0x%08lx\n", offset);
763                         break;
764                 default :
765                         printf("Error for compare command.\n");
766                         return -1;
767         }
769         return 0;
772 int isp_cmd_copy_ram_to_flash(int arg_count, char** args)
774         int ret = 0;
776         ret = isp_send_cmd_address(arg_count, args, "copy-ram-to-flash", 'C');
777         
778         if (ret != 0) {
779                 printf("Error when trying to copy data from ram to flash.\n");
780                 return ret;
781         }
782         printf("Data copied from ram to flash.\n");
784         return 0;
787 int isp_cmd_go(int arg_count, char** args)
789         char buf[SERIAL_BUFSIZE];
790         int ret = 0, len = 0;
791         /* Arguments */
792         unsigned long int addr = 0;
793         char* mode = NULL;
795         /* Check go arguments */
796         if (arg_count != 2) {
797                 printf("go command needs address (> 0x200) and mode ('thumb' or 'arm').\n");
798                 return -7;
799         }
800         addr = strtoul(args[0], NULL, 0);
801         mode = args[1];
802         if (trace_on) {
803                 printf("go command called with address 0x%08lx and mode %s.\n", addr, mode);
804         }
805         if (addr < 0x200) {
806                 printf("Error: address must be 0x00000200 or greater for go command.\n");
807                 return -6;
808         }
809         if (strncmp(mode, "thumb", strlen(mode)) == 0) {
810                 mode[0] = 'T';
811         } else if (strncmp(mode, "arm", strlen(mode)) == 0) {
812                 mode[0] = 'A';
813         } else {
814                 printf("Error: mode must be 'thumb' or 'arm' for go command.\n");
815                 return -5;
816         }
818         /* Create go request */
819         len = snprintf(buf, SERIAL_BUFSIZE, "G %lu %c\r\n", addr, mode[0]);
820         if (len > SERIAL_BUFSIZE) {
821                 len = SERIAL_BUFSIZE;
822         }
824         /* Send go request */
825         if (isp_serial_write(buf, len) != len) {
826                 printf("Unable to send go request.\n");
827                 return -4;
828         }
829         /* Wait for answer */
830         usleep( 5000 );
831         len = isp_serial_read(buf, SERIAL_BUFSIZE, 3);
832         if (len <= 0) {
833                 printf("Error reading go result.\n");
834                 return -3;
835         }
836         ret = isp_ret_code(buf, NULL);
837         if (ret != 0) {
838                 printf("Error when trying to execute programm at 0x%08lx in %s mode.\n", addr, mode);
839                 return -1;
840         }
842         return 0;
845 int isp_cmd_sectors_skel(int arg_count, char** args, char* name, char cmd)
847         char buf[SERIAL_BUFSIZE];
848         int ret = 0, len = 0;
849         /* Arguments */
850         unsigned long int first_sector = 0, last_sector = 0;
852         /* Check arguments */
853         if (arg_count != 2) {
854                 printf("%s command needs first and last sectors (1 sector = 4KB of flash).\n", name);
855                 return -7;
856         }
857         first_sector = strtoul(args[0], NULL, 0);
858         last_sector = strtoul(args[1], NULL, 0);
859         if (trace_on) {
860                 printf("%s command called for sectors %lu to %lu.\n", name, first_sector, last_sector);
861         }
862         if (last_sector < first_sector) {
863                 printf("Last sector must be after (or equal to) first sector for %s command.\n", name);
864                 return -6;
865         }
867         /* Create request */
868         len = snprintf(buf, SERIAL_BUFSIZE, "%c %lu %lu\r\n", cmd, first_sector, last_sector);
869         if (len > SERIAL_BUFSIZE) {
870                 len = SERIAL_BUFSIZE;
871         }
872         /* Send request */
873         if (isp_serial_write(buf, len) != len) {
874                 printf("Unable to send %s request.\n", name);
875                 return -5;
876         }
877         /* Wait for answer */
878         usleep( 5000 );
879         len = isp_serial_read(buf, 3, 3); /* Read at exactly 3 bytes, so caller can retreive info */
880         if (len <= 0) {
881                 printf("Error reading %s result.\n", name);
882                 return -4;
883         }
884         ret = isp_ret_code(buf, NULL);
886         return ret;
889 int isp_cmd_blank_check(int arg_count, char** args)
891         char* tmp = NULL;
892         unsigned long int offset = 0, content = 0;
893         char buf[SERIAL_BUFSIZE];
894         int ret = 0, len = 0;
896         ret = isp_cmd_sectors_skel(arg_count, args, "blank-check", 'I');
897         if (ret < 0) {
898                 return ret;
899         }
901         switch (ret) {
902                 case CMD_SUCCESS:
903                         printf("Specified sector(s) all blank(s).\n");
904                         break;
905                 case SECTOR_NOT_BLANK:
906                         /* read remaining data */
907                         usleep( 2000 );
908                         len = isp_serial_read(buf, SERIAL_BUFSIZE, 3);
909                         if (len <= 0) {
910                                 printf("Error reading blank-check result.\n");
911                                 return -3;
912                         }
913                         offset = strtoul(buf, &tmp, 10);
914                         content = strtoul(tmp, NULL, 10);
915                         printf("First non blank word is at offset 0x%08lx and contains 0x%08lx\n", offset, content);
916                         break;
917                 case INVALID_SECTOR :
918                         printf("Invalid sector for blank-check command.\n");
919                         return -2;
920                 case PARAM_ERROR:
921                         printf("Param error for blank-check command.\n");
922                         return -1;
923         }
925         return 0;
928 int isp_cmd_prepare_for_write(int arg_count, char** args)
930         int ret = isp_cmd_sectors_skel(arg_count, args, "prepare-for-write", 'P');
932         if (ret != 0) {
933                 printf("Error when trying to prepare sectors for write operation.\n");
934                 return ret;
935         }
936         printf("Sectors prepared for write operation.\n");
938         return 0;
941 int isp_cmd_erase(int arg_count, char** args)
943         int ret = isp_cmd_sectors_skel(arg_count, args, "erase", 'E');
944         
945         if (ret != 0) {
946                 printf("Error when trying to erase sectors.\n");
947                 return ret;
948         }
949         printf("Sectors erased.\n");
951         return 0;
955 static struct isp_command isp_cmds_list[] = {
956         {"unlock", 0, isp_cmd_unlock},
957         {"write-to-ram", 2, isp_cmd_write_to_ram},
958         {"read-memory", 3, isp_cmd_read_memory},
959         {"prepare-for-write", 2, isp_cmd_prepare_for_write},
960         {"copy-ram-to-flash", 3, isp_cmd_copy_ram_to_flash},
961         {"go", 2, isp_cmd_go},
962         {"erase", 2, isp_cmd_erase},
963         {"blank-check", 2, isp_cmd_blank_check},
964         {"read-part-id", 0, isp_cmd_part_id},
965         {"read-boot-version", 0, isp_cmd_boot_version},
966         {"compare", 3, isp_cmd_compare},
967         {"read-uid", 0, isp_cmd_read_uid},
968         {NULL, 0, NULL}
969 };
971 void isp_warn_trailing_args(int cmd_num, int arg_count, char** args)
973         int i = 0;
974         printf("command \"%s\" needs %d args, got %d.\n",
975                         isp_cmds_list[cmd_num].name,
976                         isp_cmds_list[cmd_num].nb_args, arg_count);
977         for (i=0; i<arg_count; i++) {
978                 printf("\targ[%d] : \"%s\"\n", i, args[i]);
979         }
982 /* Handle one command
983  * Return positive or NULL value when command handling is OK, or negative value otherwise.
984  */
985 int isp_handle_command(char* cmd, int arg_count, char** args)
987         int cmd_found = -1;
988         int ret = 0;
989         int index = 0;
991         if (cmd == NULL) {
992                 printf("isp_handle_command called with no command !\n");
993                 return -1;
994         }
996         while ((cmd_found == -1) && (isp_cmds_list[index].name != NULL)) {
997                 if (strncmp(isp_cmds_list[index].name, cmd, strlen(isp_cmds_list[index].name)) == 0) {
998                         cmd_found = index;
999                         break;
1000                 }
1001                 index++;
1002         }
1003         if (cmd_found == -1) {
1004                 printf("Unknown command \"%s\", use -h or --help for a list.\n", cmd);
1005                 return -2;
1006         }
1007         if (arg_count != isp_cmds_list[cmd_found].nb_args) {
1008                 isp_warn_trailing_args(cmd_found, arg_count, args);
1009         }
1010         ret = isp_cmds_list[cmd_found].handler(arg_count, args);
1012         return ret;