2019-10-20 19:12:05 +01:00
/*
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 < http : //www.gnu.org/licenses/>.
*/
# ifdef USE_ARDUINO_SLAVE
2019-10-21 11:25:22 +01:00
/*********************************************************************************************\
* Arduino slave
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-10-20 19:12:05 +01:00
2019-10-21 11:25:22 +01:00
# define XDRV_31 31
2019-10-20 19:12:05 +01:00
# 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
2019-10-21 11:25:22 +01:00
# include <TasmotaSerial.h>
# include <ArduinoHexParse.h>
2019-10-20 19:12:05 +01:00
2019-10-21 11:25:22 +01:00
struct ASLAVE {
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 ;
2019-10-20 19:12:05 +01:00
TasmotaSerial * ArduinoSlave_Serial ;
2019-10-21 11:25:22 +01:00
uint32_t ArduinoSlaveFlashStart ( void )
{
return ( ESP . getSketchSize ( ) / SPI_FLASH_SEC_SIZE ) + 2 ; // Stay on the safe side
}
2019-10-20 19:12:05 +01:00
uint8_t ArduinoSlave_UpdateInit ( void )
{
2019-10-21 11:25:22 +01:00
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 ;
2019-10-20 19:12:05 +01:00
return 0 ;
}
void ArduinoSlave_Reset ( void )
{
2019-10-21 11:25:22 +01:00
if ( ASlave . type ) {
digitalWrite ( pin [ GPIO_ARDUINO_RST ] , ! ASlave . inverted ) ;
2019-10-20 19:12:05 +01:00
delay ( 1 ) ;
2019-10-21 11:25:22 +01:00
digitalWrite ( pin [ GPIO_ARDUINO_RST ] , ASlave . inverted ) ;
2019-10-20 19:12:05 +01:00
delay ( 1 ) ;
2019-10-21 11:25:22 +01:00
digitalWrite ( pin [ GPIO_ARDUINO_RST ] , ! ASlave . inverted ) ;
2019-10-20 19:12:05 +01:00
delay ( 5 ) ;
}
}
2019-10-21 11:25:22 +01:00
uint8_t ArduinoSlave_waitForSerialData ( int dataCount , int timeout )
{
2019-10-20 19:12:05 +01:00
int timer = 0 ;
while ( timer < timeout ) {
if ( ArduinoSlave_Serial - > available ( ) > = dataCount ) {
return 1 ;
}
delay ( 1 ) ;
timer + + ;
}
return 0 ;
}
2019-10-21 11:25:22 +01:00
uint8_t ArduinoSlave_sendBytes ( uint8_t * bytes , int count )
{
2019-10-20 19:12:05 +01:00
ArduinoSlave_Serial - > write ( bytes , count ) ;
ArduinoSlave_waitForSerialData ( 2 , 1000 ) ;
2019-10-21 11:25:22 +01:00
uint8_t sync = ArduinoSlave_Serial - > read ( ) ;
uint8_t ok = ArduinoSlave_Serial - > read ( ) ;
2019-10-20 19:12:05 +01:00
if ( sync = = 0x14 & & ok = = 0x10 ) {
return 1 ;
}
return 0 ;
}
2019-10-21 11:25:22 +01:00
uint8_t ArduinoSlave_execCmd ( uint8_t cmd )
{
uint8_t bytes [ ] = { cmd , CONST_STK_CRC_EOP } ;
2019-10-20 19:12:05 +01:00
return ArduinoSlave_sendBytes ( bytes , 2 ) ;
}
2019-10-21 11:25:22 +01:00
uint8_t ArduinoSlave_execParam ( uint8_t cmd , uint8_t * params , int count )
{
uint8_t bytes [ 32 ] ;
2019-10-20 19:12:05 +01:00
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 )
{
2019-10-21 11:25:22 +01:00
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 } ;
2019-10-20 19:12:05 +01:00
ArduinoSlave_Serial - > begin ( USE_ARDUINO_FLASH_SPEED ) ;
2019-10-21 11:25:22 +01:00
if ( ArduinoSlave_Serial - > hardwareSerial ( ) ) {
2019-10-20 19:12:05 +01:00
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
}
2019-10-21 11:25:22 +01:00
uint8_t ArduinoSlave_loadAddress ( uint8_t adrHi , uint8_t adrLo )
{
uint8_t params [ ] = { adrHi , adrLo } ;
2019-10-20 19:12:05 +01:00
return ArduinoSlave_execParam ( CMND_STK_LOAD_ADDRESS , params , sizeof ( params ) ) ;
}
2019-10-21 11:25:22 +01:00
void ArduinoSlave_FlashPage ( uint8_t * address , uint8_t * data )
2019-10-20 19:12:05 +01:00
{
2019-10-21 11:25:22 +01:00
uint8_t Header [ ] = { CMND_STK_PROG_PAGE , 0x00 , 0x80 , 0x46 } ;
2019-10-20 19:12:05 +01:00
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 ] ;
2019-10-21 11:25:22 +01:00
uint32_t flash_start = ArduinoSlaveFlashStart ( ) * SPI_FLASH_SEC_SIZE ;
2019-10-20 19:12:05 +01:00
while ( reading ) {
2019-10-21 11:25:22 +01:00
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 ) {
2019-10-20 19:12:05 +01:00
reading = false ;
}
2019-10-21 11:25:22 +01:00
for ( uint32_t ca = 0 ; ca < SPI_FLASH_SEC_SIZE ; ca + + ) {
2019-10-20 19:12:05 +01:00
processed + + ;
2019-10-21 11:25:22 +01:00
if ( processed < = ASlave . spi_hex_size ) {
2019-10-20 19:12:05 +01:00
if ( ' : ' = = flash_buffer [ ca ] ) {
position = 0 ;
}
if ( 0x0D = = flash_buffer [ ca ] ) {
thishexline [ position ] = 0 ;
2019-10-21 11:25:22 +01:00
hexParse . ParseLine ( ( uint8_t * ) thishexline ) ;
2019-10-20 19:12:05 +01:00
if ( hexParse . IsFlashPageReady ( ) ) {
2019-10-21 11:25:22 +01:00
uint8_t * page = hexParse . GetFlashPage ( ) ;
uint8_t * address = hexParse . GetLoadAddress ( ) ;
2019-10-20 19:12:05 +01:00
ArduinoSlave_FlashPage ( address , page ) ;
}
} else {
if ( 0x0A ! = flash_buffer [ ca ] ) {
thishexline [ position ] = flash_buffer [ ca ] ;
position + + ;
}
}
}
}
}
2019-10-21 11:25:22 +01:00
ASlave . flashing = false ;
2019-10-20 19:12:05 +01:00
ArduinoSlave_exitProgMode ( ) ;
restart_flag = 2 ;
}
void ArduinoSlave_SetFlagFlashing ( bool value )
{
2019-10-21 11:25:22 +01:00
ASlave . flashing = value ;
2019-10-20 19:12:05 +01:00
}
bool ArduinoSlave_GetFlagFlashing ( void )
{
2019-10-21 11:25:22 +01:00
return ASlave . flashing ;
2019-10-20 19:12:05 +01:00
}
void ArduinoSlave_WriteBuffer ( uint8_t * buf , size_t size )
{
2019-10-21 11:25:22 +01:00
if ( 0 = = ASlave . spi_sector_cursor ) { // Starting a new sector write so we need to erase it first
ESP . flashEraseSector ( ASlave . spi_sector_counter ) ;
2019-10-20 19:12:05 +01:00
}
2019-10-21 11:25:22 +01:00
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 + + ;
2019-10-20 19:12:05 +01:00
}
}
void ArduinoSlave_Init ( void )
{
2019-10-21 11:25:22 +01:00
if ( ASlave . type ) {
2019-10-20 19:12:05 +01:00
return ;
}
2019-10-21 11:25:22 +01:00
if ( ( pin [ GPIO_ARDUINO_RXD ] < 99 ) & & ( pin [ GPIO_ARDUINO_TXD ] < 99 ) & &
( ( pin [ GPIO_ARDUINO_RST ] < 99 ) | | ( pin [ GPIO_ARDUINO_RST_INV ] < 99 ) ) ) {
2019-10-20 19:12:05 +01:00
ArduinoSlave_Serial = new TasmotaSerial ( pin [ GPIO_ARDUINO_RXD ] , pin [ GPIO_ARDUINO_TXD ] , 1 , 0 , 200 ) ;
if ( ArduinoSlave_Serial - > begin ( USE_ARDUINO_SERIAL_SPEED ) ) {
2019-10-21 11:25:22 +01:00
if ( ArduinoSlave_Serial - > hardwareSerial ( ) ) {
2019-10-20 19:12:05 +01:00
ClaimSerial ( ) ;
}
2019-10-21 11:25:22 +01:00
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 ;
2019-10-20 19:12:05 +01:00
ArduinoSlave_Reset ( ) ;
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( " Arduino Slave Enabled " ) ) ;
}
}
}
void ArduinoSlave_Show ( bool json )
{
2019-10-21 11:25:22 +01:00
if ( ASlave . type ) {
2019-10-20 19:12:05 +01:00
ArduinoSlave_Serial - > flush ( ) ;
ArduinoSlave_Serial - > print ( " JSON " ) ;
ArduinoSlave_Serial - > find ( char ( 0xFE ) ) ;
2019-10-21 11:25:22 +01:00
char buffer [ 100 ] ;
2019-10-20 19:12:05 +01:00
uint16_t haveread = ArduinoSlave_Serial - > readBytesUntil ( char ( 0xFF ) , buffer , sizeof ( buffer ) - 1 ) ;
buffer [ haveread ] = ' \0 ' ;
if ( json ) {
ResponseAppend_P ( PSTR ( " , \" ArduinoSlave \" :%s " ) , buffer ) ;
}
}
}
2019-10-21 11:25:22 +01:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-10-20 19:12:05 +01:00
bool Xdrv31 ( uint8_t function )
{
bool result = false ;
2019-10-21 11:25:22 +01:00
2019-10-20 19:12:05 +01:00
switch ( function ) {
case FUNC_EVERY_SECOND :
ArduinoSlave_Init ( ) ;
break ;
case FUNC_JSON_APPEND :
ArduinoSlave_Show ( 1 ) ;
break ;
}
2019-10-21 11:25:22 +01:00
return result ;
2019-10-20 19:12:05 +01:00
}
2019-10-21 11:25:22 +01:00
# endif // USE_ARDUINO_SLAVE