mirror of https://github.com/jeelabs/esp-link.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
5.0 KiB
149 lines
5.0 KiB
// Copyright (c) 2015 by Thorsten von Eicken, see LICENSE.txt in the esp-link repo
|
|
// Copyright (c) 2016-2017 by Danny Backx
|
|
|
|
#include <esp8266.h>
|
|
#include <osapi.h>
|
|
#include "cgi.h"
|
|
#include "config.h"
|
|
#include "serial/uart.h"
|
|
#include "stk500v2.h"
|
|
#include "serial/serbridge.h"
|
|
#include "serial/serled.h"
|
|
|
|
#include "pgmshared.h"
|
|
|
|
struct optibootData *optibootData;
|
|
|
|
char responseBuf[RESP_SZ]; // buffer to accumulate responses from optiboot
|
|
short responseLen = 0; // amount accumulated so far
|
|
char errMessage[ERR_MAX]; // error message
|
|
|
|
// verify that N chars are hex characters
|
|
bool ICACHE_FLASH_ATTR checkHex(char *buf, short len) {
|
|
while (len--) {
|
|
char c = *buf++;
|
|
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
|
|
continue;
|
|
DBG("OB non-hex\n");
|
|
os_sprintf(errMessage, "Non hex char in POST record: '%c'/0x%02x", c, c);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// get hex value of some hex characters
|
|
uint32_t ICACHE_FLASH_ATTR getHexValue(char *buf, short len) {
|
|
uint32_t v = 0;
|
|
while (len--) {
|
|
v = (v<<4) | (uint32_t)(*buf & 0xf);
|
|
if (*buf > '9') v += 9;
|
|
buf++;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
// verify checksum
|
|
static bool ICACHE_FLASH_ATTR verifyChecksum(char *buf, short len) {
|
|
uint8_t sum = 0;
|
|
while (len >= 2) {
|
|
sum += (uint8_t)getHexValue(buf, 2);
|
|
buf += 2;
|
|
len -= 2;
|
|
}
|
|
return sum == 0;
|
|
}
|
|
|
|
// We've not built one function that works on both, but kept the different functions.
|
|
// This calls one or the other
|
|
static bool ICACHE_FLASH_ATTR programPage() {
|
|
if (optibootData->mega)
|
|
return megaProgramPage();
|
|
return optibootProgramPage();
|
|
}
|
|
|
|
// Process a hex record -- assumes that the records starts with ':' & hex length
|
|
bool ICACHE_FLASH_ATTR processRecord(char *buf, short len) {
|
|
buf++; len--; // skip leading ':'
|
|
// check we have all hex chars
|
|
if (!checkHex(buf, len)) return false;
|
|
// verify checksum
|
|
if (!verifyChecksum(buf, len)) {
|
|
buf[len] = 0;
|
|
os_sprintf(errMessage, "Invalid checksum for record %s", buf);
|
|
return false;
|
|
}
|
|
// dispatch based on record type
|
|
uint8_t type = getHexValue(buf+6, 2);
|
|
switch (type) {
|
|
case 0x00: { // Intel HEX data record
|
|
//DBG("OB REC data %ld pglen=%d\n", getHexValue(buf, 2), optibootData->pageLen);
|
|
uint32_t addr = getHexValue(buf+2, 4);
|
|
// check whether we need to program previous record(s)
|
|
if (optibootData->pageLen > 0 &&
|
|
addr != ((optibootData->address+optibootData->pageLen)&0xffff)) {
|
|
//DBG("OB addr chg\n");
|
|
//DBG("processRecord addr chg, len %d, addr 0x%04x\n", optibootData->pageLen, addr);
|
|
if (!programPage()) return false;
|
|
}
|
|
// set address, unless we're adding to the end (programPage may have changed pageLen)
|
|
if (optibootData->pageLen == 0) {
|
|
optibootData->address = (optibootData->address & 0xffff0000) | addr;
|
|
//DBG("OB set-addr 0x%lx\n", optibootData->address);
|
|
}
|
|
// append record
|
|
uint16_t recLen = getHexValue(buf, 2);
|
|
for (uint16_t i=0; i<recLen; i++)
|
|
optibootData->pageBuf[optibootData->pageLen++] = getHexValue(buf+8+2*i, 2);
|
|
// program page, if we have a full page
|
|
if (optibootData->pageLen >= optibootData->pgmSz) {
|
|
//DBG("OB full\n");
|
|
DBG("processRecord %d, call programPage() %08x\n", optibootData->pgmSz, optibootData->address + optibootData->segment);
|
|
if (!programPage()) return false;
|
|
}
|
|
break; }
|
|
case 0x01: // Intel HEX EOF record
|
|
DBG("OB EOF\n");
|
|
// program any remaining partial page
|
|
#if 1
|
|
if (optibootData->pageLen > 0) {
|
|
// DBG("processRecord remaining partial page, len %d, addr 0x%04x\n", optibootData->pageLen, optibootData->address + optibootData->segment);
|
|
if (!programPage()) return false;
|
|
}
|
|
optibootData->eof = true;
|
|
#else
|
|
if (optibootData->pageLen > 0) {
|
|
// HACK : fill up with 0xFF
|
|
while (optibootData->pageLen < 256) {
|
|
optibootData->pageBuf[optibootData->pageLen++] = 0xFF;
|
|
}
|
|
if (!programPage()) return false;
|
|
}
|
|
optibootData->eof = true;
|
|
#endif
|
|
break;
|
|
case 0x04: // Intel HEX address record
|
|
DBG("OB address 0x%x\n", getHexValue(buf+8, 4) << 16);
|
|
// program any remaining partial page
|
|
if (optibootData->pageLen > 0) {
|
|
DBG("processRecord 0x04 remaining partial page, len %d, addr 0x%04x\n",
|
|
optibootData->pageLen, optibootData->address + optibootData->segment);
|
|
if (!programPage()) return false;
|
|
}
|
|
optibootData->address = getHexValue(buf+8, 4) << 16;
|
|
break;
|
|
case 0x05: // Intel HEX start address (MDK-ARM only)
|
|
// ignore, there's no way to tell optiboot that...
|
|
break;
|
|
case 0x02: // Intel HEX extended segment address record
|
|
// Depending on the case, just ignoring this record could solve the problem
|
|
// optibootData->segment = getHexValue(buf+8, 4) << 4;
|
|
DBG("OB segment 0x%08X\n", optibootData->segment);
|
|
return true;
|
|
default:
|
|
// DBG("OB bad record type\n");
|
|
DBG(errMessage, "Invalid/unknown record type: 0x%02x, packet %s", type, buf);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|