merge megaflash and split-up-recv back in

fix-master
Thorsten von Eicken 8 years ago
parent 1d2ebd94be
commit 02b31b1818
No known key found for this signature in database
GPG Key ID: C7F972A59D834B46
  1. 7
      .travis.yml
  2. 26
      Makefile
  3. 10
      cmd/cmd.h
  4. 210
      cmd/handlers.c
  5. 1167
      esp-link/cgimega.c
  6. 14
      esp-link/cgimega.h
  7. 148
      esp-link/cgioptiboot.c
  8. 114
      esp-link/cgiwifi.c
  9. 6
      esp-link/cgiwifi.h
  10. 16
      esp-link/main.c
  11. 149
      esp-link/pgmshared.c
  12. 54
      esp-link/pgmshared.h
  13. 114
      esp-link/stk500v2.h
  14. 2
      include/esp8266.h
  15. 114
      megaflash
  16. 4
      rest/rest.c
  17. 1
      serial/serbridge.c
  18. 18
      socket/socket.c

@ -2,9 +2,12 @@
language: c
git:
depth: 1000
before_install:
- curl -Ls http://s3.voneicken.com/xtensa-lx106-elf-20160330.tgx | tar Jxf -
- curl -Ls http://s3.voneicken.com/esp_iot_sdk_v2.0.0.p1.tgx | tar -C .. -Jxf -
- curl -Ls http://s3.voneicken.com/esp_iot_sdk_v2.1.0.tgx | tar -C .. -Jxf -
after_script:
# upload to an S3 bucket, requires S3_BUCKET, AWS_ACCESS_KEY_ID and AWS_SECRET_KEY to be set
@ -25,6 +28,8 @@ script:
- export XTENSA_TOOLS_ROOT=$PWD/xtensa-lx106-elf/bin/
- export BRANCH=$TRAVIS_BRANCH
#- export SDK_BASE=$PWD/esp_iot_sdk_v2.0.0.p1
- git tag -n1
- git describe --tags --match 'v*.0' --long --debug
- make release
notifications:

