I release this plugin to cvs, now that I released new firmware images (see http://joerg.hohensohn.bei.t-online.de/archos/flash) with my new CRC check.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3953 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
0c0867cf5d
commit
60589066dd
1 changed files with 854 additions and 0 deletions
854
apps/plugins/firmware_flash.c
Normal file
854
apps/plugins/firmware_flash.c
Normal file
|
@ -0,0 +1,854 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Plugin for reprogramming the whole Flash ROM chip with a new content.
|
||||
* !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SHURE WHAT YOU DO !!!
|
||||
*
|
||||
* Copyright (C) 2003 Jörg Hohensohn [IDC]Dragon
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "plugin.h"
|
||||
|
||||
#ifndef SIMULATOR
|
||||
|
||||
/* define DUMMY if you only want to "play" with the UI, does no harm */
|
||||
/* #define DUMMY */
|
||||
|
||||
#ifndef UINT8
|
||||
#define UINT8 unsigned char
|
||||
#endif
|
||||
|
||||
#ifndef UINT16
|
||||
#define UINT16 unsigned short
|
||||
#endif
|
||||
|
||||
#ifndef UINT32
|
||||
#define UINT32 unsigned long
|
||||
#endif
|
||||
|
||||
#if defined(ARCHOS_PLAYER)
|
||||
#define FILENAME "/firmware_play.bin"
|
||||
#define KEEP VERSION_ADR /* keep the firmware version */
|
||||
#elif defined(ARCHOS_RECORDER)
|
||||
#define FILENAME "/firmware_rec.bin"
|
||||
#define KEEP MASK_ADR /* keep the mask value */
|
||||
#elif defined(ARCHOS_FMRECORDER)
|
||||
#define FILENAME "/firmware_fm.bin"
|
||||
#define KEEP MASK_ADR /* keep the mask value */
|
||||
#else
|
||||
#error ("No known platform given!")
|
||||
#endif
|
||||
|
||||
/* result of the CheckFirmwareFile() function */
|
||||
typedef enum
|
||||
{
|
||||
eOK = 0,
|
||||
eFileNotFound, /* errors from here on */
|
||||
eTooBig,
|
||||
eTooSmall,
|
||||
eReadErr,
|
||||
eBadContent,
|
||||
eCrcErr,
|
||||
} tCheckResult;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 manufacturer;
|
||||
UINT8 id;
|
||||
int size;
|
||||
char name[32];
|
||||
} tFlashInfo;
|
||||
|
||||
static struct plugin_api* rb; /* here is a global api struct pointer */
|
||||
|
||||
#define MASK_ADR 0xFC /* position of hardware mask value in Flash */
|
||||
#define VERSION_ADR 0xFE /* position of firmware version value in Flash */
|
||||
#define SEC_SIZE 4096 /* size of one flash sector */
|
||||
static UINT8* sector; /* better not place this on the stack... */
|
||||
static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
|
||||
|
||||
|
||||
/***************** Flash Functions *****************/
|
||||
|
||||
|
||||
/* read the manufacturer and device ID */
|
||||
bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
|
||||
{
|
||||
UINT8 not_manu, not_id; /* read values before switching to ID mode */
|
||||
UINT8 manu, id; /* read values when in ID mode */
|
||||
|
||||
pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */
|
||||
|
||||
/* read the normal content */
|
||||
not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
|
||||
not_id = pBase[1]; /* from the "ARCH" marker */
|
||||
|
||||
pBase[0x5555] = 0xAA; /* enter command mode */
|
||||
pBase[0x2AAA] = 0x55;
|
||||
pBase[0x5555] = 0x90; /* ID command */
|
||||
rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
|
||||
|
||||
manu = pBase[0];
|
||||
id = pBase[1];
|
||||
|
||||
pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
|
||||
rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
|
||||
|
||||
/* I assume success if the obtained values are different from
|
||||
the normal flash content. This is not perfectly bulletproof, they
|
||||
could theoretically be the same by chance, causing us to fail. */
|
||||
if (not_manu != manu || not_id != id) /* a value has changed */
|
||||
{
|
||||
*pManufacturerID = manu; /* return the results */
|
||||
*pDeviceID = id;
|
||||
return true; /* success */
|
||||
}
|
||||
return false; /* fail */
|
||||
}
|
||||
|
||||
|
||||
/* erase the sector which contains the given address */
|
||||
bool EraseSector(volatile UINT8* pAddr)
|
||||
{
|
||||
#ifdef DUMMY
|
||||
(void)pAddr; /* prevents warning */
|
||||
return true;
|
||||
#else
|
||||
volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
|
||||
unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */
|
||||
|
||||
pBase[0x5555] = 0xAA; /* enter command mode */
|
||||
pBase[0x2AAA] = 0x55;
|
||||
pBase[0x5555] = 0x80; /* erase command */
|
||||
pBase[0x5555] = 0xAA; /* enter command mode */
|
||||
pBase[0x2AAA] = 0x55;
|
||||
*pAddr = 0x30; /* erase the sector */
|
||||
|
||||
/* I counted 7 instructions for this loop -> min. 0.58 us per round */
|
||||
/* Plus memory waitstates it will be much more, gives margin */
|
||||
while (*pAddr != 0xFF && --timeout); /* poll for erased */
|
||||
|
||||
return (timeout != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* address must be in an erased location */
|
||||
inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
|
||||
{
|
||||
#ifdef DUMMY
|
||||
(void)pAddr; /* prevents warnings */
|
||||
(void)data;
|
||||
return true;
|
||||
#else
|
||||
unsigned timeout = 35; /* the timeout loop should be no less than 20us */
|
||||
|
||||
if (~*pAddr & data) /* just a safety feature, not really necessary */
|
||||
return false; /* can't set any bit from 0 to 1 */
|
||||
|
||||
FB[0x5555] = 0xAA; /* enter command mode */
|
||||
FB[0x2AAA] = 0x55;
|
||||
FB[0x5555] = 0xA0; /* byte program command */
|
||||
|
||||
*pAddr = data;
|
||||
|
||||
/* I counted 7 instructions for this loop -> min. 0.58 us per round */
|
||||
/* Plus memory waitstates it will be much more, gives margin */
|
||||
while (*pAddr != data && --timeout); /* poll for programmed */
|
||||
|
||||
return (timeout != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* this returns true if supported and fills the info struct */
|
||||
bool GetFlashInfo(tFlashInfo* pInfo)
|
||||
{
|
||||
rb->memset(pInfo, 0, sizeof(tFlashInfo));
|
||||
|
||||
if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
|
||||
return false;
|
||||
|
||||
if (pInfo->manufacturer == 0xBF) /* SST */
|
||||
{
|
||||
if (pInfo->id == 0xD6)
|
||||
{
|
||||
pInfo->size = 256* 1024; /* 256k */
|
||||
rb->strcpy(pInfo->name, "SST39VF020");
|
||||
return true;
|
||||
}
|
||||
else if (pInfo->id == 0xD7)
|
||||
{
|
||||
pInfo->size = 512* 1024; /* 512k */
|
||||
rb->strcpy(pInfo->name, "SST39VF040");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*********** Utility Functions ************/
|
||||
|
||||
|
||||
/* Tool function to calculate a CRC32 across some buffer */
|
||||
/* third argument is either 0xFFFFFFFF to start or value from last piece */
|
||||
unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
|
||||
{
|
||||
/* CCITT standard polynomial 0x04C11DB7 */
|
||||
static const unsigned crc32_lookup[16] =
|
||||
{ /* lookup table for 4 bits at a time is affordable */
|
||||
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
|
||||
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
|
||||
0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
|
||||
0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
|
||||
};
|
||||
|
||||
unsigned char byte;
|
||||
unsigned t;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
byte = *buf++; /* get one byte of data */
|
||||
|
||||
/* upper nibble of our data */
|
||||
t = crc32 >> 28; /* extract the 4 most significant bits */
|
||||
t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
|
||||
crc32 <<= 4; /* shift the CRC register left 4 bits */
|
||||
crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
|
||||
|
||||
/* lower nibble of our data */
|
||||
t = crc32 >> 28; /* extract the 4 most significant bits */
|
||||
t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
|
||||
crc32 <<= 4; /* shift the CRC register left 4 bits */
|
||||
crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
|
||||
}
|
||||
|
||||
return crc32;
|
||||
}
|
||||
|
||||
|
||||
/*********** Firmware File Functions ************/
|
||||
|
||||
tCheckResult CheckFirmwareFile(char* filename, int chipsize)
|
||||
{
|
||||
int i;
|
||||
int fd;
|
||||
int fileleft; /* size info, how many left for reading */
|
||||
int fileread = 0; /* total size as read from the file */
|
||||
int read_now; /* how many to read for this sector */
|
||||
int got_now; /* how many gotten for this sector */
|
||||
unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
|
||||
unsigned file_crc; /* CRC value read from file */
|
||||
bool has_crc;
|
||||
|
||||
fd = rb->open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return eFileNotFound;
|
||||
|
||||
fileleft = rb->filesize(fd);
|
||||
if (fileleft > chipsize)
|
||||
{
|
||||
rb->close(fd);
|
||||
return eTooBig;
|
||||
}
|
||||
else if (fileleft < 50000) /* give it some reasonable lower limit */
|
||||
{
|
||||
rb->close(fd);
|
||||
return eTooSmall;
|
||||
}
|
||||
|
||||
if (fileleft == 256*1024)
|
||||
{ // original dumped firmware file has no CRC
|
||||
has_crc = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_crc = true;
|
||||
fileleft -= sizeof(unsigned); // exclude the last 4 bytes
|
||||
}
|
||||
|
||||
/* do some sanity checks */
|
||||
|
||||
got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
|
||||
fileread += got_now;
|
||||
fileleft -= got_now;
|
||||
if (got_now != SEC_SIZE)
|
||||
{
|
||||
rb->close(fd);
|
||||
return eReadErr;
|
||||
}
|
||||
|
||||
if (has_crc)
|
||||
crc32 = crc_32(sector, SEC_SIZE, crc32); /* checksum */
|
||||
|
||||
/* compare some bytes which have to be identical */
|
||||
if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
|
||||
{
|
||||
rb->close(fd);
|
||||
return eBadContent;
|
||||
}
|
||||
|
||||
for (i = 0x30; i<MASK_ADR-1; i++) /* leave one byte for me */
|
||||
{
|
||||
if (sector[i] != FB[i])
|
||||
{
|
||||
rb->close(fd);
|
||||
return eBadContent;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we can read the whole file, and do checksum */
|
||||
do
|
||||
{
|
||||
read_now = MIN(SEC_SIZE, fileleft);
|
||||
got_now = rb->read(fd, sector, read_now);
|
||||
fileread += got_now;
|
||||
fileleft -= got_now;
|
||||
|
||||
if (read_now != got_now)
|
||||
{
|
||||
rb->close(fd);
|
||||
return eReadErr;
|
||||
}
|
||||
|
||||
if (has_crc)
|
||||
{
|
||||
crc32 = crc_32(sector, got_now, crc32); /* checksum */
|
||||
}
|
||||
} while (fileleft);
|
||||
|
||||
if (has_crc)
|
||||
{
|
||||
got_now = rb->read(fd, &file_crc, sizeof(file_crc));
|
||||
if (got_now != sizeof(file_crc))
|
||||
{
|
||||
rb->close(fd);
|
||||
return eReadErr;
|
||||
}
|
||||
}
|
||||
|
||||
/* must be EOF now */
|
||||
got_now = rb->read(fd, sector, SEC_SIZE);
|
||||
rb->close(fd);
|
||||
if (got_now != 0)
|
||||
return eReadErr;
|
||||
|
||||
if (has_crc && file_crc != crc32)
|
||||
return eCrcErr;
|
||||
|
||||
return eOK;
|
||||
}
|
||||
|
||||
|
||||
/* returns the # of failures, 0 on success */
|
||||
unsigned ProgramFirmwareFile(char* filename, int chipsize)
|
||||
{
|
||||
int i, j;
|
||||
int fd;
|
||||
int read = SEC_SIZE; /* how many for this sector */
|
||||
UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
|
||||
unsigned failures = 0;
|
||||
|
||||
fd = rb->open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
for (i=0; i<chipsize; i+=SEC_SIZE)
|
||||
{
|
||||
if (!EraseSector(FB + i))
|
||||
{
|
||||
/* nothing we can do, let the programming count the errors */
|
||||
}
|
||||
|
||||
if (read == SEC_SIZE) /* not EOF yet */
|
||||
{
|
||||
read = rb->read(fd, sector, SEC_SIZE);
|
||||
if (i==0)
|
||||
{ /* put original value back in */
|
||||
*(UINT16*)(sector + KEEP) = keep;
|
||||
}
|
||||
|
||||
for (j=0; j<read; j++)
|
||||
{
|
||||
if (!ProgramByte(FB + i + j, sector[j]))
|
||||
{
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rb->close(fd);
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
/* returns the # of failures, 0 on success */
|
||||
unsigned VerifyFirmwareFile(char* filename)
|
||||
{
|
||||
int i=0, j;
|
||||
int fd;
|
||||
int read = SEC_SIZE; /* how many for this sector */
|
||||
unsigned failures = 0;
|
||||
|
||||
fd = rb->open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
do
|
||||
{
|
||||
read = rb->read(fd, sector, SEC_SIZE);
|
||||
|
||||
for (j=0; j<read; j++)
|
||||
{
|
||||
/* position of keep value is no error */
|
||||
if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
|
||||
{
|
||||
failures++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
while (read == SEC_SIZE);
|
||||
|
||||
rb->close(fd);
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
/***************** User Interface Functions *****************/
|
||||
|
||||
int WaitForButton(void)
|
||||
{
|
||||
int button;
|
||||
|
||||
do
|
||||
{
|
||||
button = rb->button_get(true);
|
||||
} while (button & BUTTON_REL);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
/* Recorder implementation */
|
||||
|
||||
/* helper for DoUserDialog() */
|
||||
void ShowFlashInfo(tFlashInfo* pInfo)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
if (!pInfo->manufacturer)
|
||||
{
|
||||
rb->lcd_puts(0, 0, "Flash: M=?? D=??");
|
||||
rb->lcd_puts(0, 1, "Impossible to program");
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
|
||||
pInfo->manufacturer, pInfo->id);
|
||||
rb->lcd_puts(0, 0, buf);
|
||||
|
||||
|
||||
if (pInfo->size)
|
||||
{
|
||||
rb->lcd_puts(0, 1, pInfo->name);
|
||||
rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
|
||||
rb->lcd_puts(0, 2, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->lcd_puts(0, 1, "Unsupported chip");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rb->lcd_update();
|
||||
}
|
||||
|
||||
|
||||
/* Kind of our main function, defines the application flow. */
|
||||
void DoUserDialog(void)
|
||||
{
|
||||
tFlashInfo FlashInfo;
|
||||
char buf[32];
|
||||
int button;
|
||||
int rc; /* generic return code */
|
||||
int memleft;
|
||||
unsigned boot_crc;
|
||||
|
||||
rb->lcd_setfont(FONT_SYSFIXED);
|
||||
|
||||
/* check boot ROM */
|
||||
boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
|
||||
if (boot_crc != 0x56DBA4EE) /* Version 1 */
|
||||
{ /* no support for any other yet */
|
||||
rb->splash(HZ*3, 0, true, "Wrong boot ROM");
|
||||
return; /* exit */
|
||||
}
|
||||
|
||||
/* "allocate" memory */
|
||||
sector = rb->plugin_get_buffer(&memleft);
|
||||
if (memleft < SEC_SIZE) /* need buffer for a flash sector */
|
||||
{
|
||||
rb->splash(HZ*3, 0, true, "Out of memory");
|
||||
return; /* exit */
|
||||
}
|
||||
|
||||
rc = GetFlashInfo(&FlashInfo);
|
||||
ShowFlashInfo(&FlashInfo);
|
||||
if (FlashInfo.size == 0) /* no valid chip */
|
||||
{
|
||||
rb->splash(HZ*3, 0, true, "Sorry!");
|
||||
return; /* exit */
|
||||
}
|
||||
|
||||
rb->lcd_puts(0, 3, "using file:");
|
||||
rb->lcd_puts(0, 4, FILENAME);
|
||||
rb->lcd_puts(0, 6, "[F1] to check file");
|
||||
rb->lcd_puts(0, 7, "other key to exit");
|
||||
rb->lcd_update();
|
||||
|
||||
button = WaitForButton();
|
||||
if (button != BUTTON_F1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts(0, 0, "checking...");
|
||||
rb->lcd_update();
|
||||
|
||||
rc = CheckFirmwareFile(FILENAME, FlashInfo.size);
|
||||
rb->lcd_puts(0, 0, "checked:");
|
||||
switch (rc)
|
||||
{
|
||||
case eOK:
|
||||
rb->lcd_puts(0, 1, "File OK.");
|
||||
break;
|
||||
case eFileNotFound:
|
||||
rb->lcd_puts(0, 1, "File not found.");
|
||||
rb->lcd_puts(0, 2, "Put this in root:");
|
||||
rb->lcd_puts(0, 4, FILENAME);
|
||||
break;
|
||||
case eTooBig:
|
||||
rb->lcd_puts(0, 1, "File too big,");
|
||||
rb->lcd_puts(0, 2, "larger than chip.");
|
||||
break;
|
||||
case eTooSmall:
|
||||
rb->lcd_puts(0, 1, "File too small.");
|
||||
rb->lcd_puts(0, 2, "Incomplete?");
|
||||
break;
|
||||
case eReadErr:
|
||||
rb->lcd_puts(0, 1, "Read error.");
|
||||
break;
|
||||
case eBadContent:
|
||||
rb->lcd_puts(0, 1, "File invalid.");
|
||||
rb->lcd_puts(0, 2, "Sanity check fail.");
|
||||
break;
|
||||
case eCrcErr:
|
||||
rb->lcd_puts(0, 1, "File invalid.");
|
||||
rb->lcd_puts(0, 2, "CRC check failed,");
|
||||
rb->lcd_puts(0, 3, "checksum mismatch.");
|
||||
break;
|
||||
default:
|
||||
rb->lcd_puts(0, 1, "Check failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == eOK)
|
||||
{
|
||||
rb->lcd_puts(0, 6, "[F2] to program");
|
||||
rb->lcd_puts(0, 7, "other key to exit");
|
||||
}
|
||||
else
|
||||
{ /* error occured */
|
||||
rb->lcd_puts(0, 6, "Any key to exit");
|
||||
}
|
||||
|
||||
rb->lcd_update();
|
||||
|
||||
button = WaitForButton();
|
||||
if (button != BUTTON_F2 || rc != eOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts(0, 0, "Program all Flash?");
|
||||
rb->lcd_puts(0, 1, "Are you shure?");
|
||||
rb->lcd_puts(0, 2, "If it goes wrong,");
|
||||
rb->lcd_puts(0, 3, "it kills your box!");
|
||||
rb->lcd_puts(0, 4, "See documentation.");
|
||||
|
||||
rb->lcd_puts(0, 6, "[F3] to proceed");
|
||||
rb->lcd_puts(0, 7, "other key to exit");
|
||||
rb->lcd_update();
|
||||
|
||||
button = WaitForButton();
|
||||
if (button != BUTTON_F3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts(0, 0, "Programming...");
|
||||
rb->lcd_update();
|
||||
|
||||
rc = ProgramFirmwareFile(FILENAME, FlashInfo.size);
|
||||
if (rc)
|
||||
{ /* errors */
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts(0, 0, "Panic:");
|
||||
rb->lcd_puts(0, 1, "Programming fail!");
|
||||
rb->snprintf(buf, sizeof(buf), "%d errors", rc);
|
||||
rb->lcd_puts(0, 2, buf);
|
||||
rb->lcd_update();
|
||||
button = WaitForButton();
|
||||
}
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts(0, 0, "Verifying...");
|
||||
rb->lcd_update();
|
||||
|
||||
rc = VerifyFirmwareFile(FILENAME);
|
||||
|
||||
rb->lcd_clear_display();
|
||||
if (rc == 0)
|
||||
{
|
||||
rb->lcd_puts(0, 0, "Verify OK.");
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->lcd_puts(0, 0, "Panic:");
|
||||
rb->lcd_puts(0, 1, "Verify fail!");
|
||||
rb->snprintf(buf, sizeof(buf), "%d errors", rc);
|
||||
rb->lcd_puts(0, 2, buf);
|
||||
}
|
||||
rb->lcd_puts(0, 7, "Any key to exit");
|
||||
rb->lcd_update();
|
||||
|
||||
button = WaitForButton();
|
||||
}
|
||||
|
||||
#else /* HAVE_LCD_BITMAP */
|
||||
/* Player implementation */
|
||||
|
||||
/* helper for DoUserDialog() */
|
||||
void ShowFlashInfo(tFlashInfo* pInfo)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
if (!pInfo->manufacturer)
|
||||
{
|
||||
rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
|
||||
rb->lcd_puts_scroll(0, 1, "Impossible to program");
|
||||
WaitForButton();
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
|
||||
pInfo->manufacturer, pInfo->id);
|
||||
rb->lcd_puts_scroll(0, 0, buf);
|
||||
|
||||
if (pInfo->size)
|
||||
{
|
||||
rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
|
||||
rb->lcd_puts_scroll(0, 1, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->lcd_puts_scroll(0, 1, "Unsupported chip");
|
||||
WaitForButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DoUserDialog(void)
|
||||
{
|
||||
tFlashInfo FlashInfo;
|
||||
char buf[32];
|
||||
int button;
|
||||
int rc; /* generic return code */
|
||||
int memleft;
|
||||
unsigned boot_crc;
|
||||
|
||||
/* check boot ROM */
|
||||
boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
|
||||
if (boot_crc != 0x56DBA4EE) /* Version 1 */
|
||||
{ /* no support for any other yet */
|
||||
rb->splash(HZ*3, 0, true, "Wrong boot ROM");
|
||||
return; /* exit */
|
||||
}
|
||||
|
||||
/* "allocate" memory */
|
||||
sector = rb->plugin_get_buffer(&memleft);
|
||||
if (memleft < SEC_SIZE) /* need buffer for a flash sector */
|
||||
{
|
||||
rb->splash(HZ*3, 0, true, "Out of memory");
|
||||
return; /* exit */
|
||||
}
|
||||
|
||||
rc = GetFlashInfo(&FlashInfo);
|
||||
ShowFlashInfo(&FlashInfo);
|
||||
|
||||
if (FlashInfo.size == 0) /* no valid chip */
|
||||
{
|
||||
return; /* exit */
|
||||
}
|
||||
|
||||
rb->lcd_puts_scroll(0, 0, FILENAME);
|
||||
rb->lcd_puts_scroll(0, 1, "[Menu] to check");
|
||||
|
||||
button = WaitForButton();
|
||||
if (button != BUTTON_MENU)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts(0, 0, "Checking...");
|
||||
|
||||
rc = CheckFirmwareFile(FILENAME, FlashInfo.size);
|
||||
rb->lcd_puts(0, 0, "Checked:");
|
||||
switch (rc)
|
||||
{
|
||||
case eOK:
|
||||
rb->lcd_puts(0, 1, "File OK.");
|
||||
break;
|
||||
case eFileNotFound:
|
||||
rb->lcd_puts_scroll(0, 0, "File not found:");
|
||||
rb->lcd_puts_scroll(0, 1, FILENAME);
|
||||
break;
|
||||
case eTooBig:
|
||||
rb->lcd_puts_scroll(0, 0, "File too big,");
|
||||
rb->lcd_puts_scroll(0, 1, "larger than chip.");
|
||||
break;
|
||||
case eTooSmall:
|
||||
rb->lcd_puts_scroll(0, 0, "File too small.");
|
||||
rb->lcd_puts_scroll(0, 1, "Incomplete?");
|
||||
break;
|
||||
case eReadErr:
|
||||
rb->lcd_puts_scroll(0, 0, "Read error.");
|
||||
break;
|
||||
case eBadContent:
|
||||
rb->lcd_puts_scroll(0, 0, "File invalid.");
|
||||
rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
|
||||
break;
|
||||
case eCrcErr:
|
||||
rb->lcd_puts_scroll(0, 0, "File invalid.");
|
||||
rb->lcd_puts_scroll(0, 1, "CRC check failed.");
|
||||
break;
|
||||
default:
|
||||
rb->lcd_puts_scroll(0, 0, "Check failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
rb->sleep(HZ*3);
|
||||
|
||||
if (rc == eOK)
|
||||
{
|
||||
rb->lcd_puts_scroll(0, 0, "[On] to program,");
|
||||
rb->lcd_puts_scroll(0, 1, "other key to exit.");
|
||||
}
|
||||
else
|
||||
{ /* error occured */
|
||||
return;
|
||||
}
|
||||
|
||||
button = WaitForButton();
|
||||
|
||||
if (button != BUTTON_ON)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts_scroll(0, 0, "Are you sure?");
|
||||
rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
|
||||
|
||||
button = WaitForButton();
|
||||
|
||||
if (button != BUTTON_RIGHT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts_scroll(0, 0, "Programming...");
|
||||
|
||||
rc = ProgramFirmwareFile(FILENAME, FlashInfo.size);
|
||||
|
||||
if (rc)
|
||||
{ /* errors */
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts_scroll(0, 0, "Programming failed!");
|
||||
rb->snprintf(buf, sizeof(buf), "%d errors", rc);
|
||||
rb->lcd_puts_scroll(0, 1, buf);
|
||||
WaitForButton();
|
||||
}
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts_scroll(0, 0, "Verifying...");
|
||||
|
||||
rc = VerifyFirmwareFile(FILENAME);
|
||||
|
||||
rb->lcd_clear_display();
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
rb->lcd_puts_scroll(0, 0, "Verify OK.");
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
|
||||
rb->lcd_puts_scroll(0, 0, buf);
|
||||
}
|
||||
|
||||
rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
|
||||
WaitForButton();
|
||||
}
|
||||
|
||||
#endif /* not HAVE_LCD_BITMAP */
|
||||
|
||||
|
||||
/***************** Plugin Entry Point *****************/
|
||||
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
||||
{
|
||||
/* this macro should be called as the first thing you do in the plugin.
|
||||
it test that the api version and model the plugin was compiled for
|
||||
matches the machine it is running on */
|
||||
TEST_PLUGIN_API(api);
|
||||
|
||||
/* if you don't use the parameter, you can do like
|
||||
this to avoid the compiler warning about it */
|
||||
(void)parameter;
|
||||
|
||||
rb = api; /* copy to global api pointer */
|
||||
|
||||
/* now go ahead and have fun! */
|
||||
DoUserDialog();
|
||||
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
#endif /* #ifndef SIMULATOR */
|
||||
|
Loading…
Reference in a new issue