diff --git a/ProtocolTask.cpp b/ProtocolTask.cpp index 85d7c4a..db69521 100644 --- a/ProtocolTask.cpp +++ b/ProtocolTask.cpp @@ -43,7 +43,7 @@ constexpr uint8_t PROTOCOL_TASK_PERIOD = 100; * @brief Constructor, sets all member variables */ ProtocolTask::ProtocolTask(Proto::Node node, UART_HandleTypeDef* huart, uint16_t uartTaskCmd) : Task(TASK_PROTOCOL_QUEUE_DEPTH_OBJS), - uartTaskCommand(uartTaskCmd) + uartTaskCommand(uartTaskCmd), numUartErrors_(0) { // Setup Buffers protocolRxBuffer = soar_malloc(PROTOCOL_RX_BUFFER_SZ_BYTES+1); @@ -144,6 +144,11 @@ void ProtocolTask::Run(void * pvParams) UARTTask::Inst().SendCommandReference(protoTx); break; } + case EVENT_UART_INTERRUPT_ARM_ERROR: { + // Attempt to receive data again + ReceiveData(); + break; + } default: break; } @@ -158,8 +163,50 @@ void ProtocolTask::Run(void * pvParams) */ bool ProtocolTask::ReceiveData() { - HAL_UART_Receive_IT((UART_HandleTypeDef*)uartHandle, &protocolRxChar, 1); - return true; + // If HAL_UART_Receive_IT succeeds, return true + if (HAL_OK == HAL_UART_Receive_IT((UART_HandleTypeDef*)uartHandle, &protocolRxChar, 1)) { + numUartErrors_ = 0; + return true; + } + + // If we had an error attempt to abort the receive and re-arm the interrupt + HAL_UART_AbortReceive((UART_HandleTypeDef*)uartHandle); + + // Attempt to arm the interrupt again, if success return true + if (HAL_OK == HAL_UART_Receive_IT((UART_HandleTypeDef*)uartHandle, &protocolRxChar, 1)) { + numUartErrors_ = 0; + return true; + } + + // If we've reached the full number of errors, reset the system + if (++numUartErrors_ >= PROTOCOL_MAX_NUM_ERRORS_UNTIL_RESET) { + SOAR_ASSERT(false, "UART Error Limit Reached -- Board Resetting\n"); + } + + // Delay then try again next task cycle until the error limit is reached + osDelay(PROTOCOL_UART_RX_ERROR_RETRY_DELAY_MS); + Command cm(PROTOCOL_COMMAND, EVENT_UART_INTERRUPT_ARM_ERROR); + qEvtQueue->Send(cm); + + return false; +} + +/** + * @brief Receive data from ISR, currently receives by arming interrupt + */ +bool ProtocolTask::ReceiveDataFromISR() +{ + // If HAL_UART_Receive_IT succeeds, return true + if (HAL_OK == HAL_UART_Receive_IT((UART_HandleTypeDef*)uartHandle, &protocolRxChar, 1)) { + numUartErrors_ = 0; + return true; + } + + // We had an error arming the interrupt, handle this in the next task cycle + Command cm(PROTOCOL_COMMAND, EVENT_UART_INTERRUPT_ARM_ERROR); + qEvtQueue->SendFromISR(cm); + + return false; } /** @@ -254,7 +301,7 @@ void ProtocolTask::InterruptRxData() } //Re-arm the interrupt - ReceiveData(); + ReceiveDataFromISR(); } /** diff --git a/ProtocolTask.hpp b/ProtocolTask.hpp index 6f72c48..aafde1a 100644 --- a/ProtocolTask.hpp +++ b/ProtocolTask.hpp @@ -22,7 +22,9 @@ enum PROTOCOL_TASK_COMMANDS { PROTOCOL_TASK_COMMAND_NONE = 0, EVENT_PROTOCOL_RX_COMPLETE, PROTOCOL_RX_DECODED_DATA, - PROTOCOL_TX_REQUEST_DATA + PROTOCOL_TX_REQUEST_DATA, + + EVENT_UART_INTERRUPT_ARM_ERROR }; /* Macros ------------------------------------------------------------------*/ @@ -43,6 +45,10 @@ constexpr uint8_t PROTOCOL_CHECKSUM_BYTES = 2; constexpr uint8_t PROTOCOL_OVERHEAD_BYTES = 1 + PROTOCOL_CHECKSUM_BYTES; // Size of the protocol overhead *PRE-COBS* (message ID + 2 byte checksum) constexpr uint16_t PROTOCOL_MINIMUM_MESSAGE_LENGTH = PROTOCOL_OVERHEAD_BYTES + 1; +// Error Handling +constexpr uint8_t PROTOCOL_MAX_NUM_ERRORS_UNTIL_RESET = 200; // Number of consecutive UART errors before a system reset is triggered +constexpr uint16_t PROTOCOL_UART_RX_ERROR_RETRY_DELAY_MS = 1; // Delay between UART error retries + /* Class ------------------------------------------------------------------*/ class ProtocolTask : public Task { @@ -72,6 +78,7 @@ class ProtocolTask : public Task virtual void HandleProtobufTelemetryMessage(EmbeddedProto::ReadBufferFixedSize& readBuffer) = 0; bool ReceiveData(); + bool ReceiveDataFromISR(); // Helper functions @@ -89,6 +96,8 @@ class ProtocolTask : public Task const UART_HandleTypeDef* uartHandle; const uint16_t uartTaskCommand; + + uint8_t numUartErrors_; }; #endif // SOAR_SYSTEM_PROTOCOL_TASK_HPP_