mirror of https://github.com/arendst/Tasmota.git
Refactor RF Bridge fw upload
This commit is contained in:
parent
04c5212e4b
commit
d8678d149d
|
@ -35,15 +35,11 @@ const uint16_t CHUNKED_BUFFER_SIZE = (MESSZ / 2) - 100; // Chunk buffer size (s
|
||||||
|
|
||||||
const uint16_t HTTP_REFRESH_TIME = 2345; // milliseconds
|
const uint16_t HTTP_REFRESH_TIME = 2345; // milliseconds
|
||||||
const uint16_t HTTP_RESTART_RECONNECT_TIME = 9000; // milliseconds - Allow time for restart and wifi reconnect
|
const uint16_t HTTP_RESTART_RECONNECT_TIME = 9000; // milliseconds - Allow time for restart and wifi reconnect
|
||||||
const uint16_t HTTP_OTA_RESTART_RECONNECT_TIME = 20000; // milliseconds - Allow time for uploading binary, unzip/write to final destination and wifi reconnect
|
const uint16_t HTTP_OTA_RESTART_RECONNECT_TIME = 24000; // milliseconds - Allow time for uploading binary, unzip/write to final destination and wifi reconnect
|
||||||
|
|
||||||
#include <ESP8266WebServer.h>
|
#include <ESP8266WebServer.h>
|
||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
|
|
||||||
#ifdef USE_RF_FLASH
|
|
||||||
uint8_t *efm8bb1_update = nullptr;
|
|
||||||
#endif // USE_RF_FLASH
|
|
||||||
|
|
||||||
enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTACLIENT, UPL_EFR32, UPL_SHD };
|
enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTACLIENT, UPL_EFR32, UPL_SHD };
|
||||||
|
|
||||||
#ifdef USE_UNISHOX_COMPRESSION
|
#ifdef USE_UNISHOX_COMPRESSION
|
||||||
|
@ -792,11 +788,7 @@ const char kLoggingLevels[] PROGMEM = D_NONE "|" D_ERROR "|" D_INFO "|" D_DEBUG
|
||||||
const char kEmulationOptions[] PROGMEM = D_NONE "|" D_BELKIN_WEMO "|" D_HUE_BRIDGE;
|
const char kEmulationOptions[] PROGMEM = D_NONE "|" D_BELKIN_WEMO "|" D_HUE_BRIDGE;
|
||||||
|
|
||||||
const char kUploadErrors[] PROGMEM =
|
const char kUploadErrors[] PROGMEM =
|
||||||
D_UPLOAD_ERR_1 "|" D_UPLOAD_ERR_2 "|" D_UPLOAD_ERR_3 "|" D_UPLOAD_ERR_4 "|" D_UPLOAD_ERR_5 "|" D_UPLOAD_ERR_6 "|" D_UPLOAD_ERR_7 "|" D_UPLOAD_ERR_8 "|" D_UPLOAD_ERR_9
|
D_UPLOAD_ERR_1 "|" D_UPLOAD_ERR_2 "|" D_UPLOAD_ERR_3 "|" D_UPLOAD_ERR_4 "|" D_UPLOAD_ERR_5 "|" D_UPLOAD_ERR_6 "|" D_UPLOAD_ERR_7 "|" D_UPLOAD_ERR_8 "|" D_UPLOAD_ERR_9;
|
||||||
#ifdef USE_RF_FLASH
|
|
||||||
"|" D_UPLOAD_ERR_10 "|" D_UPLOAD_ERR_11 "|" D_UPLOAD_ERR_12 "|" D_UPLOAD_ERR_13
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
const uint16_t DNS_PORT = 53;
|
const uint16_t DNS_PORT = 53;
|
||||||
enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY};
|
enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY};
|
||||||
|
@ -2569,12 +2561,17 @@ void HandleInformation(void)
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#if defined(USE_ZIGBEE_EZSP) || defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE)
|
#if defined(USE_ZIGBEE_EZSP) || defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE) || defined(USE_RF_FLASH)
|
||||||
|
#define USE_WEB_FW_UPGRADE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_WEB_FW_UPGRADE
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
size_t spi_hex_size;
|
size_t spi_hex_size;
|
||||||
size_t spi_sector_counter;
|
size_t spi_sector_counter;
|
||||||
size_t spi_sector_cursor;
|
size_t spi_sector_cursor;
|
||||||
|
bool active;
|
||||||
bool ready;
|
bool ready;
|
||||||
} BUpload;
|
} BUpload;
|
||||||
|
|
||||||
|
@ -2582,12 +2579,13 @@ uint32_t BUploadStartSector(void) {
|
||||||
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
|
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t BUploadInit(void) {
|
void BUploadInit(uint32_t file_type) {
|
||||||
|
Web.upload_file_type = file_type;
|
||||||
BUpload.spi_hex_size = 0;
|
BUpload.spi_hex_size = 0;
|
||||||
BUpload.spi_sector_counter = BUploadStartSector();
|
BUpload.spi_sector_counter = BUploadStartSector();
|
||||||
BUpload.spi_sector_cursor = 0;
|
BUpload.spi_sector_cursor = 0;
|
||||||
|
BUpload.active = true;
|
||||||
BUpload.ready = false;
|
BUpload.ready = false;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BUploadWriteBuffer(uint8_t *buf, size_t size) {
|
uint32_t BUploadWriteBuffer(uint8_t *buf, size_t size) {
|
||||||
|
@ -2607,7 +2605,13 @@ uint32_t BUploadWriteBuffer(uint8_t *buf, size_t size) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // USE_ZIGBEE_EZSP or USE_TASMOTA_CLIENT or SHELLY_FW_UPGRADE
|
void BUploadDone(void) {
|
||||||
|
Web.upload_file_type = UPL_TASMOTA;
|
||||||
|
BUpload.active = false;
|
||||||
|
BUpload.ready = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_WEB_FW_UPGRADE
|
||||||
|
|
||||||
void HandleUpgradeFirmware(void)
|
void HandleUpgradeFirmware(void)
|
||||||
{
|
{
|
||||||
|
@ -2660,7 +2664,7 @@ void HandleUploadDone(void)
|
||||||
|
|
||||||
#if defined(USE_ZIGBEE_EZSP)
|
#if defined(USE_ZIGBEE_EZSP)
|
||||||
if ((UPL_EFR32 == Web.upload_file_type) && !Web.upload_error && BUpload.ready) {
|
if ((UPL_EFR32 == Web.upload_file_type) && !Web.upload_error && BUpload.ready) {
|
||||||
BUpload.ready = false; // Make sure not to follow thru again
|
BUploadDone(); // Make sure not to follow thru again
|
||||||
// GUI xmodem
|
// GUI xmodem
|
||||||
ZigbeeUploadStep1Done(BUploadStartSector(), BUpload.spi_hex_size);
|
ZigbeeUploadStep1Done(BUploadStartSector(), BUpload.spi_hex_size);
|
||||||
HandleZigbeeXfer();
|
HandleZigbeeXfer();
|
||||||
|
@ -2693,11 +2697,7 @@ void HandleUploadDone(void)
|
||||||
WSContentSend_P(PSTR("<div style='text-align:center;'><b>" D_UPLOAD " <font color='#"));
|
WSContentSend_P(PSTR("<div style='text-align:center;'><b>" D_UPLOAD " <font color='#"));
|
||||||
if (Web.upload_error) {
|
if (Web.upload_error) {
|
||||||
WSContentSend_P(PSTR("%06x'>" D_FAILED "</font></b><br><br>"), WebColor(COL_TEXT_WARNING));
|
WSContentSend_P(PSTR("%06x'>" D_FAILED "</font></b><br><br>"), WebColor(COL_TEXT_WARNING));
|
||||||
#ifdef USE_RF_FLASH
|
|
||||||
if (Web.upload_error < 15) {
|
|
||||||
#else
|
|
||||||
if (Web.upload_error < 10) {
|
if (Web.upload_error < 10) {
|
||||||
#endif
|
|
||||||
GetTextIndexed(error, sizeof(error), Web.upload_error -1, kUploadErrors);
|
GetTextIndexed(error, sizeof(error), Web.upload_error -1, kUploadErrors);
|
||||||
} else {
|
} else {
|
||||||
snprintf_P(error, sizeof(error), PSTR(D_UPLOAD_ERROR_CODE " %d"), Web.upload_error);
|
snprintf_P(error, sizeof(error), PSTR(D_UPLOAD_ERROR_CODE " %d"), Web.upload_error);
|
||||||
|
@ -2709,7 +2709,7 @@ void HandleUploadDone(void)
|
||||||
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br>"), WebColor(COL_TEXT_SUCCESS));
|
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br>"), WebColor(COL_TEXT_SUCCESS));
|
||||||
TasmotaGlobal.restart_flag = 2; // Always restart to re-enable disabled features during update
|
TasmotaGlobal.restart_flag = 2; // Always restart to re-enable disabled features during update
|
||||||
|
|
||||||
#if defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE)
|
#if defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE) || defined(USE_RF_FLASH)
|
||||||
if (BUpload.ready) {
|
if (BUpload.ready) {
|
||||||
WSContentSend_P(PSTR("<br><div style='text-align:center;'><b>" D_TRANSFER_STARTED " ...</b></div>"));
|
WSContentSend_P(PSTR("<br><div style='text-align:center;'><b>" D_TRANSFER_STARTED " ...</b></div>"));
|
||||||
TasmotaGlobal.restart_flag = 0; // Hold restart as code still needs to be transferred to STM
|
TasmotaGlobal.restart_flag = 0; // Hold restart as code still needs to be transferred to STM
|
||||||
|
@ -2726,8 +2726,13 @@ void HandleUploadDone(void)
|
||||||
WSContentSpaceButton(BUTTON_MAIN);
|
WSContentSpaceButton(BUTTON_MAIN);
|
||||||
WSContentStop();
|
WSContentStop();
|
||||||
|
|
||||||
#if defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE)
|
#ifdef USE_WEB_FW_UPGRADE
|
||||||
if (BUpload.ready) {
|
if (BUpload.ready) {
|
||||||
|
#ifdef USE_RF_FLASH
|
||||||
|
if (UPL_EFM8BB1 == Web.upload_file_type) {
|
||||||
|
SnfBrFlash(BUploadStartSector() * SPI_FLASH_SEC_SIZE, BUpload.spi_hex_size);
|
||||||
|
}
|
||||||
|
#endif // USE_RF_FLASH
|
||||||
#ifdef SHELLY_FW_UPGRADE
|
#ifdef SHELLY_FW_UPGRADE
|
||||||
if (UPL_SHD == Web.upload_file_type) {
|
if (UPL_SHD == Web.upload_file_type) {
|
||||||
ShdFlash(BUploadStartSector() * SPI_FLASH_SEC_SIZE, BUpload.spi_hex_size);
|
ShdFlash(BUploadStartSector() * SPI_FLASH_SEC_SIZE, BUpload.spi_hex_size);
|
||||||
|
@ -2738,9 +2743,9 @@ void HandleUploadDone(void)
|
||||||
TasmotaClient_Flash(BUploadStartSector() * SPI_FLASH_SEC_SIZE, BUpload.spi_hex_size);
|
TasmotaClient_Flash(BUploadStartSector() * SPI_FLASH_SEC_SIZE, BUpload.spi_hex_size);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
BUploadDone();
|
||||||
}
|
}
|
||||||
#endif // USE_TASMOTA_CLIENT or SHELLY_FW_UPGRADE
|
#endif // USE_WEB_FW_UPGRADE
|
||||||
Web.upload_file_type = UPL_TASMOTA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleUploadLoop(void)
|
void HandleUploadLoop(void)
|
||||||
|
@ -2784,155 +2789,96 @@ void HandleUploadLoop(void)
|
||||||
if (Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT
|
if (Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT
|
||||||
MqttDisconnect();
|
MqttDisconnect();
|
||||||
}
|
}
|
||||||
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
|
||||||
if (!Update.begin(maxSketchSpace)) { //start with max available size
|
|
||||||
|
|
||||||
// if (_serialoutput) Update.printError(Serial);
|
|
||||||
// if (Update.getError() == UPDATE_ERROR_BOOTSTRAP) {
|
|
||||||
// if (_serialoutput) Serial.println("Device still in UART update mode, perform powercycle");
|
|
||||||
// }
|
|
||||||
|
|
||||||
Web.upload_error = 2; // Not enough space
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Web.upload_progress_dot_count = 0;
|
Web.upload_progress_dot_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***** Step2: Write upload file
|
// ***** Step2: Write upload file
|
||||||
else if (!Web.upload_error && (UPLOAD_FILE_WRITE == upload.status)) {
|
else if (UPLOAD_FILE_WRITE == upload.status) {
|
||||||
if (0 == upload.totalSize) {
|
if (0 == upload.totalSize) { // First block received
|
||||||
if (UPL_SETTINGS == Web.upload_file_type) {
|
if (UPL_SETTINGS == Web.upload_file_type) {
|
||||||
Web.config_block_count = 0;
|
Web.config_block_count = 0;
|
||||||
}
|
}
|
||||||
else {
|
#ifdef USE_WEB_FW_UPGRADE
|
||||||
#ifdef USE_RF_FLASH
|
#ifdef USE_RF_FLASH
|
||||||
if ((SONOFF_BRIDGE == TasmotaGlobal.module_type) && (':' == upload.buf[0])) { // Check if this is a RF bridge FW file
|
else if ((SONOFF_BRIDGE == TasmotaGlobal.module_type) && (':' == upload.buf[0])) { // Check if this is a RF bridge FW file
|
||||||
Update.end(); // End esp8266 update session
|
BUploadInit(UPL_EFM8BB1);
|
||||||
Web.upload_file_type = UPL_EFM8BB1;
|
}
|
||||||
|
|
||||||
Web.upload_error = SnfBrUpdateInit(); // 10, 11
|
|
||||||
if (Web.upload_error != 0) { return; }
|
|
||||||
} else
|
|
||||||
#endif // USE_RF_FLASH
|
#endif // USE_RF_FLASH
|
||||||
#if defined(USE_ZIGBEE_EZSP) || defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE)
|
#ifdef USE_ZIGBEE_EZSP
|
||||||
#if defined(USE_ZIGBEE_EZSP)
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
if ((SONOFF_ZB_BRIDGE == TasmotaGlobal.module_type) && (0xEB == upload.buf[0])) { // Check if this is a Zigbee bridge FW file
|
else if ((SONOFF_ZB_BRIDGE == TasmotaGlobal.module_type) && (0xEB == upload.buf[0])) { // Check if this is a Zigbee bridge FW file
|
||||||
#else // ESP32
|
#else // ESP32
|
||||||
if (PinUsed(GPIO_ZIGBEE_RX) && PinUsed(GPIO_ZIGBEE_TX) && (0xEB == upload.buf[0])) { // Check if this is a Zigbee bridge FW file
|
else if (PinUsed(GPIO_ZIGBEE_RX) && PinUsed(GPIO_ZIGBEE_TX) && (0xEB == upload.buf[0])) { // Check if this is a Zigbee bridge FW file
|
||||||
#endif // ESP8266 or ESP32
|
#endif // ESP8266 or ESP32
|
||||||
// Read complete file into ESP8266 flash
|
// Read complete file into ESP8266 flash
|
||||||
// Current files are about 200k
|
// Current files are about 200k
|
||||||
Web.upload_file_type = UPL_EFR32;
|
Web.upload_error = ZigbeeUploadStep1Init(); // 1
|
||||||
|
if (Web.upload_error != 0) { return; }
|
||||||
Web.upload_error = ZigbeeUploadStep1Init(); // 1
|
BUploadInit(UPL_EFR32);
|
||||||
if (Web.upload_error != 0) {
|
|
||||||
Update.end(); // End esp8266 update session
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(USE_TASMOTA_CLIENT)
|
|
||||||
if (TasmotaClient_Available() && (':' == upload.buf[0])) { // Check if this is a ARDUINO CLIENT hex file
|
|
||||||
Web.upload_file_type = UPL_TASMOTACLIENT;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(SHELLY_FW_UPGRADE)
|
|
||||||
if (ShdPresent() && (0x00 == upload.buf[0]) && (0x10 == upload.buf[1])) {
|
|
||||||
Web.upload_file_type = UPL_SHD;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if ((UPL_TASMOTACLIENT == Web.upload_file_type) || (UPL_SHD == Web.upload_file_type) || (UPL_EFR32 == Web.upload_file_type)) {
|
|
||||||
Update.end(); // End esp8266 update session
|
|
||||||
|
|
||||||
Web.upload_error = BUploadInit();
|
|
||||||
if (Web.upload_error != 0) { return; }
|
|
||||||
} else
|
|
||||||
#endif // USE_ZIGBEE_EZSP or USE_TASMOTA_CLIENT or SHELLY_FW_UPGRADE
|
|
||||||
{
|
|
||||||
if ((upload.buf[0] != 0xE9) && (upload.buf[0] != 0x1F)) { // 0x1F is gzipped 0xE9
|
|
||||||
Web.upload_error = 3; // Magic byte is not 0xE9
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (0xE9 == upload.buf[0]) {
|
|
||||||
uint32_t bin_flash_size = ESP.magicFlashChipSize((upload.buf[3] & 0xf0) >> 4);
|
|
||||||
if (bin_flash_size > ESP.getFlashChipRealSize()) {
|
|
||||||
Web.upload_error = 4; // Program flash size is larger than real flash size
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// upload.buf[2] = 3; // Force DOUT - ESP8285
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "File type %d"), Web.upload_file_type);
|
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
if (UPL_SETTINGS == Web.upload_file_type) {
|
#ifdef USE_TASMOTA_CLIENT
|
||||||
if (!Web.upload_error) {
|
else if (TasmotaClient_Available() && (':' == upload.buf[0])) { // Check if this is a ARDUINO CLIENT hex file
|
||||||
if (upload.currentSize > (sizeof(Settings) - (Web.config_block_count * HTTP_UPLOAD_BUFLEN))) {
|
BUploadInit(UPL_TASMOTACLIENT);
|
||||||
Web.upload_error = 9; // File too large
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(settings_buffer + (Web.config_block_count * HTTP_UPLOAD_BUFLEN), upload.buf, upload.currentSize);
|
|
||||||
Web.config_block_count++;
|
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
#ifdef USE_RF_FLASH
|
#ifdef SHELLY_FW_UPGRADE
|
||||||
else if (UPL_EFM8BB1 == Web.upload_file_type) {
|
else if (ShdPresent() && (0x00 == upload.buf[0]) && (0x10 == upload.buf[1])) {
|
||||||
if (efm8bb1_update != nullptr) { // We have carry over data since last write, i. e. a start but not an end
|
BUploadInit(UPL_SHD);
|
||||||
ssize_t result = rf_glue_remnant_with_new_data_and_write(efm8bb1_update, upload.buf, upload.currentSize);
|
|
||||||
free(efm8bb1_update);
|
|
||||||
efm8bb1_update = nullptr;
|
|
||||||
if (result != 0) {
|
|
||||||
Web.upload_error = abs(result); // 2 = Not enough space, 8 = File invalid, 12, 13
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ssize_t result = rf_search_and_write(upload.buf, upload.currentSize);
|
#endif
|
||||||
if (result < 0) {
|
#endif // USE_WEB_FW_UPGRADE
|
||||||
Web.upload_error = abs(result); // 8, 12, 13
|
else if ((upload.buf[0] != 0xE9) && (upload.buf[0] != 0x1F)) { // 0x1F is gzipped 0xE9
|
||||||
|
Web.upload_error = 3; // Invalid file signature - Magic byte is not 0xE9
|
||||||
return;
|
return;
|
||||||
} else if (result > 0) {
|
|
||||||
if ((size_t)result > upload.currentSize) {
|
|
||||||
// Offset is larger than the buffer supplied, this should not happen
|
|
||||||
Web.upload_error = 9; // File too large - Failed to decode RF firmware
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// A remnant has been detected, allocate data for it plus a null termination byte
|
|
||||||
size_t remnant_sz = upload.currentSize - result;
|
|
||||||
efm8bb1_update = (uint8_t *) malloc(remnant_sz + 1);
|
|
||||||
if (efm8bb1_update == nullptr) {
|
|
||||||
Web.upload_error = 2; // Not enough space - Unable to allocate memory to store new RF firmware
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(efm8bb1_update, upload.buf + result, remnant_sz);
|
|
||||||
// Add null termination at the end of of remnant buffer
|
|
||||||
efm8bb1_update[remnant_sz] = '\0';
|
|
||||||
}
|
}
|
||||||
|
if (UPL_TASMOTA == Web.upload_file_type) {
|
||||||
|
if (0xE9 == upload.buf[0]) {
|
||||||
|
uint32_t bin_flash_size = ESP.magicFlashChipSize((upload.buf[3] & 0xf0) >> 4);
|
||||||
|
if (bin_flash_size > ESP.getFlashChipRealSize()) {
|
||||||
|
Web.upload_error = 4; // Program flash size is larger than real flash size
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// upload.buf[2] = 3; // Force DOUT - ESP8285
|
||||||
|
}
|
||||||
|
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||||
|
if (!Update.begin(maxSketchSpace)) { //start with max available size
|
||||||
|
Web.upload_error = 2; // Not enough space
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "File type %d"), Web.upload_file_type);
|
||||||
|
} // First block received
|
||||||
|
|
||||||
|
if (UPL_SETTINGS == Web.upload_file_type) {
|
||||||
|
if (upload.currentSize > (sizeof(Settings) - (Web.config_block_count * HTTP_UPLOAD_BUFLEN))) {
|
||||||
|
Web.upload_error = 9; // File too large
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(settings_buffer + (Web.config_block_count * HTTP_UPLOAD_BUFLEN), upload.buf, upload.currentSize);
|
||||||
|
Web.config_block_count++;
|
||||||
}
|
}
|
||||||
#endif // USE_RF_FLASH
|
#ifdef USE_WEB_FW_UPGRADE
|
||||||
#if defined(USE_ZIGBEE_EZSP) || defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE)
|
else if (BUpload.active) {
|
||||||
else if ((UPL_EFR32 == Web.upload_file_type) || (UPL_TASMOTACLIENT == Web.upload_file_type) || (UPL_SHD == Web.upload_file_type)) {
|
|
||||||
// Write a block
|
// Write a block
|
||||||
Web.upload_error = BUploadWriteBuffer(upload.buf, upload.currentSize);
|
Web.upload_error = BUploadWriteBuffer(upload.buf, upload.currentSize);
|
||||||
if (Web.upload_error != 0) { return; }
|
if (Web.upload_error != 0) { return; }
|
||||||
}
|
}
|
||||||
#endif // USE_ZIGBEE_EZSP or USE_TASMOTA_CLIENT or SHELLY_FW_UPGRADE
|
#endif // USE_WEB_FW_UPGRADE
|
||||||
else { // firmware
|
else if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
|
||||||
if (!Web.upload_error && (Update.write(upload.buf, upload.currentSize) != upload.currentSize)) {
|
Web.upload_error = 5; // Upload buffer miscompare
|
||||||
Web.upload_error = 5; // Upload buffer miscompare
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (_serialoutput) {
|
||||||
if (_serialoutput) {
|
Serial.printf(".");
|
||||||
Serial.printf(".");
|
Web.upload_progress_dot_count++;
|
||||||
Web.upload_progress_dot_count++;
|
if (!(Web.upload_progress_dot_count % 80)) { Serial.println(); }
|
||||||
if (!(Web.upload_progress_dot_count % 80)) { Serial.println(); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***** Step3: Finish upload file
|
// ***** Step3: Finish upload file
|
||||||
else if(!Web.upload_error && (UPLOAD_FILE_END == upload.status)) {
|
else if (UPLOAD_FILE_END == upload.status) {
|
||||||
if (_serialoutput && (Web.upload_progress_dot_count % 80)) {
|
if (_serialoutput && (Web.upload_progress_dot_count % 80)) {
|
||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
|
@ -2976,29 +2922,18 @@ void HandleUploadLoop(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef USE_RF_FLASH
|
#ifdef USE_WEB_FW_UPGRADE
|
||||||
else if (UPL_EFM8BB1 == Web.upload_file_type) {
|
else if (BUpload.active) {
|
||||||
// RF FW flash done
|
|
||||||
// Web.upload_file_type = UPL_TASMOTA;
|
|
||||||
}
|
|
||||||
#endif // USE_RF_FLASH
|
|
||||||
#if defined(USE_ZIGBEE_EZSP) || defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE)
|
|
||||||
else if ((UPL_EFR32 == Web.upload_file_type) || (UPL_TASMOTACLIENT == Web.upload_file_type) || (UPL_SHD == Web.upload_file_type)) {
|
|
||||||
// Done writing the hex to SPI flash
|
// Done writing the hex to SPI flash
|
||||||
BUpload.ready = true; // So we know on upload success page if it needs to flash hex or do a normal restart
|
BUpload.ready = true; // So we know on upload success page if it needs to flash hex or do a normal restart
|
||||||
// Web.upload_file_type = UPL_TASMOTA;
|
|
||||||
}
|
}
|
||||||
#endif // USE_ZIGBEE_EZSP or USE_TASMOTA_CLIENT or SHELLY_FW_UPGRADE
|
#endif // USE_WEB_FW_UPGRADE
|
||||||
else {
|
else if (!Update.end(true)) { // true to set the size to the current progress
|
||||||
if (!Update.end(true)) { // true to set the size to the current progress
|
if (_serialoutput) { Update.printError(Serial); }
|
||||||
if (_serialoutput) { Update.printError(Serial); }
|
Web.upload_error = 6; // Upload failed. Enable logging 3
|
||||||
Web.upload_error = 6; // Upload failed. Enable logging 3
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!Web.upload_error) {
|
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_SUCCESSFUL " %u bytes"), upload.totalSize);
|
|
||||||
}
|
}
|
||||||
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_SUCCESSFUL " %u bytes"), upload.totalSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***** Step4: Abort upload file
|
// ***** Step4: Abort upload file
|
||||||
|
|
|
@ -58,68 +58,9 @@ struct SONOFFBRIDGE {
|
||||||
#include "ihx.h"
|
#include "ihx.h"
|
||||||
#include "c2.h"
|
#include "c2.h"
|
||||||
|
|
||||||
const ssize_t RF_RECORD_NO_START_FOUND = -1;
|
uint32_t rf_decode_and_write(uint8_t *record, size_t size) {
|
||||||
const ssize_t RF_RECORD_NO_END_FOUND = -2;
|
|
||||||
|
|
||||||
ssize_t rf_find_hex_record_start(uint8_t *buf, size_t size)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
if (buf[i] == ':') {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return RF_RECORD_NO_START_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t rf_find_hex_record_end(uint8_t *buf, size_t size)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
if (buf[i] == '\n') {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return RF_RECORD_NO_END_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t rf_glue_remnant_with_new_data_and_write(const uint8_t *remnant_data, uint8_t *new_data, size_t new_data_len)
|
|
||||||
{
|
|
||||||
ssize_t record_start;
|
|
||||||
ssize_t record_end;
|
|
||||||
ssize_t glue_record_sz;
|
|
||||||
uint8_t *glue_buf;
|
|
||||||
ssize_t result;
|
|
||||||
|
|
||||||
if (remnant_data[0] != ':') { return -8; } // File invalid - RF Remnant data did not start with a start token
|
|
||||||
|
|
||||||
// Find end token in new data
|
|
||||||
record_end = rf_find_hex_record_end(new_data, new_data_len);
|
|
||||||
record_start = rf_find_hex_record_start(new_data, new_data_len);
|
|
||||||
|
|
||||||
// Be paranoid and check that there is no start marker before the end record
|
|
||||||
// If so this implies that there was something wrong with the last start marker saved
|
|
||||||
// in the last upload part
|
|
||||||
if ((record_start != RF_RECORD_NO_START_FOUND) && (record_start < record_end)) {
|
|
||||||
return -8; // File invalid - Unexpected RF start marker found before RF end marker
|
|
||||||
}
|
|
||||||
|
|
||||||
glue_record_sz = strlen((const char *) remnant_data) + record_end;
|
|
||||||
|
|
||||||
glue_buf = (uint8_t *) malloc(glue_record_sz);
|
|
||||||
if (glue_buf == nullptr) { return -2; } // Not enough space
|
|
||||||
|
|
||||||
// Assemble new glue buffer
|
|
||||||
memcpy(glue_buf, remnant_data, strlen((const char *) remnant_data));
|
|
||||||
memcpy(glue_buf + strlen((const char *) remnant_data), new_data, record_end);
|
|
||||||
|
|
||||||
result = rf_decode_and_write(glue_buf, glue_record_sz);
|
|
||||||
free(glue_buf);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t rf_decode_and_write(uint8_t *record, size_t size)
|
|
||||||
{
|
|
||||||
uint8_t err = ihx_decode(record, size);
|
uint8_t err = ihx_decode(record, size);
|
||||||
if (err != IHX_SUCCESS) { return -13; } // Failed to decode RF firmware
|
if (err != IHX_SUCCESS) { return 13; } // Failed to decode RF firmware
|
||||||
|
|
||||||
ihx_t *h = (ihx_t *) record;
|
ihx_t *h = (ihx_t *) record;
|
||||||
if (h->record_type == IHX_RT_DATA) {
|
if (h->record_type == IHX_RT_DATA) {
|
||||||
|
@ -135,47 +76,49 @@ ssize_t rf_decode_and_write(uint8_t *record, size_t size)
|
||||||
err = c2_reset();
|
err = c2_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != C2_SUCCESS) { return -12; } // Failed to write to RF chip
|
if (err != C2_SUCCESS) { return 12; } // Failed to write to RF chip
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t rf_search_and_write(uint8_t *buf, size_t size)
|
uint32_t rf_search_and_write(uint8_t *data, size_t size) {
|
||||||
{
|
|
||||||
// Binary contains a set of commands, decode and program each one
|
// Binary contains a set of commands, decode and program each one
|
||||||
ssize_t rec_end;
|
uint8_t buf[64];
|
||||||
ssize_t rec_start;
|
uint8_t* p_data = data;
|
||||||
ssize_t err;
|
uint32_t addr = 0;
|
||||||
|
uint32_t rec_end;
|
||||||
|
uint32_t rec_start;
|
||||||
|
uint32_t rec_size;
|
||||||
|
uint32_t err;
|
||||||
|
|
||||||
|
while (addr < size) {
|
||||||
|
memcpy(buf, p_data, sizeof(buf)); // Must load flash using memcpy on 4-byte boundary
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
// Find starts and ends of commands
|
// Find starts and ends of commands
|
||||||
rec_start = rf_find_hex_record_start(buf + i, size - i);
|
for (rec_start = 0; rec_start < 8; rec_start++) {
|
||||||
if (rec_start == RF_RECORD_NO_START_FOUND) {
|
if (':' == buf[rec_start]) { break; }
|
||||||
// There is nothing left to save in this buffer
|
|
||||||
return -8; // File invalid
|
|
||||||
}
|
}
|
||||||
|
if (rec_start > 7) { return 8; } // File invalid - RF Remnant data did not start with a start token
|
||||||
// Translate rec_start from local buffer position to chunk position
|
for (rec_end = rec_start; rec_end < sizeof(buf); rec_end++) {
|
||||||
rec_start += i;
|
if ('\n' == buf[rec_end]) { break; }
|
||||||
rec_end = rf_find_hex_record_end(buf + rec_start, size - rec_start);
|
|
||||||
if (rec_end == RF_RECORD_NO_END_FOUND) {
|
|
||||||
// We have found a start but not an end, save remnant
|
|
||||||
return rec_start;
|
|
||||||
}
|
}
|
||||||
|
if (rec_end == sizeof(buf)) { return 9; } // File too large - Failed to decode RF firmware
|
||||||
|
rec_size = rec_end - rec_start;
|
||||||
|
|
||||||
// Translate rec_end from local buffer position to chunk position
|
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)&buf + rec_start, rec_size);
|
||||||
rec_end += rec_start;
|
|
||||||
|
|
||||||
err = rf_decode_and_write(buf + rec_start, rec_end - rec_start);
|
err = rf_decode_and_write(buf + rec_start, rec_size);
|
||||||
if (err < 0) { return err; }
|
if (err != 0) { return err; }
|
||||||
i = rec_end;
|
|
||||||
|
addr += rec_size +1;
|
||||||
|
p_data += (rec_end & 0xFFFC); // Stay on 4-byte boundary
|
||||||
|
delay(0);
|
||||||
}
|
}
|
||||||
// Buffer was perfectly aligned, start and end found without any remaining trailing characters
|
// Buffer was perfectly aligned, start and end found without any remaining trailing characters
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t rf_erase_flash(void)
|
uint8_t rf_erase_flash(void) {
|
||||||
{
|
|
||||||
uint8_t err;
|
uint8_t err;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 4; i++) { // HACK: Try multiple times as the command sometimes fails (unclear why)
|
for (uint32_t i = 0; i < 4; i++) { // HACK: Try multiple times as the command sometimes fails (unclear why)
|
||||||
|
@ -197,12 +140,27 @@ uint8_t rf_erase_flash(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SnfBrUpdateInit(void)
|
uint32_t SnfBrUpdateFirmware(uint8_t* data, unsigned int size) {
|
||||||
{
|
|
||||||
pinMode(PIN_C2CK, OUTPUT);
|
pinMode(PIN_C2CK, OUTPUT);
|
||||||
pinMode(PIN_C2D, INPUT);
|
pinMode(PIN_C2D, INPUT);
|
||||||
|
|
||||||
return rf_erase_flash(); // 10, 11
|
uint32_t error = rf_erase_flash(); // 10, 11
|
||||||
|
if (error) { return error; }
|
||||||
|
|
||||||
|
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("RFB: Erased"));
|
||||||
|
|
||||||
|
return rf_search_and_write(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnfBrFlash(uint32_t data, size_t size) {
|
||||||
|
// uint32_t* values = (uint32_t*)(0x40200000 + data);
|
||||||
|
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("RFB: Flash 0x%08X"), values[0]);
|
||||||
|
|
||||||
|
uint32_t error = SnfBrUpdateFirmware((uint8_t*)(0x40200000 + data), size); // Allow flash access without ESP.flashRead
|
||||||
|
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("RFB: FW flash state %d"), error);
|
||||||
|
|
||||||
|
TasmotaGlobal.restart_flag = 2; // Restart to re-init stopped services
|
||||||
}
|
}
|
||||||
#endif // USE_RF_FLASH
|
#endif // USE_RF_FLASH
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue