authorNathael Pajani <nathael.pajani@ed3l.fr>
Fri, 13 Apr 2012 03:47:07 +0000 (05:47 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Fri, 13 Apr 2012 03:47:07 +0000 (05:47 +0200)
isp_commands.c
isp_commands.h
isp_main.c
isp_utils.c

index f02c9c7..862b42a 100644 (file)
  *********************************************************************/
 
 
-#include <stdlib.h>
+#include <stdlib.h> /* strtoul */
 #include <stdio.h>
 #include <stdint.h>
 #include <unistd.h>
-#include <string.h>
+#include <string.h> /* strncmp */
 #include <ctype.h>
 #include <errno.h>
 
-/* List of commands to be supported :
-  synchronize : OK
-  unlock 
-  set-baud-rate
-  echo
-  write-to-ram
-  read-memory
-  prepare-for-write
-  copy-ram-to-flash
-  go
-  erase
-  blank-check
-  read-part-id
-  read-boot-version
-  compare
-  read-uid
-*/
-
-
 #include "isp_utils.h"
 
 extern int trace_on;
 
+struct isp_command {
+       char* name;
+       int nb_args;
+       int (*handler)(int arg_count, char** args);
+};
+
+
 #define SERIAL_BUFSIZE  128
 
 #define SYNCHRO_START "?"
-#define SYNCHRO  "Synchronized"
+#define SYNCHRO  "Synchronized\r\n"
+#define SYNCHRO_OK "OK\r\n"
+#define SYNCHRO_ECHO_OFF "A 0\r\n"
+
+#define ISP_ABORT "\e"
+#define READ_UID "N\r\n"
+#define READ_PART_ID "J\r\n"
+#define READ_BOOT_VERSION "K\r\n"
 
 
-int isp_ret_code(char* buf)
+char* error_codes[] = {
+       "CMD_SUCCESS",
+       "INVALID_COMMAND",
+       "SRC_ADDR_ERROR",
+       "DST_ADDR_ERROR",
+       "SRC_ADDR_NOT_MAPPED",
+       "DST_ADDR_NOT_MAPPED",
+       "COUNT_ERROR",
+       "INVALID_SECTOR",
+       "SECTOR_NOT_BLANK",
+       "SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION",
+       "COMPARE_ERROR",
+       "BUSY",
+       "PARAM_ERROR",
+       "ADDR_ERROR",
+       "ADDR_NOT_MAPPED",
+       "CMD_LOCKED",
+       "INVALID_CODE",
+       "INVALID_BAUD_RATE",
+       "INVALID_STOP_BIT",
+       "CODE_READ_PROTECTION_ENABLED",
+};
+
+int isp_ret_code(char* buf, char** endptr)
 {
+       unsigned int ret = 0;
+       ret = strtoul(buf, endptr, 10);
        if (trace_on) {
                /* FIXME : Find how return code are sent (binary or ASCII) */
-               printf("Received code: '0x%02x'\n", *buf);
+               if (ret > (sizeof(error_codes)/sizeof(char*))) {
+                       printf("Received unknown error code '%u' !\n", ret);
+               } else {
+                       printf("Received error code '%u': %s\n", ret, error_codes[ret]);
+               }
        }
-       return 0;
+       return ret;
 }
 
 
 /* Connect or reconnect to the target.
  * Return positive or NULL value when connection is OK, or negative value otherwise.
  */
-int isp_connect()
+int isp_connect(unsigned int crystal_freq)
 {
        char buf[SERIAL_BUFSIZE];
+       char freq[10];
+       
+       snprintf(freq, 8, "%d\r\n", crystal_freq);
 
        /* Send synchronize request */
        if (isp_serial_write(SYNCHRO_START, strlen(SYNCHRO_START)) != strlen(SYNCHRO_START)) {
                printf("Unable to send synchronize request.\n");
                return -5;
        }
-
        /* Wait for answer */
        if (isp_serial_read(buf, SERIAL_BUFSIZE, strlen(SYNCHRO)) < 0) {
                printf("Error reading synchronize answer.\n");
                return -4;
        }
-
-       /* Check answer, and acknoledge if OK */
+       /* Check answer, and acknowledge if OK */
        if (strncmp(SYNCHRO, buf, strlen(SYNCHRO)) == 0) {
                isp_serial_write(SYNCHRO, strlen(SYNCHRO));
        } else {
-               printf("Unable to synchronize.\n");
+               printf("Unable to synchronize, no synchro received.\n");
+               return -3;
+       }
+       /* Empty read buffer (echo is on) */
+       isp_serial_read(buf, strlen(SYNCHRO), strlen(SYNCHRO));
+       /* Read reply (OK) */
+       isp_serial_read(buf, SERIAL_BUFSIZE, strlen(SYNCHRO_OK));
+       if (strncmp(SYNCHRO_OK, buf, strlen(SYNCHRO_OK)) != 0) {
+               printf("Unable to synchronize, synchro not acknowledged.\n");
+               return -2;
+       }
+
+       /* Documentation says we should send crystal frequency .. sending anything is OK */
+       isp_serial_write(freq, strlen(freq));
+       /* Empty read buffer (echo is on) */
+       isp_serial_read(buf, strlen(freq), strlen(freq));
+       /* Read reply (OK) */
+       isp_serial_read(buf, SERIAL_BUFSIZE, strlen(SYNCHRO_OK));
+       if (strncmp(SYNCHRO_OK, buf, strlen(SYNCHRO_OK)) != 0) {
+               printf("Unable to synchronize, crystal frequency not acknowledged.\n");
+               return -2;
+       }
+
+       /* Turn off echo */
+       isp_serial_write(SYNCHRO_ECHO_OFF, strlen(SYNCHRO_ECHO_OFF));
+       /* Empty read buffer (echo still on) */
+       isp_serial_read(buf, strlen(SYNCHRO_ECHO_OFF), strlen(SYNCHRO_ECHO_OFF));
+       /* Read eror code for command */
+       isp_serial_read(buf, SERIAL_BUFSIZE, 3);
+
+       return 1;
+}
+
+
+int isp_cmd_read_uid(int arg_count, char** args)
+{
+       char buf[SERIAL_BUFSIZE];
+       char* tmp = NULL;
+       int i = 0, ret = 0, len = 0;
+       unsigned long int uid[4];
+       
+       /* Send read-uid request */
+       if (isp_serial_write(READ_UID, strlen(READ_UID)) != strlen(READ_UID)) {
+               printf("Unable to send read-uid request.\n");
+               return -5;
+       }
+       /* Wait for answer */
+       usleep( 5000 );
+       len = isp_serial_read(buf, SERIAL_BUFSIZE, 50);
+       if (len <= 0) {
+               printf("Error reading uid.\n");
+               return -4;
+       }
+       ret = isp_ret_code(buf, &tmp);
+       if (ret != 0) {
+               printf("This cannot happen ... as long as you trust the user manual.\n");
                return -1;
        }
+       for (i=0; i<4; i++) {
+               static char* endptr = NULL;
+               uid[i] = strtoul(tmp, &endptr, 10);
+               tmp = endptr;
+       }
+       printf("UID: 0x%08lx - 0x%08lx - 0x%08lx - 0x%08lx\n", uid[0], uid[1], uid[2], uid[3]);
 
-       /* Empty read buffer (maybe echo is on ?) */
+       return 0;
+}
+
+int isp_cmd_part_id(int arg_count, char** args)
+{
+       char buf[SERIAL_BUFSIZE];
+       int ret = 0, len = 0;
+       char* tmp = NULL;
+       unsigned long int part_id = 0;
+
+       /* Send read-part-id request */
+       if (isp_serial_write(READ_PART_ID, strlen(READ_PART_ID)) != strlen(READ_PART_ID)) {
+               printf("Unable to send read-part-id request.\n");
+               return -5;
+       }
+       /* Wait for answer */
        usleep( 5000 );
-       isp_serial_read(buf, SERIAL_BUFSIZE, 0);
+       len = isp_serial_read(buf, SERIAL_BUFSIZE, 10);
+       if (len <= 0) {
+               printf("Error reading part id.\n");
+               return -4;
+       }
+       ret = isp_ret_code(buf, &tmp);
+       if (ret != 0) {
+               printf("This cannot happen ... as long as you trust the user manual.\n");
+               return -1;
+       }
+       /* FIXME : some part IDs are on two 32bits values */
+       part_id = strtoul(tmp, NULL, 10);
+       printf("Part ID is 0x%08lx\n", part_id);
 
-       /* FIXME : Do we always turn off echo ? */
-       /* and turn off echo */
-       isp_serial_write("A 0\r\n", 5);
+       return 0;
+}
 
-       return 1;
+int isp_cmd_boot_version(int arg_count, char** args)
+{
+       char buf[SERIAL_BUFSIZE];
+       int ret = 0, len = 0;
+       char* tmp = NULL;
+       unsigned int ver[2];
+
+       /* Send read-boot-version request */
+       if (isp_serial_write(READ_BOOT_VERSION, strlen(READ_BOOT_VERSION)) != strlen(READ_BOOT_VERSION)) {
+               printf("Unable to send read-boot-version request.\n");
+               return -5;
+       }
+       /* Wait for answer */
+       usleep( 5000 );
+       len = isp_serial_read(buf, SERIAL_BUFSIZE, 5);
+       if (len <= 0) {
+               printf("Error reading boot version.\n");
+               return -4;
+       }
+       ret = isp_ret_code(buf, &tmp);
+       if (ret != 0) {
+               printf("This cannot happen ... as long as you trust the user manual.\n");
+               return -1;
+       }
+       ver[0] = strtoul(tmp, &tmp, 10);
+       ver[1] = strtoul(tmp, NULL, 10);
+       printf("Boot code version is %u.%u\n", ver[0], ver[1]);
+
+       return 0;
+}
+
+
+/* FIXME : Temporary place-holder */
+int isp_cmd_null(int arg_count, char** args)
+{
+       int i = 0;
+       printf("command not yet handled, called with %d arguments.\n", arg_count);
+       for (i=0; i<arg_count; i++) {
+               printf("\targ[%d] : \"%s\"\n", i, args[i]);
+       }
+       return 0;
+}
+
+static struct isp_command isp_cmds_list[] = {
+       {"unlock", 0, isp_cmd_null}, /* isp_cmd_unlock} */
+       {"write-to-ram", 0, isp_cmd_null}, /* isp_cmd_write-to-ram} */
+       {"read-memory", 0, isp_cmd_null}, /* isp_cmd_read-memory} */
+       {"prepare-for-write", 0, isp_cmd_null}, /* isp_cmd_prepare-for-write} */
+       {"copy-ram-to-flash", 0, isp_cmd_null}, /* isp_cmd_copy-ram-to-flash} */
+       {"go", 0, isp_cmd_null}, /* isp_cmd_go} */
+       {"erase", 0, isp_cmd_null}, /* isp_cmd_erase} */
+       {"blank-check", 0, isp_cmd_null}, /* isp_cmd_blank-check} */
+       {"read-part-id", 0, isp_cmd_part_id},
+       {"read-boot-version", 0, isp_cmd_boot_version},
+       {"compare", 0, isp_cmd_null}, /* isp_cmd_compare} */
+       {"read-uid", 0, isp_cmd_read_uid},
+       {NULL, 0, NULL}
+};
+
+void isp_warn_trailing_args(int cmd_num, int arg_count, char** args)
+{
+       int i = 0;
+       printf("command \"%s\" needs %d args, got %d.\n",
+                       isp_cmds_list[cmd_num].name,
+                       isp_cmds_list[cmd_num].nb_args, arg_count);
+       for (i=0; i<arg_count; i++) {
+               printf("\targ[%d] : \"%s\"\n", i, args[i]);
+       }
 }
 
 /* Handle one command
@@ -95,7 +274,33 @@ int isp_connect()
  */
 int isp_handle_command(char* cmd, int arg_count, char** args)
 {
-       return 1;
+       int cmd_found = -1;
+       int ret = 0;
+       int index = 0;
+
+       if (cmd == NULL) {
+               printf("isp_handle_command called with no command !\n");
+               return -1;
+       }
+
+       while ((cmd_found == -1) && (isp_cmds_list[index].name != NULL)) {
+               if (strncmp(isp_cmds_list[index].name, cmd, strlen(isp_cmds_list[index].name)) == 0) {
+                       cmd_found = index;
+                       break;
+               }
+               index++;
+       }
+       if (arg_count != isp_cmds_list[cmd_found].nb_args) {
+               isp_warn_trailing_args(cmd_found, arg_count, args);
+       }
+       isp_cmds_list[cmd_found].handler(arg_count, args);
+       
+       if (cmd_found == -1) {
+               printf("Unknown command \"%s\", use -h or --help for a list.\n", cmd);
+               return -2;
+       }
+
+       return ret;
 }
 
 
index fa67631..2c36df6 100644 (file)
@@ -30,7 +30,7 @@ int isp_ret_code(char* buf);
 /* Connect or reconnect to the target.
  * Return positive or NULL value when connection is OK, or negative value otherwise.
  */
-int isp_connect();
+int isp_connect(unsigned int crystal_freq);
 
 /* Handle one command
  * Return positive or NULL value when command handling is OK, or negative value otherwise.
index 76cc790..7e296fa 100644 (file)
@@ -14,7 +14,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include <string.h> /* strncmp */
 #include <errno.h>
 #include <getopt.h>
 
 void help(char *prog_name)
 {
        fprintf(stderr, "-----------------------------------------------------------------------\n");
-       fprintf(stderr, "Usage: %s [options] device command [command arguments]\n" \
+       fprintf(stderr, "Usage: %s [options] device [-s | --synchronize]\n" \
+               "       %s [options] device command [command arguments]\n" \
                "  Default baudrate is B115200\n" \
                "  <device> is the (host) serial line used to programm the device\n" \
                "  <command> is one of:\n" \
-               "  \t synchronize (sync done each time unless -n is used (for multiple successive calls))\n" \
                "  \t unlock \n" \
-               "  \t set-baud-rate \n" \
-               "  \t echo \n" \
                "  \t write-to-ram \n" \
                "  \t read-memory \n" \
                "  \t prepare-for-write \n" \
@@ -57,12 +54,21 @@ void help(char *prog_name)
                "  \t read-boot-version \n" \
                "  \t compare \n" \
                "  \t read-uid \n" \
+               "  Notes:\n" \
+               "   - Access to the ISP mode is done by calling this utility once with the synchronize\n" \
+               "     option and no command. This starts a session. No command can be used before starting\n" \
+               "     a session, and no other synchronize request must be done once the session is started\n" \
+               "     unless the target is reseted, which closes the session.\n" \
+               "   - Echo is turned OFF when starting a session and the command is not available.\n" \
+               "   - The set-baud-rate command is not available. The SAME baudrate MUST be used for the\n" \
+               "     whole session. It must be specified on each successive call if the default baudrate\n" \
+               "     is not used.\n" \
                "  Available options:\n" \
-               "  \t -n | --no-synchronize : Do not perform synchronization before sending command\n" \
+               "  \t -s | --synchronize : Perform synchronization (open session)\n" \
                "  \t -b | --baudrate=N : Use this baudrate (does not issue the set-baud-rate command)\n" \
                "  \t -t | --trace : turn on trace output of serial communication\n" \
                "  \t -h | --help : display this help\n" \
-               "  \t -v | --version : display version information\n", prog_name);
+               "  \t -v | --version : display version information\n", prog_name, prog_name);
        fprintf(stderr, "-----------------------------------------------------------------------\n");
 }
 
@@ -74,7 +80,8 @@ int trace_on = 0;
 int main(int argc, char** argv)
 {
        int baudrate = SERIAL_BAUD;
-       int dont_synchronize = 0;
+       int crystal_freq = 10000;
+       int synchronize = 0;
        char* isp_serial_device = NULL;
 
        /* For "command" handling */
@@ -89,7 +96,7 @@ int main(int argc, char** argv)
                int c = 0;
 
                struct option long_options[] = {
-                       {"no-synchronize", no_argument, 0, 'n'},
+                       {"synchronize", no_argument, 0, 's'},
                        {"baudrate", required_argument, 0, 'b'},
                        {"trace", no_argument, 0, 't'},
                        {"help", no_argument, 0, 'h'},
@@ -97,7 +104,7 @@ int main(int argc, char** argv)
                        {0, 0, 0, 0}
                };
 
-               c = getopt_long(argc, argv, "nb:thv", long_options, &option_index);
+               c = getopt_long(argc, argv, "sb:thv", long_options, &option_index);
 
                /* no more options to parse */
                if (c == -1) break;
@@ -115,8 +122,8 @@ int main(int argc, char** argv)
                                break;
 
                        /* s, synchronize */
-                       case 'n':
-                               dont_synchronize = 1;
+                       case 's':
+                               synchronize = 1;
                                break;
 
                        /* v, version */
@@ -152,12 +159,28 @@ int main(int argc, char** argv)
                return -1;
        }
 
+       if (synchronize) {
+               if (optind < argc) {
+                       /* no command can be specified when opening a session */
+                       printf("No command can be specified with -s or --synchronize (Session opening)\n");
+                       printf("NOT SYNCHRONIZED !\n");
+                       return -1;
+               }
+               isp_connect(crystal_freq);
+               isp_serial_close();
+               return 0;
+       }
+
        /* Next one should be "command" (if present) */
        if (optind < argc) {
                command = argv[optind++];
                if (trace_on) {
                        printf("Command : %s\n", command);
                }
+       } else {
+               printf("No command given. use -h or --help for help on available commands.\n");
+               isp_serial_close();
+               return -1;
        }
        /* And then remaining ones (if any) are command arguments */
        if (optind < argc) {
@@ -175,12 +198,7 @@ int main(int argc, char** argv)
                }
        }
 
-       if (! dont_synchronize) {
-               isp_connect();
-       }
-
-       /* FIXME : call command handler */
-       if (command != NULL) {
+       if (command != NULL)  {
                int err = 0;
                err = isp_handle_command(command, nb_cmd_args, cmd_args);
                if (err >= 0) {
@@ -190,8 +208,6 @@ int main(int argc, char** argv)
                } else {
                        printf("Error handling command \"%s\" : %d\n", command, err);
                }
-       } else {
-               printf("No command given. use -h or --help for help on available commands.\n");
        }
 
 
index c1b0707..3a858fc 100644 (file)
@@ -60,6 +60,9 @@ void isp_dump(const unsigned char* buf, unsigned int buf_size)
                        if (pass == 0) {
                                count -= 0x10;
                        } else {
+                               if (count == buf_size) {
+                                       break; /* prevent infinite loop */
+                               }
                                printf("|\n");
                        }
                        pass = !pass;