Files
edgetx-gx12/radio/src/bootloader/boot.cpp
T
2014-03-12 16:18:30 +01:00

985 lines
23 KiB
C++

/****************************************************************************
* Copyright (c) 2014 by Michael Blandford. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
****************************************************************************
* Other Authors:
* - Andre Bernet
* - Bertrand Songis
* - Bryan J. Rentoul (Gruvin)
* - Cameron Weeks
* - Erez Raviv
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini
* - Thomas Husterer
*
****************************************************************************/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef PCBTARANIS
#include "stm32f2xx_flash.h"
#endif
#include "board_taranis.h"
#include "../pwr.h"
#include "../lcd.h"
#include "../keys.h"
#include "../FatFs/ff.h"
#include "../FatFs/diskio.h"
#if defined(PCBTARANIS)
#define BOOT_KEY_UP KEY_PLUS
#define BOOT_KEY_DOWN KEY_MINUS
#define BOOT_KEY_LEFT KEY_MENU
#define BOOT_KEY_RIGHT KEY_PAGE
#define BOOT_KEY_MENU KEY_ENTER
#define BOOT_KEY_EXIT KEY_EXIT
#define DISPLAY_CHAR_WIDTH 35
#endif
// states
enum BootLoaderStates {
ST_START,
ST_DIR_CHECK,
ST_OPEN_DIR,
ST_FILE_LIST,
ST_FLASH_CHECK,
ST_FLASHING,
ST_FLASH_DONE,
ST_USB = 10,
ST_REBOOT = 11,
};
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
uint32_t FirmwareSize;
uint32_t Master_frequency;
volatile uint8_t Tenms;
uint8_t EE_timer;
TCHAR FlashFilename[60];
FIL FlashFile;
DIR Dj;
FILINFO Finfo;
TCHAR Filenames[20][50];
uint32_t FileSize[20];
uint32_t FnStartIndex;
uint32_t Valid;
uint32_t FlashSize;
uint32_t FlashBlocked = 1;
uint32_t LockBits;
uint32_t Block_buffer[1024];
UINT BlockCount;
#ifdef PCBSKY
extern int32_t EblockAddress;
#endif
extern uint32_t EepromBlocked;
extern void init_spi(void);
extern void writeBlock(void);
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
#ifdef PCBSKY
// Starts TIMER0 at full speed (MCK/2) for delay timing
// @ 36MHz this is 18MHz
// This was 6 MHz, we may need to slow it to TIMER_CLOCK2 (MCK/8=4.5 MHz)
void start_timer0()
{
register Tc *ptc;
PMC->PMC_PCER0 |= 0x00800000L; // Enable peripheral clock to TC0
ptc = TC0;// Tc block 0 (TC0-2)
ptc->TC_BCR = 0;// No sync
ptc->TC_BMR = 2;
ptc->TC_CHANNEL[0].TC_CMR = 0x00008001;// Waveform mode MCK/8 for 36MHz osc.(Upset be write below)
ptc->TC_CHANNEL[0].TC_RC = 0xFFF0;
ptc->TC_CHANNEL[0].TC_RA = 0;
ptc->TC_CHANNEL[0].TC_CMR = 0x00008040;// 0000 0000 0000 0000 1000 0000 0100 0000, stop at regC, 18MHz
ptc->TC_CHANNEL[0].TC_CCR = 5;// Enable clock and trigger it (may only need trigger)
}
void stop_timer0( void )
{
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR0_CLKDIS; // Disable clock
}
void delay2ms()
{
TC0->TC_CHANNEL[0].TC_CCR = 5;// Enable clock and trigger it (may only need trigger)
while ( TC0->TC_CHANNEL[0].TC_CV < 36000 )// 2mS, Value depends on MCK/2 (used 18MHz)
{
// Wait
}
}
#endif
#ifdef PCBTARANIS
uint32_t isFirmwareStart(uint32_t *block)
{
if ((block[0] & 0xFFFC0000) != 0x20000000) {
return 0;
}
if ((block[1] & 0xFFF00000) != 0x08000000) {
return 0;
}
if ((block[2] & 0xFFF00000) != 0x08000000) {
return 0;
}
return 1;
}
#endif
#ifdef PCBSKY
uint32_t isFirmwareStart( uint32_t *block )
{
if ( ( block[0] & 0xFFFE3000 ) != 0x20000000 )
{
return 0;
}
if ( ( block[1] & 0xFFF80000 ) != 0x00400000 )
{
return 0;
}
if ( ( block[2] & 0xFFF80000 ) != 0x00400000 )
{
return 0;
}
return 1;
}
#endif
#ifdef PCBSKY
uint32_t (*IAP_Function)(uint32_t, uint32_t);
uint32_t program( uint32_t *address, uint32_t *buffer ) // size is 256 bytes
{
uint32_t FlashSectorNum;
uint32_t flash_cmd = 0;
uint32_t i;
// uint32_t flash_status = 0;
// uint32_t EFCIndex = 0; // 0:EEFC0, 1: EEFC1
/* Initialize the function pointer (retrieve function address from NMI vector) */
if ( (uint32_t) address == 0x00408000 )
{
if ( isFirmwareStart( buffer) )
{
FlashBlocked = 0;
}
else
{
FlashBlocked = 1;
}
}
if ( FlashBlocked )
{
return 1;
}
// Always initialise this here, setting a default doesn't seem to work
IAP_Function = (uint32_t (*)(uint32_t, uint32_t)) *(( uint32_t *)0x00800008);
FlashSectorNum = (uint32_t) address;
FlashSectorNum >>= 8;// page size is 256 bytes
FlashSectorNum &= 2047;// max page number
/* Send data to the sector here */
for ( i = 0; i < 64; i += 1 )
{
*address++ = *buffer++;
}
/* build the command to send to EEFC */
flash_cmd = (0x5A << 24) | (FlashSectorNum << 8) | 0x03; //AT91C_MC_FCMD_EWP ;
__disable_irq();
/* Call the IAP function with appropriate command */
i = IAP_Function( 0, flash_cmd );
__enable_irq();
return i;
}
uint32_t readLockBits()
{
// Always initialise this here, setting a default doesn't seem to work
IAP_Function = (uint32_t (*)(uint32_t, uint32_t)) *(( uint32_t *)0x00800008);
uint32_t flash_cmd = (0x5A << 24) | 0x0A;//AT91C_MC_FCMD_GLB ;
__disable_irq();
(void) IAP_Function( 0, flash_cmd );
__enable_irq();
return EFC->EEFC_FRR;
}
void clearLockBits()
{
uint32_t i;
uint32_t flash_cmd = 0;
// Always initialise this here, setting a default doesn't seem to work
IAP_Function = (uint32_t (*)(uint32_t, uint32_t)) *(( uint32_t *)0x00800008);
for ( i = 0; i < 16; i += 1 )
{
flash_cmd = (0x5A << 24) | ((128*i) << 8) | 0x09; //AT91C_MC_FCMD_CLB ;
__disable_irq();
/* Call the IAP function with appropriate command */
(void) IAP_Function( 0, flash_cmd );
__enable_irq();
}
}
#endif
void interrupt10ms(void)
{
Tenms |= 1; // 10 mS has passed
uint8_t enuk = KEY_MENU;
uint8_t in = ~readKeys();
for (int i = 1; i < 7; i++) {
uint8_t value = in & (1 << i);
keys[enuk].input(value, (EnumKeys) enuk);
++enuk;
}
}
#ifdef PCBSKY
void init10msTimer()
{
register Tc *ptc;
register uint32_t timer;
PMC->PMC_PCER0 |= 0x02000000L; // Enable peripheral clock to TC2
timer = Master_frequency / 12800;// MCK/128 and 100 Hz
ptc = TC0;// Tc block 0 (TC0-2)
ptc->TC_BCR = 0;// No sync
ptc->TC_BMR = 0;
ptc->TC_CHANNEL[2].TC_CMR = 0x00008000;// Waveform mode
ptc->TC_CHANNEL[2].TC_RC = timer;// 10 Hz
ptc->TC_CHANNEL[2].TC_RA = timer >> 1;
ptc->TC_CHANNEL[2].TC_CMR = 0x0009C003;// 0000 0000 0000 1001 1100 0000 0000 0011
// MCK/128, set @ RA, Clear @ RC waveform
ptc->TC_CHANNEL[2].TC_CCR = 5;// Enable clock and trigger it (may only need trigger)
NVIC_EnableIRQ(TC2_IRQn);
TC0->TC_CHANNEL[2].TC_IER = TC_IER0_CPCS;
}
extern "C" void TC2_IRQHandler()
{
register uint32_t dummy;
/* Clear status bit to acknowledge interrupt */
dummy = TC0->TC_CHANNEL[2].TC_SR;
(void) dummy; // Discard value - prevents compiler warning
interrupt10ms();
}
#endif
#ifdef PCBTARANIS
void init10msTimer()
{
// Timer14
RCC->APB1ENR |= RCC_APB1ENR_TIM14EN; // Enable clock
TIM14->ARR = 9999; // 10mS
TIM14->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS from 12MHz
TIM14->CCER = 0;
TIM14->CCMR1 = 0;
TIM14->EGR = 0;
TIM14->CR1 = 5;
TIM14->DIER |= 1;
NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
}
extern "C" void TIM8_TRG_COM_TIM14_IRQHandler()
{
TIM14->SR &= ~TIM_SR_UIF;
interrupt10ms();
}
void init_hw_timer()
{
// Timer13
RCC->APB1ENR |= RCC_APB1ENR_TIM13EN; // Enable clock
TIM13->ARR = 65535;
TIM13->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 10000000 - 1;// 0.1uS from 12MHz
TIM13->CCER = 0;
TIM13->CCMR1 = 0;
TIM13->EGR = 0;
TIM13->CR1 = 1;
}
// delay in units of 0.1 uS up to 6.5535 mS
void hw_delay(uint16_t time)
{
TIM13->CNT = 0;
TIM13->EGR = 1; // Re-start counter
while ( TIM13->CNT < time) {
// wait
}
}
//After reset, write is not allowed in the Flash control register (FLASH_CR) to protect the
//Flash memory against possible unwanted operations due, for example, to electric
//disturbances. The following sequence is used to unlock this register:
//1. Write KEY1 = 0x45670123 in the Flash key register (FLASH_KEYR)
//2. Write KEY2 = 0xCDEF89AB in the Flash key register (FLASH_KEYR)
//Any wrong sequence will return a bus error and lock up the FLASH_CR register until the
//next reset.
//The FLASH_CR register can be locked again by software by setting the LOCK bit in the
//FLASH_CR register.
void unlockFlash()
{
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
}
void waitFlashIdle()
{
while (FLASH->SR & FLASH_FLAG_BSY) {
wdt_reset();
}
}
#define SECTOR_MASK ((uint32_t)0xFFFFFF07)
void eraseSector(uint32_t sector)
{
waitFlashIdle();
FLASH->CR &= CR_PSIZE_MASK;
FLASH->CR |= FLASH_PSIZE_WORD;
FLASH->CR &= SECTOR_MASK;
FLASH->CR |= FLASH_CR_SER | (sector << 3);
FLASH->CR |= FLASH_CR_STRT;
/* Wait for operation to be completed */
waitFlashIdle();
/* if the erase operation is completed, disable the SER Bit */
FLASH->CR &= (~FLASH_CR_SER);
FLASH->CR &= SECTOR_MASK;
}
uint32_t program(uint32_t *address, uint32_t *buffer) // size is 256 bytes
{
uint32_t i;
if ((uint32_t) address == 0x08008000) {
if (isFirmwareStart(buffer)) {
FlashBlocked = 0;
}
else {
FlashBlocked = 1;
}
}
if (FlashBlocked) {
return 1;
}
if ((uint32_t) address == 0x08008000) {
eraseSector(2);
}
if ((uint32_t) address == 0x0800C000) {
eraseSector(3);
}
if ((uint32_t) address == 0x08010000) {
eraseSector(4);
}
if ((uint32_t) address == 0x08020000) {
eraseSector(5);
}
if ((uint32_t) address == 0x08040000) {
eraseSector(6);
}
if ((uint32_t) address == 0x08060000) {
eraseSector(7);
}
// Now program the 256 bytes
for (i = 0; i < 64; i += 1) {
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
be done by word */
// Wait for last operation to be completed
waitFlashIdle();
FLASH->CR &= CR_PSIZE_MASK;
FLASH->CR |= FLASH_PSIZE_WORD;
FLASH->CR |= FLASH_CR_PG;
*address = *buffer;
/* Wait for operation to be completed */
waitFlashIdle();
FLASH->CR &= (~FLASH_CR_PG);
/* Check the written value */
if (*address != *buffer) {
/* Flash content doesn't match SRAM content */
return 2;
}
/* Increment FLASH destination address */
address += 1;
buffer += 1;
}
return 0;
}
#endif
uint8_t *cpystr(uint8_t *dest, uint8_t *source)
{
while ((*dest++ = *source++))
;
return dest - 1;
}
FRESULT readBinDir(DIR *dj, FILINFO *fno)
{
FRESULT fr;
uint32_t loop;
do {
loop = 0;
fr = f_readdir(dj, fno); // First entry
if (fr != FR_OK || fno->fname[0] == 0) {
break;
}
if (*fno->lfname == 0) {
cpystr((uint8_t *) fno->lfname, (uint8_t *) fno->fname); // Copy 8.3 name
}
int32_t len = strlen(fno->lfname) - 4;
if (len < 0) {
loop = 1;
}
if (fno->lfname[len] != '.') {
loop = 1;
}
if ((fno->lfname[len + 1] != 'b') && (fno->lfname[len + 1] != 'B')) {
loop = 1;
}
if ((fno->lfname[len + 2] != 'i') && (fno->lfname[len + 2] != 'I')) {
loop = 1;
}
if ((fno->lfname[len + 3] != 'n') && (fno->lfname[len + 3] != 'N')) {
loop = 1;
}
} while (loop);
return fr;
}
uint32_t fillNames(uint32_t index)
{
uint32_t i;
FRESULT fr;
Finfo.lfname = Filenames[0];
Finfo.lfsize = 48;
fr = f_readdir(&Dj, 0); // rewind
fr = f_readdir(&Dj, &Finfo); // Skip .
fr = f_readdir(&Dj, &Finfo); // Skip ..
i = 0;
while (i <= index) {
fr = readBinDir(&Dj, &Finfo); // First entry
FileSize[0] = Finfo.fsize;
i += 1;
if (fr == FR_NO_FILE) {
return 0;
}
}
for (i = 1; i < 7; i += 1) {
Finfo.lfname = Filenames[i];
fr = readBinDir(&Dj, &Finfo); // First entry
FileSize[i] = Finfo.fsize;
if (fr != FR_OK || Finfo.fname[0] == 0) {
break;
}
}
return i;
}
FRESULT openFirmwareFile(uint32_t index)
{
cpystr(cpystr((uint8_t *) FlashFilename, (uint8_t *) "\\firmware\\"),
(uint8_t *) Filenames[index]);
f_open(&FlashFile, FlashFilename, FA_READ);
f_lseek(&FlashFile, 32768);
return f_read(&FlashFile, (BYTE *) Block_buffer, 4096, &BlockCount);
}
uint8_t flashFile(uint32_t index)
{
FRESULT fr;
lcd_clear();
lcd_putsLeft(0, "\005Flash File");
if (Valid == 0) {
// Validate file here
// return 3 if invalid
fr = openFirmwareFile(index);
fr = f_close(&FlashFile);
Valid = 1;
if (isFirmwareStart(Block_buffer) == 0) {
Valid = 2;
}
}
if (Valid == 2) {
lcd_putsLeft(3 * FH, "NOT A VALID FIRMWARE");
#ifdef PCBTARANIS
lcd_putsLeft(6 * FH, "\015[EXIT]");
#else
lcd_putsLeft( 6*FH,"\007[EXIT]");
#endif
uint8_t event = getEvent();
if (event == EVT_KEY_FIRST(BOOT_KEY_EXIT)) {
return 3;
}
return 4; //
}
lcd_putsnAtt(0, 2 * FH, Filenames[index], DISPLAY_CHAR_WIDTH, 0);
#ifdef PCBTARANIS
lcd_putsLeft(6 * FH, "\010[ENTER]\021[EXIT]");
lcd_putsLeft(5 * FH, "\010YES\021NO");
#else
lcd_putsLeft( 6*FH,"\003[MENU]\013[EXIT]");
lcd_putsLeft( 5*FH,"\003YES\013NO");
#endif
uint8_t event = getEvent();
if (event == EVT_KEY_FIRST(BOOT_KEY_MENU)) {
fr = openFirmwareFile(index);
FirmwareSize = FileSize[index];
if (fr != FR_OK) {
return 4; // File open error
}
return 2;
}
if (event == EVT_KEY_FIRST(BOOT_KEY_EXIT)) {
return 1;
}
return 0;
}
extern Key keys[];
static uint32_t PowerUpDelay;
int main()
{
uint32_t i;
uint8_t index = 0;
#ifdef PCBTARANIS
uint8_t TenCount = 2;
#endif
uint8_t maxhsize = DISPLAY_CHAR_WIDTH;
FRESULT fr;
uint32_t state = ST_START;
uint32_t nameCount = 0;
uint32_t vpos = 0;
uint32_t hpos = 0;
#ifdef PCBTARANIS
uint32_t firmwareAddress = 0x08000000;
#endif
#ifdef PCBSKY
uint32_t firmwareAddress = 0x00400000;
#endif
uint32_t firmwareWritten = 0;
#ifdef PCBTARANIS
wdt_reset();
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // Enable portA clock
#endif
pwrInit();
#ifdef PCBSKY
MATRIX->CCFG_SYSIO |= 0x000000F0L; // Disable syspins, enable B4,5,6,7
#endif
#ifdef PCBSKY
init_SDcard();
PIOC->PIO_PER = PIO_PC25; // Enable bit C25 (USB-detect)
start_timer0();
#endif
lcdInit();
#ifdef PCBSKY
extern uint8_t OptrexDisplay;
OptrexDisplay = 1;
#endif
lcd_clear();
#ifdef PCBTARANIS
lcd_putsLeft(0, "\006Boot Loader");
#endif
lcdRefresh();
#ifdef PCBSKY
OptrexDisplay = 0;
lcdRefresh();
#endif
#ifdef PCBTARANIS
keysInit();
I2C_EE_Init();
init_hw_timer();
#endif
__enable_irq();
init10msTimer();
#ifdef PCBSKY
EblockAddress = -1;
init_spi();
#endif
#ifdef PCBSKY
uint32_t chip_id = CHIPID->CHIPID_CIDR;
FlashSize = ( (chip_id >> 8 ) & 0x000F ) == 9 ? 256 : 512;
#endif
#ifdef PCBTARANIS
FlashSize = 512;
#endif
#ifdef PCBSKY
LockBits = readLockBits();
if ( LockBits )
{
clearLockBits();
}
#endif
#ifdef PCBTARANIS
// SD card detect pin
// configure_pins( SD_PRESENT_GPIO_Pin, PIN_PORTD | PIN_INPUT | PIN_PULLUP ) ;
sdInit();
unlockFlash();
usbInit();
usbStart();
#endif
for (;;) {
#ifdef PCBSKY
usbMassStorage();
#endif
wdt_reset();
if (Tenms) {
wdt_reset(); // Retrigger hardware watchdog
if (EE_timer) {
if (--EE_timer == 0) {
#ifdef PCBSKY
writeBlock();
#endif
}
}
Tenms = 0;
lcd_clear();
lcd_putsLeft(0, CENTER "Boot Loader");
lcd_invert_line(0);
{
if (usbPlugged()) {
state = ST_USB;
}
if (state == ST_USB) {
#ifdef PCBSKY
lcd_putsLeft( 3*FH, "\010BUSY" );
#endif
#ifdef PCBTARANIS
lcd_putsLeft(3 * FH, "\016BUSY");
#endif
if (usbPlugged() == 0) {
state = ST_START;
}
#ifdef PCBSKY
lcd_putc( 0, 6*FH, 'F' );
lcd_putc( 6, 6*FH, '0' + FlashBlocked );
lcd_putc( 0, 7*FH, 'E' );
lcd_putc( 6, 7*FH, '0' + EepromBlocked );
#endif
}
if (state == ST_START) {
sdInit();
fr = FR_OK;
}
else {
fr = FR_OK;
}
if (fr == FR_OK) {
if (state == ST_START) {
state = ST_DIR_CHECK;
}
}
if (state == ST_DIR_CHECK) {
fr = f_chdir("/firmware");
if (fr == FR_OK) {
state = ST_OPEN_DIR;
index = 0;
}
}
if (state == ST_DIR_CHECK) {
#ifdef PCBSKY
lcd_putsLeft( 2*FH, "\005No Firmware" );
#endif
#ifdef PCBTARANIS
lcd_putsLeft(2 * FH, "\013No Firmware");
#endif
}
if (state == ST_OPEN_DIR) {
fr = f_opendir(&Dj, ".");
if (fr == FR_OK) {
state = ST_FILE_LIST;
index = 0;
nameCount = fillNames(0);
hpos = 0;
vpos = 0;
}
}
if (state == ST_FILE_LIST) {
uint32_t limit = 6;
if (nameCount < limit) {
limit = nameCount;
}
maxhsize = 0;
for (i = 0; i < limit; i += 1) {
uint32_t x;
x = strlen(Filenames[i]);
if (x > maxhsize) {
maxhsize = x;
}
if (x > DISPLAY_CHAR_WIDTH) {
if ((hpos + DISPLAY_CHAR_WIDTH) > x) {
x = x - DISPLAY_CHAR_WIDTH;
}
else {
x = hpos;
}
}
else {
x = 0;
}
lcd_putsnAtt(0, 16 + FH * i, &Filenames[i][x], DISPLAY_CHAR_WIDTH,
0);
}
{
uint8_t event = getEvent();
if ((event == EVT_KEY_REPT(BOOT_KEY_DOWN))
|| event == EVT_KEY_FIRST(BOOT_KEY_DOWN)) {
if (vpos < limit - 1) {
vpos += 1;
}
else {
if (nameCount > limit) {
index += 1;
nameCount = fillNames(index);
}
}
}
if ((event == EVT_KEY_REPT(BOOT_KEY_UP))
|| (event == EVT_KEY_FIRST(BOOT_KEY_UP))) {
if (vpos > 0) {
vpos -= 1;
}
else {
if (index) {
index -= 1;
nameCount = fillNames(index);
}
}
}
if ((event == EVT_KEY_REPT(BOOT_KEY_RIGHT))
|| (event == EVT_KEY_FIRST(BOOT_KEY_RIGHT))) {
if (hpos + DISPLAY_CHAR_WIDTH < maxhsize) {
hpos += 1;
}
}
if ((event == EVT_KEY_REPT(BOOT_KEY_LEFT))
|| (event == EVT_KEY_FIRST(BOOT_KEY_LEFT))) {
if (hpos) {
hpos -= 1;
}
}
if (event == EVT_KEY_LONG(BOOT_KEY_MENU)) {
// Select file to flash
state = ST_FLASH_CHECK;
Valid = 0;
}
if (event == EVT_KEY_LONG(BOOT_KEY_EXIT)) {
state = ST_REBOOT;
}
}
lcd_invert_line(2 + vpos);
// lcd_char_inverse( 0, 2*FH+FH*vpos, DISPLAY_CHAR_WIDTH*FW, 0 ) ;
}
if (state == ST_FLASH_CHECK) {
i = flashFile(vpos);
FirmwareSize = FileSize[vpos] - 32768;
if (i == 1) {
state = ST_FILE_LIST; // Canceled
}
if (i == 2) {
#ifdef PCBSKY
firmwareAddress = 0x00408000;
#endif
#ifdef PCBTARANIS
firmwareAddress = 0x08008000;
#endif
firmwareWritten = 0;
state = ST_FLASHING; // confirmed
}
if (i == 3) {
// Invalid file
state = ST_FILE_LIST; // Canceled
}
}
if (state == ST_FLASHING) {
// Commit to flashing
uint32_t blockOffset = 0;
lcd_putsLeft(3 * FH, "Flashing");
while (BlockCount) {
program((uint32_t *) firmwareAddress, &Block_buffer[blockOffset]);// size is 256 bytes
blockOffset += 64; // 32-bit words (256 bytes)
firmwareAddress += 256;
if (BlockCount > 256) {
BlockCount -= 256;
}
else {
BlockCount = 0;
}
}
firmwareWritten += 1;
uint32_t width = FirmwareSize / 4096;
lcd_hline(0, 5 * FH - 1, width + 1);
lcd_hline(0, 6 * FH, width + 1);
lcd_vline(width, 5 * FH, 8);
for (i = 0; i < firmwareWritten; i += 1) {
lcd_vline(i, 5 * FH, 8);
}
fr = f_read(&FlashFile, (BYTE *) Block_buffer, 4096, &BlockCount);
if (BlockCount == 0) {
state = ST_FLASH_DONE;
}
if (firmwareWritten > FlashSize / 4 - 9)// (127-8, or 63-8) 4K blocks
{
state = ST_FLASH_DONE; // Backstop
}
}
if (state == ST_FLASH_DONE) {
uint8_t event = getEvent();
lcd_putsLeft(3 * FH, "Flashing Complete");
if (event == EVT_KEY_FIRST(BOOT_KEY_EXIT)) {
state = ST_FILE_LIST;
}
}
}
if (--TenCount == 0) {
TenCount = 2;
lcdRefresh();
}
if (PowerUpDelay < 20) // 200 mS
{
PowerUpDelay += 1;
}
else {
sdPoll10ms();
}
}
if ((state < ST_FLASH_CHECK) || (state == ST_FLASH_DONE)) {
if (pwrCheck() == e_power_off) {
pwrOff();
for (;;) {
// Wait for power to go off
}
}
}
if (state < ST_FILE_LIST) {
if (getEvent() == EVT_KEY_LONG(BOOT_KEY_EXIT)) {
state = ST_REBOOT;
}
}
if (state == ST_REBOOT) {
if ((~readKeys() & 0x7E) == 0) {
NVIC_SystemReset();
}
}
}
return 0;
}