Skip to content

Commit

Permalink
Merge branch 'master' into deece-rs485
Browse files Browse the repository at this point in the history
  • Loading branch information
tve committed Jun 16, 2017
2 parents dbe4959 + a59d4c3 commit 5c08f98
Show file tree
Hide file tree
Showing 9 changed files with 1,649 additions and 126 deletions.
1,167 changes: 1,167 additions & 0 deletions esp-link/cgimega.c

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions esp-link/cgimega.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2016-2017 by Danny Backx, see LICENSE.txt in the esp-link repo

#ifndef CGIMEGA_H
#define CGIMEGA_H

#include <httpd.h>

int ICACHE_FLASH_ATTR cgiMegaSync(HttpdConnData *connData);
int ICACHE_FLASH_ATTR cgiMegaData(HttpdConnData *connData);
int ICACHE_FLASH_ATTR cgiMegaRead(HttpdConnData *connData);
int ICACHE_FLASH_ATTR cgiMegaFuse(HttpdConnData *connData);
int ICACHE_FLASH_ATTR cgiMegaRebootMCU(HttpdConnData *connData);

#endif
129 changes: 9 additions & 120 deletions esp-link/cgioptiboot.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// Copyright (c) 2015 by Thorsten von Eicken, see LICENSE.txt in the esp-link repo

// Some code moved to esp-link/pgmshared.c to avoid code duplication.
// Those changes are Copyright (c) 2017 by Danny Backx.

// Protocol used : https://github.com/Optiboot/optiboot/wiki/HowOptibootWorks

#include <esp8266.h>
#include "cgi.h"
#include "cgioptiboot.h"
Expand All @@ -10,6 +15,8 @@
#include "mqtt_cmd.h"
#include "serled.h"

#include "pgmshared.h"

#define INIT_DELAY 150 // wait this many millisecs before sending anything
#define BAUD_INTERVAL 600 // interval after which we change baud rate
#define PGM_TIMEOUT 20000 // timeout after sync is achieved, in milliseconds
Expand Down Expand Up @@ -42,33 +49,12 @@ static short ackWait; // counter of expected ACKs
static uint16_t optibootVers;
static uint32_t baudRate; // baud rate at which we're programming

#define RESP_SZ 64
static char responseBuf[RESP_SZ]; // buffer to accumulate responses from optiboot
static short responseLen = 0; // amount accumulated so far
#define ERR_MAX 128
static char errMessage[ERR_MAX]; // error message

#define MAX_PAGE_SZ 512 // max flash page size supported
#define MAX_SAVED 512 // max chars in saved buffer
// structure used to remember request details from one callback to the next
// allocated dynamically so we don't burn so much static RAM
static struct optibootData {
char *saved; // buffer for saved incomplete hex records
char *pageBuf; // buffer for received data to be sent to AVR
uint16_t pageLen; // number of bytes in pageBuf
uint16_t pgmSz; // size of flash page to be programmed at a time
uint16_t pgmDone; // number of bytes programmed
uint32_t address; // address to write next page to
uint32_t startTime; // time of program POST request
HttpdConnData *conn; // request doing the programming, so we can cancel it
bool eof; // got EOF record
} *optibootData;

// forward function references
static void optibootTimerCB(void *);
static void optibootUartRecv(char *buffer, short length);
static bool processRecord(char *buf, short len);
static bool programPage(void);
static void armTimer(uint32_t ms);
static void initBaud(void);

Expand Down Expand Up @@ -175,30 +161,6 @@ int ICACHE_FLASH_ATTR cgiOptibootSync(HttpdConnData *connData) {
return HTTPD_CGI_DONE;
}

// verify that N chars are hex characters
static 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
static 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;
}

//===== Cgi to write firmware to Optiboot, requires prior sync call
int ICACHE_FLASH_ATTR cgiOptibootData(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
Expand Down Expand Up @@ -228,6 +190,7 @@ int ICACHE_FLASH_ATTR cgiOptibootData(HttpdConnData *connData) {
errorResponse(connData, 400, "Out of memory");
return HTTPD_CGI_DONE;
}
optibootData->mega = false;
optibootData->pageBuf = pageBuf;
optibootData->saved = saved;
optibootData->startTime = system_get_time();
Expand Down Expand Up @@ -332,80 +295,6 @@ int ICACHE_FLASH_ATTR cgiOptibootData(HttpdConnData *connData) {
return HTTPD_CGI_DONE;
}

// 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;
}

// Process a hex record -- assumes that the records starts with ':' & hex length
static 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: { // data
//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");
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");
if (!programPage()) return false;
}
break; }
case 0x01: // EOF
DBG("OB EOF\n");
// program any remaining partial page
if (optibootData->pageLen > 0)
if (!programPage()) return false;
optibootData->eof = true;
break;
case 0x04: // address
DBG("OB address 0x%x\n", getHexValue(buf+8, 4) << 16);
// program any remaining partial page
if (optibootData->pageLen > 0)
if (!programPage()) return false;
optibootData->address = getHexValue(buf+8, 4) << 16;
break;
case 0x05: // start address
// ignore, there's no way to tell optiboot that...
break;
default:
DBG("OB bad record type\n");
os_sprintf(errMessage, "Invalid/unknown record type: 0x%02x", type);
return false;
}
return true;
}

// Poll UART for ACKs, max 50ms
static bool pollAck() {
char recv[16];
Expand All @@ -426,7 +315,7 @@ static bool pollAck() {
}

// Program a flash page
static bool ICACHE_FLASH_ATTR programPage(void) {
bool ICACHE_FLASH_ATTR optibootProgramPage(void) {
if (optibootData->pageLen == 0) return true;
armTimer(PGM_TIMEOUT); // keep the timerCB out of the picture

Expand Down
9 changes: 9 additions & 0 deletions esp-link/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "cgimqtt.h"
#include "cgiflash.h"
#include "cgioptiboot.h"
#include "cgimega.h"
#include "cgiwebserversetup.h"
#include "auth.h"
#include "espfs.h"
Expand Down Expand Up @@ -69,8 +70,16 @@ HttpdBuiltInUrl builtInUrls[] = {
{ "/flash/next", cgiGetFirmwareNext, NULL },
{ "/flash/upload", cgiUploadFirmware, NULL },
{ "/flash/reboot", cgiRebootFirmware, NULL },

{ "/pgm/sync", cgiOptibootSync, NULL },
{ "/pgm/upload", cgiOptibootData, NULL },

{ "/pgmmega/sync", cgiMegaSync, NULL }, // Start programming mode
{ "/pgmmega/upload", cgiMegaData, NULL }, // Upload stuff
{ "/pgmmega/read/*", cgiMegaRead, NULL }, // Download stuff (to verify)
{ "/pgmmega/fuse/*", cgiMegaFuse, NULL }, // Read or write fuse
{ "/pgmmega/rebootmcu", cgiMegaRebootMCU, NULL }, // Get out of programming mode

{ "/log/text", ajaxLog, NULL },
{ "/log/dbg", ajaxLogDbg, NULL },
{ "/log/reset", cgiReset, NULL },
Expand Down
149 changes: 149 additions & 0 deletions esp-link/pgmshared.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// 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 "uart.h"
#include "stk500v2.h"
#include "serbridge.h"
#include "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;
}

Loading

0 comments on commit 5c08f98

Please sign in to comment.