diff --git a/sonoff/xdrv_31_arduino_slave.ino b/sonoff/xdrv_31_arduino_slave.ino new file mode 100644 index 000000000..09e434126 --- /dev/null +++ b/sonoff/xdrv_31_arduino_slave.ino @@ -0,0 +1,277 @@ +/* + xdrv_31_arduino_slave.ino - Support for Arduino Slave on Serial + + Copyright (C) 2019 Andre Thomas and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_ARDUINO_SLAVE + +#include +#include + +#define CONST_STK_CRC_EOP 0x20 + +#define CMND_STK_GET_SYNC 0x30 +#define CMND_STK_SET_DEVICE 0x42 +#define CMND_STK_SET_DEVICE_EXT 0x45 +#define CMND_STK_ENTER_PROGMODE 0x50 +#define CMND_STK_LEAVE_PROGMODE 0x51 +#define CMND_STK_LOAD_ADDRESS 0x55 +#define CMND_STK_PROG_PAGE 0x64 + +uint32_t as_spi_hex_size = 0; +uint8_t as_spi_sector_start = 0x96; +uint8_t as_spi_sector_counter = 0x96; +uint8_t as_spi_sector_cursor = 0; +bool as_flashing = false; + +uint8_t as_type = 0; + +TasmotaSerial *ArduinoSlave_Serial; + +#define XDRV_31 31 + +uint8_t ArduinoSlave_UpdateInit(void) +{ + as_spi_hex_size = 0; + as_spi_sector_counter = as_spi_sector_start; // Reset the pre-defined write address where firmware will temporarily be stored + as_spi_sector_cursor = 0; + return 0; +} + +void ArduinoSlave_Reset(void) +{ + if (as_type) { +#ifdef USE_ARDUINO_INVERT_RESET + digitalWrite(pin[GPIO_ARDUINO_RESET], LOW); + delay(1); + digitalWrite(pin[GPIO_ARDUINO_RESET], HIGH); + delay(1); + digitalWrite(pin[GPIO_ARDUINO_RESET], LOW); + delay(5); +#else + digitalWrite(pin[GPIO_ARDUINO_RESET], HIGH); + delay(1); + digitalWrite(pin[GPIO_ARDUINO_RESET], LOW); + delay(1); + digitalWrite(pin[GPIO_ARDUINO_RESET], HIGH); + delay(5); +#endif + } +} + +uint8_t ArduinoSlave_waitForSerialData(int dataCount, int timeout) { + int timer = 0; + while (timer < timeout) { + if (ArduinoSlave_Serial->available() >= dataCount) { + return 1; + } + delay(1); + timer++; + } + return 0; +} + +byte ArduinoSlave_sendBytes(byte* bytes, int count) { + ArduinoSlave_Serial->write(bytes, count); + ArduinoSlave_waitForSerialData(2, 1000); + byte sync = ArduinoSlave_Serial->read(); + byte ok = ArduinoSlave_Serial->read(); + if (sync == 0x14 && ok == 0x10) { + return 1; + } + return 0; +} + +byte ArduinoSlave_execCmd(byte cmd) { + byte bytes[] = { cmd, CONST_STK_CRC_EOP }; + return ArduinoSlave_sendBytes(bytes, 2); +} + +byte ArduinoSlave_execParam(byte cmd, byte* params, int count) { + byte bytes[32]; + bytes[0] = cmd; + int i = 0; + while (i < count) { + bytes[i + 1] = params[i]; + i++; + } + bytes[i + 1] = CONST_STK_CRC_EOP; + return ArduinoSlave_sendBytes(bytes, i + 2); +} + +uint8_t ArduinoSlave_exitProgMode(void) +{ + return ArduinoSlave_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode +} + +void ArduinoSlave_SetupFlash(void) +{ + byte ProgParams[] = {0x86,0x00,0x00,0x01,0x01,0x01,0x01,0x03,0xff,0xff,0xff,0xff,0x00,0x80,0x04,0x00,0x00,0x00,0x80,0x00}; + byte ExtProgParams[] = {0x05,0x04,0xd7,0xc2,0x00}; + ArduinoSlave_Serial->begin(USE_ARDUINO_FLASH_SPEED); + if (ArduinoSlave_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 +} + +uint8_t ArduinoSlave_loadAddress(byte adrHi, byte adrLo) { + byte params[] = { adrHi, adrLo }; + return ArduinoSlave_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params)); +} + +void ArduinoSlave_FlashPage(byte* address, byte* data) +{ + byte Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46}; + ArduinoSlave_loadAddress(address[1], address[0]); + ArduinoSlave_Serial->write(Header, 4); + for (int i = 0; i < 128; i++) { + ArduinoSlave_Serial->write(data[i]); + } + ArduinoSlave_Serial->write(CONST_STK_CRC_EOP); + ArduinoSlave_waitForSerialData(2, 1000); + ArduinoSlave_Serial->read(); + ArduinoSlave_Serial->read(); +} + +void ArduinoSlave_Flash(void) +{ + bool reading = true; + uint32_t read = 0; + uint32_t processed = 0; + char thishexline[50]; + uint8_t position = 0; + char* flash_buffer; + ArduinoHexParse hexParse = ArduinoHexParse(); + + ArduinoSlave_SetupFlash(); + + flash_buffer = new char[SPI_FLASH_SEC_SIZE]; + while (reading) { + ESP.flashRead(0x96000 + read, (uint32_t*)flash_buffer, FLASH_SECTOR_SIZE); + read = read + FLASH_SECTOR_SIZE; + if (read >= as_spi_hex_size) { + reading = false; + } + for (uint16_t ca=0; cabegin(USE_ARDUINO_SERIAL_SPEED)) { + if (ArduinoSlave_Serial->hardwareSerial()) { + ClaimSerial(); + } + pinMode(pin[GPIO_ARDUINO_RESET], OUTPUT); + as_type = 1; + ArduinoSlave_Reset(); + AddLog_P2(LOG_LEVEL_INFO, PSTR("Arduino Slave Enabled")); + } + } +} + +void ArduinoSlave_Show(bool json) +{ + if (as_type) { + char buffer[100]; + ArduinoSlave_Serial->flush(); + ArduinoSlave_Serial->print("JSON"); + ArduinoSlave_Serial->find(char(0xFE)); + uint16_t haveread = ArduinoSlave_Serial->readBytesUntil(char(0xFF), buffer, sizeof(buffer)-1); + buffer[haveread] = '\0'; + if (json) { + ResponseAppend_P(PSTR(",\"ArduinoSlave\":%s"), buffer); + } + } +} + +bool Xdrv31(uint8_t function) +{ + bool result = false; + switch (function) { + case FUNC_EVERY_SECOND: + ArduinoSlave_Init(); + break; + case FUNC_JSON_APPEND: + ArduinoSlave_Show(1); + break; + case FUNC_COMMAND_DRIVER: + break; + default: + break; + } +} + +#endif // USE_ARDUINO_SLAVE \ No newline at end of file