From 8c5934890e8019372ff1406fac270bec97f85bbf Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 26 Oct 2019 22:58:04 +0200 Subject: [PATCH] ArduinoSlave->TasmotaSlave --- sonoff/sonoff_template.h | 18 +- sonoff/xdrv_01_webserver.ino | 30 +-- sonoff/xdrv_31_arduino_slave.ino | 412 ++++++++++++++++++++++--------- 3 files changed, 324 insertions(+), 136 deletions(-) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index f85543cd0..51cd2d0fd 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -208,10 +208,9 @@ enum UserSelectablePins { GPIO_SM2135_DAT, // SM2135 Dat GPIO_DEEPSLEEP, // Kill switch for deepsleep GPIO_EXS_ENABLE, // EXS MCU Enable - GPIO_ARDUINO_TXD, // Arduino Slave TX - GPIO_ARDUINO_RXD, // Arduino Slave RX - GPIO_ARDUINO_RST, // Arduino Reset Pin - GPIO_ARDUINO_RST_INV, // Arduino Reset Pin inverted + GPIO_TASMOTASLAVE_TXD, // Arduino Slave TX + GPIO_TASMOTASLAVE_RXD, // Arduino Slave RX + GPIO_TASMOTASLAVE_RST, // Arduino Reset Pin GPIO_SENSOR_END }; // Programmer selectable GPIO functionality @@ -290,7 +289,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|" D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|" D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|" - D_SENSOR_ARDUINO_TX "|" D_SENSOR_ARDUINO_RX "|" D_SENSOR_ARDUINO_RESET "|" D_SENSOR_ARDUINO_RESET "i|" + D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -703,11 +702,10 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_PN532_TXD, // PN532 HSU Tx GPIO_PN532_RXD, // PN532 HSU Rx #endif -#ifdef USE_ARDUINO_SLAVE - GPIO_ARDUINO_TXD, // Arduino Slave TX - GPIO_ARDUINO_RXD, // Arduino Slave RX - GPIO_ARDUINO_RST, // Arduino Reset Pin - GPIO_ARDUINO_RST_INV, // Arduino Reset Pin inverted +#ifdef USE_TASMOTA_SLAVE + GPIO_TASMOTASLAVE_TXD, // Tasmota Slave TX + GPIO_TASMOTASLAVE_RXD, // Tasmota Slave RX + GPIO_TASMOTASLAVE_RST, // Tasmota Reset Pin #endif #ifdef USE_RDM6300 GPIO_RDM6300_RX, diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index 40b3bab83..17622e920 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -44,7 +44,7 @@ const uint16_t HTTP_REFRESH_TIME = 2345; // milliseconds uint8_t *efm8bb1_update = nullptr; #endif // USE_RF_FLASH -enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_ARDUINOSLAVE }; +enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTASLAVE }; static const char * HEADER_KEYS[] = { "User-Agent", }; @@ -2037,8 +2037,8 @@ void HandleUploadDone(void) WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS)); WSContentSend_P(HTTP_MSG_RSTRT); ShowWebSource(SRC_WEBGUI); -#ifdef USE_ARDUINO_SLAVE - if (ArduinoSlave_GetFlagFlashing()) { +#ifdef USE_TASMOTA_SLAVE + if (TasmotaSlave_GetFlagFlashing()) { restart_flag = 0; } else { // It was a normal firmware file, or we are ready to restart device restart_flag = 2; @@ -2051,9 +2051,9 @@ void HandleUploadDone(void) WSContentSend_P(PSTR("
")); WSContentSpaceButton(BUTTON_MAIN); WSContentStop(); -#ifdef USE_ARDUINO_SLAVE - if (ArduinoSlave_GetFlagFlashing()) { - ArduinoSlave_Flash(); +#ifdef USE_TASMOTA_SLAVE + if (TasmotaSlave_GetFlagFlashing()) { + TasmotaSlave_Flash(); } #endif } @@ -2121,11 +2121,11 @@ void HandleUploadLoop(void) if (Web.upload_error != 0) { return; } } else #endif // USE_RF_FLASH -#ifdef USE_ARDUINO_SLAVE +#ifdef USE_TASMOTA_SLAVE if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a ARDUINO SLAVE hex file Update.end(); // End esp8266 update session - Web.upload_file_type = UPL_ARDUINOSLAVE; - Web.upload_error = ArduinoSlave_UpdateInit(); + Web.upload_file_type = UPL_TASMOTASLAVE; + Web.upload_error = TasmotaSlave_UpdateInit(); if (Web.upload_error != 0) { return; } } else #endif @@ -2187,9 +2187,9 @@ void HandleUploadLoop(void) } } #endif // USE_RF_FLASH -#ifdef USE_ARDUINO_SLAVE - else if (UPL_ARDUINOSLAVE == Web.upload_file_type) { - ArduinoSlave_WriteBuffer(upload.buf, upload.currentSize); +#ifdef USE_TASMOTA_SLAVE + else if (UPL_TASMOTASLAVE == Web.upload_file_type) { + TasmotaSlave_WriteBuffer(upload.buf, upload.currentSize); } #endif else { // firmware @@ -2243,10 +2243,10 @@ void HandleUploadLoop(void) Web.upload_file_type = UPL_TASMOTA; } #endif // USE_RF_FLASH -#ifdef USE_ARDUINO_SLAVE - else if (UPL_ARDUINOSLAVE == Web.upload_file_type) { +#ifdef USE_TASMOTA_SLAVE + else if (UPL_TASMOTASLAVE == Web.upload_file_type) { // Done writing the hex to SPI flash - ArduinoSlave_SetFlagFlashing(true); // So we know on upload success page if it needs to flash hex or do a normal restart + TasmotaSlave_SetFlagFlashing(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 diff --git a/sonoff/xdrv_31_arduino_slave.ino b/sonoff/xdrv_31_arduino_slave.ino index 497ab28dd..dff94182b 100644 --- a/sonoff/xdrv_31_arduino_slave.ino +++ b/sonoff/xdrv_31_arduino_slave.ino @@ -1,5 +1,5 @@ /* - xdrv_31_arduino_slave.ino - Support for Arduino Slave on Serial + xdrv_31_tasmota_slave.ino - Support for external microcontroller slave on serial Copyright (C) 2019 Andre Thomas and Theo Arends @@ -17,9 +17,9 @@ along with this program. If not, see . */ -#ifdef USE_ARDUINO_SLAVE +#ifdef USE_TASMOTA_SLAVE /*********************************************************************************************\ - * Arduino slave + * Tasmota slave \*********************************************************************************************/ #define XDRV_31 31 @@ -34,50 +34,182 @@ #define CMND_STK_LOAD_ADDRESS 0x55 #define CMND_STK_PROG_PAGE 0x64 -#include -#include +/*************************************************\ + * Tasmota Slave Specific Commands +\*************************************************/ -struct ASLAVE { +#define CMND_START 0xFC +#define CMND_END 0xFD + +#define CMND_FEATURES 0x01 +#define CMND_JSON 0x02 + +#define PARAM_DATA_START 0xFE +#define PARAM_DATA_END 0xFF + + +#include + +/* + * Embedding class in here since its rather specific to Arduino bootloader + */ + +class SimpleHexParse { + public: + SimpleHexParse(void); + uint8_t parseLine(char *hexline); + uint8_t ptr_l = 0; + uint8_t ptr_h = 0; + bool PageIsReady = false; + bool firstrun = true; + bool EndOfFile = false; + uint8_t FlashPage[128]; + uint8_t FlashPageIdx = 0; + uint8_t layoverBuffer[16]; + uint8_t layoverIdx = 0; + uint8_t getByte(char *hexline, uint8_t idx); +}; + +SimpleHexParse::SimpleHexParse(void) +{ + +} + +uint8_t SimpleHexParse::parseLine(char *hexline) +{ + if (layoverIdx) { + memcpy(&FlashPage[0], &layoverBuffer[0], layoverIdx); + FlashPageIdx = layoverIdx; + layoverIdx = 0; + } + uint8_t len = getByte(hexline, 1); + uint8_t addr_h = getByte(hexline, 2); + uint8_t addr_l = getByte(hexline, 3); + uint8_t rectype = getByte(hexline, 4); + for (uint8_t idx = 0; idx < len; idx++) { + if (FlashPageIdx < 128) { + FlashPage[FlashPageIdx] = getByte(hexline, idx+5); + FlashPageIdx++; + } else { // We have layover bytes + layoverBuffer[layoverIdx] = getByte(hexline, idx+5); + layoverIdx++; + } + } + if (1 == rectype) { + EndOfFile = true; + while (FlashPageIdx < 128) { + FlashPage[FlashPageIdx] = 0xFF; + FlashPageIdx++; + } + } + if (FlashPageIdx == 128) { + if (firstrun) { + firstrun = false; + } else { + ptr_l += 0x40; + if (ptr_l == 0) { + ptr_l = 0; + ptr_h++; + } + } + firstrun = false; + PageIsReady = true; + } + return 0; +} + +uint8_t SimpleHexParse::getByte(char* hexline, uint8_t idx) +{ + char buff[3]; + buff[3] = '\0'; + memcpy(&buff, &hexline[(idx*2)-1], 2); + return strtol(buff, 0, 16); +} + +/* + * End of embedded class SimpleHexParse + */ + +struct TSLAVE { uint32_t spi_hex_size = 0; uint32_t spi_sector_counter = 0; uint8_t spi_sector_cursor = 0; - uint8_t inverted = LOW; bool type = false; bool flashing = false; -} ASlave; + bool SerialEnabled = false; + uint8_t waitstate = 0; // We use this so that features detection does not slow down other stuff on startup +} TSlave; -TasmotaSerial *ArduinoSlave_Serial; +typedef union { + uint16_t data; + struct { + uint16_t json : 1; + uint16_t spare1 : 1; + uint16_t spare2 : 1; + uint16_t spare3 : 1; + uint16_t spare4 : 1; + uint16_t spare5 : 1; + uint16_t spare6 : 1; + uint16_t spare7 : 1; + uint16_t spare8 : 1; + uint16_t spare9 : 1; + uint16_t spare10 : 1; + uint16_t spare11 : 1; + uint16_t spare12 : 1; + uint16_t spare13 : 1; + uint16_t spare14 : 1; + uint16_t spare15 : 1; + }; +} TSlaveFeatureCfg; -uint32_t ArduinoSlaveFlashStart(void) +/* + * The structure below must remain 4 byte aligned to be compatible with + * Tasmota as master + */ + +struct FEATURES { + uint32_t features_version; + TSlaveFeatureCfg features; + uint16_t spare4; +} TSlaveSettings; + +struct COMMAND { + uint8_t command; + uint8_t parameter; + uint8_t unused2; + uint8_t unused3; +} Command; + +TasmotaSerial *TasmotaSlave_Serial; + +uint32_t TasmotaSlave_FlashStart(void) { return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side } -uint8_t ArduinoSlave_UpdateInit(void) +uint8_t TasmotaSlave_UpdateInit(void) { - ASlave.spi_hex_size = 0; - ASlave.spi_sector_counter = ArduinoSlaveFlashStart(); // Reset the pre-defined write address where firmware will temporarily be stored - ASlave.spi_sector_cursor = 0; + TSlave.spi_hex_size = 0; + TSlave.spi_sector_counter = TasmotaSlave_FlashStart(); // Reset the pre-defined write address where firmware will temporarily be stored + TSlave.spi_sector_cursor = 0; return 0; } -void ArduinoSlave_Reset(void) +void TasmotaSlave_Reset(void) { - if (ASlave.type) { - digitalWrite(pin[GPIO_ARDUINO_RST], !ASlave.inverted); + if (TSlave.SerialEnabled) { + digitalWrite(pin[GPIO_TASMOTASLAVE_RST], LOW); delay(1); - digitalWrite(pin[GPIO_ARDUINO_RST], ASlave.inverted); - delay(1); - digitalWrite(pin[GPIO_ARDUINO_RST], !ASlave.inverted); + digitalWrite(pin[GPIO_TASMOTASLAVE_RST], HIGH); delay(5); } } -uint8_t ArduinoSlave_waitForSerialData(int dataCount, int timeout) +uint8_t TasmotaSlave_waitForSerialData(int dataCount, int timeout) { int timer = 0; while (timer < timeout) { - if (ArduinoSlave_Serial->available() >= dataCount) { + if (TasmotaSlave_Serial->available() >= dataCount) { return 1; } delay(1); @@ -86,25 +218,25 @@ uint8_t ArduinoSlave_waitForSerialData(int dataCount, int timeout) return 0; } -uint8_t ArduinoSlave_sendBytes(uint8_t* bytes, int count) +uint8_t TasmotaSlave_sendBytes(uint8_t* bytes, int count) { - ArduinoSlave_Serial->write(bytes, count); - ArduinoSlave_waitForSerialData(2, 1000); - uint8_t sync = ArduinoSlave_Serial->read(); - uint8_t ok = ArduinoSlave_Serial->read(); - if (sync == 0x14 && ok == 0x10) { + TasmotaSlave_Serial->write(bytes, count); + TasmotaSlave_waitForSerialData(2, 1000); + uint8_t sync = TasmotaSlave_Serial->read(); + uint8_t ok = TasmotaSlave_Serial->read(); + if ((sync == 0x14) && (ok == 0x10)) { return 1; } return 0; } -uint8_t ArduinoSlave_execCmd(uint8_t cmd) +uint8_t TasmotaSlave_execCmd(uint8_t cmd) { uint8_t bytes[] = { cmd, CONST_STK_CRC_EOP }; - return ArduinoSlave_sendBytes(bytes, 2); + return TasmotaSlave_sendBytes(bytes, 2); } -uint8_t ArduinoSlave_execParam(uint8_t cmd, uint8_t* params, int count) +uint8_t TasmotaSlave_execParam(uint8_t cmd, uint8_t* params, int count) { uint8_t bytes[32]; bytes[0] = cmd; @@ -114,50 +246,87 @@ uint8_t ArduinoSlave_execParam(uint8_t cmd, uint8_t* params, int count) i++; } bytes[i + 1] = CONST_STK_CRC_EOP; - return ArduinoSlave_sendBytes(bytes, i + 2); + return TasmotaSlave_sendBytes(bytes, i + 2); } -uint8_t ArduinoSlave_exitProgMode(void) +uint8_t TasmotaSlave_exitProgMode(void) { - return ArduinoSlave_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode + return TasmotaSlave_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode } -void ArduinoSlave_SetupFlash(void) +void TasmotaSlave_SetupFlash(void) { - uint8_t ProgParams[] = {0x86,0x00,0x00,0x01,0x01,0x01,0x01,0x03,0xff,0xff,0xff,0xff,0x00,0x80,0x04,0x00,0x00,0x00,0x80,0x00}; - uint8_t ExtProgParams[] = {0x05,0x04,0xd7,0xc2,0x00}; - ArduinoSlave_Serial->begin(USE_ARDUINO_FLASH_SPEED); - if (ArduinoSlave_Serial->hardwareSerial()) { + uint8_t ProgParams[] = {0x86, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00}; + uint8_t ExtProgParams[] = {0x05, 0x04, 0xd7, 0xc2, 0x00}; + TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_FLASH_SPEED); + if (TasmotaSlave_Serial->hardwareSerial()) { ClaimSerial(); } - ArduinoSlave_Reset(); - ArduinoSlave_execCmd(CMND_STK_GET_SYNC); - ArduinoSlave_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams)); // Set programming parameters - ArduinoSlave_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams)); // Set extended programming parameters - ArduinoSlave_execCmd(CMND_STK_ENTER_PROGMODE); // Enter programming mode + TasmotaSlave_Reset(); + + uint8_t timer = 0; + bool no_error = false; + while (200 > timer) { + if (TasmotaSlave_execCmd(CMND_STK_GET_SYNC)) { + timer = 200; + no_error = true; + } + delay(1); + } + + if (no_error) { + AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Found bootloader")); + } else { + AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Bootloader could not be found")); + } + + if (no_error) { + if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams))) { + } else { + no_error = true; + AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (1)")); + } + } + + if (no_error) { + if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams))) { + } else { + no_error = true; + AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (2)")); + } + } + + if (no_error) { + if (TasmotaSlave_execCmd(CMND_STK_ENTER_PROGMODE)) { + } else { + no_error = true; + AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Failed to put bootloader into programming mode")); + } + } + } -uint8_t ArduinoSlave_loadAddress(uint8_t adrHi, uint8_t adrLo) +uint8_t TasmotaSlave_loadAddress(uint8_t adrHi, uint8_t adrLo) { - uint8_t params[] = { adrHi, adrLo }; - return ArduinoSlave_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params)); + uint8_t params[] = { adrLo, adrHi }; + return TasmotaSlave_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params)); } -void ArduinoSlave_FlashPage(uint8_t* address, uint8_t* data) +void TasmotaSlave_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data) { uint8_t Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46}; - ArduinoSlave_loadAddress(address[1], address[0]); - ArduinoSlave_Serial->write(Header, 4); + TasmotaSlave_loadAddress(addr_h, addr_l); + TasmotaSlave_Serial->write(Header, 4); for (int i = 0; i < 128; i++) { - ArduinoSlave_Serial->write(data[i]); + TasmotaSlave_Serial->write(data[i]); } - ArduinoSlave_Serial->write(CONST_STK_CRC_EOP); - ArduinoSlave_waitForSerialData(2, 1000); - ArduinoSlave_Serial->read(); - ArduinoSlave_Serial->read(); + TasmotaSlave_Serial->write(CONST_STK_CRC_EOP); + TasmotaSlave_waitForSerialData(2, 1000); + TasmotaSlave_Serial->read(); + TasmotaSlave_Serial->read(); } -void ArduinoSlave_Flash(void) +void TasmotaSlave_Flash(void) { bool reading = true; uint32_t read = 0; @@ -165,31 +334,31 @@ void ArduinoSlave_Flash(void) char thishexline[50]; uint8_t position = 0; char* flash_buffer; - ArduinoHexParse hexParse = ArduinoHexParse(); + SimpleHexParse hexParse = SimpleHexParse(); - ArduinoSlave_SetupFlash(); + TasmotaSlave_SetupFlash(); flash_buffer = new char[SPI_FLASH_SEC_SIZE]; - uint32_t flash_start = ArduinoSlaveFlashStart() * SPI_FLASH_SEC_SIZE; + uint32_t flash_start = TasmotaSlave_FlashStart() * SPI_FLASH_SEC_SIZE; while (reading) { ESP.flashRead(flash_start + read, (uint32_t*)flash_buffer, SPI_FLASH_SEC_SIZE); read = read + SPI_FLASH_SEC_SIZE; - if (read >= ASlave.spi_hex_size) { + if (read >= TSlave.spi_hex_size) { reading = false; } for (uint32_t ca = 0; ca < SPI_FLASH_SEC_SIZE; ca++) { processed++; - if (processed <= ASlave.spi_hex_size) { + if ((processed <= TSlave.spi_hex_size) && (!hexParse.EndOfFile)) { if (':' == flash_buffer[ca]) { position = 0; } if (0x0D == flash_buffer[ca]) { thishexline[position] = 0; - hexParse.ParseLine((uint8_t*)thishexline); - if (hexParse.IsFlashPageReady()) { - uint8_t* page = hexParse.GetFlashPage(); - uint8_t* address = hexParse.GetLoadAddress(); - ArduinoSlave_FlashPage(address, page); + hexParse.parseLine(thishexline); + if (hexParse.PageIsReady) { + TasmotaSlave_FlashPage(hexParse.ptr_h, hexParse.ptr_l, hexParse.FlashPage); + hexParse.PageIsReady = false; + hexParse.FlashPageIdx = 0; } } else { if (0x0A != flash_buffer[ca]) { @@ -200,72 +369,93 @@ void ArduinoSlave_Flash(void) } } } - ASlave.flashing = false; - ArduinoSlave_exitProgMode(); + TasmotaSlave_exitProgMode(); + TSlave.flashing = false; restart_flag = 2; } -void ArduinoSlave_SetFlagFlashing(bool value) +void TasmotaSlave_SetFlagFlashing(bool value) { - ASlave.flashing = value; + TSlave.flashing = value; } -bool ArduinoSlave_GetFlagFlashing(void) +bool TasmotaSlave_GetFlagFlashing(void) { - return ASlave.flashing ; + return TSlave.flashing; } -void ArduinoSlave_WriteBuffer(uint8_t *buf, size_t size) +void TasmotaSlave_WriteBuffer(uint8_t *buf, size_t size) { - if (0 == ASlave.spi_sector_cursor) { // Starting a new sector write so we need to erase it first - ESP.flashEraseSector(ASlave.spi_sector_counter); + if (0 == TSlave.spi_sector_cursor) { // Starting a new sector write so we need to erase it first + ESP.flashEraseSector(TSlave.spi_sector_counter); } - ASlave.spi_sector_cursor++; - ESP.flashWrite((ASlave.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((ASlave.spi_sector_cursor-1)*2048), (uint32_t*)buf, size); - ASlave.spi_hex_size = ASlave.spi_hex_size + size; - if (2 == ASlave.spi_sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase - ASlave.spi_sector_cursor = 0; - ASlave.spi_sector_counter++; + TSlave.spi_sector_cursor++; + ESP.flashWrite((TSlave.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((TSlave.spi_sector_cursor-1)*2048), (uint32_t*)buf, size); + TSlave.spi_hex_size = TSlave.spi_hex_size + size; + if (2 == TSlave.spi_sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase + TSlave.spi_sector_cursor = 0; + TSlave.spi_sector_counter++; } } -void ArduinoSlave_Init(void) +void TasmotaSlave_Init(void) { - if (ASlave.type) { + if (TSlave.type) { return; } - if ((pin[GPIO_ARDUINO_RXD] < 99) && (pin[GPIO_ARDUINO_TXD] < 99) && - ((pin[GPIO_ARDUINO_RST] < 99) || (pin[GPIO_ARDUINO_RST_INV] < 99))) { - ArduinoSlave_Serial = new TasmotaSerial(pin[GPIO_ARDUINO_RXD], pin[GPIO_ARDUINO_TXD], 1, 0, 200); - if (ArduinoSlave_Serial->begin(USE_ARDUINO_SERIAL_SPEED)) { - if (ArduinoSlave_Serial->hardwareSerial()) { - ClaimSerial(); + if (10 > TSlave.waitstate) { + TSlave.waitstate++; + return; + } + if (!TSlave.SerialEnabled) { + if ((pin[GPIO_TASMOTASLAVE_RXD] < 99) && (pin[GPIO_TASMOTASLAVE_TXD] < 99) && (pin[GPIO_TASMOTASLAVE_RST] < 99)) { + TasmotaSlave_Serial = new TasmotaSerial(pin[GPIO_TASMOTASLAVE_RXD], pin[GPIO_TASMOTASLAVE_TXD], 1, 0, 200); + if (TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_SERIAL_SPEED)) { + if (TasmotaSlave_Serial->hardwareSerial()) { + ClaimSerial(); + } + pinMode(pin[GPIO_TASMOTASLAVE_RST], OUTPUT); + TasmotaSlave_Reset(); + TSlave.SerialEnabled = true; + AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Enabled")); } - if (pin[GPIO_ARDUINO_RST_INV] < 99) { - pin[GPIO_ARDUINO_RST] = pin[GPIO_ARDUINO_RST_INV]; - pin[GPIO_ARDUINO_RST_INV] = 99; - ASlave.inverted = HIGH; - } - pinMode(pin[GPIO_ARDUINO_RST], OUTPUT); - ASlave.type = true; - ArduinoSlave_Reset(); - AddLog_P2(LOG_LEVEL_INFO, PSTR("Arduino Slave Enabled")); + } + } + if (TSlave.SerialEnabled) { // All go for hardware now we need to detect features if there are any + TasmotaSlave_sendCmnd(CMND_FEATURES, 0); + char buffer[32]; + TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)); + uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)); + memcpy(&TSlaveSettings, &buffer, sizeof(TSlaveSettings)); + if (20191026 <= TSlaveSettings.features_version) { + TSlave.type = true; + AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u"), TSlaveSettings.features_version); } } } -void ArduinoSlave_Show(bool json) +void TasmotaSlave_Show(void) { - if (ASlave.type) { - ArduinoSlave_Serial->flush(); - ArduinoSlave_Serial->print("JSON"); - ArduinoSlave_Serial->find(char(0xFE)); + if ((TSlave.type) && (TSlaveSettings.features.json)) { char buffer[100]; - uint16_t haveread = ArduinoSlave_Serial->readBytesUntil(char(0xFF), buffer, sizeof(buffer)-1); - buffer[haveread] = '\0'; - if (json) { - ResponseAppend_P(PSTR(",\"ArduinoSlave\":%s"), buffer); - } + TasmotaSlave_sendCmnd(CMND_JSON, 0); + TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)-1); + uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)-1); + buffer[len] = '\0'; + ResponseAppend_P(PSTR(",\"TasmotaSlave\":%s"), buffer); + } +} + +void TasmotaSlave_sendCmnd(uint8_t cmnd, uint8_t param) +{ + Command.command = cmnd; + Command.parameter = param; + char buffer[sizeof(Command)+2]; + buffer[0] = CMND_START; + memcpy(&buffer[1], &Command, sizeof(Command)); + buffer[sizeof(Command)+1] = CMND_END; + for (uint8_t ca = 0; ca < sizeof(buffer); ca++) { + TasmotaSlave_Serial->write(buffer[ca]); } } @@ -279,13 +469,13 @@ bool Xdrv31(uint8_t function) switch (function) { case FUNC_EVERY_SECOND: - ArduinoSlave_Init(); + TasmotaSlave_Init(); break; case FUNC_JSON_APPEND: - ArduinoSlave_Show(1); + TasmotaSlave_Show(); break; } return result; } -#endif // USE_ARDUINO_SLAVE \ No newline at end of file +#endif // USE_TASMOTA_SLAVE \ No newline at end of file