Statistics: Posted by John Liu — Wed Jul 18, 2018 10:33 am
Statistics: Posted by Pato — Tue Jun 26, 2018 3:37 pm
Statistics: Posted by AgentSmithers — Tue Jun 26, 2018 10:16 am
Code:
typedef struct {
uint8 rom_slot; // rom slot to update, or FLASH_BY_ADDR
ota_callback callback; // user callback when completed
uint32 total_len;
uint32 content_len;
struct espconn *conn;
ip_addr_t ip;
//rboot_write_status write_status;
} upgrade_status;
#define OTA_CHUNK_SIZE 512 /**< Chunk size of the raw data we handle and flash (aka size of our working buffer) */
static upgrade_status *upgrade;
static char buffer_g_u8[OTA_CHUNK_SIZE]; /* Working buffer */
static uint16 pos_g_u16 = 0; /* Current position in the working buffer [bytes]*/
// called when connection receives data (hopefully the rom)
static void ICACHE_FLASH_ATTR upgrade_recvcb(void *arg, char *pusrdata, uint16 length)
{
os_timer_disarm(&ota_timer); // MANAGE TIMER TO EXIT IN CASE OF FAILURE
// We treat the data by chunk of 512 bytes, as we can only writes data at addresses
// and with length that are multiples of 512 bytes. << Wrong, just need to be a multiple of 4 bytes !!
static uint32 address_u32 = 0x01000;
static uint32 progress_u32 = 0; //Nb o bytes of data flashed
uint16 nbToCopy_u16 = 0;
uint16 nbConsumed_u16 = 0 ;
while(length > nbConsumed_u16)
{
// Copy as many bytes in the working buffer as we can (until buffer is full or
// there is no more bytes received via TCP)
nbToCopy_u16 = (uint16) Min(length - nbConsumed_u16, OTA_CHUNK_SIZE - pos_g_u16);
os_memcpy(buffer_g_u8 + pos_g_u16, pusrdata + nbConsumed_u16, nbToCopy_u16);
pos_g_u16 = (uint16) (pos_g_u16 + nbToCopy_u16); // Roll back to zero if we reached the end of the buffer
nbConsumed_u16 = (uint16) (nbConsumed_u16 + nbToCopy_u16);
if(pos_g_u16 == OTA_CHUNK_SIZE) // The position cursor is out of the buffer's bound, meaning we filled the buffer
{
pos_g_u16 = 0;
if(upgrade->content_len == 0) // We haven't parsed the header yet. Assumes all the info we need is in the first 512 bytes of the header (header is generally shorter)
{
// Get content length fromthe header Content-Length
char *ptrContentLen_pc;
ptrContentLen_pc = os_strstr(buffer_g_u8, "Content-Length: ");
if(ptrContentLen_pc != NULL)
{
upgrade->content_len = (uint32) atoi(ptrContentLen_pc + 16); // USE STRTOUL to handle errors ?
os_printf("Total size = %d \n", upgrade->content_len);
}
// Find the start of the content payload, here the bytes of the new software
// to flash.
// To flash by block of 512 bytes, we then need to move the payload received
// to the start of the buffer (that were occupied before by the headers).
char *ptrDataStart_pc;
uint16 dataPos_u16;
uint16 dataLen_u16;
ptrDataStart_pc = os_strstr(buffer_g_u8, "\r\n\r\n");
if(ptrDataStart_pc != NULL)
{
ptrDataStart_pc += 4; // Skip the "\r\n\r\n" sequence
dataPos_u16 = (uint16) (ptrDataStart_pc - buffer_g_u8); // Index of the first byte of data in the bufer
dataLen_u16 = (uint16) (OTA_CHUNK_SIZE - dataPos_u16); // Nb of byte of the payload in this chunk
os_printf("Start of data found, %d bytes remainings \n", dataLen_u16);
os_memmove(&buffer_g_u8[0], &buffer_g_u8[dataPos_u16], dataLen_u16); // Use memmove instead of memcpy to hanle overlaps
pos_g_u16 = dataLen_u16; // Positionate the curor righ aftert the data
os_printf("Moved bytes \n");
}
}
else
{
// Our buffer is full and only contains bytes of the payload, it's time to flash !
progress_u32 += OTA_CHUNK_SIZE;
SpiFlashOpResult res;
// Erase next flash sector (requiered according to the doc)
if(address_u32 % SPI_FLASH_SEC_SIZE == 0)
{
os_printf("Erasing next sector \n");
spi_flash_erase_sector((uint16)(address_u32/SPI_FLASH_SEC_SIZE));
}
os_printf("Flashing at address 0x%06X, consummed %d/%d \n", address_u32, progress_u32, upgrade->content_len);
res = spi_flash_write(address_u32, (uint32*)buffer_g_u8, OTA_CHUNK_SIZE);
address_u32 += OTA_CHUNK_SIZE;
//if(res == SPI_FLASH_RESULT_OK) os_printf("OK\n");
if(res == SPI_FLASH_RESULT_ERR) os_printf("ERR\n");
if(res == SPI_FLASH_RESULT_TIMEOUT) os_printf("TIMEOUT\n");
}
}
else
{
// The bufer is not full, because it's the last chunk or an incomplete one.
// If it's the last, we flash the remaning bytes
uint32 remaining_u32 = upgrade->content_len - progress_u32;
if((progress_u32 > 0) && (remaining_u32 < OTA_CHUNK_SIZE))
{
// Erase next flash sector (requiered according to the doc)
if(address_u32 % SPI_FLASH_SEC_SIZE == 0)
{
os_printf("Erasing next sector \n");
spi_flash_erase_sector((uint16)(address_u32/SPI_FLASH_SEC_SIZE));
}
progress_u32 += remaining_u32;
spi_flash_write(address_u32, (uint32*)buffer_g_u8, OTA_CHUNK_SIZE);
os_printf("Flashing at address 0x%06X, consummed %d/%d \n", address_u32, progress_u32, upgrade->content_len);
// Finalize
system_upgrade_flag_set(UPGRADE_FLAG_FINISH);
ota_deinit();
}
}
}
}
Statistics: Posted by Pato — Fri Jun 22, 2018 5:38 pm
Statistics: Posted by AgentSmithers — Mon Jun 18, 2018 11:16 pm
Statistics: Posted by Pato — Sun Jun 17, 2018 6:17 pm
NB2: You said
The process of SPIWriting the Data is specific to your code
Do you mean I must write "manually" each bytes of the new app to the SPI flash with the SPI functions? If so, what are the OTA upgrade functions for? I thought they were already supposed to manage it.
Yea, I'm just your friendly neighborhood forum Spiderman... It's either this or back to basket weaving so I tend to try to keep my critical thinking sharp.
NB3: I saw you already spent a large amount of time helping other people on this forum (and sometimes on others websites), that's very appreciable and kind. Thanks. Really.
Code:
/*
* \brief: otaHandleUpload handles a POST to update the firmware
*
* Returns the number of bytes consumed from the request, -1 if a response has been sent.
*/
LOCAL int16_t ICACHE_FLASH_ATTR otaHandleUpload(OtaConn *oc) {
uint32_t offset = oc->rxBufOff;
// assume no error yet...
char *err = NULL;
uint16_t code = 400;
// check overall size
if (oc->reqLen > flashMaxSize[flashSizeMap]) {
os_printf("OTA: FW too large: %ld > %ld\n",
(long int) oc->reqLen,
(long int) flashMaxSize[flashSizeMap]);
err = "Firmware image too large";
} else if (oc->reqLen < OTA_CHUNK_SZ) {
os_printf("OTA: FW too small: %ld\n", (long int) oc->reqLen);
err = "Firmware too small";
}
// check that we have at least OTA_CHUNK_SZ bytes buffered or it's the last chunk, else we can't write
if (oc->rxBufFill < OTA_CHUNK_SZ && offset+OTA_CHUNK_SZ <= oc->reqLen) return 0;
uint16_t toFlash = OTA_CHUNK_SZ;
if (oc->rxBufFill < toFlash) toFlash = oc->rxBufFill;
// let's see which partition we need to flash
uint8 id = system_upgrade_userbin_check();
// check that data starts with an appropriate header
if (err == NULL && offset == 0) err = check_header(oc->rxBuffer+oc->rxBufOff, 1-id);
// return an error if there is one
if (err != NULL) {
os_printf("OTA Error %d: %s\n", code, err);
sendResponse(oc, code, err);
return -1;
}
// let's see which what flash address we're uploading to
uint32_t address = id ? 0x1000 : flashUser2Addr[flashSizeMap];
address += offset;
// erase next flash block if necessary
if (address % SPI_FLASH_SEC_SIZE == 0){
os_printf("OTA Flashing 0x%05lx\n", (long unsigned int) address);
spi_flash_erase_sector(address/SPI_FLASH_SEC_SIZE);
}
// write the data
//os_printf("Writing %d bytes at 0x%05x (%d of %d)\n", connData->post->buffSize, address,
// connData->post->received, connData->post->len);
spi_flash_write(address, (uint32 *)oc->rxBuffer, toFlash); <======= THIS HERE PATO!!!!!!
if (offset + toFlash == oc->reqLen) {
sendResponse(oc, 200, "");
return -1;
}
return toFlash;
}
Statistics: Posted by AgentSmithers — Thu Jun 07, 2018 12:37 pm
Code:
python -m SimpleHTTPServer 8070
The process of SPIWriting the Data is specific to your code
Code:
/*
* FOTA test code: once it's connected to Wifi, it starts the FOTA process:
* it connects to a local server to retrieve the new bin to flash and upgrades. That's all.
* Core code based on https://harizanov.com/2015/06/firmware-over-the-air-fota-for-esp8266-soc/
*/
#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "user_interface.h"
#include "mem.h"
#include "upgrade.h"
#include "ip_addr.h"
#include "espconn.h"
uint32 priv_param_start_sec;
char ssid[32] = "MyWifiSSID";
char password[64] = "superpassword";
/**
* @brief Was present in IoT_Demo/user/user_main.c on which this code is based...
*/
uint32 ICACHE_FLASH_ATTR user_rf_cal_sector_set(void)
{
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
priv_param_start_sec = 0x3C;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
priv_param_start_sec = 0x7C;
break;
case FLASH_SIZE_16M_MAP_512_512:
rf_cal_sec = 512 - 5;
priv_param_start_sec = 0x7C;
break;
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
priv_param_start_sec = 0xFC;
break;
case FLASH_SIZE_32M_MAP_512_512:
rf_cal_sec = 1024 - 5;
priv_param_start_sec = 0x7C;
break;
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
priv_param_start_sec = 0xFC;
break;
case FLASH_SIZE_64M_MAP_1024_1024:
rf_cal_sec = 2048 - 5;
priv_param_start_sec = 0xFC;
break;
case FLASH_SIZE_128M_MAP_1024_1024:
rf_cal_sec = 4096 - 5;
priv_param_start_sec = 0xFC;
break;
default:
rf_cal_sec = 0;
priv_param_start_sec = 0;
break;
}
return rf_cal_sec;
}
/**
* @brief Was present in IoT_Demo/user/user_main.c on wich this code is based...
*/
void ICACHE_FLASH_ATTR user_rf_pre_init(void)
{
}
/**
* @brief Callback function called when the upgrade process ended, because of
* timeout or upgrade finished ?
*/
static void OtaFinishedCallback(void *arg)
{
struct upgrade_server_info *update = arg;
if (update->upgrade_flag == true)
{
os_printf("[OTA] Success, now rebooting!\n");
system_upgrade_reboot();
}
else
{
os_printf("[OTA] Failed!\n");
}
}
/**
* @brief Start the OTA upgrade process.
*
*/
static void HandleUpgrade(const uint8 *server_ip, uint16_t port, const char *path)
{
const char* file;
uint8_t userBin = system_upgrade_userbin_check();
/* Check wich slot/bin is currently running to determine the new bin to download */
switch(userBin)
{
case UPGRADE_FW_BIN1: file = "user2.app"; break;
case UPGRADE_FW_BIN2: file = "user1.app"; break;
default:
os_printf("[OTA] Invalid userbin number! \n");
return;
}
/* Set the info about source server and upgrade process properties */
struct upgrade_server_info* update = (struct upgrade_server_info *)os_zalloc(sizeof(struct upgrade_server_info));
os_memcpy(update->ip, server_ip, 4);
update->pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn));
update->port = port;
update->check_cb = OtaFinishedCallback;
update->check_times = 60000;
update->url = (uint8 *)os_zalloc(512);
os_sprintf((char*)update->url, "GET %s%s HTTP/1.0\r\nHost: "IPSTR":%d\r\nConnection: close\r\n\r\n",
path, file, IP2STR(update->ip), update->port);
os_printf("[OTA] Server "IPSTR":%d. Path: %s%s\n", IP2STR(update->ip), update->port, path, file);
os_printf("Request: %s \n", update->url);
/* Debug */
if (system_upgrade_start(update) == false) os_printf("[OTA] Could not start upgrade\n");
else os_printf("[OTA] Started upgrading...\n");
}
/**
* @brief Callback function called when the wifi connection is fully operational.
* Launch the OTA upgrade.
*
*/
void WifiConnectedCb(System_Event_t *event)
{
/* Run OTA process only when we are fully connected to WiFi */
if(event->event == EVENT_STAMODE_GOT_IP)
{
os_printf("Connected to Wifi (EVENT_STAMODE_GOT_IP) \n");
os_printf("Now Testing FOTA... \n");
uint8 serverIp[] = {192, 168, 0, 106};
uint16 port = 8070;
char path[] = "pato/espOtaTest/";
HandleUpgrade(serverIp, port, path);
}
}
/**
* @brief Called when system is fully initialized. Here we do our custom initialization
* like connecting to wifi and setting timers.
*/
void PostInitCb()
{
/* Connect to WiFi */
os_printf("I'm version 1 ! \n");
os_printf("Setting up the Esp as a Wifi station... \n");
struct station_config stationConfig;
os_memcpy(stationConfig.ssid, ssid, 32);
os_memcpy(stationConfig.password, password, 64);
wifi_set_opmode_current(STATION_MODE);
wifi_station_set_config(&stationConfig);
wifi_set_event_handler_cb(WifiConnectedCb);
wifi_station_connect();
os_printf("Connecting to WiFi... \n");
}
/**
* @brief Main entry point of our programm
*/
void user_init()
{
system_init_done_cb(PostInitCb);
}
Statistics: Posted by Pato — Wed Jun 06, 2018 6:06 pm
Statistics: Posted by AgentSmithers — Wed Jun 06, 2018 2:01 am
Code:
system_upgrade_start
upgrade_connect 50768
upgrade_connect_cb
pusrdata = HTTP/1.0 200 OK
server do not support HEAD method now send GET message
pusrdata = Server: SimpleHTTP/0.6 Python/2.7.9
Date: Tue, 05 Jun 2018 12:40:31 GMT
Content-type: application/octet-stream
Content-Length: 231316
Last-Modified: Mon, 04 Jun 2018 13:49:22 GMT
sumlength = 231316
sec_block 57
.........................................................upgrade_get_sum_disconcb 46888
erase sector=1 ok
erase sector=2 ok
erase sector=3 ok
(more erase ok...)
erase sector=55 ok
erase sector=56 ok
erase sector=57 ok
ALL=57 sectors erase ok!
upgrade_connect_cb
totallen = 17
totallen = 1477
totallen = 2937
(more totallen...)
totallen = 230697
totallen = 231519
(nothing more is printed)...
upgrade_check_cb << Called on timeout, here I check the flag indicating the result of the upgrade: it is always false (failed, upgrade_flag == false)
Statistics: Posted by Pato — Tue Jun 05, 2018 10:42 pm