SingingCat 0
application
flashapp.c
Go to the documentation of this file.
1#include "flashapp.h"
2#include "led.h"
3#include "app_update.h"
4#include "user_app_exe.h"
15static char errbuf[80];
16static uint8_t flashloader;
17static byte flashbuf[512];
18static int offset = 0;
19static byte flashmode = 0;
20static void *baseadr;
21static uint32_t f_flags = 0;
22
23const struct consumerinfo flashconsumerinfo = { &flash_app_consumer, &flash_app_close };
24
25static void flash_start() {
26 led_indicate(LED_FLASHSTART);
27}
28static void flash_end() {
29 led_indicate(LED_FLASHEND);
30}
34static int comparemem(byte *adr1, byte *adr2, int size) {
35 int i;
36
37 for (i = 0; i < size; i++) {
38 if (*adr1++ != *adr2++) {
39 return 0;
40 }
41 }
42 return 1;
43}
44
45static void set_new_userapp(int streamfd, void *baseaddr) {
46 if (userapp_checksum_valid(baseadr)) {
47 printf("[flashapp] Set new userapp to %p\r\n", baseadr);
48 config_set_userapp((int32_t)baseadr);
49 return;
50 }
51 struct userapp_info *uai = baseadr;
52
53 if (uai->magic != 0x53435541) {
54 stream_seterror(streamfd, "[flashapp] not setting new userapp, invalid magic %p\r\n", uai->magic);
55 return;
56 }
57 uint32_t checksum = calc_crc32((void *)uai, uai->length, 8);
58
59 stream_seterror(streamfd, "[flashapp] Not setting new userapp to %p (checksum error). Calculated: %p, Expected: %p (length=%i)\r\n", baseadr, checksum, uai->checksum, uai->length);
60}
61
62void flash_debug() {
63 baseadr = (void *)0x08034800;
64 flash_app_close(1, 77);
65}
66int flash_app_close(int fd, int reason) {
67 if (reason != 0) {
68 goto no_activate;
69 }
70
71 if (f_flags & (1 << FLASH_FLAGS_SET_LATEST_USERAPP)) {
72 set_new_userapp(fd, baseadr);
73 invoke_stop();
74 user_app_exe_init(); // re-init
75 }
76 if (f_flags & (1 << FLASH_FLAGS_START_USERAPP)) {
77 user_app_enable(); // enable userapp. after we finished flashing, it makes sense to try the userapp again
78 }
79 if ((f_flags & (1 << FLASH_FLAGS_USE_DIRECT_WRITE)) == 0) {
80 mculib_flash_lock(MAIN_MCULIBHANDLE);
81 }
82 // if flags has not been set, OR flag bit has been set:
83 if ((f_flags == 0) || (f_flags & (1 << FLASH_FLAGS_SET_LATEST_APP))) {
84 if (flashloader == 0) {
85 struct app_header *ah = baseadr;
86 if (ah->magic == 0x53434657) {
87 set_latest_app(baseadr);
88 }
89 }
90 }
91
92no_activate:
93 flash_end();
94 printf("[flashapp] Flash closed (fd=%i,reason=%i,flags=%i)\r\n", fd, reason, f_flags);
95 return 0;
96}
97
98
102int flash_app_consumer(int streamfd, byte *b, int size) {
103 int r;
104
105 r = 0;
106
107 // do some real work
108
109 // get size and check base
110 if (offset == 0) {
111 flash_start();
112 if (!flashloader) {
113 struct app_header *header = (struct app_header *)b;
114 if (header->base != ((uint32_t)baseadr)) {
115 stream_seterror(streamfd, "[flashapp] Base mismatch. Expected %p and got %p", baseadr, header->base);
116 flash_end();
117 return 101;
118 }
119 }
120 }
121 if (flashmode == 5) {
122 stream_seterror(streamfd, "[flashapp] Flash failed - previous block was padded");
123 flash_end();
124 return 82;
125 }
126 if (size < sizeof(flashbuf)) {
127 size = sizeof(flashbuf);
128 flashmode = 5;
129 }
130
131 // simple retry mechanism
132 int retries = 0;
133
134 for (;;) {
135 retries++;
136 if ((r = flash_write(b, baseadr + offset, size))) {
137 if (retries > 3) {
138 stream_seterror(streamfd, "%s", errbuf);
139 goto fail;
140 }
141 } else {
142 break;
143 }
144 }
145 printf("[flashapp] written from %i to %i at %p\r\n", offset, offset + size, baseadr + offset);
146 offset = offset + size;
147 flash_end();
148 return 0;
149fail:
150 flash_end();
151 return r;
152}
153
157int flash_write(byte *b, void *adr, int size) {
158 int r;
159
160 // if direct access, just copy the bytes
161 if ((f_flags & (1 << FLASH_FLAGS_USE_DIRECT_WRITE)) != 0) {
162 byte *target = (byte *)adr;
163 for (r = 0; r < size; r++) {
164 target[r] = b[r];
165 }
166 return 0;
167 }
168
169
170 // write to flash
171 if (comparemem(b, adr, size)) {
172 // only execute if actually different.
173 // otherwise just return sucessfully
174 printf("[flashapp] %i bytes @ %p optimized out, bytes identical\r\n", size, adr);
175 return 0;
176 }
177 mculib_flash_lock(MAIN_MCULIBHANDLE);
178 if ((r = mculib_flash_unlock(MAIN_MCULIBHANDLE))) {
179 snprintf(errbuf, sizeof(errbuf), "[flashapp] unlock failed (%i)\r\n", r);
180 mculib_flash_lock(MAIN_MCULIBHANDLE);
181 return r;
182 }
183 if ((f_flags & (1 << FLASH_FLAGS_PRE_ERASE)) == 0) {
184 if ((r = mculib_flash_erase(MAIN_MCULIBHANDLE, adr, size))) {
185 snprintf(errbuf, sizeof(errbuf), "[flashapp] erase failed (%i)\r\n", r);
186 mculib_flash_lock(MAIN_MCULIBHANDLE);
187 return r;
188 }
189 }
190 if ((f_flags & (1 << FLASH_FLAGS_WRITE_OLD))) {
191 r = mculib_flash_write(MAIN_MCULIBHANDLE, b, adr, size);
192 } else {
193 // page is faster, but not tested as well yet - 8/1/2022 cnw
194 r = mculib_flash_write_page(MAIN_MCULIBHANDLE, b, adr, size);
195 }
196 mculib_flash_lock(MAIN_MCULIBHANDLE);
197 if (r) {
198 snprintf(errbuf, sizeof(errbuf), "[flashapp] write failure at address %p (%i bytes): %i\r\n", adr, size, r);
199 return r;
200 }
201 printf("[flashapp] written %i bytes @ %p\n", size, adr);
202 return 0;
203}
204
205// init for an incoming flash (called before 1st flash_app_consumer)
206// also used by usb
207int flash_app_init(void *base, uint32_t flags) {
208 printf("[flashapp] init, base=%p, flags=%i\r\n", base, flags);
209 f_flags = flags;
210 offset = 0;
211 flashmode = 0;
212 baseadr = base;
213 if (f_flags & (1 << FLASH_FLAGS_STOP_USERAPP)) {
214 user_app_disable(); // disable userapp
215 }
216 return 0;
217}
218static void flash_action_not_supported(struct command *com, int errno) {
219 send_command_reply_with_args(com, COMFLAGS_ACK, "errno=%i", errno);
220}
224void flashcom(struct command *com) {
225 const char *para;
226 struct command *data = NULL;
227
228 errbuf[0] = 0; // clear, we use it later in fail function
229 int bases = loader_get_app_base_address_count();
230 int i;
231 int fd;
232
233 int ec = 0;
234 void *writeto = NULL;
235 uint32_t flags = 0;
236
237 flashloader = 0;
238
239 if ((para = namedarg(com, "action")) != NULL) { // it is a new modern "action" command
240 return flash_action_not_supported(com, 1); // 1 indicates "not supported"
241 }
242 if ((para = namedarg(com, "flags")) != NULL) { // para flags?
243 flags = atoi(para);
244 }
245
246 // NEWER method: we allow the server to set a base.
247 if ((para = namedarg(com, "base")) != NULL) { // did server specify base?
248 long base = ascii_parse_hex((const byte *)para, strlen(para), NULL);
249 if (base == 0) {
250 ec = 6;
251 goto fail;
252 }
253 if ((void *)base == get_app_header()) {
254 ec = 7;
255 goto fail;
256 }
257 writeto = (void *)base;
258 if ((para = namedarg(com, "lf")) != NULL) { // para lf? if so we're special, trying to write loader
259 flashloader = 1;
260 printf("[flashapp] Update loader enabled (2)\r\n");
261 }
262 goto got_base;
263 }
264
265
266 // CURRENT method: we work out a base that suits us (and expect the binary to match)
267
268 if ((para = namedarg(com, "lf")) != NULL) { // para lf? if so we're special, trying to write loader
269 flashloader = 1;
270 printf("[flashapp] Update loader enabled\r\n");
271 writeto = (void *)0x8000000;
272 goto got_base;
273 }
274
275
276
277 printf("[flashapp] Got %i base addresses\r\n", bases);
278 for (i = 0; i < bases; i++) {
279 void *optadr = loader_get_app_base_address(i);
280 printf("[flashapp] %i. baseaddress = %p\r\n", i, optadr);
281 if ((optadr != NULL) && (optadr != get_app_header())) {
282 writeto = optadr;
283 break;
284 }
285 }
286 if (writeto == NULL) {
287 printf("[flashapp] No baseaddress for flash!\n");
288 ec = 1;
289 goto fail;
290 }
291
292
293got_base:
294 printf("[flashapp] Expecting flash at address 0x%p\r\n", writeto);
295 flash_app_init(writeto, flags);
296 // writeto is now the best address to write to
297 if ((para = namedarg(com, "fd")) == NULL) {
298 ec = 2;
299 goto fail;
300 }
301 fd = atoi(para);
302 // associate this consumer with the stream and provide a buffer to the stream
303 int er = stream_associate(fd, &flashconsumerinfo, (byte *)&flashbuf, sizeof(flashbuf), 512);
304
305 if (er != 0) {
306 printf("[flashapp] Failed to associate stream with flash (%i)\r\n", er);
307 ec = 3;
308 goto fail;
309 }
310 data = get_data_reply(com);
311 if (data == NULL) {
312 printf("[flashapp] failed to alloc command\r\n");
313 ec = 4;
314 goto fail;
315 }
316 struct app_header *ap = (struct app_header *)writeto;
317
318 command_add_arg(data, "base=%p", writeto);
319 command_add_arg(data, "version=%i", ap->version);
320 if (send_command(data) != 0) {
321 printf("[flashapp] Failed to send flash data to sender\r\n");
322 ec = 5;
323 goto fail;
324 }
325
326 if (data != NULL) {
327 free_command(data);
328 }
329 send_command_reply(com, COMFLAGS_ACK | COMFLAGS_SUCCESS);
330 printf("[flashapp] Flash setup ok (base=%p)\r\n", writeto);
331 return;
332fail:
333 printf("[flashapp] Flash setup failed (%i)\r\n", ec);
334 if (data != NULL) {
335 free_command(data);
336 }
337 char e[100];
338 char e2[200];
339
340 snprintf(e, 99, "err=%i", ec);
341 snprintf(e2, 100, "em=%s", errbuf);
342 send_command_reply_with_args(com, COMFLAGS_ACK, e, e2);
343}
int send_command_reply_with_args(struct command *com, byte flags, const char *format,...)
send a reply to a command
Definition: queue.c:588
int stream_associate(int fd, const struct consumerinfo *c, byte *buf, int bufsize, int packetsize)
associate a stream with a consumer. return 0 if ok otherwise errorcode
Definition: streams.c:124
int send_command(struct command *com)
send a command to another module (or broadcast)
Definition: queue.c:374
void free_command(struct command *com)
free a command
Definition: queue.c:200
void command_add_arg(struct command *com, const char *format,...)
adds an arg to a partially initialised command structure
int flash_write(byte *b, void *adr, int size)
unlock, erase, write, lock
Definition: flashapp.c:157
const char * namedarg(struct command *com, const char *name)
get a named arg (key-value pair) or NULL
int send_command_reply(struct command *com, byte flags)
send a reply to a command
Definition: queue.c:562
int flash_app_consumer(int streamfd, byte *b, int size)
called by stream whenever we got sufficient bytes (and only on full blocks!)
Definition: flashapp.c:102
struct command * get_data_reply(struct command *com)
allocates and initializes a packet to be send as "data" to the command typically you'd add some data ...
Definition: queue.c:271
void flashcom(struct command *com)
set up a flash connection, associate with stream, called by command-handler for command "flash-app"
Definition: flashapp.c:224
int com
Definition: command.h:22
uint8_t flags
Definition: command.h:23
this must be implemented by the userapp, stored in flash at the beginning of the file (offset 0)