From 1b4d98a7f04367f700ae4713d34fd768d22ae455 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Wed, 18 Mar 2020 19:07:41 -0700 Subject: [PATCH] Add new CanTxMessage class, consume in OBD2 (#1186) * relocate * include path * simulator makefile * fix mre while we're at it * it would help if I fixed it right * add can_msg * convert obd2 * guard properly * better include order * docs & headers * inject CAN device Co-authored-by: Matthew Kennedy --- firmware/controllers/obd2.cpp | 32 ++++---- firmware/hw_layer/drivers/can/can_hw.cpp | 7 ++ firmware/hw_layer/drivers/can/can_msg_tx.cpp | 56 +++++++++++++ firmware/hw_layer/drivers/can/can_msg_tx.h | 86 ++++++++++++++++++++ firmware/hw_layer/drivers/drivers.mk | 1 + 5 files changed, 165 insertions(+), 17 deletions(-) create mode 100644 firmware/hw_layer/drivers/can/can_msg_tx.cpp create mode 100644 firmware/hw_layer/drivers/can/can_msg_tx.h diff --git a/firmware/controllers/obd2.cpp b/firmware/controllers/obd2.cpp index bfa8a384d8..d57c92e16a 100644 --- a/firmware/controllers/obd2.cpp +++ b/firmware/controllers/obd2.cpp @@ -30,7 +30,7 @@ #include "os_access.h" #include "engine.h" #include "obd2.h" -#include "can_hw.h" +#include "can_msg_tx.h" #include "vehicle_speed.h" #include "map.h" #include "maf.h" @@ -39,8 +39,6 @@ #include "fuel_math.h" #include "thermistors.h" -extern CANTxFrame txmsg; - EXTERN_ENGINE ; @@ -70,19 +68,17 @@ static const int16_t supportedPids4160[] = { }; static void obdSendPacket(int mode, int PID, int numBytes, uint32_t iValue) { - commonTxInit(OBD_TEST_RESPONSE); + CanTxMessage resp(OBD_TEST_RESPONSE); // write number of bytes - txmsg.data8[0] = (uint8_t)(2 + numBytes); + resp[0] = (uint8_t)(2 + numBytes); // write 2 bytes of header - txmsg.data8[1] = (uint8_t)(0x40 + mode); - txmsg.data8[2] = (uint8_t)PID; + resp[1] = (uint8_t)(0x40 + mode); + resp[2] = (uint8_t)PID; // write N data bytes for (int i = 8 * (numBytes - 1), j = 3; i >= 0; i -= 8, j++) { - txmsg.data8[j] = (uint8_t)((iValue >> i) & 0xff); + resp[j] = (uint8_t)((iValue >> i) & 0xff); } - - sendCanMessage(); } static void obdSendValue(int mode, int PID, int numBytes, float value) { @@ -185,13 +181,15 @@ static void handleGetDataRequest(CANRxFrame *rx) { } static void handleDtcRequest(int numCodes, int *dtcCode) { - int numBytes = numCodes * 2; - // write CAN-TP Single Frame header? - txmsg.data8[0] = (uint8_t)((0 << 4) | numBytes); - for (int i = 0, j = 1; i < numCodes; i++) { - txmsg.data8[j++] = (uint8_t)((dtcCode[i] >> 8) & 0xff); - txmsg.data8[j++] = (uint8_t)(dtcCode[i] & 0xff); - } + // TODO: this appears to be unfinished? + + // int numBytes = numCodes * 2; + // // write CAN-TP Single Frame header? + // txmsg.data8[0] = (uint8_t)((0 << 4) | numBytes); + // for (int i = 0, j = 1; i < numCodes; i++) { + // txmsg.data8[j++] = (uint8_t)((dtcCode[i] >> 8) & 0xff); + // txmsg.data8[j++] = (uint8_t)(dtcCode[i] & 0xff); + // } } #if HAL_USE_CAN diff --git a/firmware/hw_layer/drivers/can/can_hw.cpp b/firmware/hw_layer/drivers/can/can_hw.cpp index adf89a200e..1a5972d381 100644 --- a/firmware/hw_layer/drivers/can/can_hw.cpp +++ b/firmware/hw_layer/drivers/can/can_hw.cpp @@ -17,6 +17,7 @@ #include "periodic_thread_controller.h" #include "pin_repository.h" #include "can_hw.h" +#include "can_msg_tx.h" #include "string.h" #include "obd2.h" #include "mpu_util.h" @@ -369,6 +370,12 @@ void initCan(void) { canStart(&CAND1, &canConfig500); #endif /* STM32_CAN_USE_CAN2 */ + // Plumb CAN device to tx system + CanTxMessage::setDevice(detectCanDevice( + CONFIG(canRxPin), + CONFIG(canTxPin) + )); + // fire up threads, as necessary if (CONFIG(canWriteEnabled)) { canWrite.setPeriod(CONFIG(canSleepPeriodMs)); diff --git a/firmware/hw_layer/drivers/can/can_msg_tx.cpp b/firmware/hw_layer/drivers/can/can_msg_tx.cpp new file mode 100644 index 0000000000..a316f2f9ff --- /dev/null +++ b/firmware/hw_layer/drivers/can/can_msg_tx.cpp @@ -0,0 +1,56 @@ +/** + * @file can_msg_tx.cpp + * + * CAN message transmission + * + * @date Mar 13, 2020 + * @author Matthew Kennedy, (c) 2012-2020 + */ + +#include "efifeatures.h" +#include "global.h" + +#if EFI_CAN_SUPPORT +#include "can_msg_tx.h" + + +/*static*/ CANDriver* CanTxMessage::s_device = nullptr; + +/*static*/ void CanTxMessage::setDevice(CANDriver* device) { + s_device = device; +} + +CanTxMessage::CanTxMessage(uint32_t eid) { + m_frame.IDE = CAN_IDE_STD; + m_frame.EID = eid; + m_frame.RTR = CAN_RTR_DATA; + m_frame.DLC = 8; + memset(m_frame.data8, 0, sizeof(m_frame.data8)); +} + +CanTxMessage::~CanTxMessage() { + auto device = s_device; + + if (!device) { + warning(CUSTOM_ERR_CAN_CONFIGURATION, "CAN configuration issue"); + return; + } + + // 100 ms timeout + canTransmit(device, CAN_ANY_MAILBOX, &m_frame, TIME_MS2I(100)); +} + +uint8_t& CanTxMessage::operator[](size_t index) { + return m_frame.data8[index]; +} + +void CanTxMessage::setShortValue(uint16_t value, size_t offset) { + m_frame.data8[offset] = value & 0xFF; + m_frame.data8[offset + 1] = value >> 8; +} + +void CanTxMessage::setBit(size_t byteIdx, size_t bitIdx) { + m_frame.data8[byteIdx] |= 1 << bitIdx; +} + +#endif // EFI_CAN_SUPPORT diff --git a/firmware/hw_layer/drivers/can/can_msg_tx.h b/firmware/hw_layer/drivers/can/can_msg_tx.h new file mode 100644 index 0000000000..15e30b37d9 --- /dev/null +++ b/firmware/hw_layer/drivers/can/can_msg_tx.h @@ -0,0 +1,86 @@ +/** + * @file can_msg_tx.h + * + * CAN message transmission + * + * @date Mar 13, 2020 + * @author Matthew Kennedy, (c) 2012-2020 + */ + +#pragma once + +#include +#include + +#include "os_access.h" + +/** + * Represent a message to be transmitted over CAN. + * + * Usage: + * * Create an instance of CanTxMessage + * * Set any data you'd like to transmit either using the subscript operator to directly access bytes, or any of the helper functions. + * * Upon destruction, the message is transmitted. + */ +class CanTxMessage +{ +public: + /** + * Create a new CAN message, with the specified extended ID. + */ + CanTxMessage(uint32_t eid); + + /** + * Destruction of an instance of CanTxMessage will transmit the message over the wire. + */ + ~CanTxMessage(); + + /** + * Configures the device for all messages to transmit from. + */ + static void setDevice(CANDriver* device); + + /** + * @brief Read & write the raw underlying 8-byte buffer. + */ + uint8_t& operator[](size_t); + + /** + * @brief Write a 16-bit short value to the buffer. Note: this writes in big endian byte order. + */ + void setShortValue(uint16_t value, size_t offset); + + /** + * @brief Set a single bit in the transmit buffer. Useful for single-bit flags. + */ + void setBit(size_t byteIdx, size_t bitIdx); + +protected: + CANTxFrame m_frame; + +private: + static CANDriver* s_device; +}; + +/** + * A CAN message based on a type, removing the need for manually flipping bits/bytes. + */ +template +class CanTxTyped final : public CanTxMessage +{ + static_assert(sizeof(TData) == sizeof(CANTxFrame::data8)); + +public: + CanTxTyped(uint32_t eid) : CanTxMessage(eid) { } + + /** + * Access members of the templated type. + * + * So you can do: + * CanTxTyped d; + * d->memberOfMyType = 23; + */ + TData* operator->() { + return reinterpret_cast(&m_frame.data8); + } +}; diff --git a/firmware/hw_layer/drivers/drivers.mk b/firmware/hw_layer/drivers/drivers.mk index adbae36569..19d4b8235e 100644 --- a/firmware/hw_layer/drivers/drivers.mk +++ b/firmware/hw_layer/drivers/drivers.mk @@ -16,4 +16,5 @@ HW_LAYER_DRIVERS = \ HW_LAYER_DRIVERS_CPP = \ $(DRIVERS_DIR)/can/can_hw.cpp \ + $(DRIVERS_DIR)/can/can_msg_tx.cpp \