diff --git a/firmware/console/binary/tunerstudio.cpp b/firmware/console/binary/tunerstudio.cpp index 486edaf9eb..cc1cd1e511 100644 --- a/firmware/console/binary/tunerstudio.cpp +++ b/firmware/console/binary/tunerstudio.cpp @@ -418,6 +418,7 @@ static int tsProcessOne(TsChannelBase* tsChannel) { // assume there's connection loss and notify the bluetooth init code bluetoothSoftwareDisconnectNotify(); #endif /* EFI_BLUETOOTH_SETUP */ + tsChannel->in_sync = false; return -1; } @@ -430,63 +431,89 @@ static int tsProcessOne(TsChannelBase* tsChannel) { received = tsChannel->readTimeout(&secondByte, 1, TS_COMMUNICATION_TIMEOUT_SHORT); if (received != 1) { tunerStudioError(tsChannel, "TS: ERROR: no second byte"); + tsChannel->in_sync = false; return -1; } uint16_t incomingPacketSize = firstByte << 8 | secondByte; + size_t expectedSize = incomingPacketSize + CRC_VALUE_SIZE; - if (incomingPacketSize == 0 || incomingPacketSize > (sizeof(tsChannel->scratchBuffer) - CRC_WRAPPING_SIZE)) { - efiPrintf("process_ts: channel=%s invalid size: %d", tsChannel->name, incomingPacketSize); - tunerStudioError(tsChannel, "process_ts: ERROR: CRC header size"); - sendErrorCode(tsChannel, TS_RESPONSE_UNDERRUN); + if (incomingPacketSize == 0 || expectedSize > sizeof(tsChannel->scratchBuffer)) { + if (tsChannel->in_sync) { + efiPrintf("process_ts: channel=%s invalid size: %d", tsChannel->name, incomingPacketSize); + tunerStudioError(tsChannel, "process_ts: ERROR: CRC header size"); + /* send error only if previously we where in sync */ + sendErrorCode(tsChannel, TS_RESPONSE_UNDERRUN); + } + tsChannel->in_sync = false; return -1; } - received = tsChannel->readTimeout((uint8_t* )tsChannel->scratchBuffer, 1, TS_COMMUNICATION_TIMEOUT); - if (received != 1) { - tunerStudioError(tsChannel, "ERROR: did not receive command"); - sendErrorCode(tsChannel, TS_RESPONSE_UNDERRUN); - return -1; - } + char command; + if (tsChannel->in_sync) { + /* we are in sync state, packet size should be correct so lets receive full packet and then check if command is supported + * otherwise (if abort reception in middle of packet) it will break syncronization and cause error on next packet */ + received = tsChannel->readTimeout((uint8_t*)(tsChannel->scratchBuffer), expectedSize, TS_COMMUNICATION_TIMEOUT); + command = tsChannel->scratchBuffer[0]; - char command = tsChannel->scratchBuffer[0]; - if (!isKnownCommand(command)) { - efiPrintf("unexpected command %x", command); - sendErrorCode(tsChannel, TS_RESPONSE_UNRECOGNIZED_COMMAND); - return -1; + if (received != expectedSize) { + /* print and send error as we where in sync */ + efiPrintf("Got only %d bytes while expecting %d for command %c", received, + expectedSize, command); + tunerStudioError(tsChannel, "ERROR: not enough bytes in stream"); + sendErrorCode(tsChannel, TS_RESPONSE_UNDERRUN); + tsChannel->in_sync = false; + return -1; + } + + if (!isKnownCommand(command)) { + /* print and send error as we where in sync */ + efiPrintf("unexpected command %x", command); + sendErrorCode(tsChannel, TS_RESPONSE_UNRECOGNIZED_COMMAND); + tsChannel->in_sync = false; + return -1; + } + } else { + /* receive only command byte to check if it is supported */ + received = tsChannel->readTimeout((uint8_t*)(tsChannel->scratchBuffer), 1, TS_COMMUNICATION_TIMEOUT_SHORT); + command = tsChannel->scratchBuffer[0]; + + if (!isKnownCommand(command)) { + /* do not report any error as we are not in sync */ + return -1; + } + + received = tsChannel->readTimeout((uint8_t*)(tsChannel->scratchBuffer) + 1, expectedSize - 1, TS_COMMUNICATION_TIMEOUT); + if (received != expectedSize - 1) { + /* do not report any error as we are not in sync */ + return -1; + } } #if EFI_SIMULATOR - logMsg("command %c\r\n", command); + logMsg("command %c\r\n", command); #endif - int expectedSize = incomingPacketSize + CRC_VALUE_SIZE - 1; - received = tsChannel->readTimeout((uint8_t*)(tsChannel->scratchBuffer + 1), expectedSize, TS_COMMUNICATION_TIMEOUT); - if (received != expectedSize) { - efiPrintf("Got only %d bytes while expecting %d for command %c", received, - expectedSize, command); - tunerStudioError(tsChannel, "ERROR: not enough bytes in stream"); - sendErrorCode(tsChannel, TS_RESPONSE_UNDERRUN); - return -1; - } - uint32_t expectedCrc = *(uint32_t*) (tsChannel->scratchBuffer + incomingPacketSize); expectedCrc = SWAP_UINT32(expectedCrc); uint32_t actualCrc = crc32(tsChannel->scratchBuffer, incomingPacketSize); if (actualCrc != expectedCrc) { - efiPrintf("TunerStudio: CRC %x %x %x %x", tsChannel->scratchBuffer[incomingPacketSize + 0], - tsChannel->scratchBuffer[incomingPacketSize + 1], tsChannel->scratchBuffer[incomingPacketSize + 2], - tsChannel->scratchBuffer[incomingPacketSize + 3]); - - efiPrintf("TunerStudio: command %c actual CRC %x/expected %x", tsChannel->scratchBuffer[0], - actualCrc, expectedCrc); - tunerStudioError(tsChannel, "ERROR: CRC issue"); - sendErrorCode(tsChannel, TS_RESPONSE_CRC_FAILURE); + /* send error only if previously we where in sync */ + if (tsChannel->in_sync) { + efiPrintf("TunerStudio: command %c actual CRC %x/expected %x", tsChannel->scratchBuffer[0], + actualCrc, expectedCrc); + tunerStudioError(tsChannel, "ERROR: CRC issue"); + sendErrorCode(tsChannel, TS_RESPONSE_CRC_FAILURE); + tsChannel->in_sync = false; + } return -1; } + /* we were able to receive known command with correct crc and size! */ + tsChannel->in_sync = true; + int success = tsInstance.handleCrcCommand(tsChannel, tsChannel->scratchBuffer, incomingPacketSize); if (!success) { diff --git a/firmware/console/binary/tunerstudio_io.h b/firmware/console/binary/tunerstudio_io.h index 8debb66b2b..274c674b23 100644 --- a/firmware/console/binary/tunerstudio_io.h +++ b/firmware/console/binary/tunerstudio_io.h @@ -62,6 +62,18 @@ public: void crcAndWriteBuffer(uint8_t responseCode, size_t size); void copyAndWriteSmallCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size); + /* When TsChannel is in "not in sync" state tsProcessOne will silently try to find + * begining of packet. + * As soon as tsProcessOne was able to receive valid packet with valid size and crc + * TsChannel becomes "in sync". That means it will react on any futher errors: it will + * emit packet with error code and switch back to "not in sync" mode. + * This insures that RE will send only one error message after lost of syncronization + * with TS. + * Also while in "not in sync" state - tsProcessOne will not try to receive whole packet + * by one read. Instead after getting packet size it will try to receive one byte of + * command and check if it is supported. */ + bool in_sync = false; + private: void writeCrcPacketLarge(uint8_t responseCode, const uint8_t* buf, size_t size); };