@ -189,7 +189,8 @@ endif
TRAVIS_BRANCH?=$(shell git symbolic-ref --short HEAD --quiet)
# Use git describe to get the latest version tag, commits since then, sha and dirty flag, this
# results is something like "v1.2.0-13-ab6cedf-dirty"
VERSION := $(shell (git describe --tags --match 'v*' --long --dirty || echo "no-tag") | sed -re 's/(\.0)?-/./')
NO_TAG ?= "no-tag"
VERSION := $(shell (git describe --tags --match 'v*.0' --long --dirty || echo $(NO_TAG)) | sed -re 's/(\.0)?-/./')
# If not on master then insert the branch name
ifneq ($(TRAVIS_BRANCH),master)
ifneq ($(findstring V%,$(TRAVIS_BRANCH)),)
@ -199,19 +200,6 @@ endif
VERSION :=$(VERSION)
$(info VERSION is $(VERSION))
# OLD - DEPRECATED
# This queries git to produce a version string like "esp-link v0.9.0 2015-06-01 34bc76"
# If you don't have a proper git checkout or are on windows, then simply swap for the constant
# Steps to release: create release on github, git pull, git describe --tags to verify you're
# on the release tag, make release, upload esp-link.tgz into the release files
#VERSION ?= "esp-link custom version"
#DATE := $(shell date '+%F %T')
#BRANCH ?= $(shell if git diff --quiet HEAD; then git describe --tags; \
# else git symbolic-ref --short HEAD; fi)
#SHA := $(shell if git diff --quiet HEAD; then git rev-parse --short HEAD | cut -d"/" -f 3; \
# else echo "development"; fi)
#VERSION ?=esp-link $(BRANCH) - $(DATE) - $(SHA)
# Output directors to store intermediate compiled files
# relative to the project directory
BUILD_BASE = build
@ -519,3 +507,13 @@ ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes")
endif
$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir))))
depend:
makedepend -p${BUILD_BASE}/ -Y -- $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) -I${XTENSA_TOOLS_ROOT}../xtensa-lx106-elf/include -I${XTENSA_TOOLS_ROOT}../lib/gcc/xtensa-lx106-elf/4.8.2/include -- */*.c
# Rebuild version at least at every Makefile change
${BUILD_BASE}/esp-link/main.o: Makefile
# DO NOT DELETE

@ -42,11 +42,14 @@ typedef enum {
CMD_CB_ADD,
CMD_CB_EVENTS,
CMD_GET_TIME, // get current time in seconds since the unix epoch
CMD_GET_WIFI_INFO, // query ip address info
CMD_SET_WIFI_INFO, // set ip address info
CMD_MQTT_SETUP = 10, // set-up callbacks
CMD_MQTT_PUBLISH, // publish a message
CMD_MQTT_SUBSCRIBE, // subscribe to a topic
CMD_MQTT_LWT, // set the last-will-topic and messge
CMD_MQTT_GET_CLIENTID,
CMD_REST_SETUP = 20, // set-up callbacks
CMD_REST_REQUEST, // do REST request
@ -58,6 +61,13 @@ typedef enum {
CMD_SOCKET_SETUP = 40, // set-up callbacks
CMD_SOCKET_SEND, // send data over UDP socket
CMD_WIFI_GET_APCOUNT = 50, // Query the number of networks / Access Points known
CMD_WIFI_GET_APNAME, // Query the name (SSID) of an Access Point (AP)
CMD_WIFI_SELECT_SSID, // Connect to a specific network
CMD_WIFI_SIGNAL_STRENGTH, // Query RSSI
CMD_WIFI_GET_SSID, // Query SSID currently connected to
CMD_WIFI_START_SCAN, // Trigger a scan (takes a long time)
} CmdName;
typedef void (*cmdfunc_t)(CmdPacket *cmd);

@ -17,6 +17,10 @@
#ifdef SOCKET
#include <socket.h>
#endif
#include <ip_addr.h>
#include "esp-link/cgi.h"
#include "config.h"
#ifdef CMD_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
@ -28,8 +32,19 @@ static void cmdNull(CmdPacket *cmd);
static void cmdSync(CmdPacket *cmd);
static void cmdWifiStatus(CmdPacket *cmd);
static void cmdGetTime(CmdPacket *cmd);
static void cmdGetWifiInfo(CmdPacket *cmd);
// static void cmdSetWifiInfo(CmdPacket *cmd);
static void cmdAddCallback(CmdPacket *cmd);
static void cmdWifiGetApCount(CmdPacket *cmd);
static void cmdWifiGetApName(CmdPacket *cmd);
static void cmdWifiSelectSSID(CmdPacket *cmd);
static void cmdWifiSignalStrength(CmdPacket *cmd);
static void cmdWifiQuerySSID(CmdPacket *cmd);
static void cmdWifiStartScan(CmdPacket *cmd);
void cmdMqttGetClientId(CmdPacket *cmd);
// keep track of last status sent to uC so we can notify it when it changes
static uint8_t lastWifiStatus = wifiIsDisconnected;
// keep track of whether we have registered our cb handler with the wifi subsystem
@ -44,11 +59,22 @@ const CmdList commands[] = {
{CMD_WIFI_STATUS, "WIFI_STATUS", cmdWifiStatus},
{CMD_CB_ADD, "ADD_CB", cmdAddCallback},
{CMD_GET_TIME, "GET_TIME", cmdGetTime},
{CMD_GET_WIFI_INFO, "GET_WIFI_INFO", cmdGetWifiInfo},
// {CMD_SET_WIFI_INFO, "SET_WIFI_INFO", cmdSetWifiInfo},
{CMD_WIFI_GET_APCOUNT, "WIFI_GET_APCOUNT", cmdWifiGetApCount},
{CMD_WIFI_GET_APNAME, "WIFI_GET_APNAME", cmdWifiGetApName},
{CMD_WIFI_SELECT_SSID, "WIFI_SELECT_SSID", cmdWifiSelectSSID},
{CMD_WIFI_SIGNAL_STRENGTH, "WIFI_SIGNAL_STRENGTH", cmdWifiSignalStrength},
{CMD_WIFI_GET_SSID, "WIFI_GET_SSID", cmdWifiQuerySSID},
{CMD_WIFI_START_SCAN, "WIFI_START_SCAN", cmdWifiStartScan},
#ifdef MQTT
{CMD_MQTT_SETUP, "MQTT_SETUP", MQTTCMD_Setup},
{CMD_MQTT_PUBLISH, "MQTT_PUB", MQTTCMD_Publish},
{CMD_MQTT_SUBSCRIBE , "MQTT_SUB", MQTTCMD_Subscribe},
{CMD_MQTT_LWT, "MQTT_LWT", MQTTCMD_Lwt},
{CMD_MQTT_GET_CLIENTID,"MQTT_CLIENTID", cmdMqttGetClientId},
#endif
#ifdef REST
{CMD_REST_SETUP, "REST_SETUP", REST_Setup},
@ -72,7 +98,7 @@ CmdCallback callbacks[MAX_CALLBACKS]; // cleared in cmdSync
uint32_t ICACHE_FLASH_ATTR
cmdAddCb(char* name, uint32_t cb) {
for (uint8_t i = 0; i < MAX_CALLBACKS; i++) {
//os_printf("cmdAddCb: index %d name=%s cb=%p\n", i, callbacks[i].name,
//DBG("cmdAddCb: index %d name=%s cb=%p\n", i, callbacks[i].name,
// (void *)callbacks[i].callback);
// find existing callback or add to the end
if (os_strncmp(callbacks[i].name, name, CMD_CBNLEN) == 0 || callbacks[i].name[0] == '\0') {
@ -89,7 +115,7 @@ cmdAddCb(char* name, uint32_t cb) {
CmdCallback* ICACHE_FLASH_ATTR
cmdGetCbByName(char* name) {
for (uint8_t i = 0; i < MAX_CALLBACKS; i++) {
//os_printf("cmdGetCbByName: index %d name=%s cb=%p\n", i, callbacks[i].name,
//DBG("cmdGetCbByName: index %d name=%s cb=%p\n", i, callbacks[i].name,
// (void *)callbacks[i].callback);
// if callback doesn't exist or it's null
if (os_strncmp(callbacks[i].name, name, CMD_CBNLEN) == 0) {
@ -97,7 +123,7 @@ cmdGetCbByName(char* name) {
return &callbacks[i];
}
}
os_printf("cmdGetCbByName: cb %s not found\n", name);
DBG("cmdGetCbByName: cb %s not found\n", name);
return 0;
}
@ -178,6 +204,33 @@ cmdGetTime(CmdPacket *cmd) {
return;
}
// Command handler for IP information
static void ICACHE_FLASH_ATTR
cmdGetWifiInfo(CmdPacket *cmd) {
CmdRequest req;
cmdRequest(&req, cmd);
if(cmd->argc != 0 || cmd->value == 0) {
cmdResponseStart(CMD_RESP_V, 0, 0);
cmdResponseEnd();
return;
}
uint32_t callback = req.cmd->value;
struct ip_info info;
wifi_get_ip_info(0, &info);
uint8_t mac[6];
wifi_get_macaddr(0, mac);
cmdResponseStart(CMD_RESP_CB, callback, 4);
cmdResponseBody(&info.ip.addr, sizeof(info.ip.addr));
cmdResponseBody(&info.netmask.addr, sizeof(info.netmask.addr));
cmdResponseBody(&info.gw.addr, sizeof(info.gw.addr));
cmdResponseBody(mac, sizeof(mac));
cmdResponseEnd();
}
// Command handler to add a callback to the named-callbacks list, this is for a callback to the uC
static void ICACHE_FLASH_ATTR
cmdAddCallback(CmdPacket *cmd) {
@ -197,3 +250,154 @@ cmdAddCallback(CmdPacket *cmd) {
cmdAddCb(name, cmd->value); // save the sensor callback
}
// Query the number of wifi access points
static void ICACHE_FLASH_ATTR cmdWifiGetApCount(CmdPacket *cmd) {
int n = wifiGetApCount();
DBG("WifiGetApCount : %d\n", n);
cmdResponseStart(CMD_RESP_V, n, 0);
cmdResponseEnd();
}
// Query the name of a wifi access point
static void ICACHE_FLASH_ATTR cmdWifiGetApName(CmdPacket *cmd) {
CmdRequest req;
cmdRequest(&req, cmd);
int argc = cmdGetArgc(&req);
DBG("cmdWifiGetApName: argc %d\n", argc);
if (argc != 1)
return;
uint16_t i;
cmdPopArg(&req, (uint8_t*)&i, 2);
uint32_t callback = req.cmd->value;
char myssid[33];
wifiGetApName(i, myssid);
myssid[32] = '\0';
DBG("wifiGetApName(%d) -> {%s}\n", i, myssid);
cmdResponseStart(CMD_RESP_CB, callback, 1);
cmdResponseBody(myssid, strlen(myssid)+1);
cmdResponseEnd();
}
/*
* Select a wireless network.
* This can be called in two ways :
* - with a pair of strings (SSID, password)
* - with a number and a string (index into network array, password)
*/
static void ICACHE_FLASH_ATTR cmdWifiSelectSSID(CmdPacket *cmd) {
CmdRequest req;
cmdRequest(&req, cmd);
int argc = cmdGetArgc(&req);
char ssid[33], pass[65];
if (argc != 2) return;
int len = cmdArgLen(&req);
if (len == 1) {
// Assume this is the index
uint8_t ix;
cmdPopArg(&req, &ix, 1);
wifiGetApName(ix, ssid);
ssid[32] = '\0';
} else {
// Longer than 1 byte: must be SSID
if (len > 32) return;
cmdPopArg(&req, ssid, len);
ssid[len] = 0;
}
// Extract password from message
len = cmdArgLen(&req);
if (len > 64) return;
cmdPopArg(&req, pass, len);
pass[len] = 0;
DBG("SelectSSID(%s,%s)", ssid, pass);
connectToNetwork(ssid, pass);
}
#if 0
/*
* Once we're attached to some wireless network, choose not to pick up address from
* DHCP or so but set our own.
*/
static void ICACHE_FLASH_ATTR cmdSetWifiInfo(CmdPacket *cmd) {
DBG("SetWifiInfo()\n");
}
#endif
static void ICACHE_FLASH_ATTR cmdWifiSignalStrength(CmdPacket *cmd) {
CmdRequest req;
cmdRequest(&req, cmd);
int argc = cmdGetArgc(&req);
if (argc != 1) {
DBG("cmdWifiSignalStrength: argc %d\n", argc);
return;
}
char x;
cmdPopArg(&req, (uint8_t*)&x, 1);
int i = x;
DBG("cmdWifiSignalStrength: argc %d, ", argc);
DBG("i %d\n", i);
int rssi = wifiSignalStrength(i);
cmdResponseStart(CMD_RESP_V, rssi, 0);
cmdResponseEnd();
}
//
static void ICACHE_FLASH_ATTR cmdWifiQuerySSID(CmdPacket *cmd) {
CmdRequest req;
cmdRequest(&req, cmd);
uint32_t callback = req.cmd->value;
struct station_config conf;
bool res = wifi_station_get_config(&conf);
if (res) {
// #warning handle me
} else {
}
DBG("QuerySSID : %s\n", conf.ssid);
cmdResponseStart(CMD_RESP_CB, callback, 1);
cmdResponseBody(conf.ssid, strlen((char *)conf.ssid)+1);
cmdResponseEnd();
}
// Start scanning, API interface
static void ICACHE_FLASH_ATTR cmdWifiStartScan(CmdPacket *cmd) {
// call a function that belongs in esp-link/cgiwifi.c due to variable access
wifiStartScan();
}
// Command handler for MQTT information
void ICACHE_FLASH_ATTR cmdMqttGetClientId(CmdPacket *cmd) {
CmdRequest req;
cmdRequest(&req, cmd);
if(cmd->argc != 0 || cmd->value == 0) {
cmdResponseStart(CMD_RESP_V, 0, 0);
cmdResponseEnd();
return;
}
uint32_t callback = req.cmd->value;
cmdResponseStart(CMD_RESP_CB, callback, 1);
cmdResponseBody(flashConfig.mqtt_clientid, strlen(flashConfig.mqtt_clientid)+1);
cmdResponseEnd();
os_printf("MqttGetClientId : %s\n", flashConfig.mqtt_clientid);
}

