Gordon Williams 9bc9ab8c20 colours
2013-10-02 12:43:43 +01:00

180 lines
6.0 KiB
C

/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Bootloader entry point
* ----------------------------------------------------------------------------
*/
#include "platform_config.h"
#include "utils.h"
#define BOOTLOADER_MAJOR_VERSION 3 // needed for Ext Erase in stm32loader.py
#define BOOTLOADER_MINOR_VERSION 0
#define CMD_GET (0x00)
#define CMD_GET_ID (0x02)
#define CMD_READ (0x11)
#define CMD_WRITE (0x31)
#define CMD_EXTERASE (0x44)
#define FLASH_START 0x08000000
#define BOOTLOADER_SIZE (10*1024)
#define ACK (0x79)
#define NACK (0x1F)
typedef enum {
BLS_UNDEFINED,
BLS_INITED, // Has got 0x7F byte...
BLS_COMMAND_FIRST_BYTE, // Got first byte of command - waiting for inverted byte
BLS_EXPECT_DATA,
} BootloaderState;
void setLEDs(int l) {
jshPinOutput(LED1_PININDEX, l&1);
jshPinOutput(LED2_PININDEX, (l>>1)&1);
jshPinOutput(LED3_PININDEX, (l>>2)&1);
}
int main(void) {
initHardware();
int flashy = 0;
BootloaderState state = BLS_UNDEFINED;
char currentCommand = 0;
while (1) {
if (!jshIsUSBSERIALConnected()) {
jshPinOutput(LED2_PININDEX, 0);
// reset, led off
} else {
int f = (flashy>>9) & 0x7F;
if (f&0x40) f=128-f;
jshPinOutput(LED3_PININDEX, ((flashy++)&0xFF)<f);
// flash led
int d = getc();
if (d>=0) { // if we have data
if (state==BLS_EXPECT_DATA) {
} else if (state==BLS_INITED) {
currentCommand = d;
state = BLS_COMMAND_FIRST_BYTE;
} else if (state==BLS_COMMAND_FIRST_BYTE) {
if (currentCommand == d^0xFF) {
unsigned int addr,i;
char chksum, buffer[256];
unsigned int nBytesMinusOne, nPages;
// confirmed
switch (currentCommand) {
case CMD_GET: // get bootloader info
putc(ACK);
putc(5); // 6 bytes
// now report what we support
putc(BOOTLOADER_MAJOR_VERSION<<4 | BOOTLOADER_MINOR_VERSION); // Bootloader version
// list supported commands
putc(CMD_GET);
putc(CMD_GET_ID);
putc(CMD_READ);
putc(CMD_WRITE);
putc(CMD_EXTERASE); // erase
putc(ACK); // last byte
break;
case CMD_GET_ID: // get chip ID
putc(ACK);
putc(1); // 2 bytes
// now report what we support
putc(0x04);
// 0x30 F1 XL density
// 0x14 F1 high density
putc(0x30); // TODO: really?
putc(ACK); // last byte
break;
case CMD_READ: // read memory
putc(ACK);
addr = getc_blocking() << 24;
addr |= getc_blocking() << 16;
addr |= getc_blocking() << 8;
addr |= getc_blocking();
chksum = getc_blocking();
// TODO: check checksum
putc(ACK);
nBytesMinusOne = getc_blocking();
chksum = getc_blocking();
// TODO: check checksum
putc(ACK);
for (i=0;i<=nBytesMinusOne;i++)
putc(((unsigned char*)addr)[i]);
break;
case CMD_WRITE: // write memory
putc(ACK);
addr = getc_blocking() << 24;
addr |= getc_blocking() << 16;
addr |= getc_blocking() << 8;
addr |= getc_blocking();
chksum = getc_blocking();
// TODO: check checksum and address&3==0
putc(ACK);
setLEDs(2); // green = wait for data
nBytesMinusOne = getc_blocking();
for (i=0;i<=nBytesMinusOne;i++)
buffer[i] = getc_blocking();
chksum = getc_blocking();
setLEDs(1); // red = write
// TODO: check checksum and (nBytesMinusOne+1)&3==0
FLASH_UnlockBank1();
for (i=0;i<=nBytesMinusOne;i+=4) {
unsigned int realaddr = addr+i;
if (realaddr >= (FLASH_START+BOOTLOADER_SIZE)) // protect bootloader
FLASH_ProgramWord(realaddr, *(unsigned int*)&buffer[i]);
}
FLASH_LockBank1();
setLEDs(0); // off
putc(ACK);
break;
case CMD_EXTERASE: // erase memory
putc(ACK);
nPages = getc_blocking() << 8;
nPages |= getc_blocking();
chksum = getc_blocking();
// TODO: check checksum
if (nPages == 0xFFFF) {
// all pages (except us!)
setLEDs(1); // red = write
FLASH_UnlockBank1();
for (i=BOOTLOADER_SIZE;i<FLASH_TOTAL;i+=FLASH_PAGE_SIZE)
FLASH_ErasePage((uint32_t)(FLASH_START + i));
FLASH_LockBank1();
setLEDs(0); // off
putc(ACK);
} else {
putc(NACK); // not implemented
}
break;
default: // unknown command
putc(NACK);
break;
}
} else {
// not correct
putc(NACK);
}
state = BLS_INITED;
} else {
switch (d) {
case 0x7F: // initialisation byte
putc(state == BLS_UNDEFINED ? ACK : NACK);
state = BLS_INITED;
break;
}
}
}
}
}
}