diff --git a/README.md b/README.md index 2e6d246..4255e1f 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ anywhere in the application code. ## Can Bus -TODO Add description +Mainly defers to the TACOS CAN module, but provides a simple interface for sending and receiving messages. -Configuration: +Expandable for isotp. ## Watchdog diff --git a/include/sta/rtos/queue.tpp b/include/sta/rtos/queue.tpp index 3814188..0d97029 100644 --- a/include/sta/rtos/queue.tpp +++ b/include/sta/rtos/queue.tpp @@ -24,19 +24,19 @@ namespace sta template RtosQueue::RtosQueue(uint32_t length) - : handle_{osMessageQueueNew(length, sizeof(Message), NULL)} + : handle_{osMessageQueueNew(length, sizeof(T), NULL)} { STA_ASSERT(handle_ != NULL); } template - bool RtosQueue::put(const Message & msg, uint32_t timeout /* = osWaitForever */) + bool RtosQueue::put(const T & msg, uint32_t timeout /* = osWaitForever */) { return (osOK == osMessageQueuePut(handle_, &msg, 0, timeout)); } template - bool RtosQueue::get(Message * outMsg, uint32_t timeout /* = osWaitForever */) + bool RtosQueue::get(T * outMsg, uint32_t timeout /* = osWaitForever */) { uint8_t prio; return (osOK == osMessageQueueGet(handle_, outMsg, &prio, timeout)); diff --git a/include/sta/rtos/system/can_bus.hpp b/include/sta/rtos/system/can_bus.hpp index 7a95306..906af71 100644 --- a/include/sta/rtos/system/can_bus.hpp +++ b/include/sta/rtos/system/can_bus.hpp @@ -5,7 +5,6 @@ #ifndef STA_RTOS_SYSTEM_CAN_BUS_HPP #define STA_RTOS_SYSTEM_CAN_BUS_HPP - /** * @defgroup STA_RTOS_CanBus CAN driver * @ingroup STA_RTOS_API @@ -20,16 +19,17 @@ * * @ingroup STA_RTOS_BuildConfig */ -# define STA_RTOS_CAN_BUS_ENABLE +# define STA_CAN_BUS_ENABLE #endif // DOXYGEN #include -#ifdef STA_RTOS_CAN_BUS_ENABLE +#ifdef STA_CAN_BUS_ENABLE - -#include +#include +#include #include +#include #include @@ -60,34 +60,30 @@ * @{ */ - /** * @brief CAN frame available. */ -#define STA_RTOS_CAN_FLAG_MSG_AVAIL 0x000010U +#define STA_RTOS_CAN_FLAG_MSG_AVAIL 0x1U /** * @brief Send CAN message. */ -#define STA_RTOS_CAN_FLAG_MSG_SEND 0x000020U +#define STA_RTOS_CAN_FLAG_MSG_SEND 0x1U << 1 /** * @brief CAN data message in queue. */ -#define STA_RTOS_CAN_FLAG_DATA_QUEUED 0x000040U +#define STA_RTOS_CAN_FLAG_DATA_QUEUED 0x1U << 2 /** * @brief CAN system message in queue. */ -#define STA_RTOS_CAN_FLAG_SYS_QUEUED 0x000080U -/** - * @brief Show ISOTP statistics. - */ -#define STA_RTOS_CAN_FLAG_SHOW_STATS 0x000100U - +#define STA_RTOS_CAN_FLAG_SYS_QUEUED 0x1U << 3 /** * @brief CAN SID bits used for system messages. */ #define STA_CAN_SID_SYS_BITS UINT32_C(0x3) +#define STA_RTOS_CAN_ANY STA_RTOS_CAN_FLAG_MSG_AVAIL | STA_RTOS_CAN_FLAG_MSG_AVAIL | STA_RTOS_CAN_FLAG_DATA_QUEUED | STA_RTOS_CAN_FLAG_SYS_QUEUED + /** @} */ @@ -108,62 +104,66 @@ namespace sta /** - * @brief Return CanController for use in CAN system task. + * @brief Return CAN_HandleTypeDef for use in CAN system task. * * Implementation must be provided by application. */ - extern CanController * getCanController(); - - - - /** - * @brief Send notification to CAN driver. - * - * @param flags Event flags - */ - void notifyCanBus(uint32_t flags); - - - /** - * @brief Place data message in CAN driver TX queue. - * - * @param msg Message to transmit - * @param timeout Timeout for placing message (0 = no wait, osWaitForever = blocking) - * @return True if message was queued successfully - */ - bool queueCanBusMsg(const CanDataMsg & msg, uint32_t timeout); - /** - * @brief Place system message in CAN driver TX queue. - * - * @param msg Message to transmit - * @param timeout Timeout for placing message (0 = no wait, osWaitForever = blocking) - * @return True if message was queued successfully - */ - bool queueCanBusMsg(const CanSysMsg & msg, uint32_t timeout); - - /** - * @brief Retrieve data message from CAN driver TX queue. - * - * @param[out] msg Output address for retrieved message - * @param timeout Timeout for retrieving message (0 = no wait, osWaitForever = blocking) - * @return True if message was retrieved successfully - */ - bool getCanBusMsg(CanDataMsg * msg, uint32_t timeout); - /** - * @brief Retrieve system message from CAN driver TX queue. - * - * @param[out] msg Destination for retrieved message - * @param timeout Timeout for retrieving message (0 = no wait, osWaitForever = blocking) - * @return True if message was retrieved successfully - */ - bool getCanBusMsg(CanSysMsg * msg, uint32_t timeout); - + extern CAN_HandleTypeDef * getCanController(); /** @} */ } // namespace rtos } // namespace sta +namespace sta +{ -#endif // STA_RTOS_CAN_BUS_ENABLE + class AlpakaCanBus + { + public: + static const uint8_t FIFO_SYS = 0; + static const uint8_t FIFO_DATA = 1; + + public: + AlpakaCanBus(CanController * controller, TimeMsFn timeMs); + + + /** + * @brief Send system message. + * + * @param msg Message + */ + void send(const CanSysMsg & msg); + + private: + /** + * @brief Configure CAN filters. + */ + void setupSubscriptions(); + + private: + CanController * controller_; + }; + +} // namespace sta + +namespace debug +{ + /** + * @brief Output CAN frame ID to UART. + * + * @param id Frame ID + */ + void printFrameID(const sta::CanFrameId & id); + + /** + * @brief Output CAN frame payload to UART. + * + * @param payload Payload buffer + * @param size Payload size + */ + void printPayloadHex(const uint8_t * payload, uint8_t size); +} // namespace debug + +#endif // STA_CAN_BUS_ENABLE #endif // STA_RTOS_SYSTEM_CAN_BUS_HPP diff --git a/src/debug/stack_overflow.cpp b/src/debug/stack_overflow.cpp index 158c454..e4a07ba 100644 --- a/src/debug/stack_overflow.cpp +++ b/src/debug/stack_overflow.cpp @@ -1,7 +1,7 @@ #include #ifdef STA_RTOS_STACK_OVERFLOW_HOOK -#include +#include #include #include diff --git a/src/system/can_bus.cpp b/src/system/can_bus.cpp index b1f06cf..365e01d 100644 --- a/src/system/can_bus.cpp +++ b/src/system/can_bus.cpp @@ -2,155 +2,25 @@ * @file * @brief CAN driver thread. */ -#include -#ifdef STA_RTOS_CAN_BUS_ENABLE -#include -#include -#include +#include +#ifdef STA_CAN_BUS_ENABLE + +#include +#include +#include #include -#include -#include #include -#include #include -#include +#include +#include +#include #include #include #include - -namespace -{ - StaticTask_t canBusCB; - StaticQueue_t canBusDataQueueCB; - StaticQueue_t canBusSysQueueCB; - - osThreadId_t canBusTaskHandle = nullptr; - osMessageQueueId_t canBusDataQueueHandle = nullptr; - osMessageQueueId_t canBusSysQueueHandle = nullptr; - - sta::CanController * canBusController = nullptr; - - const size_t queueLength = 8; - - // Static memory buffers - CanDataMsg canBusDataQueueBuffer[queueLength]; - CanSysMsg canBusSysQueueBuffer[queueLength]; - uint32_t canBusStack[256]; -} - - -extern "C" void canBusTask(void *); - - -namespace sta -{ - namespace rtos - { - void initCanBus() - { - // Create thread using static allocation - const osThreadAttr_t taskAttributes = { - .name = "sysCanBus", - .cb_mem = &canBusCB, - .cb_size = sizeof(canBusCB), - .stack_mem = &canBusStack[0], - .stack_size = sizeof(canBusStack), - .priority = (osPriority_t) osPriorityLow, - }; - - canBusTaskHandle = osThreadNew(canBusTask, NULL, &taskAttributes); - STA_ASSERT_MSG(canBusTaskHandle != nullptr, "System CAN task initialization failed"); - - - // Create message queues using static allocation - const osMessageQueueAttr_t dataQueueAttributes = { - .name = "sysCanDataOut", - .attr_bits = 0, - .cb_mem = &canBusDataQueueCB, - .cb_size = sizeof(canBusDataQueueCB), - .mq_mem = &canBusDataQueueBuffer, - .mq_size = sizeof(canBusDataQueueBuffer) - }; - - canBusDataQueueHandle = osMessageQueueNew(queueLength, sizeof(CanDataMsg), &dataQueueAttributes); - STA_ASSERT_MSG(canBusDataQueueHandle != nullptr, "System CAN data message queue initialization failed"); - - const osMessageQueueAttr_t sysQueueAttributes = { - .name = "sysCanSysOut", - .attr_bits = 0, - .cb_mem = &canBusSysQueueCB, - .cb_size = sizeof(canBusSysQueueCB), - .mq_mem = &canBusSysQueueBuffer, - .mq_size = sizeof(canBusSysQueueBuffer) - }; - - canBusSysQueueHandle = osMessageQueueNew(queueLength, sizeof(CanSysMsg), &sysQueueAttributes); - STA_ASSERT_MSG(canBusSysQueueHandle != nullptr, "System CAN system message queue initialization failed"); - - - // Get initialized CAN controller from application - canBusController = getCanController(); - } - - - void notifyCanBus(uint32_t flags) - { - // Send flags to thread - osThreadFlagsSet(canBusTaskHandle, flags); - } - - - bool queueCanBusMsg(const CanDataMsg & msg, uint32_t timeout) - { - STA_ASSERT((msg.header.sid & STA_CAN_SID_SYS_BITS) == 0); - STA_ASSERT(msg.header.payloadLength <= sizeof(msg.payload)); - - if (osOK == osMessageQueuePut(canBusDataQueueHandle, &msg, 0, timeout)) - { - // Signal thread - osThreadFlagsSet(canBusTaskHandle, STA_RTOS_CAN_FLAG_DATA_QUEUED); - return true; - } - else - { - return false; - } - } - - bool queueCanBusMsg(const CanSysMsg & msg, uint32_t timeout) - { - STA_ASSERT((msg.header.sid & ~STA_CAN_SID_SYS_BITS) == 0); - - if (osOK == osMessageQueuePut(canBusSysQueueHandle, &msg, 0, timeout)) - { - // Signal thread - osThreadFlagsSet(canBusTaskHandle, STA_RTOS_CAN_FLAG_SYS_QUEUED); - return true; - } - else - { - return false; - } - } - - - bool getCanBusMsg(CanDataMsg * msg, uint32_t timeout) - { - return (osOK == osMessageQueueGet(canBusDataQueueHandle, msg, 0, timeout)); - } - - bool getCanBusMsg(CanSysMsg * msg, uint32_t timeout) - { - return (osOK == osMessageQueueGet(canBusSysQueueHandle, msg, 0, timeout)); - } - } // namespace rtos -} // namespace sta - - namespace debug { /** @@ -188,146 +58,11 @@ namespace debug } } // namespace debug - -namespace dummy -{ - void handleSysMessage(const sta::CanRxHeader & header, const uint8_t * payload) - { - // Write frame payload to DebugSerial - STA_DEBUG_PRINTLN("[event] RX sys frame"); - - debug::printFrameID(header.id); - debug::printPayloadHex(payload, header.payloadLength); - - // TODO Forward message to other threads - } - - void handleDataMessage(const sta::IsotpMessage & msg) - { - STA_ASSERT(msg.buffer != nullptr); - STA_ASSERT(msg.size != 0); - - STA_DEBUG_PRINTLN("[event] RX data message"); - - debug::printFrameID(msg.frameID); - - // TODO Forward message to other threads - -// if (buffer[0] == DEMO_BMP_PACKET_ID) -// { -// BmpPacket packet; -// if (unpack(buffer + 1, size - 1, &packet)) -// { -// STA_DEBUG_PRINTLN(); -// STA_DEBUG_PRINTLN("# ############"); -// STA_DEBUG_PRINTLN("# ## BMP380 ##"); -// STA_DEBUG_PRINTLN("# ############"); -// STA_DEBUG_PRINTLN("#"); -// -// STA_DEBUG_PRINT("# temperature: "); -// STA_DEBUG_PRINT(packet.temperature); -// STA_DEBUG_PRINTLN(" *C"); -// STA_DEBUG_PRINT("# pressure: "); -// STA_DEBUG_PRINT(packet.pressure); -// STA_DEBUG_PRINTLN(" Pa"); -// STA_DEBUG_PRINT("# altitude: "); -// STA_DEBUG_PRINT(packet.altitude); -// STA_DEBUG_PRINTLN(" m"); -// STA_DEBUG_PRINTLN(); -// } -// else -// { -// STA_DEBUG_PRINTLN("[error] BMP unpack failed"); -// } -// } -// else - { - STA_DEBUG_PRINT("ID: "); - STA_DEBUG_PRINTLN(msg.buffer[0], sta::IntegerBase::HEX); - STA_DEBUG_PRINT("size: "); - STA_DEBUG_PRINTLN(msg.size); - } - } -} // namespace dummy - - - namespace sta { - class AlpakaCanBus + AlpakaCanBus::AlpakaCanBus(CanController * controller, TimeMsFn timeMs) + : controller_{controller} { - public: - using SysMsgHandler = void (*)(const CanRxHeader &, const uint8_t *); - using DataMsgHandler = void (*)(const IsotpMessage &); - - static const uint8_t FIFO_SYS = 0; - static const uint8_t FIFO_DATA = 1; - - public: - AlpakaCanBus(CanController * controller, TimeMsFn timeMs, SysMsgHandler sysMsgHandler, DataMsgHandler dataMsgHandler); - - - /** - * @brief Send system message. - * - * @param msg Message - */ - void send(const CanSysMsg & msg); - - /** - * @brief Send data message. - * - * @param msg Message - */ - void send(const CanDataMsg & msg); - - - /** - * @brief Process transmissions. - * - * Call regularly to advance transmission. - */ - void processTx(); - - /** - * @brief Process received CAN messages. - */ - void processRx(); - - /** - * @brief Display ISOTP TX/RX statistics. - */ - void showStatistics(); - - private: - /** - * @brief Configure CAN filters. - */ - void setupSubscriptions(); - - /** - * @brief Handle received data message CAN frames. - * - * @param header CAN frame header - * @param payload Payload buffer - */ - void receiveDataFrame(const CanRxHeader & header, const uint8_t * payload); - - private: - CanController * controller_; - IsotpTransmitter tx_; - IsotpReceiver rx_; - SysMsgHandler handleSysMsg_; - DataMsgHandler handleDataMsg_; - }; - - - AlpakaCanBus::AlpakaCanBus(CanController * controller, TimeMsFn timeMs, SysMsgHandler sysMsgHandler, DataMsgHandler dataMsgHandler) - : controller_{controller}, tx_{controller, timeMs}, rx_{controller, timeMs}, handleSysMsg_{sysMsgHandler}, handleDataMsg_{dataMsgHandler} - { - STA_ASSERT(handleSysMsg_ != nullptr); - STA_ASSERT(handleDataMsg_ != nullptr); - setupSubscriptions(); } @@ -336,98 +71,13 @@ namespace sta { CanTxHeader header; header.id.format = static_cast(msg.header.format); - header.id.sid = msg.header.sid & STA_CAN_SID_SYS_BITS; + header.id.sid = msg.header.sid; header.id.eid = msg.header.eid; header.payloadLength = msg.header.payloadLength; controller_->sendFrame(header, msg.payload); } - void AlpakaCanBus::send(const CanDataMsg & msg) - { - CanFrameId frameID; - frameID.format = static_cast(msg.header.format); - frameID.sid = msg.header.sid & ~STA_CAN_SID_SYS_BITS; - frameID.eid = msg.header.eid; - - // Start transmission via ISO-TP - tx_.send(frameID, msg.payload, msg.header.payloadLength); - } - - - inline void AlpakaCanBus::processTx() - { - tx_.process(); - } - - - void AlpakaCanBus::processRx() - { - for (auto fifo : controller_->getPendingRxFifos()) - { - CanRxHeader header; - uint8_t payload[STA_RTOS_CAN_BUS_MAX_PAYLOAD_SIZE]; - - if (controller_->receiveFrame(fifo, &header, payload)) - { -// debug::displayFrameUART(frame); - - // Forward frame to callback - switch (fifo) - { - case FIFO_SYS: - handleSysMsg_(header, payload); - break; - - case FIFO_DATA: - receiveDataFrame(header, payload); - break; - - default: - STA_ASSERT(false); - } - } - } - } - - void AlpakaCanBus::showStatistics() - { - STA_DEBUG_PRINTLN(); - STA_DEBUG_PRINTLN("# ######################"); - STA_DEBUG_PRINTLN("# ## ISOTP statistics ##"); - STA_DEBUG_PRINTLN("# ######################"); - STA_DEBUG_PRINTLN("#"); - - const auto & txStats = tx_.stats(); - STA_DEBUG_PRINTLN("# Transmitter"); - STA_DEBUG_PRINT("# messages: "); - STA_DEBUG_PRINTLN(txStats.messages); - STA_DEBUG_PRINT("# blocks: "); - STA_DEBUG_PRINTLN(txStats.blocks); - STA_DEBUG_PRINT("# frames: "); - STA_DEBUG_PRINTLN(txStats.frames); - STA_DEBUG_PRINT("# timeouts: "); - STA_DEBUG_PRINTLN(txStats.timeouts); - STA_DEBUG_PRINTLN("#"); - - const auto & rxStats = rx_.stats(); - STA_DEBUG_PRINTLN("# Receiver"); - STA_DEBUG_PRINT("# messages: "); - STA_DEBUG_PRINTLN(rxStats.messages); - STA_DEBUG_PRINT("# blocks: "); - STA_DEBUG_PRINTLN(rxStats.blocks); - STA_DEBUG_PRINT("# frames: "); - STA_DEBUG_PRINTLN(rxStats.frames); - STA_DEBUG_PRINT("# timeouts: "); - STA_DEBUG_PRINTLN(rxStats.timeouts); - STA_DEBUG_PRINT("# flow control errors: "); - STA_DEBUG_PRINTLN(rxStats.flowErrors); - STA_DEBUG_PRINT("# overflows: "); - STA_DEBUG_PRINTLN(rxStats.overflows); - STA_DEBUG_PRINTLN(); - } - - void AlpakaCanBus::setupSubscriptions() { // Make sure to receive all messages @@ -452,96 +102,6 @@ namespace sta filter.fifo = FIFO_DATA; controller_->configureFilter(FIFO_DATA, filter, true); } - - void AlpakaCanBus::receiveDataFrame(const CanRxHeader & header, const uint8_t * payload) - { - // Write frame payload to DebugSerial - STA_DEBUG_PRINTLN("[event] RX data frame"); - debug::printPayloadHex(payload, header.payloadLength); - - // Process RX frame - auto handle = rx_.processFrame(header, payload); - - if (handle != IsotpReceiver::INVALID_HANDLE) - { - // Get message if completed - IsotpMessage msg; - if (rx_.getMessage(handle, &msg)) - { - handleDataMsg_(msg); - } - - // Handle FC responses - rx_.processFC(handle); - } - - // Process TX frame - tx_.processFrame(header, payload); - } } // namespace sta - - -/** - * @brief CAN driver thread entry function. - */ -void canBusTask(void *) -{ - using namespace sta; - - STA_ASSERT_MSG(canBusController != nullptr, "System CAN bus not initialized"); - - // Setup ISO-TP transceiver - AlpakaCanBus canBus(canBusController, HAL_GetTick, dummy::handleSysMessage, dummy::handleDataMessage); - - - rtos::waitForStartupEvent(); - - while (true) - { - uint32_t flags = osThreadFlagsWait(STA_RTOS_THREAD_FLAGS_VALID_BITS, osFlagsWaitAny, 50); - - if (flags != static_cast(osErrorTimeout)) - { - STA_ASSERT_MSG((flags & osStatusReserved) == flags, "Unexpected error occurred in wait"); - - if (flags & STA_RTOS_CAN_FLAG_SYS_QUEUED) - { - // Take messages from queue until empty - CanSysMsg msg; - while (rtos::getCanBusMsg(&msg, 0)) - { - canBus.send(msg); - } - } - - if (flags & STA_RTOS_CAN_FLAG_DATA_QUEUED) - { - // Take messages from queue until empty - CanDataMsg msg; - while (rtos::getCanBusMsg(&msg, 0)) - { - canBus.send(msg); - } - } - - if (flags & STA_RTOS_CAN_FLAG_MSG_AVAIL) - { - STA_DEBUG_PRINTLN("[event] CAN INT"); - - canBus.processRx(); - } - - if (flags & STA_RTOS_CAN_FLAG_SHOW_STATS) - { - canBus.showStatistics(); - } - } - - // Process ISOTP transmissions - canBus.processTx(); - } -} - - -#endif // STA_RTOS_CAN_BUS_ENABLE +#endif // STA_CAN_BUS_ENABLE diff --git a/src/system/startup.cpp b/src/system/startup.cpp index f68decc..bbe4b03 100644 --- a/src/system/startup.cpp +++ b/src/system/startup.cpp @@ -32,9 +32,6 @@ namespace sta initWatchdog(); #endif // STA_RTOS_WATCHDOG_ENABLE -#ifdef STA_RTOS_CAN_BUS_ENABLE - initCanBus(); -#endif // STA_RTOS_CAN_BUS_ENABLE } } // namespace rtos } // namespace sta