summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/firmware_flash.c854
1 files changed, 854 insertions, 0 deletions
diff --git a/apps/plugins/firmware_flash.c b/apps/plugins/firmware_flash.c
new file mode 100644
index 0000000000..d24a174c12
--- /dev/null
+++ b/apps/plugins/firmware_flash.c
@@ -0,0 +1,854 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Plugin for reprogramming the whole Flash ROM chip with a new content.
11* !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SHURE WHAT YOU DO !!!
12*
13* Copyright (C) 2003 Jörg Hohensohn [IDC]Dragon
14*
15* All files in this archive are subject to the GNU General Public License.
16* See the file COPYING in the source tree root for full license agreement.
17*
18* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19* KIND, either express or implied.
20*
21****************************************************************************/
22#include "plugin.h"
23
24#ifndef SIMULATOR
25
26/* define DUMMY if you only want to "play" with the UI, does no harm */
27/* #define DUMMY */
28
29#ifndef UINT8
30#define UINT8 unsigned char
31#endif
32
33#ifndef UINT16
34#define UINT16 unsigned short
35#endif
36
37#ifndef UINT32
38#define UINT32 unsigned long
39#endif
40
41#if defined(ARCHOS_PLAYER)
42#define FILENAME "/firmware_play.bin"
43#define KEEP VERSION_ADR /* keep the firmware version */
44#elif defined(ARCHOS_RECORDER)
45#define FILENAME "/firmware_rec.bin"
46#define KEEP MASK_ADR /* keep the mask value */
47#elif defined(ARCHOS_FMRECORDER)
48#define FILENAME "/firmware_fm.bin"
49#define KEEP MASK_ADR /* keep the mask value */
50#else
51#error ("No known platform given!")
52#endif
53
54/* result of the CheckFirmwareFile() function */
55typedef enum
56{
57 eOK = 0,
58 eFileNotFound, /* errors from here on */
59 eTooBig,
60 eTooSmall,
61 eReadErr,
62 eBadContent,
63 eCrcErr,
64} tCheckResult;
65
66typedef struct
67{
68 UINT8 manufacturer;
69 UINT8 id;
70 int size;
71 char name[32];
72} tFlashInfo;
73
74static struct plugin_api* rb; /* here is a global api struct pointer */
75
76#define MASK_ADR 0xFC /* position of hardware mask value in Flash */
77#define VERSION_ADR 0xFE /* position of firmware version value in Flash */
78#define SEC_SIZE 4096 /* size of one flash sector */
79static UINT8* sector; /* better not place this on the stack... */
80static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
81
82
83/***************** Flash Functions *****************/
84
85
86/* read the manufacturer and device ID */
87bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
88{
89 UINT8 not_manu, not_id; /* read values before switching to ID mode */
90 UINT8 manu, id; /* read values when in ID mode */
91
92 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */
93
94 /* read the normal content */
95 not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
96 not_id = pBase[1]; /* from the "ARCH" marker */
97
98 pBase[0x5555] = 0xAA; /* enter command mode */
99 pBase[0x2AAA] = 0x55;
100 pBase[0x5555] = 0x90; /* ID command */
101 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
102
103 manu = pBase[0];
104 id = pBase[1];
105
106 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
107 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
108
109 /* I assume success if the obtained values are different from
110 the normal flash content. This is not perfectly bulletproof, they
111 could theoretically be the same by chance, causing us to fail. */
112 if (not_manu != manu || not_id != id) /* a value has changed */
113 {
114 *pManufacturerID = manu; /* return the results */
115 *pDeviceID = id;
116 return true; /* success */
117 }
118 return false; /* fail */
119}
120
121
122/* erase the sector which contains the given address */
123bool EraseSector(volatile UINT8* pAddr)
124{
125#ifdef DUMMY
126 (void)pAddr; /* prevents warning */
127 return true;
128#else
129 volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
130 unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */
131
132 pBase[0x5555] = 0xAA; /* enter command mode */
133 pBase[0x2AAA] = 0x55;
134 pBase[0x5555] = 0x80; /* erase command */
135 pBase[0x5555] = 0xAA; /* enter command mode */
136 pBase[0x2AAA] = 0x55;
137 *pAddr = 0x30; /* erase the sector */
138
139 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
140 /* Plus memory waitstates it will be much more, gives margin */
141 while (*pAddr != 0xFF && --timeout); /* poll for erased */
142
143 return (timeout != 0);
144#endif
145}
146
147
148/* address must be in an erased location */
149inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
150{
151#ifdef DUMMY
152 (void)pAddr; /* prevents warnings */
153 (void)data;
154 return true;
155#else
156 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
157
158 if (~*pAddr & data) /* just a safety feature, not really necessary */
159 return false; /* can't set any bit from 0 to 1 */
160
161 FB[0x5555] = 0xAA; /* enter command mode */
162 FB[0x2AAA] = 0x55;
163 FB[0x5555] = 0xA0; /* byte program command */
164
165 *pAddr = data;
166
167 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
168 /* Plus memory waitstates it will be much more, gives margin */
169 while (*pAddr != data && --timeout); /* poll for programmed */
170
171 return (timeout != 0);
172#endif
173}
174
175
176/* this returns true if supported and fills the info struct */
177bool GetFlashInfo(tFlashInfo* pInfo)
178{
179 rb->memset(pInfo, 0, sizeof(tFlashInfo));
180
181 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
182 return false;
183
184 if (pInfo->manufacturer == 0xBF) /* SST */
185 {
186 if (pInfo->id == 0xD6)
187 {
188 pInfo->size = 256* 1024; /* 256k */
189 rb->strcpy(pInfo->name, "SST39VF020");
190 return true;
191 }
192 else if (pInfo->id == 0xD7)
193 {
194 pInfo->size = 512* 1024; /* 512k */
195 rb->strcpy(pInfo->name, "SST39VF040");
196 return true;
197 }
198 else
199 return false;
200 }
201 return false;
202}
203
204
205/*********** Utility Functions ************/
206
207
208/* Tool function to calculate a CRC32 across some buffer */
209/* third argument is either 0xFFFFFFFF to start or value from last piece */
210unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
211{
212 /* CCITT standard polynomial 0x04C11DB7 */
213 static const unsigned crc32_lookup[16] =
214 { /* lookup table for 4 bits at a time is affordable */
215 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
216 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
217 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
218 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
219 };
220
221 unsigned char byte;
222 unsigned t;
223
224 while (len--)
225 {
226 byte = *buf++; /* get one byte of data */
227
228 /* upper nibble of our data */
229 t = crc32 >> 28; /* extract the 4 most significant bits */
230 t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
231 crc32 <<= 4; /* shift the CRC register left 4 bits */
232 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
233
234 /* lower nibble of our data */
235 t = crc32 >> 28; /* extract the 4 most significant bits */
236 t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
237 crc32 <<= 4; /* shift the CRC register left 4 bits */
238 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
239 }
240
241 return crc32;
242}
243
244
245/*********** Firmware File Functions ************/
246
247tCheckResult CheckFirmwareFile(char* filename, int chipsize)
248{
249 int i;
250 int fd;
251 int fileleft; /* size info, how many left for reading */
252 int fileread = 0; /* total size as read from the file */
253 int read_now; /* how many to read for this sector */
254 int got_now; /* how many gotten for this sector */
255 unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
256 unsigned file_crc; /* CRC value read from file */
257 bool has_crc;
258
259 fd = rb->open(filename, O_RDONLY);
260 if (fd < 0)
261 return eFileNotFound;
262
263 fileleft = rb->filesize(fd);
264 if (fileleft > chipsize)
265 {
266 rb->close(fd);
267 return eTooBig;
268 }
269 else if (fileleft < 50000) /* give it some reasonable lower limit */
270 {
271 rb->close(fd);
272 return eTooSmall;
273 }
274
275 if (fileleft == 256*1024)
276 { // original dumped firmware file has no CRC
277 has_crc = false;
278 }
279 else
280 {
281 has_crc = true;
282 fileleft -= sizeof(unsigned); // exclude the last 4 bytes
283 }
284
285 /* do some sanity checks */
286
287 got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
288 fileread += got_now;
289 fileleft -= got_now;
290 if (got_now != SEC_SIZE)
291 {
292 rb->close(fd);
293 return eReadErr;
294 }
295
296 if (has_crc)
297 crc32 = crc_32(sector, SEC_SIZE, crc32); /* checksum */
298
299 /* compare some bytes which have to be identical */
300 if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
301 {
302 rb->close(fd);
303 return eBadContent;
304 }
305
306 for (i = 0x30; i<MASK_ADR-1; i++) /* leave one byte for me */
307 {
308 if (sector[i] != FB[i])
309 {
310 rb->close(fd);
311 return eBadContent;
312 }
313 }
314
315 /* check if we can read the whole file, and do checksum */
316 do
317 {
318 read_now = MIN(SEC_SIZE, fileleft);
319 got_now = rb->read(fd, sector, read_now);
320 fileread += got_now;
321 fileleft -= got_now;
322
323 if (read_now != got_now)
324 {
325 rb->close(fd);
326 return eReadErr;
327 }
328
329 if (has_crc)
330 {
331 crc32 = crc_32(sector, got_now, crc32); /* checksum */
332 }
333 } while (fileleft);
334
335 if (has_crc)
336 {
337 got_now = rb->read(fd, &file_crc, sizeof(file_crc));
338 if (got_now != sizeof(file_crc))
339 {
340 rb->close(fd);
341 return eReadErr;
342 }
343 }
344
345 /* must be EOF now */
346 got_now = rb->read(fd, sector, SEC_SIZE);
347 rb->close(fd);
348 if (got_now != 0)
349 return eReadErr;
350
351 if (has_crc && file_crc != crc32)
352 return eCrcErr;
353
354 return eOK;
355}
356
357
358/* returns the # of failures, 0 on success */
359unsigned ProgramFirmwareFile(char* filename, int chipsize)
360{
361 int i, j;
362 int fd;
363 int read = SEC_SIZE; /* how many for this sector */
364 UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
365 unsigned failures = 0;
366
367 fd = rb->open(filename, O_RDONLY);
368 if (fd < 0)
369 return false;
370
371 for (i=0; i<chipsize; i+=SEC_SIZE)
372 {
373 if (!EraseSector(FB + i))
374 {
375 /* nothing we can do, let the programming count the errors */
376 }
377
378 if (read == SEC_SIZE) /* not EOF yet */
379 {
380 read = rb->read(fd, sector, SEC_SIZE);
381 if (i==0)
382 { /* put original value back in */
383 *(UINT16*)(sector + KEEP) = keep;
384 }
385
386 for (j=0; j<read; j++)
387 {
388 if (!ProgramByte(FB + i + j, sector[j]))
389 {
390 failures++;
391 }
392 }
393 }
394 }
395
396 rb->close(fd);
397
398 return failures;
399}
400
401/* returns the # of failures, 0 on success */
402unsigned VerifyFirmwareFile(char* filename)
403{
404 int i=0, j;
405 int fd;
406 int read = SEC_SIZE; /* how many for this sector */
407 unsigned failures = 0;
408
409 fd = rb->open(filename, O_RDONLY);
410 if (fd < 0)
411 return false;
412
413 do
414 {
415 read = rb->read(fd, sector, SEC_SIZE);
416
417 for (j=0; j<read; j++)
418 {
419 /* position of keep value is no error */
420 if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
421 {
422 failures++;
423 }
424 i++;
425 }
426 }
427 while (read == SEC_SIZE);
428
429 rb->close(fd);
430
431 return failures;
432}
433
434
435/***************** User Interface Functions *****************/
436
437int WaitForButton(void)
438{
439 int button;
440
441 do
442 {
443 button = rb->button_get(true);
444 } while (button & BUTTON_REL);
445
446 return button;
447}
448
449#ifdef HAVE_LCD_BITMAP
450/* Recorder implementation */
451
452/* helper for DoUserDialog() */
453void ShowFlashInfo(tFlashInfo* pInfo)
454{
455 char buf[32];
456
457 if (!pInfo->manufacturer)
458 {
459 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
460 rb->lcd_puts(0, 1, "Impossible to program");
461 }
462 else
463 {
464 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
465 pInfo->manufacturer, pInfo->id);
466 rb->lcd_puts(0, 0, buf);
467
468
469 if (pInfo->size)
470 {
471 rb->lcd_puts(0, 1, pInfo->name);
472 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
473 rb->lcd_puts(0, 2, buf);
474 }
475 else
476 {
477 rb->lcd_puts(0, 1, "Unsupported chip");
478 }
479
480 }
481
482 rb->lcd_update();
483}
484
485
486/* Kind of our main function, defines the application flow. */
487void DoUserDialog(void)
488{
489 tFlashInfo FlashInfo;
490 char buf[32];
491 int button;
492 int rc; /* generic return code */
493 int memleft;
494 unsigned boot_crc;
495
496 rb->lcd_setfont(FONT_SYSFIXED);
497
498 /* check boot ROM */
499 boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
500 if (boot_crc != 0x56DBA4EE) /* Version 1 */
501 { /* no support for any other yet */
502 rb->splash(HZ*3, 0, true, "Wrong boot ROM");
503 return; /* exit */
504 }
505
506 /* "allocate" memory */
507 sector = rb->plugin_get_buffer(&memleft);
508 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
509 {
510 rb->splash(HZ*3, 0, true, "Out of memory");
511 return; /* exit */
512 }
513
514 rc = GetFlashInfo(&FlashInfo);
515 ShowFlashInfo(&FlashInfo);
516 if (FlashInfo.size == 0) /* no valid chip */
517 {
518 rb->splash(HZ*3, 0, true, "Sorry!");
519 return; /* exit */
520 }
521
522 rb->lcd_puts(0, 3, "using file:");
523 rb->lcd_puts(0, 4, FILENAME);
524 rb->lcd_puts(0, 6, "[F1] to check file");
525 rb->lcd_puts(0, 7, "other key to exit");
526 rb->lcd_update();
527
528 button = WaitForButton();
529 if (button != BUTTON_F1)
530 {
531 return;
532 }
533
534 rb->lcd_clear_display();
535 rb->lcd_puts(0, 0, "checking...");
536 rb->lcd_update();
537
538 rc = CheckFirmwareFile(FILENAME, FlashInfo.size);
539 rb->lcd_puts(0, 0, "checked:");
540 switch (rc)
541 {
542 case eOK:
543 rb->lcd_puts(0, 1, "File OK.");
544 break;
545 case eFileNotFound:
546 rb->lcd_puts(0, 1, "File not found.");
547 rb->lcd_puts(0, 2, "Put this in root:");
548 rb->lcd_puts(0, 4, FILENAME);
549 break;
550 case eTooBig:
551 rb->lcd_puts(0, 1, "File too big,");
552 rb->lcd_puts(0, 2, "larger than chip.");
553 break;
554 case eTooSmall:
555 rb->lcd_puts(0, 1, "File too small.");
556 rb->lcd_puts(0, 2, "Incomplete?");
557 break;
558 case eReadErr:
559 rb->lcd_puts(0, 1, "Read error.");
560 break;
561 case eBadContent:
562 rb->lcd_puts(0, 1, "File invalid.");
563 rb->lcd_puts(0, 2, "Sanity check fail.");
564 break;
565 case eCrcErr:
566 rb->lcd_puts(0, 1, "File invalid.");
567 rb->lcd_puts(0, 2, "CRC check failed,");
568 rb->lcd_puts(0, 3, "checksum mismatch.");
569 break;
570 default:
571 rb->lcd_puts(0, 1, "Check failed.");
572 break;
573 }
574
575 if (rc == eOK)
576 {
577 rb->lcd_puts(0, 6, "[F2] to program");
578 rb->lcd_puts(0, 7, "other key to exit");
579 }
580 else
581 { /* error occured */
582 rb->lcd_puts(0, 6, "Any key to exit");
583 }
584
585 rb->lcd_update();
586
587 button = WaitForButton();
588 if (button != BUTTON_F2 || rc != eOK)
589 {
590 return;
591 }
592
593 rb->lcd_clear_display();
594 rb->lcd_puts(0, 0, "Program all Flash?");
595 rb->lcd_puts(0, 1, "Are you shure?");
596 rb->lcd_puts(0, 2, "If it goes wrong,");
597 rb->lcd_puts(0, 3, "it kills your box!");
598 rb->lcd_puts(0, 4, "See documentation.");
599
600 rb->lcd_puts(0, 6, "[F3] to proceed");
601 rb->lcd_puts(0, 7, "other key to exit");
602 rb->lcd_update();
603
604 button = WaitForButton();
605 if (button != BUTTON_F3)
606 {
607 return;
608 }
609
610 rb->lcd_clear_display();
611 rb->lcd_puts(0, 0, "Programming...");
612 rb->lcd_update();
613
614 rc = ProgramFirmwareFile(FILENAME, FlashInfo.size);
615 if (rc)
616 { /* errors */
617 rb->lcd_clear_display();
618 rb->lcd_puts(0, 0, "Panic:");
619 rb->lcd_puts(0, 1, "Programming fail!");
620 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
621 rb->lcd_puts(0, 2, buf);
622 rb->lcd_update();
623 button = WaitForButton();
624 }
625
626 rb->lcd_clear_display();
627 rb->lcd_puts(0, 0, "Verifying...");
628 rb->lcd_update();
629
630 rc = VerifyFirmwareFile(FILENAME);
631
632 rb->lcd_clear_display();
633 if (rc == 0)
634 {
635 rb->lcd_puts(0, 0, "Verify OK.");
636 }
637 else
638 {
639 rb->lcd_puts(0, 0, "Panic:");
640 rb->lcd_puts(0, 1, "Verify fail!");
641 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
642 rb->lcd_puts(0, 2, buf);
643 }
644 rb->lcd_puts(0, 7, "Any key to exit");
645 rb->lcd_update();
646
647 button = WaitForButton();
648}
649
650#else /* HAVE_LCD_BITMAP */
651/* Player implementation */
652
653/* helper for DoUserDialog() */
654void ShowFlashInfo(tFlashInfo* pInfo)
655{
656 char buf[32];
657
658 if (!pInfo->manufacturer)
659 {
660 rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
661 rb->lcd_puts_scroll(0, 1, "Impossible to program");
662 WaitForButton();
663 }
664 else
665 {
666 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
667 pInfo->manufacturer, pInfo->id);
668 rb->lcd_puts_scroll(0, 0, buf);
669
670 if (pInfo->size)
671 {
672 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
673 rb->lcd_puts_scroll(0, 1, buf);
674 }
675 else
676 {
677 rb->lcd_puts_scroll(0, 1, "Unsupported chip");
678 WaitForButton();
679 }
680 }
681}
682
683
684void DoUserDialog(void)
685{
686 tFlashInfo FlashInfo;
687 char buf[32];
688 int button;
689 int rc; /* generic return code */
690 int memleft;
691 unsigned boot_crc;
692
693 /* check boot ROM */
694 boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
695 if (boot_crc != 0x56DBA4EE) /* Version 1 */
696 { /* no support for any other yet */
697 rb->splash(HZ*3, 0, true, "Wrong boot ROM");
698 return; /* exit */
699 }
700
701 /* "allocate" memory */
702 sector = rb->plugin_get_buffer(&memleft);
703 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
704 {
705 rb->splash(HZ*3, 0, true, "Out of memory");
706 return; /* exit */
707 }
708
709 rc = GetFlashInfo(&FlashInfo);
710 ShowFlashInfo(&FlashInfo);
711
712 if (FlashInfo.size == 0) /* no valid chip */
713 {
714 return; /* exit */
715 }
716
717 rb->lcd_puts_scroll(0, 0, FILENAME);
718 rb->lcd_puts_scroll(0, 1, "[Menu] to check");
719
720 button = WaitForButton();
721 if (button != BUTTON_MENU)
722 {
723 return;
724 }
725
726 rb->lcd_clear_display();
727 rb->lcd_puts(0, 0, "Checking...");
728
729 rc = CheckFirmwareFile(FILENAME, FlashInfo.size);
730 rb->lcd_puts(0, 0, "Checked:");
731 switch (rc)
732 {
733 case eOK:
734 rb->lcd_puts(0, 1, "File OK.");
735 break;
736 case eFileNotFound:
737 rb->lcd_puts_scroll(0, 0, "File not found:");
738 rb->lcd_puts_scroll(0, 1, FILENAME);
739 break;
740 case eTooBig:
741 rb->lcd_puts_scroll(0, 0, "File too big,");
742 rb->lcd_puts_scroll(0, 1, "larger than chip.");
743 break;
744 case eTooSmall:
745 rb->lcd_puts_scroll(0, 0, "File too small.");
746 rb->lcd_puts_scroll(0, 1, "Incomplete?");
747 break;
748 case eReadErr:
749 rb->lcd_puts_scroll(0, 0, "Read error.");
750 break;
751 case eBadContent:
752 rb->lcd_puts_scroll(0, 0, "File invalid.");
753 rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
754 break;
755 case eCrcErr:
756 rb->lcd_puts_scroll(0, 0, "File invalid.");
757 rb->lcd_puts_scroll(0, 1, "CRC check failed.");
758 break;
759 default:
760 rb->lcd_puts_scroll(0, 0, "Check failed.");
761 break;
762 }
763
764 rb->sleep(HZ*3);
765
766 if (rc == eOK)
767 {
768 rb->lcd_puts_scroll(0, 0, "[On] to program,");
769 rb->lcd_puts_scroll(0, 1, "other key to exit.");
770 }
771 else
772 { /* error occured */
773 return;
774 }
775
776 button = WaitForButton();
777
778 if (button != BUTTON_ON)
779 {
780 return;
781 }
782
783 rb->lcd_clear_display();
784 rb->lcd_puts_scroll(0, 0, "Are you sure?");
785 rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
786
787 button = WaitForButton();
788
789 if (button != BUTTON_RIGHT)
790 {
791 return;
792 }
793
794 rb->lcd_clear_display();
795 rb->lcd_puts_scroll(0, 0, "Programming...");
796
797 rc = ProgramFirmwareFile(FILENAME, FlashInfo.size);
798
799 if (rc)
800 { /* errors */
801 rb->lcd_clear_display();
802 rb->lcd_puts_scroll(0, 0, "Programming failed!");
803 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
804 rb->lcd_puts_scroll(0, 1, buf);
805 WaitForButton();
806 }
807
808 rb->lcd_clear_display();
809 rb->lcd_puts_scroll(0, 0, "Verifying...");
810
811 rc = VerifyFirmwareFile(FILENAME);
812
813 rb->lcd_clear_display();
814
815 if (rc == 0)
816 {
817 rb->lcd_puts_scroll(0, 0, "Verify OK.");
818 }
819 else
820 {
821 rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
822 rb->lcd_puts_scroll(0, 0, buf);
823 }
824
825 rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
826 WaitForButton();
827}
828
829#endif /* not HAVE_LCD_BITMAP */
830
831
832/***************** Plugin Entry Point *****************/
833
834enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
835{
836 /* this macro should be called as the first thing you do in the plugin.
837 it test that the api version and model the plugin was compiled for
838 matches the machine it is running on */
839 TEST_PLUGIN_API(api);
840
841 /* if you don't use the parameter, you can do like
842 this to avoid the compiler warning about it */
843 (void)parameter;
844
845 rb = api; /* copy to global api pointer */
846
847 /* now go ahead and have fun! */
848 DoUserDialog();
849
850 return PLUGIN_OK;
851}
852
853#endif /* #ifndef SIMULATOR */
854