Merge remote-tracking branch 'mjb/master'
[fw/altos] / ao-tools / ao-dumpflash / ao-dumpflash.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <getopt.h>
23 #include <string.h>
24 #include "cc-usb.h"
25 #include "cc.h"
26
27 #define NUM_BLOCK       512
28
29 static const struct option options[] = {
30         { .name = "tty", .has_arg = 1, .val = 'T' },
31         { .name = "device", .has_arg = 1, .val = 'D' },
32         { .name = "remote", .has_arg = 0, .val = 'R' },
33         { .name = "frequency", .has_arg = 1, .val = 'F' },
34         { .name = "call", .has_arg = 1, .val = 'C' },
35         { .name = "output", .has_arg = 1, .val = 'o' },
36         { 0, 0, 0, 0},
37 };
38
39 static void usage(char *program)
40 {
41         fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] [--remote] [--frequency <radio-frequency>] [--call <radio-callsign>]\n", program);
42         exit(1);
43 }
44
45 int
46 main (int argc, char **argv)
47 {
48         struct cc_usb   *cc;
49         char            *tty = NULL;
50         char            *device = NULL;
51         int             c;
52         char            line[8192];
53         FILE            *out;
54         char            *filename;
55         int             serial_number = 0;
56         int             freq = 434550;
57         char            *call = "N0CALL";
58         int             flight = 0;
59         char            cmd;
60         int             block;
61         int             addr;
62         int             received_addr;
63         int             data[8];
64         int             done;
65         int             i;
66         int             column;
67         int             remote = 0;
68         int             any_valid;
69         int             invalid;
70         int             storage_size = 0;
71         char            *out_name;
72
73         while ((c = getopt_long(argc, argv, "T:D:F:C:o:R", options, NULL)) != -1) {
74                 switch (c) {
75                 case 'T':
76                         tty = optarg;
77                         break;
78                 case 'D':
79                         device = optarg;
80                         break;
81                 case 'R':
82                         remote = 1;
83                         break;
84                 case 'F':
85                         freq = atoi(optarg);
86                         break;
87                 case 'C':
88                         call = optarg;
89                         break;
90                 case 'o':
91                         out_name = optarg;
92                         break;
93                 default:
94                         usage(argv[0]);
95                         break;
96                 }
97         }
98         if (!tty) {
99                 if (remote)
100                         tty = cc_usbdevs_find_by_arg(device, "TeleDongle");
101                 else
102                         tty = cc_usbdevs_find_by_arg(device, "TeleMetrum");
103         }
104         if (!tty)
105                 tty = getenv("ALTOS_TTY");
106         if (!tty)
107                 tty="/dev/ttyACM0";
108
109         cc = cc_usb_open(tty);
110         if (!cc)
111                 exit(1);
112         if (remote)
113                 cc_usb_open_remote(cc, freq, call);
114
115         if (out_name) {
116                 out = fopen(out_name, "w");
117                 if (!out) {
118                         perror(out_name);
119                         cc_usb_close(cc);
120                         exit(1);
121                 }
122         } else
123                 out = stdout;
124
125         /* send a 'version' command followed by a 'flash' command */
126         cc_usb_printf(cc, "f\nv\n");
127         for (;;) {
128                 cc_usb_getline(cc, line, sizeof (line));
129                 if (sscanf(line, "serial-number %u", &serial_number) == 1)
130                         continue;
131                 if (sscanf(line, "Storage size: %u", &storage_size) == 1)
132                         continue;
133                 if (!strncmp(line, "software-version", 16))
134                         break;
135         }
136         if (!serial_number) {
137                 fprintf(stderr, "no serial number found\n");
138                 cc_usb_close(cc);
139                 exit(1);
140         }
141         if (!storage_size) {
142                 fprintf(stderr, "no storage size found\n");
143                 cc_usb_close(cc);
144                 exit(1);
145         }
146         printf ("Serial number: %d\n", serial_number);
147         printf ("Storage size:  %d\n", storage_size);
148         fprintf (stderr, "%7d of %7d", 0, storage_size/256);
149         for (block = 0; block < storage_size / 256; block++) {
150                 cc_usb_printf(cc, "e %x\n", block);
151                 fprintf (stderr, "\r%7d of %7d", block + 1, storage_size/256); fflush(stderr);
152                 for (addr = 0; addr < 0x100;) {
153                         cc_usb_getline(cc, line, sizeof (line));
154                         if (sscanf(line, "00%x %x %x %x %x %x %x %x %x",
155                                           &received_addr,
156                                           &data[0], &data[1], &data[2], &data[3],
157                                           &data[4], &data[5], &data[6], &data[7]) == 9)
158                         {
159                                 if (received_addr != addr)
160                                         fprintf(stderr, "data out of sync at 0x%x\n",
161                                                 block * 256 + received_addr);
162
163                                 fprintf (out, "%08x", block * 256 + addr);
164                                 for (i = 0; i < 8; i++)
165                                         fprintf (out, " %02x", data[i]);
166                                 fprintf (out, "\n");
167
168                                 addr += 8;
169                         }
170                 }
171         }
172         fprintf(stderr, "\n");
173         cc_usb_close(cc);
174         exit (0);
175 }