Fix TUYA state machine (in TUYA v1) (#20110)

* rework state machine

* some comments

* wip

* looks good now

* little updates
This commit is contained in:
Barbudor 2023-12-08 20:33:40 +01:00 committed by GitHub
parent faa29b2e57
commit 73268e4bb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -78,7 +78,6 @@ struct TUYA {
bool SuspendTopic = false; // Used to reduce the load at init time or when polling the configuraton on demand
uint32_t ignore_topic_timeout = 0; // Suppress the /STAT topic (if enabled) to avoid data overflow until the configuration is over
bool ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction
uint8_t cmd_status = 0; // Current status of serial-read
uint8_t cmd_checksum = 0; // Checksum of tuya command
uint8_t data_len = 0; // Data lenght of command
uint8_t wifi_state = -2; // Keep MCU wifi-status in sync with WifiState()
@ -1262,36 +1261,7 @@ void TuyaInit(void) {
Tuya.active = false;
}
void TuyaSerialInput(void)
{
while (TuyaSerial->available()) {
yield();
uint8_t serial_in_byte = TuyaSerial->read();
if (serial_in_byte == 0x55) { // Start TUYA Packet
Tuya.cmd_status = 1;
Tuya.buffer[Tuya.byte_counter++] = serial_in_byte;
Tuya.cmd_checksum += serial_in_byte;
}
else if (Tuya.cmd_status == 1 && serial_in_byte == 0xAA) { // Only packtes with header 0x55AA are valid
Tuya.cmd_status = 2;
Tuya.byte_counter = 0;
Tuya.buffer[Tuya.byte_counter++] = 0x55;
Tuya.buffer[Tuya.byte_counter++] = 0xAA;
Tuya.cmd_checksum = 0xFF;
}
else if (Tuya.cmd_status == 2) {
if (Tuya.byte_counter == 5) { // Get length of data
Tuya.cmd_status = 3;
Tuya.data_len = serial_in_byte;
}
Tuya.cmd_checksum += serial_in_byte;
Tuya.buffer[Tuya.byte_counter++] = serial_in_byte;
}
else if ((Tuya.cmd_status == 3) && (Tuya.byte_counter == (6 + Tuya.data_len)) && (Tuya.cmd_checksum == serial_in_byte)) { // Compare checksum and process packet
Tuya.buffer[Tuya.byte_counter++] = serial_in_byte;
void TuyaProcessMessage(void) {
char hex_char[(Tuya.byte_counter * 2) + 2];
uint16_t len = Tuya.buffer[4] << 8 | Tuya.buffer[5];
@ -1350,14 +1320,6 @@ void TuyaSerialInput(void)
ResponseAppend_P(PSTR("}}"));
if (Settings->flag3.tuya_serial_mqtt_publish) { // SetOption66 - Enable TuyaMcuReceived messages over Mqtt
/*
for (uint8_t cmdsID = 0; sizeof(TuyaExcludeCMDsFromMQTT) > cmdsID; cmdsID++){
if (TuyaExcludeCMDsFromMQTT[cmdsID] == Tuya.buffer[3]) {
isCmdToSuppress = true;
break;
}
}
*/
for (uint8_t cmdsID = 0; cmdsID < sizeof(TuyaExcludeCMDsFromMQTT); cmdsID++) {
if (pgm_read_byte(TuyaExcludeCMDsFromMQTT +cmdsID) == Tuya.buffer[3]) {
isCmdToSuppress = true;
@ -1390,21 +1352,72 @@ void TuyaSerialInput(void)
} else {
TuyaLowPowerModePacketProcess();
}
}
void TuyaSerialInput(void)
{
/* /-------------------------------- header 55
* | /----------------------------- header AA
* | | /-------------------------- version, always 00
* | | | /----------------------- command byte
* | | | | /--+----------------- data length in bytes, big endian (high then low)
* | | | | | | /-+-+-+-+------ data bytes
* | | | | | | | | | | | /--- checksum (sum of all bytes except checksum)
* 55 AA 00 cc lh ll dd .... dd xx
* 0 1 2 3 4 5 6 .... index in Tuya buffer
* 0 1 2 2 2 2 3 3 3 3 3 Tuya.cmd_status
*/
static unsigned long time_last_byte_received = 0;
while (TuyaSerial->available()) {
yield();
uint8_t serial_in_byte = TuyaSerial->read();
time_last_byte_received = millis();
if (Tuya.byte_counter == 0) {
if (serial_in_byte == 0x55) { // Start TUYA Packet
Tuya.buffer[Tuya.byte_counter++] = 0x55;
}
}
else if (Tuya.byte_counter == 1) {
if (serial_in_byte == 0xAA) { // Only packets with header 0x55AA are valid
Tuya.buffer[Tuya.byte_counter++] = 0xAA;
Tuya.cmd_checksum = 0xFF;
} else {
Tuya.byte_counter = 0; // if not received 0xAA right after the 0x55, reset the state machine
AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("TYA: 0x55 without 0xAA - resync"));
}
}
else if (Tuya.byte_counter < 6) {
Tuya.buffer[Tuya.byte_counter++] = serial_in_byte;
Tuya.cmd_checksum += serial_in_byte;
if (Tuya.byte_counter == 6) {
// Get length of data, max buffer is 256 bytes, so only taking into account lowest byte of length
Tuya.data_len = serial_in_byte + 6;
}
}
else if (Tuya.byte_counter == Tuya.data_len) {
Tuya.buffer[Tuya.byte_counter++] = serial_in_byte;
if (Tuya.cmd_checksum == serial_in_byte) { // Compare checksum and process packet
AddLogBuffer(LOG_LEVEL_DEBUG_MORE,(uint8_t*)Tuya.buffer,Tuya.byte_counter);
TuyaProcessMessage();
} else {
AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("TYA: checksum error: 0x%02X instead of 0x%02X"), serial_in_byte, Tuya.cmd_checksum);
}
Tuya.byte_counter = 0;
Tuya.cmd_status = 0;
Tuya.cmd_checksum = 0;
Tuya.data_len = 0;
} // read additional packets from TUYA
}
else if (Tuya.byte_counter < TUYA_BUFFER_SIZE -1) { // add char to string if it still fits
Tuya.buffer[Tuya.byte_counter++] = serial_in_byte;
Tuya.cmd_checksum += serial_in_byte;
} else {
Tuya.byte_counter = 0;
Tuya.cmd_status = 0;
Tuya.cmd_checksum = 0;
Tuya.data_len = 0;
}
else { // buffer overflow, reset the state machine
Tuya.byte_counter = 0;
}
}
// reset the state machine if no bytes received since a long time
if (Tuya.byte_counter > 0 && (millis() - time_last_byte_received) > TUYA_CMD_TIMEOUT) {
Tuya.byte_counter = 0;
AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("TYA: serial receive timeout"));
}
}
@ -1651,6 +1664,7 @@ bool Xdrv16(uint32_t function) {
if (FUNC_MODULE_INIT == function) {
result = TuyaModuleSelected();
Tuya.active = result;
AddLog(LOG_LEVEL_DEBUG,PSTR("TYA: Active=%d"),Tuya.active);
}
else if (Tuya.active) {
switch (function) {