2020-03-31 02:38:08 +02:00
# include "wled.h"
/*
2020-05-22 23:30:55 +02:00
* Adalight and TPM2 handler
2020-03-31 02:38:08 +02:00
*/
enum class AdaState {
Header_A ,
Header_d ,
Header_a ,
Header_CountHi ,
Header_CountLo ,
Header_CountCheck ,
Data_Red ,
Data_Green ,
2020-05-22 23:30:55 +02:00
Data_Blue ,
TPM2_Header_Type ,
TPM2_Header_CountHi ,
2021-11-16 23:20:26 +01:00
TPM2_Header_CountLo ,
2020-03-31 02:38:08 +02:00
} ;
2022-02-01 18:21:30 +01:00
uint16_t currentBaud = 1152 ; //default baudrate 115200 (divided by 100)
2022-09-26 10:08:31 +02:00
bool continuousSendLED = false ;
uint32_t lastUpdate = 0 ;
2022-02-01 18:21:30 +01:00
2022-02-01 20:02:46 +01:00
void updateBaudRate ( uint32_t rate ) {
2022-02-01 18:21:30 +01:00
uint16_t rate100 = rate / 100 ;
2022-02-01 20:02:46 +01:00
if ( rate100 = = currentBaud | | rate100 < 96 ) return ;
2022-02-01 18:21:30 +01:00
currentBaud = rate100 ;
2022-09-11 00:16:48 +02:00
if ( ! pinManager . isPinAllocated ( hardwareTX ) | | pinManager . getPinOwner ( hardwareTX ) = = PinOwner : : DebugOut ) {
2022-02-01 18:21:30 +01:00
Serial . print ( F ( " Baud is now " ) ) ; Serial . println ( rate ) ;
2022-01-29 08:35:40 +01:00
}
2022-02-01 18:21:30 +01:00
Serial . flush ( ) ;
Serial . begin ( rate ) ;
}
2022-09-26 10:08:31 +02:00
// RGB LED data return as JSON array. Slow, but easy to use on the other end.
void sendJSON ( ) {
if ( ! pinManager . isPinAllocated ( hardwareTX ) | | pinManager . getPinOwner ( hardwareTX ) = = PinOwner : : DebugOut ) {
uint16_t used = strip . getLengthTotal ( ) ;
Serial . write ( ' [ ' ) ;
for ( uint16_t i = 0 ; i < used ; i + + ) {
Serial . print ( strip . getPixelColor ( i ) ) ;
if ( i ! = used - 1 ) Serial . write ( ' , ' ) ;
}
Serial . println ( " ] " ) ;
2023-01-06 09:24:29 +01:00
}
2022-09-26 10:08:31 +02:00
}
// RGB LED data returned as bytes in TPM2 format. Faster, and slightly less easy to use on the other end.
void sendBytes ( ) {
if ( ! pinManager . isPinAllocated ( hardwareTX ) | | pinManager . getPinOwner ( hardwareTX ) = = PinOwner : : DebugOut ) {
Serial . write ( 0xC9 ) ; Serial . write ( 0xDA ) ;
uint16_t used = strip . getLengthTotal ( ) ;
uint16_t len = used * 3 ;
Serial . write ( highByte ( len ) ) ;
Serial . write ( lowByte ( len ) ) ;
for ( uint16_t i = 0 ; i < used ; i + + ) {
uint32_t c = strip . getPixelColor ( i ) ;
Serial . write ( qadd8 ( W ( c ) , R ( c ) ) ) ; //R, add white channel to RGB channels as a simple RGBW -> RGB map
Serial . write ( qadd8 ( W ( c ) , G ( c ) ) ) ; //G
Serial . write ( qadd8 ( W ( c ) , B ( c ) ) ) ; //B
}
Serial . write ( 0x36 ) ; Serial . write ( ' \n ' ) ;
2023-01-06 09:24:29 +01:00
}
2022-09-26 10:08:31 +02:00
}
2020-03-31 02:38:08 +02:00
void handleSerial ( )
{
2022-09-11 00:16:48 +02:00
if ( pinManager . isPinAllocated ( hardwareRX ) ) return ;
2023-03-16 13:08:34 +01:00
if ( ! Serial ) return ; // arduino docs: `if (Serial)` indicates whether or not the USB CDC serial connection is open. For all non-USB CDC ports, this will always return true
2023-01-06 09:24:29 +01:00
2020-03-31 02:38:08 +02:00
# ifdef WLED_ENABLE_ADALIGHT
static auto state = AdaState : : Header_A ;
static uint16_t count = 0 ;
static uint16_t pixel = 0 ;
static byte check = 0x00 ;
static byte red = 0x00 ;
static byte green = 0x00 ;
2022-01-29 08:35:40 +01:00
2020-03-31 02:38:08 +02:00
while ( Serial . available ( ) > 0 )
{
yield ( ) ;
2021-08-26 11:04:27 +02:00
byte next = Serial . peek ( ) ;
2020-03-31 02:38:08 +02:00
switch ( state ) {
case AdaState : : Header_A :
if ( next = = ' A ' ) state = AdaState : : Header_d ;
2020-05-23 16:09:49 +02:00
else if ( next = = 0xC9 ) { //TPM2 start byte
2020-05-22 23:30:55 +02:00
state = AdaState : : TPM2_Header_Type ;
}
2021-11-16 23:20:26 +01:00
else if ( next = = ' I ' ) {
handleImprovPacket ( ) ;
return ;
} else if ( next = = ' v ' ) {
Serial . print ( " WLED " ) ; Serial . write ( ' ' ) ; Serial . println ( VERSION ) ;
2023-01-06 09:24:29 +01:00
2022-02-01 18:21:30 +01:00
} else if ( next = = 0xB0 ) { updateBaudRate ( 115200 ) ;
} else if ( next = = 0xB1 ) { updateBaudRate ( 230400 ) ;
} else if ( next = = 0xB2 ) { updateBaudRate ( 460800 ) ;
} else if ( next = = 0xB3 ) { updateBaudRate ( 500000 ) ;
} else if ( next = = 0xB4 ) { updateBaudRate ( 576000 ) ;
} else if ( next = = 0xB5 ) { updateBaudRate ( 921600 ) ;
} else if ( next = = 0xB6 ) { updateBaudRate ( 1000000 ) ;
} else if ( next = = 0xB7 ) { updateBaudRate ( 1500000 ) ;
2023-01-06 09:24:29 +01:00
2022-09-26 10:08:31 +02:00
} else if ( next = = ' l ' ) { sendJSON ( ) ; // Send LED data as JSON Array
} else if ( next = = ' L ' ) { sendBytes ( ) ; // Send LED data as TPM2 Data Packet
2023-01-06 09:24:29 +01:00
} else if ( next = = ' o ' ) { continuousSendLED = false ; // Disable Continuous Serial Streaming
2022-09-26 10:08:31 +02:00
} else if ( next = = ' O ' ) { continuousSendLED = true ; // Enable Continuous Serial Streaming
2021-11-16 23:20:26 +01:00
} else if ( next = = ' { ' ) { //JSON API
2021-08-26 11:04:27 +02:00
bool verboseResponse = false ;
2021-12-04 01:05:01 +01:00
if ( ! requestJSONBufferLock ( 16 ) ) return ;
2021-11-07 11:58:16 +01:00
Serial . setTimeout ( 100 ) ;
DeserializationError error = deserializeJson ( doc , Serial ) ;
if ( error ) {
2021-11-12 23:33:10 +01:00
releaseJSONBufferLock ( ) ;
2021-11-07 11:58:16 +01:00
return ;
2021-08-26 11:04:27 +02:00
}
2021-11-07 11:58:16 +01:00
verboseResponse = deserializeState ( doc . as < JsonObject > ( ) ) ;
2021-08-26 11:04:27 +02:00
//only send response if TX pin is unused for other purposes
2022-09-11 00:16:48 +02:00
if ( verboseResponse & & ( ! pinManager . isPinAllocated ( hardwareTX ) | | pinManager . getPinOwner ( hardwareTX ) = = PinOwner : : DebugOut ) ) {
2021-11-03 14:52:22 +01:00
doc . clear ( ) ;
2021-08-26 11:04:27 +02:00
JsonObject state = doc . createNestedObject ( " state " ) ;
serializeState ( state ) ;
JsonObject info = doc . createNestedObject ( " info " ) ;
serializeInfo ( info ) ;
serializeJson ( doc , Serial ) ;
2021-11-16 23:20:26 +01:00
Serial . println ( ) ;
2021-08-26 11:04:27 +02:00
}
2021-11-12 23:33:10 +01:00
releaseJSONBufferLock ( ) ;
2021-08-26 11:04:27 +02:00
}
2020-03-31 02:38:08 +02:00
break ;
case AdaState : : Header_d :
if ( next = = ' d ' ) state = AdaState : : Header_a ;
else state = AdaState : : Header_A ;
break ;
case AdaState : : Header_a :
if ( next = = ' a ' ) state = AdaState : : Header_CountHi ;
else state = AdaState : : Header_A ;
break ;
case AdaState : : Header_CountHi :
pixel = 0 ;
count = next * 0x100 ;
check = next ;
state = AdaState : : Header_CountLo ;
break ;
case AdaState : : Header_CountLo :
count + = next + 1 ;
check = check ^ next ^ 0x55 ;
state = AdaState : : Header_CountCheck ;
break ;
case AdaState : : Header_CountCheck :
if ( check = = next ) state = AdaState : : Data_Red ;
else state = AdaState : : Header_A ;
break ;
2020-05-22 23:30:55 +02:00
case AdaState : : TPM2_Header_Type :
state = AdaState : : Header_A ; //(unsupported) TPM2 command or invalid type
if ( next = = 0xDA ) state = AdaState : : TPM2_Header_CountHi ; //TPM2 data
else if ( next = = 0xAA ) Serial . write ( 0xAC ) ; //TPM2 ping
break ;
case AdaState : : TPM2_Header_CountHi :
pixel = 0 ;
count = ( next * 0x100 ) / 3 ;
state = AdaState : : TPM2_Header_CountLo ;
break ;
case AdaState : : TPM2_Header_CountLo :
2020-05-23 16:09:49 +02:00
count + = next / 3 ;
2020-05-22 23:30:55 +02:00
state = AdaState : : Data_Red ;
break ;
2020-03-31 02:38:08 +02:00
case AdaState : : Data_Red :
red = next ;
state = AdaState : : Data_Green ;
break ;
case AdaState : : Data_Green :
green = next ;
state = AdaState : : Data_Blue ;
break ;
case AdaState : : Data_Blue :
byte blue = next ;
2020-04-30 01:52:36 +02:00
if ( ! realtimeOverride ) setRealtimePixel ( pixel + + , red , green , blue , 0 ) ;
2020-03-31 02:38:08 +02:00
if ( - - count > 0 ) state = AdaState : : Data_Red ;
else {
2020-04-13 00:42:27 +02:00
realtimeLock ( realtimeTimeoutMs , REALTIME_MODE_ADALIGHT ) ;
2020-03-31 02:38:08 +02:00
2020-04-30 01:52:36 +02:00
if ( ! realtimeOverride ) strip . show ( ) ;
2020-03-31 02:38:08 +02:00
state = AdaState : : Header_A ;
}
break ;
}
2022-09-26 10:08:31 +02:00
// All other received bytes will disable Continuous Serial Streaming
if ( continuousSendLED & & next ! = ' O ' ) {
continuousSendLED = false ;
2023-01-06 09:24:29 +01:00
}
2021-08-26 11:04:27 +02:00
Serial . read ( ) ; //discard the byte
2020-03-31 02:38:08 +02:00
}
# endif
2022-09-26 10:08:31 +02:00
// If Continuous Serial Streaming is enabled, send new LED data as bytes
if ( continuousSendLED & & ( lastUpdate ! = strip . getLastShow ( ) ) ) {
sendBytes ( ) ;
lastUpdate = strip . getLastShow ( ) ;
}
2020-03-31 02:38:08 +02:00
}