ao-tools: Fix warnings in ao-tools
[fw/altos] / ao-tools / ao-usbload / ao-usbload.c
index 9e32b2b9ee10fa779dd85e8a34d7f29c251a2dce..6da57bace36b6b53ad6ff51bf0b078373311ebf9 100644 (file)
@@ -3,7 +3,8 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -40,7 +41,6 @@ get_uint16(struct cc_usb *cc, uint32_t addr)
 {
        uint16_t        result;
        result = ao_self_get_uint16(cc, addr);
-       printf ("read 0x%08x = 0x%04x\n", addr, result);
        return result;
 }
 
@@ -54,7 +54,6 @@ get_uint32(struct cc_usb *cc, uint32_t addr)
        uint32_t        result;
 
        result = ao_self_get_uint32(cc, addr);
-       printf ("read 0x%08x = 0x%08x\n", addr, result);
        return result;
 }
 
@@ -82,19 +81,22 @@ check_flashed(struct cc_usb *cc)
 static const struct option options[] = {
        { .name = "tty", .has_arg = 1, .val = 'T' },
        { .name = "device", .has_arg = 1, .val = 'D' },
+       { .name = "raw", .has_arg = 0, .val = 'r' },
        { .name = "cal", .has_arg = 1, .val = 'c' },
        { .name = "serial", .has_arg = 1, .val = 's' },
        { .name = "verbose", .has_arg = 1, .val = 'v' },
+       { .name = "wait", .has_arg = 0, .val = 'w' },
+       { .name = "force", .has_arg = 0, .val = 'f' },
        { 0, 0, 0, 0},
 };
 
 static void usage(char *program)
 {
-       fprintf(stderr, "usage: %s [--verbose=<verbose>] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
+       fprintf(stderr, "usage: %s [--raw] [--verbose=<verbose>] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] [--wait] [--force] file.{elf,ihx}\n", program);
        exit(1);
 }
 
-void
+static void
 done(struct cc_usb *cc, int code)
 {
 /*     cc_usb_printf(cc, "a\n"); */
@@ -113,35 +115,72 @@ ends_with(char *whole, char *suffix)
        return strcmp(whole + whole_len - suffix_len, suffix) == 0;
 }
 
+static int
+ucs2len(uint16_t *ucs2)
+{
+       int     len = 0;
+       while (*ucs2++)
+               len++;
+       return len;
+}
+
+static int
+putucs4(uint32_t c, FILE *file)
+{
+       char d;
+       int     bits;
+
+            if (c <       0x80) { d = c;                         bits= -6; }
+       else if (c <      0x800) { d= ((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+       else if (c <    0x10000) { d= ((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
+       else if (c <   0x200000) { d= ((c >> 18) & 0x07) | 0xF0;  bits= 12; }
+       else if (c <  0x4000000) { d= ((c >> 24) & 0x03) | 0xF8;  bits= 18; }
+       else if (c < 0x80000000) { d= ((c >> 30) & 0x01) | 0xFC;  bits= 24; }
+       else return EOF;
+
+       if (putc (d, file) < 0)
+               return EOF;
+
+       for ( ; bits >= 0; bits-= 6)
+               if (putc (((c >> bits) & 0x3F) | 0x80, file) < 0)
+                       return EOF;
+
+       return 0;
+}
+
+static void
+putucs2str(uint16_t *ucs2str, FILE *file)
+{
+       uint16_t        ucs2;
+
+       while ((ucs2 = *ucs2str++) != 0)
+               putucs4(ucs2, file);
+}
+
 int
 main (int argc, char **argv)
 {
        char                    *device = NULL;
        char                    *filename;
-       Elf                     *e;
+       int                     raw = 0;
        char                    *serial_end;
        unsigned int            serial = 0;
-       char                    *serial_ucs2;
-       int                     serial_ucs2_len;
-       char                    serial_int[2];
-       unsigned int            s;
-       int                     i;
-       int                     string_num;
        uint32_t                cal = 0;
-       char                    cal_int[4];
        char                    *cal_end;
        int                     c;
        int                     was_flashed = 0;
        struct ao_hex_image     *load;
-       int                     tries;
        struct cc_usb           *cc = NULL;
        char                    *tty = NULL;
        int                     success;
        int                     verbose = 0;
        struct ao_sym           *file_symbols;
        int                     num_file_symbols;
+       uint32_t                flash_base, flash_bound;
+       int                     has_flash_size = 0;
+       int                     force = 0;
 
-       while ((c = getopt_long(argc, argv, "T:D:c:s:v:", options, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "wrfT:D:c:s:v:", options, NULL)) != -1) {
                switch (c) {
                case 'T':
                        tty = optarg;
@@ -149,6 +188,12 @@ main (int argc, char **argv)
                case 'D':
                        device = optarg;
                        break;
+               case 'r':
+                       raw = 1;
+                       break;
+               case 'w':
+                       cc_default_timeout = -1;
+                       break;
                case 'c':
                        cal = strtoul(optarg, &cal_end, 10);
                        if (cal_end == optarg || *cal_end != '\0')
@@ -162,6 +207,9 @@ main (int argc, char **argv)
                case 'v':
                        verbose++;
                        break;
+               case 'f':
+                       force = 1;
+                       break;
                default:
                        usage(argv[0]);
                        break;
@@ -184,8 +232,12 @@ main (int argc, char **argv)
        } else
                usage(argv[0]);
 
-       if (ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols))
-               fprintf(stderr, "Cannot find required symbols\n");
+       if (!raw) {
+               if (!ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) {
+                       fprintf(stderr, "Cannot find required symbols\n");
+                       usage(argv[0]);
+               }
+       }
 
        {
                int     is_loader;
@@ -196,7 +248,11 @@ main (int argc, char **argv)
                        if (!this_tty)
                                this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
                        if (!this_tty)
-                               this_tty = cc_usbdevs_find_by_arg(device, "MegaMetrum");
+                               this_tty = cc_usbdevs_find_by_arg(device, "TeleMega");
+                       if (!this_tty)
+                               this_tty = cc_usbdevs_find_by_arg(device, "TeleMetrum");
+                       if (!this_tty)
+                               this_tty = cc_usbdevs_find_by_arg(device, "TeleGPS");
                        if (!this_tty)
                                this_tty = getenv("ALTOS_TTY");
                        if (!this_tty)
@@ -213,6 +269,14 @@ main (int argc, char **argv)
                                cc_usb_getline(cc, line, sizeof(line));
                                if (!strncmp(line, "altos-loader", 12))
                                        is_loader = 1;
+                               if (!strncmp(line, "flash-range", 11)) {
+                                       int i;
+                                       for (i = 11; i < strlen(line); i++)
+                                               if (line[i] != ' ')
+                                                       break;
+                                       if (sscanf(line + i, "%x %x", &flash_base, &flash_bound) == 2)
+                                               has_flash_size = 1;
+                               }
                                if (!strncmp(line, "software-version", 16))
                                        break;
                        }
@@ -253,38 +317,98 @@ main (int argc, char **argv)
 #endif
        }
 
-       /* Go fetch existing config values
-        * if available
+       /* If the device can tell us the size of flash, make sure
+        * the image fits in that
         */
-       was_flashed = check_flashed(cc);
-
-       if (!serial) {
-               if (!was_flashed) {
-                       fprintf (stderr, "Must provide serial number\n");
-                       done(cc, 1);
-               }
-               serial = get_uint16(cc, AO_SERIAL_NUMBER);
-               if (!serial || serial == 0xffff) {
-                       fprintf (stderr, "Invalid existing serial %d\n", serial);
+       if (has_flash_size) {
+               if (load->address < flash_base ||
+                   load->address + load->length > flash_bound)
+               {
+                       fprintf(stderr, "Image does not fit on device.\n");
+                       fprintf(stderr, "  Image base:  %08x bounds %08x\n",
+                               load->address, load->address + load->length);
+                       fprintf(stderr, "  Device base: %08x bounds %08x\n",
+                               flash_base, flash_bound);
                        done(cc, 1);
                }
        }
 
-       if (!cal && AO_RADIO_CAL && was_flashed) {
-               cal = get_uint32(cc, AO_RADIO_CAL);
-               if (!cal || cal == 0xffffffff) {
-                       fprintf (stderr, "Invalid existing rf cal %d\n", cal);
-                       done(cc, 1);
+       if (!raw) {
+               /* Go fetch existing config values
+                * if available
+                */
+               was_flashed = check_flashed(cc);
+
+               if (!serial) {
+                       if (!was_flashed) {
+                               fprintf (stderr, "Must provide serial number\n");
+                               done(cc, 1);
+                       }
+                       serial = get_uint16(cc, AO_SERIAL_NUMBER);
+                       if (!serial || serial == 0xffff) {
+                               fprintf (stderr, "Invalid existing serial %d\n", serial);
+                               done(cc, 1);
+                       }
                }
-       }
 
-       if (!ao_editaltos(load, serial, cal))
-               done(cc, 1);
+               if (!cal && AO_RADIO_CAL && was_flashed) {
+                       cal = get_uint32(cc, AO_RADIO_CAL);
+                       if (!cal || cal == 0xffffffff) {
+                               fprintf (stderr, "Invalid existing rf cal %d\n", cal);
+                               done(cc, 1);
+                       }
+               }
+
+               if (!force && was_flashed) {
+                       struct ao_usb_id        new_id, old_id;
+                       uint16_t                *new_product, *old_product;
+                       int                     new_len, old_len;
+
+                       if (!ao_heximage_usb_id(load, &new_id)) {
+                               fprintf(stderr, "Can't get new USB id\n");
+                               done(cc, 1);
+                       }
+
+                       if (!ao_self_get_usb_id(cc, &old_id)) {
+                               fprintf(stderr, "Can't get old USB id\n");
+                               done(cc, 1);
+                       }
+                       if (new_id.vid != old_id.vid || new_id.pid != old_id.pid) {
+                               fprintf(stderr, "USB ID mismatch (device is %04x/%04x image is %04x/%04x)\n",
+                                       old_id.vid, old_id.pid, new_id.vid, new_id.pid);
+                               done(cc, 1);
+                       }
+
+                       new_product = ao_heximage_usb_product(load);
+                       if (!new_product) {
+                               fprintf(stderr, "Can't get new USB product name\n");
+                               done(cc, 1);
+                       }
+                       old_product = ao_self_get_usb_product(cc);
+                       if (!old_product) {
+                               fprintf(stderr, "Can't get existing USB product name\n");
+                               done(cc, 1);
+                       }
+                       new_len = ucs2len(new_product);
+                       old_len = ucs2len(old_product);
+                       if (new_len != old_len || memcmp(new_product, old_product, new_len * 2) != 0) {
+                               fprintf(stderr, "USB product mismatch (device is ");
+                               putucs2str(old_product, stderr);
+                               fprintf(stderr, ", image is ");
+                               putucs2str(new_product, stderr);
+                               fprintf(stderr, ")\n");
+                               done(cc, 1);
+                       }
+               }
+
+               if (!ao_editaltos(load, serial, cal))
+                       done(cc, 1);
+       }
 
        /* And flash the resulting image to the device
         */
        success = ao_self_write(cc, load);
-               
+
        if (!success) {
                fprintf (stderr, "\"%s\": Write failed\n", filename);
                done(cc, 1);