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 <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2020-03-18 19:07:41 -07:00 committed by GitHub
parent e605b39ab1
commit 194bf2e0bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 165 additions and 17 deletions

View File

@ -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

View File

@ -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));

View File

@ -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

View File

@ -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 <cstdint>
#include <cstddef>
#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 <typename TData>
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<MyType> d;
* d->memberOfMyType = 23;
*/
TData* operator->() {
return reinterpret_cast<TData*>(&m_frame.data8);
}
};

View File

@ -16,4 +16,5 @@ HW_LAYER_DRIVERS = \
HW_LAYER_DRIVERS_CPP = \
$(DRIVERS_DIR)/can/can_hw.cpp \
$(DRIVERS_DIR)/can/can_msg_tx.cpp \