1 /*********************************************************************
2  *
3  *   ISP (In-System Programming) tool for NXP LPC Microcontrollers
4  *
5  * This tool does not give access to each isp command, instead it
6  * provides wrappers for flashing a device.
7  *
8  *
9  * Written by Nathael Pajani <nathael.pajani@nathael.net>
10  *
11  * This programm is released under the terms of the GNU GPLv3 licence
12  * as can be found on the GNU website : <http://www.gnu.org/licenses/>
13  *
14  *********************************************************************/
17 #include <stdlib.h> /* malloc, free */
18 #include <stdio.h>
19 #include <stdint.h>
21 #include <unistd.h> /* open, getopt, close, usleep */
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
26 #include <errno.h>
27 #include <getopt.h>
29 #include <termios.h> /* for serial config */
30 #include <ctype.h>
32 #include <string.h> /* strncmp, strlen, strdup */
34 #include "isp_utils.h"
35 #include "isp_commands.h"
36 #include "prog_commands.h"
37 #include "parts.h"
39 #define PROG_NAME "LPC ISP Prog tool"
40 #define VERSION   "1.03"
43 void help(char *prog_name)
44 {
45         fprintf(stderr, "---------------- "PROG_NAME" --------------------------------\n");
46         fprintf(stderr, "Usage: %s -d <dev_name> -c <command> [options] [dump/prog file name]\n" \
47                 "  Default parts description files are /etc/lpctools_parts.def or ./lpctools_parts.def\n" \
48                 "  Default baudrate is B115200\n" \
49                 "  Default oscilator frequency used is 10000 KHz\n" \
50                 "  <command> is one of:\n" \
51                 "  \t dump, flash, id, blank, go\n" \
52                 "  \t dump file_name: dump flash content to 'file'\n" \
53                 "  \t flash file_name : put 'file' to flash, erasing requiered sectors\n" \
54                 "  \t blank : erase whole flash\n" \
55                 "  \t id : get all id information\n" \
56                 "  \t go : execute programm from reset handler in thumb mode and open terminal\n" \
57                 "  Available options:\n" \
58                 "  \t -p | --parts=file : Parts description file (see defaults)\n" \
59                 "  \t -c | --command=cmd : \n" \
60                 "  \t -d | --device=dev_path : Host serial line used to programm the device\n" \
61                 "  \t -b | --baudrate=N : Use this baudrate (Same baudrate must be used across whole session)\n" \
62                 "  \t -t | --trace : turn on trace output of serial communication\n" \
63                 "  \t -f | --freq=N : Oscilator frequency of target device\n" \
64                 "  \t -n | --no-user-code : do not compute a valid user code for exception vector 7\n" \
65                 "  \t -h | --help : display this help\n" \
66                 "  \t -v | --version : display version information\n", prog_name);
67         fprintf(stderr, "-----------------------------------------------------------------------\n");
68 }
70 #define SERIAL_BAUD  B115200
72 int trace_on = 0;
73 int quiet = 0;
74 static int calc_user_code = 1; /* User code is computed by default */
76 char* parts_file_name = NULL;
77 #define DEFAULT_PART_FILE_NAME_ETC  "/etc/lpctools_parts.def"
78 #define DEFAULT_PART_FILE_NAME_CURRENT  "./lpctools_parts.def"
80 static int prog_connect_and_id(int freq);
81 static int prog_handle_command(char* cmd, int dev_id, int arg_count, char** args);
83 int main(int argc, char** argv)
84 {
85         int baudrate = SERIAL_BAUD;
86         int crystal_freq = 10000;
87         char* isp_serial_device = NULL;
88         int dev_id = 0;
90         /* For "command" handling */
91         char* command = NULL;
92         char** cmd_args = NULL;
93         int nb_cmd_args = 0;
96         /* parameter parsing */
97         while(1) {
98                 int option_index = 0;
99                 int c = 0;
101                 struct option long_options[] = {
102                         {"parts", required_argument, 0, 'p'},
103                         {"command", required_argument, 0, 'c'},
104                         {"device", required_argument, 0, 'd'},
105                         {"baudrate", required_argument, 0, 'b'},
106                         {"trace", no_argument, 0, 't'},
107                         {"freq", required_argument, 0, 'f'},
108                         {"no-user-code", no_argument, 0, 'n'},
109                         {"help", no_argument, 0, 'h'},
110                         {"version", no_argument, 0, 'v'},
111                         {0, 0, 0, 0}
112                 };
114                 c = getopt_long(argc, argv, "p:c:d:b:tf:nhv", long_options, &option_index);
116                 /* no more options to parse */
117                 if (c == -1) break;
119                 switch (c) {
120                         /* p, parts description file */
121                         case 'p':
122                                 parts_file_name = strdup(optarg);
123                                 break;
125                         /* c, command */
126                         case 'c':
127                                 command = strdup(optarg);
128                                 break;
130                         /* d, device */
131                         case 'd':
132                                 isp_serial_device = strdup(optarg);
133                                 break;
135                         /* b, baudrate */
136                         case 'b':
137                                 baudrate = atoi(optarg);
138                                 /* FIXME: validate baudrate */
139                                 break;
141                         /* t, trace */
142                         case 't':
143                                 trace_on = 1;
144                                 break;
146                         /* f, freq */
147                         case 'f':
148                                 crystal_freq = atoi(optarg);
149                                 break;
151                         /* u, user-code */
152                         case 'n':
153                                 calc_user_code = 0;
154                                 break;
156                         /* v, version */
157                         case 'v':
158                                 printf("%s Version %s\n", PROG_NAME, VERSION);
159                                 return 0;
160                                 break;
162                         /* h, help */
163                         case 'h':
164                         default:
165                                 help(argv[0]);
166                                 return 0;
167                 }
168         }
170         /* Command is mandatory */
171         if (command == NULL) {
172                 printf("No command given. use -h or --help for help on available commands.\n");
173                 return -1;
174         }
175         /* Check for default parts file availability if none given as argument */
176         if (parts_file_name == NULL) {
177                 FILE* parts_file = NULL;
179                 parts_file_name = DEFAULT_PART_FILE_NAME_CURRENT;
180                 parts_file = fopen(parts_file_name, "r");
181                 if (parts_file == NULL) {
182                         parts_file_name = DEFAULT_PART_FILE_NAME_ETC;
183                         parts_file = fopen(parts_file_name, "r");
184                 }
185                 if (parts_file == NULL) {
186                         printf("Unable to open default parts file to read LPC descriptions !\n");
187                         printf("Tried : '%s' and '%s'\n", DEFAULT_PART_FILE_NAME_ETC, DEFAULT_PART_FILE_NAME_CURRENT);
188                         return -1;
189                 }
190                 fclose(parts_file);
191         }
193         /* Open serial device */
194         if (isp_serial_device == NULL) {
195                 printf("No serial device given, exiting\n");
196                 help(argv[0]);
197                 return 0;
198         } else if (isp_serial_open(baudrate, isp_serial_device) != 0) {
199                 printf("Serial open failed, unable to initiate serial communication with target.\n");
200                 return -1;
201         }
203         if (trace_on) {
204                 printf("Serial device : %s\n", isp_serial_device);
205                 printf("Command : %s\n", command);
206         }
208         /* Parse remaining command line arguments (not options). They are command arguments */
209         if (optind < argc) {
210                 nb_cmd_args = argc - optind;
211                 cmd_args = malloc(nb_cmd_args * sizeof(char *));
212                 if (trace_on) {
213                         printf("Command arguments :\n");
214                 }
215                 while (optind < argc) {
216                         static unsigned int idx = 0;
217                         cmd_args[idx++] = argv[optind++];
218                         if (trace_on) {
219                                 printf("%s\n", cmd_args[idx - 1]);
220                         }
221                 }
222         }
224         /* First : sync with device */
225         dev_id = prog_connect_and_id(crystal_freq);
226         if (dev_id < 0) {
227                 printf("Unable to connect to target, consider hard reset of target or link\n");
228                 return -1;
229         }
231         if (command != NULL)  {
232                 int err = 0;
233                 err = prog_handle_command(command, dev_id, nb_cmd_args, cmd_args);
234                 if (err >= 0) {
235                         if (trace_on) {
236                                 printf("Command \"%s\" handled OK.\n", command);
237                         }
238                 } else {
239                         printf("Error handling command \"%s\" : %d\n", command, err);
240                 }
241         }
244         if (cmd_args != NULL) {
245                 free(cmd_args);
246         }
247         isp_serial_close();
248         return 0;
251 struct prog_command {
252         int cmd_num;
253         char* name;
254 };
256 static struct prog_command prog_cmds_list[] = {
257         {0, "dump"},
258         {1, "flash"},
259         {2, "id"},
260         {3, "blank"},
261         {4, "go"},
262         {5, NULL}
263 };
265 /*
266  * Try to connect to the target and identify the device.
267  * First try sync, and if it fails, try to read id twice. if both fail, then we are not connected
268  */
269 static int prog_connect_and_id(int freq)
271         int sync_ret = 0;
273         /* Try to connect */
274         sync_ret = isp_connect(freq, 1);
275         /* Synchro failed or already synchronised ? */
276         if (sync_ret < 0) {
277                 /* If already synchronized, then sync command and the next command fail.
278                    Sync failed, maybe we are already sync'ed, then send one command for nothing */
279                 isp_cmd_part_id(1);
280         }
282         return isp_cmd_part_id(1);
285 static int prog_handle_command(char* cmd, int dev_id, int arg_count, char** args)
287         int cmd_found = -1;
288         int ret = 0;
289         int index = 0;
290         struct part_desc* part = NULL;
292         if (cmd == NULL) {
293                 printf("prog_handle_command called with no command !\n");
294                 return -1;
295         }
297         part = find_part_in_file(dev_id, parts_file_name);
298         if (part == NULL) {
299                 printf("Unknown part number : 0x%08x.\n", dev_id);
300                 return -2;
301         }
303         while ((cmd_found == -1) && (prog_cmds_list[index].name != NULL)) {
304                 if (strncmp(prog_cmds_list[index].name, cmd, strlen(prog_cmds_list[index].name)) == 0) {
305                         cmd_found = index;
306                         break;
307                 }
308                 index++;
309         }
310         if (cmd_found == -1) {
311                 printf("Unknown command \"%s\", use -h or --help for a list.\n", cmd);
312                 return -3;
313         }
315         switch (prog_cmds_list[cmd_found].cmd_num) {
316                 case 0: /* dump, need one arg : filename */
317                         if (arg_count != 1) {
318                                 printf("command dump needs one arg (filename), got %d.\n", arg_count);
319                                 return -4;
320                         }
321                         ret = dump_to_file(part, args[0]);
322                         break;
324                 case 1: /* flash, need one arg : filename */
325                         if (arg_count != 1) {
326                                 printf("command flash needs one arg (filename), got %d.\n", arg_count);
327                                 return -4;
328                         }
329                         ret = flash_target(part, args[0], calc_user_code);
330                         break;
332                 case 2: /* id : no args */
333                         ret = get_ids();
334                         break;
336                 case 3: /* blank : no args */
337                         ret = erase_flash(part);
338                         break;
340                 case 4: /* go : no args */
341                         ret = start_prog(part);
342                         break;
343         }
345         return ret;