File diff suppressed because it is too large Load Diff

@ -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

@ -1,7 +1,11 @@
// 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 <osapi.h>
#include "cgi.h"
#include "cgioptiboot.h"
#include "config.h"
@ -11,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
@ -43,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);
@ -143,7 +128,7 @@ int ICACHE_FLASH_ATTR cgiOptibootSync(HttpdConnData *connData) {
// start sync timer
os_timer_disarm(&optibootTimer);
os_timer_setfn(&optibootTimer, optibootTimerCB, NULL);
os_timer_arm(&optibootTimer, INIT_DELAY, 0);
os_timer_arm_us(&optibootTimer, INIT_DELAY * 1000, 0);
// respond with optimistic OK
noCacheHeaders(connData, 204);
@ -176,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.
@ -229,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();
@ -333,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];
@ -427,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
@ -494,7 +382,7 @@ static bool ICACHE_FLASH_ATTR programPage(void) {
static void ICACHE_FLASH_ATTR armTimer(uint32_t ms) {
os_timer_disarm(&optibootTimer);
os_timer_arm(&optibootTimer, ms, 0);
os_timer_arm_us(&optibootTimer, ms * 1000, 0);
}
static int baudRates[] = { 0, 9600, 57600, 115200 };
@ -549,6 +437,14 @@ static void ICACHE_FLASH_ATTR optibootTimerCB(void *arg) {
}
}
#if 0
static void ICACHE_FLASH_ATTR print_buff(char *msg, char *buf, short length) {
DBG("OB GOT %s %d:", msg, length);
for (int i=0; i<length; i++) DBG(" %x", buf[i]);
DBG("\n");
}
#endif
// skip in-sync responses
static short ICACHE_FLASH_ATTR skipInSync(char *buf, short length) {
while (length > 1 && buf[0] == STK_INSYNC && buf[1] == STK_OK) {
@ -561,6 +457,7 @@ static short ICACHE_FLASH_ATTR skipInSync(char *buf, short length) {
// receive response from optiboot, we only store the last response
static void ICACHE_FLASH_ATTR optibootUartRecv(char *buf, short length) {
//print_buff("RAW", buf, length);
// append what we got to what we have accumulated
if (responseLen < RESP_SZ-1) {
char *rb = responseBuf+responseLen;
@ -569,6 +466,7 @@ static void ICACHE_FLASH_ATTR optibootUartRecv(char *buf, short length) {
responseLen = rb-responseBuf;
responseBuf[responseLen] = 0; // string terminator
}
//print_buff("RBUF", responseBuf, responseLen);
// dispatch based the current state
switch (progState) {
@ -583,13 +481,13 @@ static void ICACHE_FLASH_ATTR optibootUartRecv(char *buf, short length) {
} else if (responseLen > 1 && responseBuf[responseLen-2] == STK_INSYNC &&
responseBuf[responseLen-1] == STK_OK) {
// got sync response
os_memcpy(responseBuf, responseBuf+2, responseLen-2);
responseLen -= 2;
responseLen = 0; // ignore anything that may have accumulated
// send request to get signature
uart0_write_char(STK_READ_SIGN);
uart0_write_char(CRC_EOP);
progState++;
armTimer(PGM_INTERVAL); // reset timer
//DBG("OB: got sync, sent read-sig\n");
} else {
// nothing useful, keep at most half the buffer for error message purposes
if (responseLen > RESP_SZ/2) {

@ -13,6 +13,7 @@ Cgi/template routines for the /wifi url.
* ----------------------------------------------------------------------------
*/
#include <esp8266.h>
#include "cgiwifi.h"
#include "cgi.h"
@ -34,7 +35,7 @@ bool mdns_started = false;
// ===== wifi status change callbacks
static WifiStateChangeCb wifi_state_change_cb[4];
// Temp store for new staion config
// Temp store for new station config
struct station_config stconf;
// Temp store for new ap config
@ -226,25 +227,13 @@ static void ICACHE_FLASH_ATTR scanStartCb(void *arg) {
wifi_station_scan(NULL, wifiScanDoneCb);
}
static int ICACHE_FLASH_ATTR cgiWiFiStartScan(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
jsonHeader(connData, 200);
if (!cgiWifiAps.scanInProgress) {
cgiWifiAps.scanInProgress = 1;
os_timer_disarm(&scanTimer);
os_timer_setfn(&scanTimer, scanStartCb, NULL);
os_timer_arm(&scanTimer, 200, 0);
}
return HTTPD_CGI_DONE;
}
static int ICACHE_FLASH_ATTR cgiWiFiGetScan(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
char buff[1460];
const int chunk = 1460/64; // ssid is up to 32 chars
int len = 0;
os_printf("GET scan: cgiData=%d noAps=%d\n", (int)connData->cgiData, cgiWifiAps.noAps);
DBG("GET scan: cgiData=%d noAps=%d\n", (int)connData->cgiData, cgiWifiAps.noAps);
// handle continuation call, connData->cgiData-1 is the position in the scan results where we
// we need to continue sending from (using -1 'cause 0 means it's the first call)
@ -284,6 +273,27 @@ static int ICACHE_FLASH_ATTR cgiWiFiGetScan(HttpdConnData *connData) {
return HTTPD_CGI_MORE;
}
// Start scanning, without parameters
void ICACHE_FLASH_ATTR wifiStartScan() {
if (!cgiWifiAps.scanInProgress) {
cgiWifiAps.scanInProgress = 1;
os_timer_disarm(&scanTimer);
os_timer_setfn(&scanTimer, scanStartCb, NULL);
os_timer_arm_us(&scanTimer, 200000, 0);
}
}
// Start scanning, web interface
int ICACHE_FLASH_ATTR cgiWiFiStartScan(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
jsonHeader(connData, 200);
// Don't duplicate code, reuse the function above.
wifiStartScan();
return HTTPD_CGI_DONE;
}
int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) {
if (connData->requestType == HTTPD_METHOD_GET) {
return cgiWiFiGetScan(connData);
@ -358,7 +368,19 @@ static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) {
// IP address
os_timer_disarm(&resetTimer);
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
os_timer_arm(&resetTimer, 4*RESET_TIMEOUT, 0);
os_timer_arm_us(&resetTimer, 4*RESET_TIMEOUT * 1000, 0);
}
// Kick off connection to some network
void ICACHE_FLASH_ATTR connectToNetwork(char *ssid, char *pass) {
os_strncpy((char*)stconf.ssid, ssid, 32);
os_strncpy((char*)stconf.password, pass, 64);
DBG("Wifi try to connect to AP %s pw %s\n", ssid, pass);
// Schedule disconnect/connect
os_timer_disarm(&reassTimer);
os_timer_setfn(&reassTimer, reassTimerCb, NULL);
os_timer_arm_us(&reassTimer, 1000000, 0); // 1 second for the response of this request to make it
}
// This cgi uses the routines above to connect to a specific access point with the
@ -380,14 +402,8 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) {
if (el > 0 && pl >= 0) {
//Set to 0 if you want to disable the actual reconnecting bit
os_strncpy((char*)stconf.ssid, essid, 32);
os_strncpy((char*)stconf.password, passwd, 64);
DBG("Wifi try to connect to AP %s pw %s\n", essid, passwd);
//Schedule disconnect/connect
os_timer_disarm(&reassTimer);
os_timer_setfn(&reassTimer, reassTimerCb, NULL);
os_timer_arm(&reassTimer, 1000, 0); // 1 second for the response of this request to make it
connectToNetwork(essid, passwd);
jsonHeader(connData, 200);
} else {
jsonHeader(connData, 400);
@ -425,12 +441,12 @@ static bool ICACHE_FLASH_ATTR parse_ip(char *buff, ip_addr_t *ip_ptr) {
static void ICACHE_FLASH_ATTR debugIP() {
struct ip_info info;
if (wifi_get_ip_info(0, &info)) {
os_printf("\"ip\": \"%d.%d.%d.%d\"\n", IP2STR(&info.ip.addr));
os_printf("\"netmask\": \"%d.%d.%d.%d\"\n", IP2STR(&info.netmask.addr));
os_printf("\"gateway\": \"%d.%d.%d.%d\"\n", IP2STR(&info.gw.addr));
os_printf("\"hostname\": \"%s\"\n", wifi_station_get_hostname());
DBG("\"ip\": \"%d.%d.%d.%d\"\n", IP2STR(&info.ip.addr));
DBG("\"netmask\": \"%d.%d.%d.%d\"\n", IP2STR(&info.netmask.addr));
DBG("\"gateway\": \"%d.%d.%d.%d\"\n", IP2STR(&info.gw.addr));
DBG("\"hostname\": \"%s\"\n", wifi_station_get_hostname());
} else {
os_printf("\"ip\": \"-none-\"\n");
DBG("\"ip\": \"-none-\"\n");
}
}
#endif
@ -562,7 +578,7 @@ int ICACHE_FLASH_ATTR cgiApSettingsChange(HttpdConnData *connData) {
if (checkString(buff) && len>7 && len<=64) {
// String preprocessing done in client side, wifiap.js line 31
os_memcpy(apconf.password, buff, len);
os_printf("Setting AP password len=%d\n", len);
DBG("Setting AP password len=%d\n", len);
} else if (len != 0) {
jsonHeader(connData, 400);
httpdSend(connData, "PASSWORD not valid or out of range", -1);
@ -578,18 +594,18 @@ int ICACHE_FLASH_ATTR cgiApSettingsChange(HttpdConnData *connData) {
apconf.authmode = value;
} else {
// If out of range set by default
os_printf("Forcing AP authmode to WPA_WPA2_PSK\n");
DBG("Forcing AP authmode to WPA_WPA2_PSK\n");
apconf.authmode = 4;
}
} else {
// Valid password but wrong auth mode, default 4
os_printf("Forcing AP authmode to WPA_WPA2_PSK\n");
DBG("Forcing AP authmode to WPA_WPA2_PSK\n");
apconf.authmode = 4;
}
} else {
apconf.authmode = 0;
}
os_printf("Setting AP authmode=%d\n", apconf.authmode);
DBG("Setting AP authmode=%d\n", apconf.authmode);
// Set max connection number
len=httpdFindArg(connData->getArgs, "ap_maxconn", buff, sizeof(buff));
if(len>0){
@ -943,5 +959,39 @@ void ICACHE_FLASH_ATTR wifiInit() {
// check on the wifi in a few seconds to see whether we need to switch mode
os_timer_disarm(&resetTimer);
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
os_timer_arm_us(&resetTimer, RESET_TIMEOUT * 1000, 0);
}
// Access functions for cgiWifiAps : query the number of entries in the table
int ICACHE_FLASH_ATTR wifiGetApCount() {
if (cgiWifiAps.scanInProgress)
return 0;
return cgiWifiAps.noAps;
}
// Access functions for cgiWifiAps : returns the name of a network, i is the index into the array, return stored in memory pointed to by ptr.
ICACHE_FLASH_ATTR void wifiGetApName(int i, char *ptr) {
if (i < 0)
return;
if (i >= cgiWifiAps.noAps)
return;
if (ptr != 0)
strncpy(ptr, cgiWifiAps.apData[i]->ssid, 32);
DBG("AP %s\n", cgiWifiAps.apData[i]->ssid);
}
// Access functions for cgiWifiAps : returns the signal strength of network (i is index into array). Return current network strength for negative i.
ICACHE_FLASH_ATTR int wifiSignalStrength(int i) {
sint8 rssi;
if (i < 0 || i == 255)
rssi = wifi_station_get_rssi(); // Current network's signal strength
else if (i >= cgiWifiAps.noAps)
rssi = 0; // FIX ME
else
rssi = cgiWifiAps.apData[i]->rssi; // Signal strength of any known network
return rssi;
}

@ -24,4 +24,10 @@ int checkString(char *str);
extern uint8_t wifiState;
extern bool mdns_started;
int wifiGetApCount();
void wifiGetApName(int, char *);
int wifiSignalStrength(int);
void connectToNetwork(char *, char *);
void wifiStartScan();
#endif

@ -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"
@ -31,7 +32,10 @@
#include "log.h"
#include "gpio.h"
#include "cgiservices.h"
#ifdef WEBSERVER
#include "web-server.h"
#endif
#ifdef SYSLOG
#include "syslog.h"
@ -69,8 +73,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 },
@ -99,8 +111,10 @@ HttpdBuiltInUrl builtInUrls[] = {
#ifdef MQTT
{ "/mqtt", cgiMqtt, NULL },
#endif
#ifdef WEBSERVER
{ "/web-server/upload", cgiWebServerSetupUpload, NULL },
{ "*.json", WEB_CgiJsonHook, NULL }, //Catch-all cgi JSON queries
#endif
{ "*", cgiEspFsHook, NULL }, //Catch-all cgi function for the filesystem
{ NULL, NULL, NULL }
};
@ -177,7 +191,9 @@ user_init(void) {
//os_printf("espFsInit %s\n", res?"ERR":"ok");
// mount the http handlers
httpdInit(builtInUrls, 80);
#ifdef WEBSERVER
WEB_Init();
#endif
// init the wifi-serial transparent bridge (port 23)
serbridgeInit(23, 2323);

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

@ -0,0 +1,54 @@
// Copyright (c) 2015 by Thorsten von Eicken, see LICENSE.txt in the esp-link repo
// Copyright (c) 2017 by Danny Backx
#ifndef _PGM_SHARED_H_
#define _PGM_SHARED_H_
#include "user_config.h"
#define RESP_SZ 64
#define ERR_MAX 128
extern char responseBuf[RESP_SZ];
extern short responseLen;
extern char errMessage[ERR_MAX];
// structure used to remember request details from one callback to the next
// allocated dynamically so we don't burn so much static RAM
extern 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
uint32_t pgmDone; // number of bytes programmed
uint32_t address; // address to write next page to
uint32_t segment; // for extended segment addressing, added to the address field
uint32_t startTime; // time of program POST request
HttpdConnData *conn; // request doing the programming, so we can cancel it
bool eof; // got EOF record
// Whether to use the Mega (STK500v2) protocol
bool mega;
// STK500v2 variables
int hardwareVersion,
firmwareVersionMajor,
firmwareVersionMinor,
vTarget;
uint8_t signature[3];
uint8_t lfuse, hfuse, efuse;
} *optibootData;
bool ICACHE_FLASH_ATTR checkHex(char *buf, short len);
uint32_t ICACHE_FLASH_ATTR getHexValue(char *buf, short len);
bool ICACHE_FLASH_ATTR processRecord(char *buf, short len);
bool megaProgramPage(void);
bool optibootProgramPage(void);
#ifdef OPTIBOOT_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
#else
#define DBG(format, ...) do { } while(0)
#endif
#endif

@ -0,0 +1,114 @@
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
//*
//* Title: AVR068 - STK500 Communication Protocol
//* Filename: command.h
//* Version: 1.0
//* Last updated: 31.01.2005
//*
//* Support E-mail: avr@atmel.com
//*
//**************************************************************************
// *****************[ STK message constants ]***************************
#define MESSAGE_START 0x1B //= ESC = 27 decimal
#define TOKEN 0x0E
// *****************[ STK general command constants ]**************************
#define CMD_SIGN_ON 0x01
#define CMD_SET_PARAMETER 0x02
#define CMD_GET_PARAMETER 0x03
#define CMD_SET_DEVICE_PARAMETERS 0x04
#define CMD_OSCCAL 0x05
#define CMD_LOAD_ADDRESS 0x06
#define CMD_FIRMWARE_UPGRADE 0x07
// *****************[ STK ISP command constants ]******************************
#define CMD_ENTER_PROGMODE_ISP 0x10
#define CMD_LEAVE_PROGMODE_ISP 0x11
#define CMD_CHIP_ERASE_ISP 0x12
#define CMD_PROGRAM_FLASH_ISP 0x13
#define CMD_READ_FLASH_ISP 0x14
#define CMD_PROGRAM_EEPROM_ISP 0x15
#define CMD_READ_EEPROM_ISP 0x16
#define CMD_PROGRAM_FUSE_ISP 0x17
#define CMD_READ_FUSE_ISP 0x18
#define CMD_PROGRAM_LOCK_ISP 0x19
#define CMD_READ_LOCK_ISP 0x1A
#define CMD_READ_SIGNATURE_ISP 0x1B
#define CMD_READ_OSCCAL_ISP 0x1C
#define CMD_SPI_MULTI 0x1D
// *****************[ STK PP command constants ]*******************************
#define CMD_ENTER_PROGMODE_PP 0x20
#define CMD_LEAVE_PROGMODE_PP 0x21
#define CMD_CHIP_ERASE_PP 0x22
#define CMD_PROGRAM_FLASH_PP 0x23
#define CMD_READ_FLASH_PP 0x24
#define CMD_PROGRAM_EEPROM_PP 0x25
#define CMD_READ_EEPROM_PP 0x26
#define CMD_PROGRAM_FUSE_PP 0x27
#define CMD_READ_FUSE_PP 0x28
#define CMD_PROGRAM_LOCK_PP 0x29
#define CMD_READ_LOCK_PP 0x2A
#define CMD_READ_SIGNATURE_PP 0x2B
#define CMD_READ_OSCCAL_PP 0x2C
#define CMD_SET_CONTROL_STACK 0x2D
// *****************[ STK HVSP command constants ]*****************************
#define CMD_ENTER_PROGMODE_HVSP 0x30
#define CMD_LEAVE_PROGMODE_HVSP 0x31
#define CMD_CHIP_ERASE_HVSP 0x32
#define CMD_PROGRAM_FLASH_HVSP 0x33
#define CMD_READ_FLASH_HVSP 0x34
#define CMD_PROGRAM_EEPROM_HVSP 0x35
#define CMD_READ_EEPROM_HVSP 0x36
#define CMD_PROGRAM_FUSE_HVSP 0x37
#define CMD_READ_FUSE_HVSP 0x38
#define CMD_PROGRAM_LOCK_HVSP 0x39
#define CMD_READ_LOCK_HVSP 0x3A
#define CMD_READ_SIGNATURE_HVSP 0x3B
#define CMD_READ_OSCCAL_HVSP 0x3C
// *****************[ STK status constants ]***************************
// Success
#define STATUS_CMD_OK 0x00
// Warnings
#define STATUS_CMD_TOUT 0x80
#define STATUS_RDY_BSY_TOUT 0x81
#define STATUS_SET_PARAM_MISSING 0x82
// Errors
#define STATUS_CMD_FAILED 0xC0
#define STATUS_CKSUM_ERROR 0xC1
#define STATUS_CMD_UNKNOWN 0xC9
// *****************[ STK parameter constants ]***************************
#define PARAM_BUILD_NUMBER_LOW 0x80
#define PARAM_BUILD_NUMBER_HIGH 0x81
#define PARAM_HW_VER 0x90
#define PARAM_SW_MAJOR 0x91
#define PARAM_SW_MINOR 0x92
#define PARAM_VTARGET 0x94
#define PARAM_VADJUST 0x95
#define PARAM_OSC_PSCALE 0x96
#define PARAM_OSC_CMATCH 0x97
#define PARAM_SCK_DURATION 0x98
#define PARAM_TOPCARD_DETECT 0x9A
#define PARAM_STATUS 0x9C
#define PARAM_DATA 0x9D
#define PARAM_RESET_POLARITY 0x9E
#define PARAM_CONTROLLER_INIT 0x9F
// *****************[ STK answer constants ]***************************
#define ANSWER_CKSUM_ERROR 0xB0

@ -5,6 +5,8 @@
#undef MEMLEAK_DEBUG
#define USE_OPTIMIZE_PRINTF
#define os_timer_arm_us(a,b,c) os_timer_arm(a,b/1000,c)
#include <user_config.h>
#include <ctype.h>
#include <stdio.h>

@ -0,0 +1,114 @@
#! /bin/bash
#
# Flash an Arduino Mega with STK500v2 using the esp-link built-in programmer
# Basically we first reset the AVR and get in sync, and then send the hex file
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# Thorsten von Eicken wrote this file. As long as you retain
# this notice you can do whatever you want with this stuff. If we meet some day,
# and you think this stuff is worth it, you can buy me a beer in return.
#
# Danny Backx wrote the changes for Arduino Mega.
# ----------------------------------------------------------------------------
show_help() {
cat <<EOT
Usage: ${0##*/} [-options...] hostname sketch.hex
Flash the Mega running optiboot attached to esp-link with the sketch.
Note : this is for stk500v2 MCUs, use avrflash for Arduino Uno etc instead.
-v Be verbose
-h show this help
Example: ${0##*/} -v esp-link mysketch.hex
${0##*/} 192.168.4.1 mysketch.hex
EOT
}
if ! which curl >/dev/null; then
echo "ERROR: Cannot find curl: it is required for this script." >&2
exit 1
fi
start=`date +%s`
# ===== Parse arguments
verbose=
while getopts "hvx:" opt; do
case "$opt" in
h) show_help; exit 0 ;;
v) verbose=1 ;;
x) foo="$OPTARG" ;;
'?') show_help >&2; exit 1 ;;
esac
done
# Shift off the options and optional --.
shift "$((OPTIND-1))"
# Get the fixed arguments
if [[ $# != 2 ]]; then
show_help >&2
exit 1
fi
hostname=$1
hex=$2
re='[-A-Za-z0-9.]+'
if [[ ! "$hostname" =~ $re ]]; then
echo "ERROR: hostname ${hostname} is not a valid hostname or ip address" >&2
exit 1
fi
if [[ ! -r "$hex" ]]; then
echo "ERROR: cannot read hex file ($hex)" >&2
exit 1
fi
# ===== Get AVR in sync
[[ -n "$verbose" ]] && echo "Resetting AVR with http://$hostname/pgmmega/sync" >&2
v=; [[ -n "$verbose" ]] && v=-v
sync=`curl -m 10 $v -s -w '%{http_code}' -XPOST "http://$hostname/pgmmega/sync"`
if [[ $? != 0 || "$sync" != 204 ]]; then
echo "Error resetting AVR" >&2
exit 1
fi
while true; do
# sync=`curl -m 10 $v -s "http://$hostname/pgmmega/sync"`
sync=`curl $v -s "http://$hostname/pgmmega/sync"`
if [[ $? != 0 ]]; then
echo "Error checking sync" >&2
exit 1
fi
case "$sync" in
SYNC*)
echo "AVR in $sync" >&2
break;;
"NOT READY"*)
[[ -n "$verbose" ]] && echo " Waiting for sync..." >&2
;;
*)
echo "Error checking sync: $sync" >&2
exit 1
;;
esac
sleep 0.1
done
# ===== Send HEX file
[[ -n "$verbose" ]] && echo "Sending HEX file for programming" >&2
sync=`curl -m 20 $v -s -g -d "@$hex" "http://$hostname/pgmmega/upload"`
echo $sync
if [[ $? != 0 || ! "$sync" =~ ^Success ]]; then
echo "Error programming AVR" >&2
exit 1
fi
sec=$(( `date +%s` - $start ))
echo "Success, took $sec seconds" >&2
exit 0

@ -302,8 +302,8 @@ REST_SetHeader(CmdPacket *cmd) {
RestClient *client = restClient + (clientNum % MAX_REST);
// Get header selector
uint32_t header_index;
if (cmdPopArg(&req, (uint8_t*)&header_index, 4)) return;
uint8_t header_index;
if (cmdPopArg(&req, &header_index, 1)) return;
// Get header value
uint16_t len = cmdArgLen(&req);

@ -9,7 +9,6 @@
#include "config.h"
#include "console.h"
#include "slip.h"
#include "cmd.h"
#ifdef SYSLOG
#include "syslog.h"
#else

@ -7,7 +7,6 @@
#include "c_types.h"
#include "ip_addr.h"
#include "socket.h"
#include "cmd.h"
#define SOCK_DBG
@ -37,6 +36,8 @@ typedef struct {
// Instead, we allocate a fixed pool of connections an round-robin. What this means is that the
// attached MCU should really use at most as many SOCKET connections as there are slots in the pool.
#define MAX_SOCKET 4
#define MAX_RECEIVE_PACKET_LENGTH 100
static SocketClient socketClient[MAX_SOCKET];
static uint8_t socketNum = 0xff; // index into socketClient for next slot to allocate
@ -49,13 +50,24 @@ socketclient_recv_cb(void *arg, char *pusrdata, unsigned short length) {
uint8_t clientNum = client->conn_num;
uint8_t cb_type = USERCB_RECV;
DBG_SOCK("SOCKET #%d: Received %d bytes: %s\n", client-socketClient, length, pusrdata);
unsigned short position = 0;
do
{
unsigned short msgLen = length - position;
if( msgLen > MAX_RECEIVE_PACKET_LENGTH )
msgLen = MAX_RECEIVE_PACKET_LENGTH;
cmdResponseStart(CMD_RESP_CB, client->resp_cb, 4);
cmdResponseBody(&cb_type, 1);
cmdResponseBody(&clientNum, 1);
cmdResponseBody(&length, 2);
cmdResponseBody(pusrdata, length);
cmdResponseBody(&msgLen, 2);
cmdResponseBody(pusrdata + position, msgLen);
cmdResponseEnd();
position += msgLen;
}while(position < length );
if (client->sock_mode != SOCKET_TCP_SERVER) { // We don't wait for a response
DBG_SOCK("SOCKET #%d: disconnect after receiving\n", client-socketClient);
espconn_disconnect(client->pCon); // disconnect from the server

Loading…
Cancel
Save