altos/test: Adjust CRC error rate after FEC fix
[fw/altos] / ao-tools / ao-stmload / ao-stmload.c
1 /*
2  * Copyright © 2012 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 <err.h>
20 #include <fcntl.h>
21 #include <gelf.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <sysexits.h>
26 #include <unistd.h>
27 #include <getopt.h>
28 #include <string.h>
29 #include <stdbool.h>
30 #include "stlink-common.h"
31 #include "ao-elf.h"
32 #include "ccdbg.h"
33 #include "cc.h"
34 #include "ao-stmload.h"
35 #include "ao-selfload.h"
36 #include "ao-verbose.h"
37 #include "ao-editaltos.h"
38
39
40 /*
41  * Read a 16-bit value from the target device with arbitrary
42  * alignment
43  */
44 static uint16_t
45 get_uint16_sl(stlink_t *sl, uint32_t addr)
46 {
47         const           uint8_t *data = sl->q_buf;
48         uint32_t        actual_addr;
49         int             off;
50         uint16_t        result;
51
52         sl->q_len = 0;
53
54
55         actual_addr = addr & ~3;
56         
57         stlink_read_mem32(sl, actual_addr, 8);
58
59         if (sl->q_len != 8)
60                 abort();
61
62         off = addr & 3;
63         result = data[off] | (data[off + 1] << 8);
64         return result;
65 }
66
67 static uint16_t
68 get_uint16(stlink_t *sl, uint32_t addr)
69 {
70         uint16_t        result;
71         result = get_uint16_sl(sl, addr);
72         printf ("read 0x%08x = 0x%04x\n", addr, result);
73         return result;
74 }
75
76 /*
77  * Read a 32-bit value from the target device with arbitrary
78  * alignment
79  */
80 static uint32_t
81 get_uint32_sl(stlink_t *sl, uint32_t addr)
82 {
83         const           uint8_t *data = sl->q_buf;
84         uint32_t        actual_addr;
85         int             off;
86         uint32_t        result;
87
88         sl->q_len = 0;
89
90         printf ("read 0x%x\n", addr);
91
92         actual_addr = addr & ~3;
93         
94         stlink_read_mem32(sl, actual_addr, 8);
95
96         if (sl->q_len != 8)
97                 abort();
98
99         off = addr & 3;
100         result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24);
101         return result;
102 }
103
104 /*
105  * Read a 32-bit value from the target device with arbitrary
106  * alignment
107  */
108 static uint32_t
109 get_uint32(stlink_t *sl, uint32_t addr)
110 {
111         uint32_t        result;
112
113         result = get_uint32_sl(sl, addr);
114         printf ("read 0x%08x = 0x%08x\n", addr, result);
115         return result;
116 }
117
118 /*
119  * Check to see if the target device has been
120  * flashed with a similar firmware image before
121  *
122  * This is done by looking for the same romconfig version,
123  * which should be at the same location as the linker script
124  * places this at 0x100 from the start of the rom section
125  */
126 static int
127 check_flashed(stlink_t *sl)
128 {
129         uint16_t        romconfig_version = get_uint16(sl, AO_ROMCONFIG_VERSION);
130         uint16_t        romconfig_check = get_uint16(sl, AO_ROMCONFIG_CHECK);
131
132         if (romconfig_version != (uint16_t) ~romconfig_check) {
133                 fprintf (stderr, "Device has not been flashed before\n");
134                 return 0;
135         }
136         return 1;
137 }
138
139 static const struct option options[] = {
140         { .name = "v1", .has_arg = 0, .val = '1' },
141         { .name = "raw", .has_arg = 0, .val = 'r' },
142         { .name = "cal", .has_arg = 1, .val = 'c' },
143         { .name = "serial", .has_arg = 1, .val = 's' },
144         { .name = "verbose", .has_arg = 1, .val = 'v' },
145         { 0, 0, 0, 0},
146 };
147
148 static void usage(char *program)
149 {
150         fprintf(stderr, "usage: %s [--v1] [--raw] [--verbose=<verbose>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
151         exit(1);
152 }
153
154 void
155 done(stlink_t *sl, int code)
156 {
157         stlink_reset(sl);
158         stlink_run(sl);
159         stlink_exit_debug_mode(sl);
160         stlink_close(sl);
161         exit (code);
162 }
163
164 static int
165 ends_with(char *whole, char *suffix)
166 {
167         int whole_len = strlen(whole);
168         int suffix_len = strlen(suffix);
169
170         if (suffix_len > whole_len)
171                 return 0;
172         return strcmp(whole + whole_len - suffix_len, suffix) == 0;
173 }
174
175 int
176 main (int argc, char **argv)
177 {
178         int                     stlink_v1 = 0;
179         int                     raw = 0;
180         char                    *filename;
181         Elf                     *e;
182         char                    *serial_end;
183         unsigned int            serial = 0;
184         char                    *serial_ucs2;
185         int                     serial_ucs2_len;
186         char                    serial_int[2];
187         unsigned int            s;
188         int                     i;
189         int                     string_num;
190         uint32_t                cal = 0;
191         char                    cal_int[4];
192         char                    *cal_end;
193         int                     c;
194         stlink_t                *sl = NULL;
195         int                     was_flashed = 0;
196         struct ao_hex_image     *load;
197         int                     tries;
198         int                     success;
199         int                     verbose = 0;
200         struct ao_sym           *file_symbols;
201         int                     num_file_symbols;
202
203         while ((c = getopt_long(argc, argv, "1rc:s:v:", options, NULL)) != -1) {
204                 switch (c) {
205                 case '1':
206                         stlink_v1 = 1;
207                         break;
208                 case 'r':
209                         raw = 1;
210                         break;
211                 case 'c':
212                         cal = strtoul(optarg, &cal_end, 10);
213                         if (cal_end == optarg || *cal_end != '\0')
214                                 usage(argv[0]);
215                         break;
216                 case 's':
217                         serial = strtoul(optarg, &serial_end, 10);
218                         if (serial_end == optarg || *serial_end != '\0')
219                                 usage(argv[0]);
220                         break;
221                 case 'v':
222                         verbose++;
223                         break;
224                 default:
225                         usage(argv[0]);
226                         break;
227                 }
228         }
229
230         ao_verbose = verbose;
231
232         if (verbose > 1)
233                 ccdbg_add_debug(CC_DEBUG_BITBANG);
234
235         filename = argv[optind];
236         if (filename == NULL)
237                 usage(argv[0]);
238
239         if (ends_with (filename, ".elf")) {
240                 load = ao_load_elf(filename, &file_symbols, &num_file_symbols);
241         } else if (ends_with (filename, ".ihx")) {
242                 load = ao_hex_load(filename, &file_symbols, &num_file_symbols);
243         } else
244                 usage(argv[0]);
245
246         if (!raw) {
247                 if (!ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) {
248                         fprintf(stderr, "Cannot find required symbols\n");
249                         usage(argv[0]);
250                 }
251         }
252
253         /* Connect to the programming dongle
254          */
255         
256         for (tries = 0; tries < 3; tries++) {
257                 if (stlink_v1) {
258                         sl = stlink_v1_open(50);
259                 } else {
260                         sl = stlink_open_usb(50);
261                 
262                 }
263                 if (!sl) {
264                         fprintf (stderr, "No STLink devices present\n");
265                         done (sl, 1);
266                 }
267
268                 if (sl->chip_id != 0)
269                         break;
270                 stlink_reset(sl);
271                 stlink_close(sl);
272                 sl = NULL;
273         }
274         if (!sl) {
275                 fprintf (stderr, "Debugger connection failed\n");
276                 exit(1);
277         }
278
279         /* Verify that the loaded image fits entirely within device flash
280          */
281         if (load->address < sl->flash_base ||
282             sl->flash_base + sl->flash_size < load->address + load->length) {
283                 fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
284                          load->address, load->address + load->length);
285                 done(sl, 1);
286         }
287
288         /* Enter debugging mode
289          */
290         if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
291                 stlink_exit_dfu_mode(sl);
292
293         if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
294                 stlink_enter_swd_mode(sl);
295
296
297         if (!raw) {
298                 /* Go fetch existing config values
299                  * if available
300                  */
301                 was_flashed = check_flashed(sl);
302
303                 if (!serial) {
304                         if (!was_flashed) {
305                                 fprintf (stderr, "Must provide serial number\n");
306                                 done(sl, 1);
307                         }
308                         serial = get_uint16(sl, AO_SERIAL_NUMBER);
309                         if (!serial || serial == 0xffff) {
310                                 fprintf (stderr, "Invalid existing serial %d\n", serial);
311                                 done(sl, 1);
312                         }
313                 }
314
315                 if (!cal && AO_RADIO_CAL && was_flashed) {
316                         cal = get_uint32(sl, AO_RADIO_CAL);
317                         if (!cal || cal == 0xffffffff) {
318                                 fprintf (stderr, "Invalid existing rf cal %d\n", cal);
319                                 done(sl, 1);
320                         }
321                 }
322
323                 if (!ao_editaltos(load, serial, cal))
324                         done(sl, 1);
325         }
326
327         /* And flash the resulting image to the device
328          */
329
330         success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0);
331                 
332         if (!success) {
333                 fprintf (stderr, "\"%s\": Write failed\n", filename);
334                 done(sl, 1);
335         }
336
337         done(sl, 0);
338 }