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  *  Copyright (C) 2012 Nathael Pajani <nathael.pajani@nathael.net>
10  *
11  *  This program is free software: you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation, either version 3 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  *********************************************************************/
27 #include <stdlib.h> /* malloc, free */
28 #include <stdio.h>
29 #include <stdint.h>
31 #include <unistd.h> /* open, getopt, close, usleep */
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
36 #include <errno.h>
37 #include <getopt.h>
39 #include <termios.h> /* for serial config */
40 #include <ctype.h>
42 #include <string.h> /* strncmp, strlen, strdup */
44 #include "isp_utils.h"
45 #include "isp_commands.h"
46 #include "prog_commands.h"
47 #include "parts.h"
49 #define PROG_NAME "LPC ISP Prog tool"
50 #define VERSION   "1.07"
53 void help(char *prog_name)
54 {
55         fprintf(stderr, "---------------- "PROG_NAME" --------------------------------\n");
56         fprintf(stderr, "Usage: %s -d <dev_name> -c <command> [options] [dump/prog file name]\n" \
57                 "  Default parts description files are /etc/lpctools_parts.def or ./lpctools_parts.def\n" \
58                 "  Default baudrate is B115200\n" \
59                 "  Default oscilator frequency used is 10000 KHz\n" \
60                 "  <command> is one of:\n" \
61                 "  \t dump, flash, id, blank, go\n" \
62                 "  \t dump file_name: dump flash content to 'file'\n" \
63                 "  \t flash file_name : put 'file' to flash, erasing requiered sectors\n" \
64                 "  \t blank : erase whole flash\n" \
65                 "  \t id : get all id information\n" \
66                 "  \t go : execute program from reset handler in thumb mode and open terminal\n" \
67                 "  Available options:\n" \
68                 "  \t -p | --parts=file : Parts description file (see defaults)\n" \
69                 "  \t -c | --command=cmd : \n" \
70                 "  \t -d | --device=dev_path : Host serial line used to program the device\n" \
71                 "  \t -b | --baudrate=N : Use this baudrate (Same baudrate must be used across whole session)\n" \
72                 "  \t -t | --trace : turn on trace output of serial communication\n" \
73                 "  \t -f | --freq=N : Oscilator frequency of target device\n" \
74                 "  \t -n | --no-user-code : do not compute a valid user code for exception vector 7\n" \
75                 "  \t -h | --help : display this help\n" \
76                 "  \t -v | --version : display version information\n", prog_name);
77         fprintf(stderr, "-----------------------------------------------------------------------\n");
78 }
80 #define SERIAL_BAUD  B115200
82 int trace_on = 0;
83 int quiet = 0;
84 static int calc_user_code = 1; /* User code is computed by default */
86 char* parts_file_name = NULL;
87 #define DEFAULT_PART_FILE_NAME_ETC  "/etc/lpctools_parts.def"
88 #define DEFAULT_PART_FILE_NAME_CURRENT  "./lpctools_parts.def"
90 static int prog_connect_and_id(int freq);
91 static int prog_handle_command(char* cmd, int dev_id, int arg_count, char** args);
93 int main(int argc, char** argv)
94 {
95         int baudrate = SERIAL_BAUD;
96         int crystal_freq = 10000;
97         char* isp_serial_device = NULL;
98         int dev_id = 0;
100         /* For "command" handling */
101         char* command = NULL;
102         char** cmd_args = NULL;
103         int nb_cmd_args = 0;
106         /* parameter parsing */
107         while(1) {
108                 int option_index = 0;
109                 int c = 0;
111                 struct option long_options[] = {
112                         {"parts", required_argument, 0, 'p'},
113                         {"command", required_argument, 0, 'c'},
114                         {"device", required_argument, 0, 'd'},
115                         {"baudrate", required_argument, 0, 'b'},
116                         {"trace", no_argument, 0, 't'},
117                         {"freq", required_argument, 0, 'f'},
118                         {"no-user-code", no_argument, 0, 'n'},
119                         {"help", no_argument, 0, 'h'},
120                         {"version", no_argument, 0, 'v'},
121                         {0, 0, 0, 0}
122                 };
124                 c = getopt_long(argc, argv, "p:c:d:b:tf:nhv", long_options, &option_index);
126                 /* no more options to parse */
127                 if (c == -1) break;
129                 switch (c) {
130                         /* p, parts description file */
131                         case 'p':
132                                 parts_file_name = strdup(optarg);
133                                 break;
135                         /* c, command */
136                         case 'c':
137                                 command = strdup(optarg);
138                                 break;
140                         /* d, device */
141                         case 'd':
142                                 isp_serial_device = strdup(optarg);
143                                 break;
145                         /* b, baudrate */
146                         case 'b':
147                                 baudrate = atoi(optarg);
148                                 /* FIXME: validate baudrate */
149                                 break;
151                         /* t, trace */
152                         case 't':
153                                 trace_on = 1;
154                                 break;
156                         /* f, freq */
157                         case 'f':
158                                 crystal_freq = atoi(optarg);
159                                 break;
161                         /* n, user-code */
162                         case 'n':
163                                 calc_user_code = 0;
164                                 break;
166                         /* v, version */
167                         case 'v':
168                                 printf("%s Version %s\n", PROG_NAME, VERSION);
169                                 return 0;
170                                 break;
172                         /* h, help */
173                         case 'h':
174                         default:
175                                 help(argv[0]);
176                                 return 0;
177                 }
178         }
180         /* Command is mandatory */
181         if (command == NULL) {
182                 printf("No command given. use -h or --help for help on available commands.\n");
183                 return -1;
184         }
185         /* Check for default parts file availability if none given as argument */
186         if (parts_file_name == NULL) {
187                 FILE* parts_file = NULL;
189                 parts_file_name = DEFAULT_PART_FILE_NAME_CURRENT;
190                 parts_file = fopen(parts_file_name, "r");
191                 if (parts_file == NULL) {
192                         parts_file_name = DEFAULT_PART_FILE_NAME_ETC;
193                         parts_file = fopen(parts_file_name, "r");
194                 }
195                 if (parts_file == NULL) {
196                         printf("Unable to open default parts file to read LPC descriptions !\n");
197                         printf("Tried : '%s' and '%s'\n", DEFAULT_PART_FILE_NAME_ETC, DEFAULT_PART_FILE_NAME_CURRENT);
198                         return -1;
199                 }
200                 fclose(parts_file);
201         }
203         /* Open serial device */
204         if (isp_serial_device == NULL) {
205                 printf("No serial device given, exiting\n");
206                 help(argv[0]);
207                 return 0;
208         } else if (isp_serial_open(baudrate, isp_serial_device) != 0) {
209                 printf("Serial open failed, unable to initiate serial communication with target.\n");
210                 return -1;
211         }
213         if (trace_on) {
214                 printf("Serial device : %s\n", isp_serial_device);
215                 printf("Command : %s\n", command);
216         }
218         /* Parse remaining command line arguments (not options). They are command arguments */
219         if (optind < argc) {
220                 nb_cmd_args = argc - optind;
221                 cmd_args = malloc(nb_cmd_args * sizeof(char *));
222                 if (trace_on) {
223                         printf("Command arguments :\n");
224                 }
225                 while (optind < argc) {
226                         static unsigned int idx = 0;
227                         cmd_args[idx++] = argv[optind++];
228                         if (trace_on) {
229                                 printf("%s\n", cmd_args[idx - 1]);
230                         }
231                 }
232         }
234         /* First : sync with device */
235         dev_id = prog_connect_and_id(crystal_freq);
236         if (dev_id < 0) {
237                 printf("Unable to connect to target, consider hard reset of target or link\n");
238                 return -1;
239         }
240         if (dev_id == 0) {
241                 printf("Communication error, bad target id (0), please retry\n");
242                 return -1;
243         }
245         if (command != NULL)  {
246                 int err = 0;
247                 err = prog_handle_command(command, dev_id, nb_cmd_args, cmd_args);
248                 if (err >= 0) {
249                         if (trace_on) {
250                                 printf("Command \"%s\" handled OK.\n", command);
251                         }
252                 } else {
253                         printf("Error handling command \"%s\" : %d\n", command, err);
254                 }
255         }
258         if (cmd_args != NULL) {
259                 free(cmd_args);
260         }
261         isp_serial_close();
262         return 0;
265 struct prog_command {
266         int cmd_num;
267         char* name;
268 };
270 static struct prog_command prog_cmds_list[] = {
271         {0, "dump"},
272         {1, "flash"},
273         {2, "id"},
274         {3, "blank"},
275         {4, "go"},
276         {5, NULL}
277 };
279 /*
280  * Try to connect to the target and identify the device.
281  * First try sync, and if it fails, try to read id twice. if both fail, then we are not connected
282  */
283 static int prog_connect_and_id(int freq)
285         int sync_ret = 0;
287         /* Try to connect */
288         sync_ret = isp_connect(freq, 1);
289         /* Synchro failed or already synchronised ? */
290         if (sync_ret < 0) {
291                 /* If already synchronized, then sync command and the next command fail.
292                    Sync failed, maybe we are already sync'ed, then send one command for nothing */
293                 isp_cmd_part_id(1);
294         }
296         return isp_cmd_part_id(1);
299 static int prog_handle_command(char* cmd, int dev_id, int arg_count, char** args)
301         int cmd_found = -1;
302         int ret = 0;
303         int index = 0;
304         struct part_desc* part = NULL;
306         if (cmd == NULL) {
307                 printf("prog_handle_command called with no command !\n");
308                 return -1;
309         }
311         part = find_part_in_file(dev_id, parts_file_name);
312         if (part == NULL) {
313                 printf("Unknown part number : 0x%08x.\n", dev_id);
314                 return -2;
315         }
317         while ((cmd_found == -1) && (prog_cmds_list[index].name != NULL)) {
318                 if (strncmp(prog_cmds_list[index].name, cmd, strlen(prog_cmds_list[index].name)) == 0) {
319                         cmd_found = index;
320                         break;
321                 }
322                 index++;
323         }
324         if (cmd_found == -1) {
325                 printf("Unknown command \"%s\", use -h or --help for a list.\n", cmd);
326                 return -3;
327         }
329         switch (prog_cmds_list[cmd_found].cmd_num) {
330                 case 0: /* dump, need one arg : filename */
331                         if (arg_count != 1) {
332                                 printf("command dump needs one arg (filename), got %d.\n", arg_count);
333                                 return -4;
334                         }
335                         ret = dump_to_file(part, args[0]);
336                         break;
338                 case 1: /* flash, need one arg : filename */
339                         if (arg_count != 1) {
340                                 printf("command flash needs one arg (filename), got %d.\n", arg_count);
341                                 return -4;
342                         }
343                         ret = flash_target(part, args[0], calc_user_code);
344                         break;
346                 case 2: /* id : no args */
347                         ret = get_ids();
348                         break;
350                 case 3: /* blank : no args */
351                         ret = erase_flash(part);
352                         break;
354                 case 4: /* go : no args */
355                         ret = start_prog(part);
356                         break;
357         }
359         return ret;