284068cb57d57b2fe3ec390906779a6497778d04
[fw/stlink] / flash / main.c
1 /* simple wrapper around the stlink_flash_write function */
2
3 // TODO - this should be done as just a simple flag to the st-util command line...
4
5
6 #include <signal.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include "stlink-common.h"
12
13 #define DEBUG_LOG_LEVEL 100
14 #define STND_LOG_LEVEL  50
15
16 stlink_t *connected_stlink = NULL;
17
18 static void cleanup(int signal __attribute__((unused))) {
19     if (connected_stlink) {
20         /* Switch back to mass storage mode before closing. */
21         stlink_run(connected_stlink);
22         stlink_exit_debug_mode(connected_stlink);
23         stlink_close(connected_stlink);
24     }
25
26     exit(1);
27 }
28
29 enum st_cmds {DO_WRITE = 0, DO_READ = 1, DO_ERASE = 2};
30 struct opts
31 {
32     enum st_cmds cmd;
33     const char* devname;
34         char *serial;
35     const char* filename;
36     stm32_addr_t addr;
37     size_t size;
38     int reset;
39     int log_level;
40 };
41
42 static void usage(void)
43 {
44     puts("stlinkv1 command line: ./st-flash [--debug] [--reset] [--serial <iSerial>] {read|write} /dev/sgX path addr <size>");
45     puts("stlinkv1 command line: ./st-flash [--debug] /dev/sgX erase");
46     puts("stlinkv2 command line: ./st-flash [--debug] [--reset] [--serial <iSerial>] {read|write} path addr <size>");
47     puts("stlinkv2 command line: ./st-flash [--debug] [--serial <iSerial>] erase");
48     puts("                       use hex format for addr, <iSerial> and <size>");
49 }
50
51 static int get_opts(struct opts* o, int ac, char** av)
52 {
53     /* stlinkv1 command line: ./st-flash {read|write} /dev/sgX path addr <size> */
54     /* stlinkv2 command line: ./st-flash {read|write} path addr <size> */
55
56     unsigned int i = 0;
57
58     if (ac < 1) return -1;
59
60     if (strcmp(av[0], "--debug") == 0)
61     {
62         o->log_level = DEBUG_LOG_LEVEL;
63         ac--;
64         av++;
65     }
66     else
67     {
68         o->log_level = STND_LOG_LEVEL;
69     }
70
71     if (strcmp(av[0], "--reset") == 0)
72     {
73         o->reset = 1;
74         ac--;
75         av++;
76     }
77     else
78     {
79         o->reset = 0;
80     }
81
82     if (strcmp(av[0], "--serial") == 0)
83     {
84         ac--;
85         av++;
86             int i=strlen(av[0]);
87             if(i%2 != 0){
88                     puts("no valid hex value, length must be multiple of 2\n");
89                     return -1;
90             }
91             int j=0;
92             while(i>=0 && j<=13){
93                     char buffer[3]={0};
94                     memcpy(buffer,&av[0][i],2);
95                     o->serial[12-j] = (char)strtol((const char*)buffer,NULL, 16);
96                     j++;
97                     i-=2;
98             }
99         ac--;
100         av++;
101     }
102     else
103     {
104         o->serial = NULL;
105     }
106
107     if (ac < 1) return -1;
108
109     /* stlinkv2 */
110     o->devname = NULL;
111
112     if (strcmp(av[0], "erase") == 0)
113     {
114         o->cmd = DO_ERASE;
115
116         /* stlinkv1 mode */
117         if (ac == 2)
118         {
119             o->devname = av[1];
120             i = 1;
121         }
122     }
123     else {
124         if (ac < 3) return -1;
125         if (strcmp(av[0], "read") == 0)
126         {
127             o->cmd = DO_READ;
128
129             /* stlinkv1 mode */
130             if (ac == 5)
131             {
132                 o->devname = av[1];
133                 i = 1;
134             }
135             if (ac > 3)
136                 o->size = strtoul(av[i + 3], NULL, 16);
137         }
138         else if (strcmp(av[0], "write") == 0)
139         {
140             o->cmd = DO_WRITE;
141
142             /* stlinkv1 mode */
143             if (ac == 4)
144             {
145                 o->devname = av[1];
146                 i = 1;
147             }
148         }
149         else
150         {
151             return -1;
152         }
153     }
154
155     o->filename = av[i + 1];
156     o->addr = strtoul(av[i + 2], NULL, 16);
157
158     return 0;
159 }
160
161
162 int main(int ac, char** av)
163 {
164     stlink_t* sl = NULL;
165     struct opts o;
166     char serial_buffer[13] = {0};
167     o.serial = serial_buffer;
168     int err = -1;
169
170     o.size = 0;
171     if (get_opts(&o, ac - 1, av + 1) == -1)
172     {
173         printf("invalid command line\n");
174         usage();
175         goto on_error;
176     }
177
178     if (o.devname != NULL) /* stlinkv1 */
179     {
180         sl = stlink_v1_open(o.log_level, 1);
181         if (sl == NULL) goto on_error;
182         sl->verbose = o.log_level;
183     }
184     else /* stlinkv2 */
185     {
186             sl = stlink_open_usb(o.log_level, 1, o.serial);
187         if (sl == NULL) goto on_error;
188         sl->verbose = o.log_level;
189     }
190
191     connected_stlink = sl;
192     signal(SIGINT, &cleanup);
193     signal(SIGTERM, &cleanup);
194     signal(SIGSEGV, &cleanup);
195
196     if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
197         stlink_exit_dfu_mode(sl);
198
199     if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
200         stlink_enter_swd_mode(sl);
201
202     if (o.reset){
203         stlink_jtag_reset(sl,2);
204         stlink_reset(sl);
205     }
206
207     // Disable DMA - Set All DMA CCR Registers to zero. - AKS 1/7/2013
208     if (sl->chip_id == STM32_CHIPID_F4)
209     {
210         memset(sl->q_buf,0,4);
211         for (int i=0;i<8;i++) {
212             stlink_write_mem32(sl,0x40026000+0x10+0x18*i,4);
213             stlink_write_mem32(sl,0x40026400+0x10+0x18*i,4);
214             stlink_write_mem32(sl,0x40026000+0x24+0x18*i,4);
215             stlink_write_mem32(sl,0x40026400+0x24+0x18*i,4);
216         }
217     }
218
219     // Core must be halted to use RAM based flashloaders
220     stlink_force_debug(sl);
221     stlink_status(sl);
222
223     if (o.cmd == DO_WRITE) /* write */
224     {
225         if ((o.addr >= sl->flash_base) &&
226                 (o.addr < sl->flash_base + sl->flash_size)) {
227             err = stlink_fwrite_flash(sl, o.filename, o.addr);
228             if (err == -1)
229             {
230                 printf("stlink_fwrite_flash() == -1\n");
231                 goto on_error;
232             }
233         }
234         else if ((o.addr >= sl->sram_base) &&
235                 (o.addr < sl->sram_base + sl->sram_size)) {
236             err = stlink_fwrite_sram(sl, o.filename, o.addr);
237             if (err == -1)
238             {
239                 printf("stlink_sram_flash() == -1\n");
240                 goto on_error;
241             }
242         }
243     } else if (o.cmd == DO_ERASE)
244     {
245         err = stlink_erase_flash_mass(sl);
246         if (err == -1)
247         {
248             printf("stlink_fwrite_flash() == -1\n");
249             goto on_error;
250         }
251     }
252     else /* read */
253     {
254         if ((o.addr >= sl->flash_base) && (o.size == 0) &&
255                 (o.addr < sl->flash_base + sl->flash_size))
256             o.size = sl->flash_size;
257         else if ((o.addr >= sl->sram_base) && (o.size == 0) &&
258                 (o.addr < sl->sram_base + sl->sram_size))
259             o.size = sl->sram_size;
260         err = stlink_fread(sl, o.filename, o.addr, o.size);
261         if (err == -1)
262         {
263             printf("stlink_fread() == -1\n");
264             goto on_error;
265         }
266     }
267
268     if (o.reset){
269         stlink_jtag_reset(sl,2);
270         stlink_reset(sl);
271     }
272
273     /* success */
274     err = 0;
275
276 on_error:
277     if (sl != NULL)
278     {
279         stlink_exit_debug_mode(sl);
280         stlink_close(sl);
281     }
282
283     return err;
284 }