1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 #include <helper.h>
6
7 #include "flash.h"
8
starts_with(const char * str,const char * prefix)9 static bool starts_with(const char * str, const char * prefix) {
10 size_t n = strlen(prefix);
11
12 if (strlen(str) < n) { return(false); }
13
14 return (0 == strncmp(str, prefix, n));
15 }
16
17 // support positive integer from 0 to UINT64_MAX
18 // support decimal, hexadecimal, octal, binary format like 0xff 12 1k 1M, 0b1001
19 // negative numbers are not supported
20 // return 0 if success else return -1
get_long_integer_from_char_array(const char * const str,uint64_t * read_value)21 static int get_long_integer_from_char_array (const char *const str, uint64_t *read_value) {
22 uint64_t value;
23 char *tail;
24
25 if (starts_with (str, "0x") || starts_with (str, "0X")) { // hexadecimal
26 value = strtoul (str + 2, &tail, 16);
27 } else if (starts_with (str, "0b") || starts_with (str, "0B")) { // binary
28 value = strtoul (str + 2, &tail, 2);
29 } else if (starts_with (str, "0")) { // octal
30 value = strtoul (str + 1, &tail, 8);
31 } else { // decimal
32 value = strtoul (str, &tail, 10);
33 }
34
35 if (((tail[0] == 'k') || (tail[0] == 'K')) && (tail[1] == '\0')) {
36 value = value * 1024;
37 } else if (((tail[0] == 'm') || (tail[0] == 'M')) && (tail[1] == '\0')) {
38 value = value * 1024 * 1024;
39 } else if (tail[0] == '\0') {
40 /* value not changed */
41 } else {
42 return(-1);
43 }
44
45 *read_value = value;
46 return(0);
47 }
48
49 // support positive integer from 0 to UINT32_MAX
50 // support decimal, hexadecimal, octal, binary format like 0xff 12 1k 1M, 0b1001
51 // negative numbers are not supported
52 // return 0 if success else return -1
get_integer_from_char_array(const char * const str,uint32_t * read_value)53 static int get_integer_from_char_array (const char *const str, uint32_t *read_value) {
54 uint64_t value;
55 int result = get_long_integer_from_char_array (str, &value);
56
57 if (result != 0) {
58 return(result);
59 } else if (value > UINT32_MAX) {
60 fprintf (stderr, "*** Error: Integer greater than UINT32_MAX, cannot convert to int32_t\n");
61 return(-1);
62 } else {
63 *read_value = (uint32_t)value;
64 return(0);
65 }
66 }
67
invalid_args(const char * expected)68 static int invalid_args(const char *expected) {
69 fprintf(stderr, "*** Error: Expected args for this command: %s\n", expected);
70 return(-1);
71 }
72
bad_arg(const char * arg)73 static int bad_arg(const char *arg) {
74 fprintf(stderr, "*** Error: Invalid value for %s\n", arg);
75 return(-1);
76 }
77
flash_get_opts(struct flash_opts * o,int ac,char ** av)78 int flash_get_opts(struct flash_opts* o, int ac, char** av) {
79
80 // defaults
81 memset(o, 0, sizeof(*o));
82 o->log_level = STND_LOG_LEVEL;
83
84 // options
85 int result;
86
87 while (ac >= 1) {
88 if (strcmp(av[0], "--version") == 0) {
89 printf("v%s\n", STLINK_VERSION);
90 exit(EXIT_SUCCESS);
91 } else if (strcmp(av[0], "--debug") == 0) {
92 o->log_level = DEBUG_LOG_LEVEL;
93 } else if (strcmp(av[0], "--opt") == 0) {
94 o->opt = ENABLE_OPT;
95 } else if (strcmp(av[0], "--reset") == 0) {
96 o->reset = 1;
97 } else if (strcmp(av[0], "--serial") == 0 || starts_with(av[0], "--serial=")) {
98 const char * serial;
99
100 if (strcmp(av[0], "--serial") == 0) {
101 ac--;
102 av++;
103
104 if (ac < 1) { return(-1); }
105
106 serial = av[0];
107 } else {
108 serial = av[0] + strlen("--serial=");
109 }
110
111 memcpy(o->serial, serial, STLINK_SERIAL_BUFFER_SIZE);
112
113 } else if (strcmp(av[0], "--area") == 0 || starts_with(av[0], "--area=")) {
114 const char * area;
115
116 if (strcmp(av[0], "--area") == 0) {
117 ac--;
118 av++;
119
120 if (ac < 1) { return(-1); }
121
122 area = av[0];
123 } else {
124 area = av[0] + strlen("--area=");
125 }
126
127 if (strcmp(area, "main") == 0) {
128 o->area = FLASH_MAIN_MEMORY;
129 } else if (strcmp(area, "system") == 0) {
130 o->area = FLASH_SYSTEM_MEMORY;
131 } else if (strcmp(area, "otp") == 0) {
132 o->area = FLASH_OTP;
133 } else if (strcmp(area, "option") == 0) {
134 o->area = FLASH_OPTION_BYTES;
135 } else if (strcmp(area, "option_boot_add") == 0) {
136 o->area = FLASH_OPTION_BYTES_BOOT_ADD;
137 } else if (strcmp(area, "optcr") == 0) {
138 o->area = FLASH_OPTCR;
139 } else if (strcmp(area, "optcr1") == 0) {
140 o->area = FLASH_OPTCR1;
141 } else {
142 return(-1);
143 }
144
145 } else if (strcmp(av[0], "--freq") == 0) {
146 ac--;
147 av++;
148
149 if (ac < 1) {
150 return(-1);
151 }
152
153 o->freq = arg_parse_freq(av[0]);
154 if (o->freq < 0) {
155 return(-1);
156 }
157 } else if (starts_with(av[0], "--freq=")) {
158 o->freq = arg_parse_freq(av[0] + strlen("--freq="));
159 if (o->freq < 0) {
160 return(-1);
161 }
162 } else if (strcmp(av[0], "--format") == 0 || starts_with(av[0], "--format=")) {
163 const char * format;
164
165 if (strcmp(av[0], "--format") == 0) {
166 ac--;
167 av++;
168
169 if (ac < 1) { return(-1); }
170
171 format = av[0];
172 } else {
173 format = av[0] + strlen("--format=");
174 }
175
176 if (strcmp(format, "binary") == 0) {
177 o->format = FLASH_FORMAT_BINARY;
178 } else if (strcmp(format, "ihex") == 0) {
179 o->format = FLASH_FORMAT_IHEX;
180 } else {
181 return(bad_arg("format"));
182 }
183 } else if ( starts_with(av[0], "--flash=")) {
184 const char *arg = av[0] + strlen("--flash=");
185
186 uint32_t flash_size;
187 result = get_integer_from_char_array(arg, &flash_size);
188
189 if (result != 0) {
190 return(bad_arg ("--flash"));
191 } else {
192 o->flash_size = (size_t)flash_size;
193 }
194 } else if (strcmp(av[0], "--connect-under-reset") == 0) {
195 o->connect = CONNECT_UNDER_RESET;
196 } else if (strcmp(av[0], "--hot-plug") == 0) {
197 o->connect = CONNECT_HOT_PLUG;
198 } else {
199 break; // non-option found
200
201 }
202
203 ac--;
204 av++;
205 }
206
207 // command and (optional) device name
208 while (ac >= 1) {
209 if (strcmp(av[0], "erase") == 0) {
210 if (o->cmd != FLASH_CMD_NONE) { return(-1); }
211 o->cmd = FLASH_CMD_ERASE;
212 } else if (strcmp(av[0], "read") == 0) {
213 if (o->cmd != FLASH_CMD_NONE) { return(-1); }
214
215 o->cmd = FLASH_CMD_READ;
216 } else if (strcmp(av[0], "write") == 0) {
217 if (o->cmd != FLASH_CMD_NONE) { return(-1); }
218
219 o->cmd = FLASH_CMD_WRITE;
220 } else if (strcmp(av[0], "reset") == 0) {
221 if (o->cmd != FLASH_CMD_NONE) { return(-1); }
222
223 o->cmd = CMD_RESET;
224 } else {
225 break;
226 }
227
228 ac--;
229 av++;
230 }
231
232 switch (o->cmd) {
233 case FLASH_CMD_NONE: // no command found
234 return(-1);
235
236 case FLASH_CMD_ERASE: // no more arguments expected
237 if (ac != 0) { return(-1); }
238
239 break;
240
241 case FLASH_CMD_READ: // expect filename, addr and size
242 if ((o->area == FLASH_MAIN_MEMORY) || (o->area == FLASH_SYSTEM_MEMORY)) {
243 if (ac != 3) { return invalid_args("read <path> <addr> <size>"); }
244
245 o->filename = av[0];
246 uint32_t address;
247 result = get_integer_from_char_array(av[1], &address);
248 if (result != 0) {
249 return bad_arg ("addr");
250 } else {
251 o->addr = (stm32_addr_t) address;
252 }
253
254 uint32_t size;
255 result = get_integer_from_char_array(av[2], &size);
256 if (result != 0) {
257 return bad_arg ("size");
258 } else {
259 o->size = (size_t) size;
260 }
261
262 break;
263 } else if (o->area == FLASH_OTP) {
264 return bad_arg("TODO: otp not implemented yet");
265 if (ac > 1) { return invalid_args("otp read: [path]"); }
266 if (ac > 0) { o->filename = av[0]; }
267 break;
268 } else if (o->area == FLASH_OPTION_BYTES) {
269 if (ac > 2) { return invalid_args("option bytes read: [path] [size]"); }
270 if (ac > 0) { o->filename = av[0]; }
271 if (ac > 1) {
272 uint32_t size;
273 result = get_integer_from_char_array(av[1], &size);
274 if (result != 0) {
275 return bad_arg("option bytes read: invalid size");
276 } else {
277 o->size = (size_t) size;
278 }
279 }
280 break;
281 } else if (o->area == FLASH_OPTION_BYTES_BOOT_ADD) {
282 if (ac > 0) { return invalid_args("option bytes boot_add read"); }
283 break;
284 } else if (o->area == FLASH_OPTCR) {
285 if (ac > 0) { return invalid_args("option control register read"); }
286 break;
287 } else if (o->area == FLASH_OPTCR1) {
288 if (ac > 0) { return invalid_args("option control register 1 read"); }
289 break;
290 }
291
292 break;
293
294 case FLASH_CMD_WRITE:
295 // TODO: should be boot add 0 and boot add 1 uint32
296 if (o->area == FLASH_OPTION_BYTES) { // expect option byte value
297 if (ac != 1) { return invalid_args("option byte write <value>"); }
298 uint32_t val;
299 result = get_integer_from_char_array(av[0], &val);
300 if (result != 0) {
301 return bad_arg ("val");
302 } else {
303 o->val = (uint32_t) val;
304 }
305 } else if (o->area == FLASH_OPTION_BYTES_BOOT_ADD) { // expect option bytes boot address
306 if (ac != 1) { return invalid_args("option bytes boot_add write <value>"); }
307
308 uint32_t val;
309 result = get_integer_from_char_array(av[0], &val);
310
311 if (result != 0) {
312 return(bad_arg ("val"));
313 } else {
314 o->val = (uint32_t)val;
315 }
316 } else if (o->area == FLASH_OPTCR) { // expect option control register value
317 if (ac != 1) { return invalid_args("option control register write <value>"); }
318
319 uint32_t val;
320 result = get_integer_from_char_array(av[0], &val);
321
322 if (result != 0) {
323 return bad_arg ("val");
324 } else {
325 o->val = (uint32_t) val;
326 }
327 } else if (o->area == FLASH_OPTCR1) { // expect option control register 1 value
328 if (ac != 1) { return invalid_args("option control register 1 write <value>"); }
329
330 uint32_t val;
331 result = get_integer_from_char_array(av[0], &val);
332 if (result != 0) {
333 return bad_arg ("val");
334 } else {
335 o->val = (uint32_t) val;
336 }
337 } else if (o->format == FLASH_FORMAT_BINARY) { // expect filename and addr
338 if (ac != 2) { return invalid_args("write <path> <addr>"); }
339
340 o->filename = av[0];
341 uint32_t addr;
342 result = get_integer_from_char_array(av[1], &addr);
343
344 if (result != 0) {
345 return(bad_arg ("addr"));
346 } else {
347 o->addr = (stm32_addr_t)addr;
348 }
349 } else if (o->format == FLASH_FORMAT_IHEX) { // expect filename
350 if (ac != 1) { return(invalid_args("write <path>")); }
351
352 o->filename = av[0];
353 } else {
354 return(-1); // should have been caught during format parsing
355 }
356
357 break;
358
359 default: break;
360 }
361
362 return(0);
363 }
364