CAN update
This commit is contained in:
parent
63a24ceda8
commit
c6fa50d196
|
@ -12,44 +12,47 @@
|
||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "os_access.h"
|
#include "os_access.h"
|
||||||
|
#include "crc.h"
|
||||||
|
|
||||||
|
#if HAL_USE_CAN
|
||||||
|
|
||||||
#include "serial_can.h"
|
#include "serial_can.h"
|
||||||
|
#include "can.h"
|
||||||
|
#include "can_msg_tx.h"
|
||||||
|
|
||||||
|
static CanStreamer streamer;
|
||||||
|
static CanStreamerState state(&streamer);
|
||||||
|
static CanTsListener listener;
|
||||||
|
|
||||||
static CanStreamerState state;
|
int CanStreamerState::sendFrame(const IsoTpFrameHeader & header, const uint8_t *data, int num, can_sysinterval_t timeout) {
|
||||||
|
int dlc = 8; // standard 8 bytes
|
||||||
int CanStreamerState::sendFrame(CANDriver *canp, const IsoTpFrameHeader & header, const uint8_t *data, int num) {
|
CanTxMessage txmsg(CAN_SERIAL_TX_ID, dlc, false);
|
||||||
CANTxFrame txmsg;
|
|
||||||
memset(&txmsg, 0, sizeof(txmsg));
|
|
||||||
txmsg.IDE = CAN_IDE_STD;
|
|
||||||
txmsg.EID = CAN_TX_ID;
|
|
||||||
txmsg.RTR = CAN_RTR_DATA;
|
|
||||||
txmsg.DLC = 8; // 8 bytes
|
|
||||||
|
|
||||||
// fill the frame data according to the CAN-TP protocol (ISO 15765-2)
|
// fill the frame data according to the CAN-TP protocol (ISO 15765-2)
|
||||||
txmsg.data8[0] = (uint8_t)((header.frameType & 0xf) << 4);
|
txmsg[0] = (uint8_t)((header.frameType & 0xf) << 4);
|
||||||
int offset, maxNumBytes;
|
int offset, maxNumBytes;
|
||||||
switch (header.frameType) {
|
switch (header.frameType) {
|
||||||
case ISO_TP_FRAME_SINGLE:
|
case ISO_TP_FRAME_SINGLE:
|
||||||
offset = 1;
|
offset = 1;
|
||||||
maxNumBytes = minI(header.numBytes, txmsg.DLC - offset);
|
maxNumBytes = minI(header.numBytes, dlc - offset);
|
||||||
txmsg.data8[0] |= maxNumBytes;
|
txmsg[0] |= maxNumBytes;
|
||||||
break;
|
break;
|
||||||
case ISO_TP_FRAME_FIRST:
|
case ISO_TP_FRAME_FIRST:
|
||||||
txmsg.data8[0] |= (header.numBytes >> 8) & 0xf;
|
txmsg[0] |= (header.numBytes >> 8) & 0xf;
|
||||||
txmsg.data8[1] = (uint8_t)(header.numBytes & 0xff);
|
txmsg[1] = (uint8_t)(header.numBytes & 0xff);
|
||||||
offset = 2;
|
offset = 2;
|
||||||
maxNumBytes = minI(header.numBytes, txmsg.DLC - offset);
|
maxNumBytes = minI(header.numBytes, dlc - offset);
|
||||||
break;
|
break;
|
||||||
case ISO_TP_FRAME_CONSECUTIVE:
|
case ISO_TP_FRAME_CONSECUTIVE:
|
||||||
txmsg.data8[0] |= header.index & 0xf;
|
txmsg[0] |= header.index & 0xf;
|
||||||
offset = 1;
|
offset = 1;
|
||||||
maxNumBytes = txmsg.DLC - offset;
|
// todo: is it correct?
|
||||||
|
maxNumBytes = dlc - offset;
|
||||||
break;
|
break;
|
||||||
case ISO_TP_FRAME_FLOW_CONTROL:
|
case ISO_TP_FRAME_FLOW_CONTROL:
|
||||||
txmsg.data8[0] |= header.fcFlag & 0xf;
|
txmsg[0] |= header.fcFlag & 0xf;
|
||||||
txmsg.data8[1] = (uint8_t)(header.blockSize);
|
txmsg[1] = (uint8_t)(header.blockSize);
|
||||||
txmsg.data8[2] = (uint8_t)(header.separationTime);
|
txmsg[2] = (uint8_t)(header.separationTime);
|
||||||
offset = 3;
|
offset = 3;
|
||||||
maxNumBytes = 0; // no data is sent with 'flow control' frame
|
maxNumBytes = 0; // no data is sent with 'flow control' frame
|
||||||
break;
|
break;
|
||||||
|
@ -59,18 +62,18 @@ int CanStreamerState::sendFrame(CANDriver *canp, const IsoTpFrameHeader & header
|
||||||
// copy the contents
|
// copy the contents
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
for (int i = 0; i < numBytes; i++) {
|
for (int i = 0; i < numBytes; i++) {
|
||||||
txmsg.data8[i + offset] = data[i];
|
txmsg[i + offset] = data[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the frame!
|
// send the frame!
|
||||||
if (canTransmit(&CAND1, CAN_ANY_MAILBOX, &txmsg, TIME_MS2I(100)) == MSG_OK)
|
if (streamer->transmit(CAN_ANY_MAILBOX, &txmsg, timeout) == CAN_MSG_OK)
|
||||||
return numBytes;
|
return numBytes;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the number of copied bytes
|
// returns the number of copied bytes
|
||||||
int CanStreamerState::receiveFrame(CANDriver *canp, CANRxFrame *rxmsg, uint8_t *buf, int num) {
|
int CanStreamerState::receiveFrame(CANRxFrame *rxmsg, uint8_t *buf, int num, can_sysinterval_t timeout) {
|
||||||
if (rxmsg == nullptr || rxmsg->DLC < 1)
|
if (rxmsg == nullptr || rxmsg->DLC < 1)
|
||||||
return 0;
|
return 0;
|
||||||
int frameType = (rxmsg->data8[0] >> 4) & 0xf;
|
int frameType = (rxmsg->data8[0] >> 4) & 0xf;
|
||||||
|
@ -105,21 +108,24 @@ int CanStreamerState::receiveFrame(CANDriver *canp, CANRxFrame *rxmsg, uint8_t *
|
||||||
|
|
||||||
#if defined(TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME)
|
#if defined(TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME)
|
||||||
if (frameType == ISO_TP_FRAME_SINGLE) {
|
if (frameType == ISO_TP_FRAME_SINGLE) {
|
||||||
srcBuf = state.tmpRxBuf;
|
|
||||||
// restore the CRC on the whole packet
|
// restore the CRC on the whole packet
|
||||||
uint32_t crc = crc32((void *) (rxmsg->data + 1), numBytesAvailable);
|
uint32_t crc = crc32((void *) srcBuf, numBytesAvailable);
|
||||||
// we need a separate buffer for crc because srcBuf may not be word-aligned for direct copy
|
// we need a separate buffer for crc because srcBuf may not be word-aligned for direct copy
|
||||||
uint8_t crcBuffer[sizeof(uint32_t)];
|
uint8_t crcBuffer[sizeof(uint32_t)];
|
||||||
*(uint32_t *) (crcBuffer) = SWAP_UINT32(crc);
|
*(uint32_t *) (crcBuffer) = SWAP_UINT32(crc);
|
||||||
|
|
||||||
// now set the packet size (including the command byte)
|
// now set the packet size
|
||||||
*(uint16_t *) srcBuf = SWAP_UINT16(numBytesAvailable);
|
*(uint16_t *) tmpRxBuf = SWAP_UINT16(numBytesAvailable);
|
||||||
// copy the data
|
// copy the data
|
||||||
if (numBytesAvailable > 0)
|
if (numBytesAvailable > 0)
|
||||||
memcpy(srcBuf + 2, rxmsg->data8 + 1, numBytesAvailable);
|
memcpy(tmpRxBuf + sizeof(uint16_t), srcBuf, numBytesAvailable);
|
||||||
// copy the crc
|
// copy the crc to the end
|
||||||
memcpy(srcBuf + 2 + numBytesAvailable, crcBuffer, sizeof(crcBuffer));
|
memcpy(tmpRxBuf + sizeof(uint16_t) + numBytesAvailable, crcBuffer, sizeof(crcBuffer));
|
||||||
numBytesAvailable += 1 + sizeof(crcBuffer); // added command & crc bytes
|
|
||||||
|
// use the reconstructed tmp buffer as a source buffer
|
||||||
|
srcBuf = tmpRxBuf;
|
||||||
|
// we added the 16-bit size & 32-bit crc bytes
|
||||||
|
numBytesAvailable += sizeof(uint16_t) + sizeof(crcBuffer);
|
||||||
}
|
}
|
||||||
#endif /* TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME */
|
#endif /* TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME */
|
||||||
|
|
||||||
|
@ -142,39 +148,71 @@ int CanStreamerState::receiveFrame(CANDriver *canp, CANRxFrame *rxmsg, uint8_t *
|
||||||
header.fcFlag = 0; // = "continue to send"
|
header.fcFlag = 0; // = "continue to send"
|
||||||
header.blockSize = 0; // = the remaining "frames" to be sent without flow control or delay
|
header.blockSize = 0; // = the remaining "frames" to be sent without flow control or delay
|
||||||
header.separationTime = 0; // = wait 0 milliseconds, send immediately
|
header.separationTime = 0; // = wait 0 milliseconds, send immediately
|
||||||
sendFrame(canp, header, nullptr, 0);
|
sendFrame(header, nullptr, 0, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return numBytesToCopy;
|
return numBytesToCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CanStreamerState::sendDataTimeout(CANDriver *canp, const uint8_t *txbuf, int numBytes, sysinterval_t timeout) {
|
int CanStreamerState::sendDataTimeout(const uint8_t *txbuf, int numBytes, can_sysinterval_t timeout) {
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
msg_t ret;
|
|
||||||
|
if (numBytes < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// 1 frame
|
// 1 frame
|
||||||
if (numBytes <= 7) {
|
if (numBytes <= 7) {
|
||||||
IsoTpFrameHeader header;
|
IsoTpFrameHeader header;
|
||||||
header.frameType = ISO_TP_FRAME_SINGLE;
|
header.frameType = ISO_TP_FRAME_SINGLE;
|
||||||
header.numBytes = numBytes;
|
header.numBytes = numBytes;
|
||||||
return state.sendFrame(canp, header, txbuf, numBytes);
|
return sendFrame(header, txbuf, numBytes, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiple frames
|
// multiple frames
|
||||||
|
|
||||||
// send the first header frame
|
// send the first header frame (FF)
|
||||||
IsoTpFrameHeader header;
|
IsoTpFrameHeader header;
|
||||||
header.frameType = ISO_TP_FRAME_FIRST;
|
header.frameType = ISO_TP_FRAME_FIRST;
|
||||||
header.numBytes = numBytes;
|
header.numBytes = numBytes;
|
||||||
int numSent = state.sendFrame(canp, header, txbuf + offset, numBytes);
|
int numSent = sendFrame(header, txbuf + offset, numBytes, timeout);
|
||||||
offset += numSent;
|
offset += numSent;
|
||||||
numBytes -= numSent;
|
numBytes -= numSent;
|
||||||
int totalNumSent = numSent;
|
int totalNumSent = numSent;
|
||||||
|
|
||||||
// get a flow control frame
|
// get a flow control (FC) frame
|
||||||
CANRxFrame rxmsg;
|
CANRxFrame rxmsg;
|
||||||
if (canReceive(&CAND1, CAN_ANY_MAILBOX, &rxmsg, timeout) == MSG_OK) {
|
for (int numFcReceived = 0; ; numFcReceived++) {
|
||||||
state.receiveFrame(canp, &rxmsg, nullptr, 0);
|
if (streamer->receive(CAN_ANY_MAILBOX, &rxmsg, timeout) != CAN_MSG_OK) {
|
||||||
|
#ifdef SERIAL_CAN_DEBUG
|
||||||
|
efiPrintf("*** ERROR: CAN Flow Control frame not received");
|
||||||
|
#endif /* SERIAL_CAN_DEBUG */
|
||||||
|
//warning(CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control frame not received");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
receiveFrame(&rxmsg, nullptr, 0, timeout);
|
||||||
|
int flowStatus = rxmsg.data8[0] & 0xf;
|
||||||
|
// if something is not ok
|
||||||
|
if (flowStatus != CAN_FLOW_STATUS_OK) {
|
||||||
|
// if the receiver is not ready yet and asks to wait for the next FC frame (give it 3 attempts)
|
||||||
|
if (flowStatus == CAN_FLOW_STATUS_WAIT_MORE && numFcReceived < 3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifdef SERIAL_CAN_DEBUG
|
||||||
|
efiPrintf("*** ERROR: CAN Flow Control mode not supported");
|
||||||
|
#endif /* SERIAL_CAN_DEBUG */
|
||||||
|
//warning(CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control mode not supported");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int blockSize = rxmsg.data8[1];
|
||||||
|
int minSeparationTime = rxmsg.data8[2];
|
||||||
|
if (blockSize != 0 || minSeparationTime != 0) {
|
||||||
|
// todo: process other Flow Control fields (see ISO 15765-2)
|
||||||
|
#ifdef SERIAL_CAN_DEBUG
|
||||||
|
efiPrintf("*** ERROR: CAN Flow Control fields not supported");
|
||||||
|
#endif /* SERIAL_CAN_DEBUG */
|
||||||
|
//warning(CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control fields not supported");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the rest of the data
|
// send the rest of the data
|
||||||
|
@ -185,8 +223,8 @@ int CanStreamerState::sendDataTimeout(CANDriver *canp, const uint8_t *txbuf, int
|
||||||
IsoTpFrameHeader header;
|
IsoTpFrameHeader header;
|
||||||
header.frameType = ISO_TP_FRAME_CONSECUTIVE;
|
header.frameType = ISO_TP_FRAME_CONSECUTIVE;
|
||||||
header.index = ((idx++) & 0x0f);
|
header.index = ((idx++) & 0x0f);
|
||||||
header.numBytes = numBytes;
|
header.numBytes = len;
|
||||||
int numSent = state.sendFrame(canp, header, txbuf + offset, numBytes);
|
int numSent = sendFrame(header, txbuf + offset, len, timeout);
|
||||||
if (numSent < 1)
|
if (numSent < 1)
|
||||||
break;
|
break;
|
||||||
totalNumSent += numSent;
|
totalNumSent += numSent;
|
||||||
|
@ -209,60 +247,111 @@ int CanStreamerState::getDataFromFifo(uint8_t *rxbuf, size_t &numBytes) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void canInit(CANDriver *canp) {
|
can_msg_t CanStreamerState::streamAddToTxTimeout(size_t *np, const uint8_t *txbuf, can_sysinterval_t timeout) {
|
||||||
chEvtRegister(&CAND1.rxfull_event, &state.el, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_t canAddToTxStreamTimeout(CANDriver *canp, size_t *np,
|
|
||||||
const uint8_t *txbuf, sysinterval_t timeout) {
|
|
||||||
int numBytes = *np;
|
int numBytes = *np;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int minNumBytesRequiredToSend = 7 - state.txFifoBuf.getCount();
|
int minNumBytesRequiredToSend = 7 - txFifoBuf.getCount();
|
||||||
while (numBytes >= minNumBytesRequiredToSend) {
|
while (numBytes >= minNumBytesRequiredToSend) {
|
||||||
state.txFifoBuf.put(txbuf + offset, minNumBytesRequiredToSend);
|
txFifoBuf.put(txbuf + offset, numBytes);
|
||||||
int numSent = state.sendDataTimeout(canp, (const uint8_t *)state.txFifoBuf.elements, state.txFifoBuf.getCount(), timeout);
|
int numSent = sendDataTimeout((const uint8_t *)txFifoBuf.getElements(), txFifoBuf.getCount(), timeout);
|
||||||
if (numSent < 1)
|
if (numSent < 1)
|
||||||
break;
|
break;
|
||||||
state.txFifoBuf.clear();
|
txFifoBuf.clear();
|
||||||
offset += numSent;
|
offset += numSent;
|
||||||
numBytes -= numSent;
|
numBytes -= numSent;
|
||||||
minNumBytesRequiredToSend = 7;
|
minNumBytesRequiredToSend = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we put the rest on hold
|
// now we put the rest on hold
|
||||||
state.txFifoBuf.put(txbuf + offset, numBytes);
|
txFifoBuf.put(txbuf + offset, numBytes);
|
||||||
|
|
||||||
return MSG_OK;
|
return CAN_MSG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_t canFlushTxStream(CANDriver *canp, sysinterval_t timeout) {
|
can_msg_t CanStreamerState::streamFlushTx(can_sysinterval_t timeout) {
|
||||||
int numSent = state.sendDataTimeout(canp, (const uint8_t *)state.txFifoBuf.elements, state.txFifoBuf.getCount(), timeout);
|
int numSent = sendDataTimeout((const uint8_t *)txFifoBuf.getElements(), txFifoBuf.getCount(), timeout);
|
||||||
state.txFifoBuf.clear();
|
if (numSent != txFifoBuf.getCount()) {
|
||||||
|
//warning(CUSTOM_ERR_CAN_COMMUNICATION, "CAN sendDataTimeout() problems");
|
||||||
|
}
|
||||||
|
txFifoBuf.clear();
|
||||||
|
|
||||||
return MSG_OK;
|
return CAN_MSG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_t canStreamReceiveTimeout(CANDriver *canp, size_t *np,
|
can_msg_t CanStreamerState::streamReceiveTimeout(size_t *np, uint8_t *rxbuf, can_sysinterval_t timeout) {
|
||||||
uint8_t *rxbuf, sysinterval_t timeout) {
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
size_t numBytes = *np;
|
size_t numBytes = *np;
|
||||||
|
|
||||||
// first, fill the data from the stored buffer (saved from the previous CAN frame)
|
// first, fill the data from the stored buffer (saved from the previous CAN frame)
|
||||||
i = state.getDataFromFifo(rxbuf, numBytes);
|
i = getDataFromFifo(rxbuf, numBytes);
|
||||||
|
|
||||||
// if even more data is needed, then we receive more CAN frames
|
// if even more data is needed, then we receive more CAN frames
|
||||||
while (numBytes > 0) {
|
while (numBytes > 0) {
|
||||||
if (chEvtWaitAnyTimeout(ALL_EVENTS, timeout) == 0)
|
|
||||||
return MSG_TIMEOUT;
|
|
||||||
CANRxFrame rxmsg;
|
CANRxFrame rxmsg;
|
||||||
if (canReceive(&CAND1, CAN_ANY_MAILBOX, &rxmsg, TIME_IMMEDIATE) == MSG_OK) {
|
if (streamer->receive(CAN_ANY_MAILBOX, &rxmsg, timeout) == CAN_MSG_OK) {
|
||||||
int numReceived = state.receiveFrame(canp, &rxmsg, rxbuf + i, numBytes);
|
int numReceived = receiveFrame(&rxmsg, rxbuf + i, numBytes, timeout);
|
||||||
|
|
||||||
if (numReceived < 1)
|
if (numReceived < 1)
|
||||||
break;
|
break;
|
||||||
numBytes -= numReceived;
|
numBytes -= numReceived;
|
||||||
|
i += numReceived;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//*np -= numBytes;
|
*np -= numBytes;
|
||||||
return MSG_OK;
|
|
||||||
|
#ifdef SERIAL_CAN_DEBUG
|
||||||
|
efiPrintf("* ret: %d %d (%d)", i, *np, numBytes);
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
efiPrintf("* [%d]: %02x", j, rxbuf[j]);
|
||||||
|
}
|
||||||
|
#endif /* SERIAL_CAN_DEBUG */
|
||||||
|
|
||||||
|
return CAN_MSG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CanTsListener::decodeFrame(const CANRxFrame& frame, efitick_t /*nowNt*/) {
|
||||||
|
// todo: what if the FIFO is full?
|
||||||
|
CanRxMessage msg(frame);
|
||||||
|
if (!rxFifo.put(msg)) {
|
||||||
|
//warning(CUSTOM_ERR_CAN_COMMUNICATION, "CAN sendDataTimeout() problems");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanStreamer::init() {
|
||||||
|
registerCanListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
can_msg_t CanStreamer::transmit(canmbx_t /*mailbox*/, const CanTxMessage */*ctfp*/, can_sysinterval_t /*timeout*/) {
|
||||||
|
// we do nothing here - see CanTxMessage::~CanTxMessage()
|
||||||
|
return CAN_MSG_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
can_msg_t CanStreamer::receive(canmbx_t /*mailbox*/, CANRxFrame *crfp, can_sysinterval_t timeout) {
|
||||||
|
// see CanTsListener and processCanRxMessage()
|
||||||
|
CanRxMessage msg;
|
||||||
|
if (listener.get(msg, timeout)) {
|
||||||
|
*crfp = msg.frame;
|
||||||
|
return CAN_MSG_OK;
|
||||||
|
}
|
||||||
|
return CAN_MSG_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void canStreamInit(void) {
|
||||||
|
streamer.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_t canStreamAddToTxTimeout(size_t *np, const uint8_t *txbuf, sysinterval_t timeout) {
|
||||||
|
return state.streamAddToTxTimeout(np, txbuf, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_t canStreamFlushTx(sysinterval_t timeout) {
|
||||||
|
return state.streamFlushTx(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_t canStreamReceiveTimeout(size_t *np, uint8_t *rxbuf, sysinterval_t timeout) {
|
||||||
|
return state.streamReceiveTimeout(np, rxbuf, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAL_USE_CAN */
|
||||||
|
|
|
@ -9,8 +9,32 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "fifo_buffer.h"
|
#include "fifo_buffer.h"
|
||||||
|
#include "can_listener.h"
|
||||||
|
#include "can_msg_tx.h"
|
||||||
|
|
||||||
|
#if !EFI_UNIT_TEST
|
||||||
|
#define can_msg_t msg_t
|
||||||
|
#define can_sysinterval_t sysinterval_t
|
||||||
|
#define CAN_MSG_OK MSG_OK
|
||||||
|
#define CAN_MSG_TIMEOUT MSG_TIMEOUT
|
||||||
|
#else
|
||||||
|
#include "can_mocks.h"
|
||||||
|
#endif /* EFI_UNIT_TEST */
|
||||||
|
|
||||||
|
|
||||||
|
#define CAN_TIME_IMMEDIATE ((can_sysinterval_t)0)
|
||||||
|
|
||||||
|
#define CAN_FIFO_BUF_SIZE 64
|
||||||
|
#define CAN_FIFO_FRAME_SIZE 8
|
||||||
|
|
||||||
|
// todo: find a better place for these defs
|
||||||
|
#define CAN_SERIAL_RX_ID 0x100
|
||||||
|
#define CAN_SERIAL_TX_ID 0x102
|
||||||
|
|
||||||
|
#define CAN_FLOW_STATUS_OK 0
|
||||||
|
#define CAN_FLOW_STATUS_WAIT_MORE 1
|
||||||
|
#define CAN_FLOW_STATUS_ABORT 2
|
||||||
|
|
||||||
#define CAN_TX_ID 0x102
|
|
||||||
|
|
||||||
enum IsoTpFrameType {
|
enum IsoTpFrameType {
|
||||||
ISO_TP_FRAME_SINGLE = 0,
|
ISO_TP_FRAME_SINGLE = 0,
|
||||||
|
@ -33,10 +57,17 @@ public:
|
||||||
int separationTime;
|
int separationTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// We need an abstraction layer for unit-testing
|
||||||
|
class ICanStreamer {
|
||||||
|
public:
|
||||||
|
virtual can_msg_t transmit(canmbx_t mailbox, const CanTxMessage *ctfp, can_sysinterval_t timeout) = 0;
|
||||||
|
virtual can_msg_t receive(canmbx_t mailbox, CANRxFrame *crfp, can_sysinterval_t timeout) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class CanStreamerState {
|
class CanStreamerState {
|
||||||
public:
|
public:
|
||||||
fifo_buffer<uint8_t, 64> rxFifoBuf;
|
fifo_buffer<uint8_t, CAN_FIFO_BUF_SIZE> rxFifoBuf;
|
||||||
fifo_buffer<uint8_t, 64> txFifoBuf;
|
fifo_buffer<uint8_t, CAN_FIFO_BUF_SIZE> txFifoBuf;
|
||||||
|
|
||||||
#if defined(TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME)
|
#if defined(TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME)
|
||||||
// used to restore the original packet with CRC
|
// used to restore the original packet with CRC
|
||||||
|
@ -47,21 +78,70 @@ public:
|
||||||
int waitingForNumBytes = 0;
|
int waitingForNumBytes = 0;
|
||||||
int waitingForFrameIndex = 0;
|
int waitingForFrameIndex = 0;
|
||||||
|
|
||||||
event_listener_t el;
|
ICanStreamer *streamer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int sendFrame(CANDriver *canp, const IsoTpFrameHeader & header, const uint8_t *data, int num);
|
CanStreamerState(ICanStreamer *s) : streamer(s) {}
|
||||||
int receiveFrame(CANDriver *canp, CANRxFrame *rxmsg, uint8_t *buf, int num);
|
|
||||||
|
int sendFrame(const IsoTpFrameHeader & header, const uint8_t *data, int num, can_sysinterval_t timeout);
|
||||||
|
int receiveFrame(CANRxFrame *rxmsg, uint8_t *buf, int num, can_sysinterval_t timeout);
|
||||||
int getDataFromFifo(uint8_t *rxbuf, size_t &numBytes);
|
int getDataFromFifo(uint8_t *rxbuf, size_t &numBytes);
|
||||||
// returns the number of bytes sent
|
// returns the number of bytes sent
|
||||||
int sendDataTimeout(CANDriver *canp, const uint8_t *txbuf, int numBytes, sysinterval_t timeout);
|
int sendDataTimeout(const uint8_t *txbuf, int numBytes, can_sysinterval_t timeout);
|
||||||
|
|
||||||
|
// streaming support for TS I/O (see tunerstudio_io.cpp)
|
||||||
|
can_msg_t streamAddToTxTimeout(size_t *np, const uint8_t *txbuf, can_sysinterval_t timeout);
|
||||||
|
can_msg_t streamFlushTx(can_sysinterval_t timeout);
|
||||||
|
can_msg_t streamReceiveTimeout(size_t *np, uint8_t *rxbuf, can_sysinterval_t timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
void canInit(CANDriver *canp);
|
class CanRxMessage {
|
||||||
|
public:
|
||||||
|
CanRxMessage() {}
|
||||||
|
CanRxMessage(const CANRxFrame &f) {
|
||||||
|
frame = f;
|
||||||
|
}
|
||||||
|
CanRxMessage(const CanRxMessage& msg) : frame(msg.frame) {}
|
||||||
|
CanRxMessage& operator=(const CanRxMessage& msg) {
|
||||||
|
frame = msg.frame;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
CANRxFrame frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CanTsListener : public CanListener {
|
||||||
|
public:
|
||||||
|
CanTsListener()
|
||||||
|
: CanListener(CAN_SERIAL_RX_ID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void decodeFrame(const CANRxFrame& frame, efitick_t nowNt);
|
||||||
|
|
||||||
|
bool get(CanRxMessage &item, int timeout) {
|
||||||
|
return rxFifo.get(item, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
fifo_buffer_sync<CanRxMessage, CAN_FIFO_FRAME_SIZE> rxFifo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if HAL_USE_CAN
|
||||||
|
class CanStreamer : public ICanStreamer {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
|
||||||
|
virtual can_msg_t transmit(canmbx_t mailbox, const CanTxMessage *ctfp, can_sysinterval_t timeout) override;
|
||||||
|
virtual can_msg_t receive(canmbx_t mailbox, CANRxFrame *crfp, can_sysinterval_t timeout) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
void canStreamInit(void);
|
||||||
|
|
||||||
// we don't have canStreamSendTimeout() because we need to "bufferize" the stream and send it in fixed-length packets
|
// we don't have canStreamSendTimeout() because we need to "bufferize" the stream and send it in fixed-length packets
|
||||||
msg_t canAddToTxStreamTimeout(CANDriver *canp, size_t *np, const uint8_t *txbuf, sysinterval_t timeout);
|
msg_t canStreamAddToTxTimeout(size_t *np, const uint8_t *txbuf, sysinterval_t timeout);
|
||||||
msg_t canFlushTxStream(CANDriver *canp, sysinterval_t timeout);
|
msg_t canStreamFlushTx(sysinterval_t timeout);
|
||||||
|
|
||||||
msg_t canStreamReceiveTimeout(CANDriver *canp, size_t *np, uint8_t *rxbuf, sysinterval_t timeout);
|
|
||||||
|
|
||||||
|
msg_t canStreamReceiveTimeout(size_t *np, uint8_t *rxbuf, sysinterval_t timeout);
|
||||||
|
#endif /* HAL_USE_CAN */
|
||||||
|
|
|
@ -1,41 +1,57 @@
|
||||||
// TODO: @andreika-git finish this implementation
|
/**
|
||||||
|
* @file This file implements CAN-to-TS bridge.
|
||||||
|
*
|
||||||
|
* @date Apr 24, 2021
|
||||||
|
* @author andreika <prometheus.pcb@gmail.com>
|
||||||
|
* @author Andrey Belomutskiy, (c) 2012-2021
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
#include "tunerstudio.h"
|
||||||
#include "tunerstudio_io.h"
|
#include "tunerstudio_io.h"
|
||||||
|
|
||||||
#ifdef TS_CAN_DEVICE
|
#ifdef EFI_CAN_SERIAL
|
||||||
#include "serial_can.h"
|
#include "serial_can.h"
|
||||||
|
#include "can_hw.h"
|
||||||
|
|
||||||
|
#if !EFI_CAN_SUPPORT
|
||||||
|
#error "EFI_CAN_SERIAL requires EFI_CAN_SUPPORT"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class CanTsChannel : public TsChannelBase {
|
class CanTsChannel : public TsChannelBase {
|
||||||
|
public:
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
// TsChannelBase implementation
|
// TsChannelBase implementation
|
||||||
void write(const uint8_t* buffer, size_t size) override;
|
void write(const uint8_t* buffer, size_t size) override;
|
||||||
size_t readTimeout(uint8_t* buffer, size_t size, int timeout) override;
|
size_t readTimeout(uint8_t* buffer, size_t size, int timeout) override;
|
||||||
void flush() override;
|
void flush() override;
|
||||||
bool isReady() override;
|
bool isReady() const override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
// Special override for writeCrcPacket for small packets
|
// Special override for writeCrcPacket for small packets
|
||||||
void writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size) override;
|
void writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static CANConfig tsCanConfig = { CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP, CAN_BTR_500 };
|
|
||||||
|
|
||||||
void CanTsChannel::start() {
|
void CanTsChannel::start() {
|
||||||
efiSetPadMode("ts can rx", GPIOG_13/*engineConfiguration->canRxPin*/, PAL_MODE_ALTERNATE(TS_CAN_AF)); // CAN2_RX2_0
|
if (!getIsCanEnabled()) {
|
||||||
efiSetPadMode("ts can tx", GPIOG_14/*engineConfiguration->canTxPin*/, PAL_MODE_ALTERNATE(TS_CAN_AF)); // CAN2_TX2_0
|
warning(CUSTOM_ERR_CAN_CONFIGURATION, "CAN not enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
canStart(&TS_CAN_DEVICE, &tsCanConfig);
|
if (!CONFIG(canReadEnabled) || !CONFIG(canWriteEnabled)) {
|
||||||
canInit(&TS_CAN_DEVICE);
|
warning(CUSTOM_ERR_CAN_CONFIGURATION, "CAN read or write not enabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanTsChannel::stop() {
|
void CanTsChannel::stop() {
|
||||||
canStop(&TS_CAN_DEVICE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanTsChannel::writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size) {
|
void CanTsChannel::writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size) {
|
||||||
#ifdef TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME
|
#ifdef TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME
|
||||||
// a special case for short packets: we can sent them in 1 frame, without CRC & size,
|
// a special case for short packets: we can send them in 1 frame, without CRC & size,
|
||||||
// because the CAN protocol is already protected by its own checksum.
|
// because the CAN protocol is already protected by its own checksum.
|
||||||
if ((size + 1) <= 7) {
|
if ((size + 1) <= 7) {
|
||||||
write(&responseCode, 1); // header without size
|
write(&responseCode, 1); // header without size
|
||||||
|
@ -45,28 +61,48 @@ void CanTsChannel::writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size
|
||||||
flush();
|
flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif /* TS_CAN_DEVICE */
|
#endif /* TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME */
|
||||||
|
|
||||||
// Packet too large, use default implementation
|
// Packet too large, use default implementation
|
||||||
TsChannelBase::writeCrcPacket(responseCode, buf, size);
|
TsChannelBase::writeCrcPacket(responseCode, buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanTsChannel::write(const uint8_t* buffer, size_t size) {
|
void CanTsChannel::write(const uint8_t* buffer, size_t size) {
|
||||||
canAddToTxStreamTimeout(&TS_CAN_DEVICE, &size, buffer, BINARY_IO_TIMEOUT);
|
canStreamAddToTxTimeout(&size, buffer, BINARY_IO_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CanTsChannel::readTimeout(uint8_t* buffer, size_t size, int timeout) {
|
size_t CanTsChannel::readTimeout(uint8_t* buffer, size_t size, int timeout) {
|
||||||
canStreamReceiveTimeout(&TS_CAN_DEVICE, &size, buffer, timeout);
|
canStreamReceiveTimeout(&size, buffer, timeout);
|
||||||
|
//!!!!!!!!!!!!!
|
||||||
|
efiPrintf("--RT: %d %02x", size, (size > 0 ? buffer[0] : 0));
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanTsChannel::flush() {
|
void CanTsChannel::flush() {
|
||||||
canFlushTxStream(&TS_CAN_DEVICE);
|
canStreamFlushTx(BINARY_IO_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanTsChannel::isReady() {
|
bool CanTsChannel::isReady() const {
|
||||||
// this channel is always ready
|
// this channel is always ready
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // def TS_CAN_DEVICE
|
static CanTsChannel canChannel;
|
||||||
|
|
||||||
|
struct CanTsThread : public TunerstudioThread {
|
||||||
|
CanTsThread() : TunerstudioThread("CAN TS Channel") { }
|
||||||
|
|
||||||
|
TsChannelBase* setupChannel() override {
|
||||||
|
canChannel.start();
|
||||||
|
return &canChannel;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static CanTsThread canTsThread;
|
||||||
|
|
||||||
|
void startCanConsole() {
|
||||||
|
canTsThread.Start();
|
||||||
|
canStreamInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // def EFI_CAN_SERIAL
|
||||||
|
|
|
@ -3,6 +3,7 @@ TUNERSTUDIO_SRC_CPP = $(PROJECT_DIR)/console/binary/tunerstudio_io.cpp \
|
||||||
$(PROJECT_DIR)/console/binary/tunerstudio_io_serial.cpp \
|
$(PROJECT_DIR)/console/binary/tunerstudio_io_serial.cpp \
|
||||||
$(PROJECT_DIR)/console/binary/tunerstudio_io_serial_ports.cpp \
|
$(PROJECT_DIR)/console/binary/tunerstudio_io_serial_ports.cpp \
|
||||||
$(PROJECT_DIR)/console/binary/ts_can_channel.cpp \
|
$(PROJECT_DIR)/console/binary/ts_can_channel.cpp \
|
||||||
|
$(PROJECT_DIR)/console/binary/serial_can.cpp \
|
||||||
$(PROJECT_DIR)/console/binary/tunerstudio.cpp \
|
$(PROJECT_DIR)/console/binary/tunerstudio.cpp \
|
||||||
$(PROJECT_DIR)/console/binary/tunerstudio_commands.cpp \
|
$(PROJECT_DIR)/console/binary/tunerstudio_commands.cpp \
|
||||||
$(PROJECT_DIR)/console/binary/bluetooth.cpp \
|
$(PROJECT_DIR)/console/binary/bluetooth.cpp \
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
// Base functions that use the above virtual implementation
|
// Base functions that use the above virtual implementation
|
||||||
size_t read(uint8_t* buffer, size_t size);
|
size_t read(uint8_t* buffer, size_t size);
|
||||||
|
|
||||||
#ifdef TS_CAN_DEVICE
|
#ifdef EFI_CAN_SERIAL
|
||||||
virtual // CAN device needs this function to be virtual for small-packet optimization
|
virtual // CAN device needs this function to be virtual for small-packet optimization
|
||||||
#endif
|
#endif
|
||||||
void writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size);
|
void writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size);
|
||||||
|
@ -123,4 +123,6 @@ protected:
|
||||||
void startSerialChannels();
|
void startSerialChannels();
|
||||||
SerialTsChannelBase* getBluetoothChannel();
|
SerialTsChannelBase* getBluetoothChannel();
|
||||||
|
|
||||||
|
void startCanConsole();
|
||||||
|
|
||||||
void sendOkResponse(TsChannelBase *tsChannel, ts_response_format_e mode);
|
void sendOkResponse(TsChannelBase *tsChannel, ts_response_format_e mode);
|
||||||
|
|
|
@ -11,21 +11,21 @@
|
||||||
|
|
||||||
class CanListener {
|
class CanListener {
|
||||||
public:
|
public:
|
||||||
CanListener(uint32_t eid)
|
CanListener(uint32_t id)
|
||||||
: m_eid(eid)
|
: m_id(id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CanListener* processFrame(const CANRxFrame& frame, efitick_t nowNt) {
|
CanListener* processFrame(const CANRxFrame& frame, efitick_t nowNt) {
|
||||||
if (CAN_EID(frame) == m_eid) {
|
if (CAN_ID(frame) == m_id) {
|
||||||
decodeFrame(frame, nowNt);
|
decodeFrame(frame, nowNt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_next;
|
return m_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getEid() {
|
uint32_t getId() {
|
||||||
return m_eid;
|
return m_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setNext(CanListener* next) {
|
void setNext(CanListener* next) {
|
||||||
|
@ -41,5 +41,5 @@ protected:
|
||||||
CanListener* m_next = nullptr;
|
CanListener* m_next = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const uint32_t m_eid;
|
const uint32_t m_id;
|
||||||
};
|
};
|
||||||
|
|
|
@ -70,10 +70,8 @@ static void printPacket(const CANRxFrame &rx) {
|
||||||
// only print info if we're in can debug mode
|
// only print info if we're in can debug mode
|
||||||
|
|
||||||
// internet people use both hex and decimal to discuss packed IDs, for usability it's better to print both right here
|
// internet people use both hex and decimal to discuss packed IDs, for usability it's better to print both right here
|
||||||
efiPrintf("CAN_rx %x %d %x %x %x %x %x %x %x %x %x",
|
efiPrintf("CAN_rx %x(%d) %d: %02x %02x %02x %02x %02x %02x %02x %02x", CAN_SID(rx),
|
||||||
CAN_SID(rx),
|
CAN_SID(rx), rx.DLC, rx.data8[0], rx.data8[1], rx.data8[2], rx.data8[3],
|
||||||
CAN_SID(rx), rx.DLC,
|
|
||||||
rx.data8[0], rx.data8[1], rx.data8[2], rx.data8[3],
|
|
||||||
rx.data8[4], rx.data8[5], rx.data8[6], rx.data8[7]);
|
rx.data8[4], rx.data8[5], rx.data8[6], rx.data8[7]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,9 @@ void CanWrite::PeriodicTask(efitime_t nowNt) {
|
||||||
cycleCount = 0;
|
cycleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_CAN_UPDATE_DASH
|
||||||
updateDash(cycle);
|
updateDash(cycle);
|
||||||
|
#endif /* DISABLE_CAN_UPDATE_DASH */
|
||||||
|
|
||||||
if (engineConfiguration->enableAemXSeries && cycle.isInterval(CI::_50ms)) {
|
if (engineConfiguration->enableAemXSeries && cycle.isInterval(CI::_50ms)) {
|
||||||
sendWidebandInfo();
|
sendWidebandInfo();
|
||||||
|
|
|
@ -234,13 +234,15 @@ void startCanPins() {
|
||||||
void initCan(void) {
|
void initCan(void) {
|
||||||
addConsoleAction("caninfo", canInfo);
|
addConsoleAction("caninfo", canInfo);
|
||||||
|
|
||||||
isCanEnabled =
|
isCanEnabled = false;
|
||||||
|
|
||||||
|
bool isCanConfigGood =
|
||||||
(isBrainPinValid(engineConfiguration->canTxPin)) && // both pins are set...
|
(isBrainPinValid(engineConfiguration->canTxPin)) && // both pins are set...
|
||||||
(isBrainPinValid(engineConfiguration->canRxPin)) &&
|
(isBrainPinValid(engineConfiguration->canRxPin)) &&
|
||||||
(engineConfiguration->canWriteEnabled || engineConfiguration->canReadEnabled) ; // ...and either read or write is enabled
|
(engineConfiguration->canWriteEnabled || engineConfiguration->canReadEnabled) ; // ...and either read or write is enabled
|
||||||
|
|
||||||
// nothing to do if we aren't enabled...
|
// nothing to do if we aren't enabled...
|
||||||
if (!isCanEnabled) {
|
if (!isCanConfigGood) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +286,12 @@ void initCan(void) {
|
||||||
if (engineConfiguration->canReadEnabled) {
|
if (engineConfiguration->canReadEnabled) {
|
||||||
canRead.Start();
|
canRead.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isCanEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getIsCanEnabled(void) {
|
||||||
|
return isCanEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* EFI_CAN_SUPPORT */
|
#endif /* EFI_CAN_SUPPORT */
|
||||||
|
|
|
@ -17,6 +17,7 @@ void setCanVss(int type);
|
||||||
void stopCanPins();
|
void stopCanPins();
|
||||||
void startCanPins();
|
void startCanPins();
|
||||||
void enableFrankensoCan();
|
void enableFrankensoCan();
|
||||||
|
bool getIsCanEnabled(void);
|
||||||
#if EFI_TUNER_STUDIO
|
#if EFI_TUNER_STUDIO
|
||||||
void postCanState(TunerStudioOutputChannels *tsOutputChannels);
|
void postCanState(TunerStudioOutputChannels *tsOutputChannels);
|
||||||
#endif /* EFI_TUNER_STUDIO */
|
#endif /* EFI_TUNER_STUDIO */
|
||||||
|
|
|
@ -243,6 +243,11 @@ void runRusEfiWithConfig() {
|
||||||
initMmcCard();
|
initMmcCard();
|
||||||
#endif /* EFI_FILE_LOGGING */
|
#endif /* EFI_FILE_LOGGING */
|
||||||
|
|
||||||
|
#if EFI_CAN_SERIAL
|
||||||
|
// needs to be called after initCan() inside initHardware()
|
||||||
|
startCanConsole();
|
||||||
|
#endif /* EFI_CAN_SERIAL */
|
||||||
|
|
||||||
#if HW_CHECK_ALWAYS_STIMULATE
|
#if HW_CHECK_ALWAYS_STIMULATE
|
||||||
// we need a special binary for final assembly check. We cannot afford to require too much software or too many steps
|
// we need a special binary for final assembly check. We cannot afford to require too much software or too many steps
|
||||||
// to be executed at the place of assembly
|
// to be executed at the place of assembly
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,7 @@ TESTS_SRC_CPP = \
|
||||||
tests/test_gpio.cpp \
|
tests/test_gpio.cpp \
|
||||||
tests/test_limp.cpp \
|
tests/test_limp.cpp \
|
||||||
tests/trigger/test_all_triggers.cpp \
|
tests/trigger/test_all_triggers.cpp \
|
||||||
|
tests/test_can_serial.cpp \
|
||||||
tests/test_stepper.cpp \
|
tests/test_stepper.cpp \
|
||||||
tests/sensor/test_frequency_sensor.cpp \
|
tests/sensor/test_frequency_sensor.cpp \
|
||||||
tests/sensor/test_turbocharger_speed_converter.cpp \
|
tests/sensor/test_turbocharger_speed_converter.cpp \
|
||||||
|
|
Loading…
Reference in New Issue