From 525c0b23467abcc84e6ce62f7e6d34290923de0f Mon Sep 17 00:00:00 2001 From: DFlak Date: Fri, 17 Apr 2026 00:02:51 +0200 Subject: [PATCH] Update ECU firmware for CAN ISO-TP support --- firmware/console/binary/serial_can.cpp | 65 +++++----------------- firmware/console/binary/serial_can.h | 33 +++++++---- firmware/console/binary/ts_can_channel.cpp | 2 +- 3 files changed, 39 insertions(+), 61 deletions(-) diff --git a/firmware/console/binary/serial_can.cpp b/firmware/console/binary/serial_can.cpp index b2cecbe815..84a56d4010 100644 --- a/firmware/console/binary/serial_can.cpp +++ b/firmware/console/binary/serial_can.cpp @@ -38,7 +38,7 @@ static CanTsListener listener; int CanStreamerState::sendFrame( const IsoTpFrameHeader& header, const uint8_t* data, int num, can_sysinterval_t timeout) { int dlc = 8; // standard 8 bytes - CanTxMessage txmsg(CAN_ECU_SERIAL_TX_ID, dlc, CanBusIndex::Bus0, false); + CanTxMessage txmsg(this->txId, dlc, this->busIndex, false); // fill the frame data according to the CAN-TP protocol (ISO 15765-2) txmsg[0] = (uint8_t)((header.frameType & 0xf) << 4); @@ -56,9 +56,8 @@ int CanStreamerState::sendFrame( maxNumBytes = minI(header.numBytes, dlc - offset); break; case ISO_TP_FRAME_CONSECUTIVE: - txmsg[0] |= header.index & 0xf; + txmsg[0] |= (uint8_t)(header.index & 0xf); offset = 1; - // todo: is it correct? maxNumBytes = dlc - offset; break; case ISO_TP_FRAME_FLOW_CONTROL: @@ -82,7 +81,7 @@ int CanStreamerState::sendFrame( } // send the frame! - if (streamer->transmit(CAN_ANY_MAILBOX, &txmsg, timeout) == CAN_MSG_OK) { + if (streamer->transmit(this->txId, CAN_ANY_MAILBOX, &txmsg, timeout) == CAN_MSG_OK) { return numBytes; } return 0; @@ -120,36 +119,14 @@ int CanStreamerState::receiveFrame(CANRxFrame* rxmsg, uint8_t* buf, int num, can this->waitingForFrameIndex = (this->waitingForFrameIndex + 1) & 0xf; break; case ISO_TP_FRAME_FLOW_CONTROL: - // todo: currently we just ignore the FC frame + // Flow control is handled inside sendDataTimeout return 0; default: // bad frame type return 0; } -#if defined(TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME) - if (frameType == ISO_TP_FRAME_SINGLE) { - // restore the CRC on the whole packet - uint32_t crc = crc32((void*)srcBuf, numBytesAvailable); - // we need a separate buffer for crc because srcBuf may not be word-aligned for direct copy - uint8_t crcBuffer[sizeof(uint32_t)]; - *(uint32_t*)(crcBuffer) = SWAP_UINT32(crc); - - // now set the packet size - *(uint16_t*)tmpRxBuf = SWAP_UINT16(numBytesAvailable); - // copy the data - if (numBytesAvailable > 0) { - memcpy(tmpRxBuf + sizeof(uint16_t), srcBuf, numBytesAvailable); - } - // copy the crc to the end - memcpy(tmpRxBuf + sizeof(uint16_t) + numBytesAvailable, crcBuffer, sizeof(crcBuffer)); - // 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 */ int numBytesToCopy = minI(num, numBytesAvailable); if (buf != nullptr) { @@ -214,9 +191,7 @@ int CanStreamerState::sendDataTimeout(const uint8_t* txbuf, int numBytes, can_sy CANRxFrame rxmsg; for (int numFcReceived = 0;; numFcReceived++) { if (streamer->receive(CAN_ANY_MAILBOX, &rxmsg, timeout) != CAN_MSG_OK) { -#ifdef SERIAL_CAN_DEBUG - PRINT("*** ERROR: CAN Flow Control frame not received" PRINT_EOL); -#endif /* SERIAL_CAN_DEBUG */ + // warning(ObdCode::CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control frame not received"); return 0; } @@ -228,21 +203,14 @@ int CanStreamerState::sendDataTimeout(const uint8_t* txbuf, int numBytes, can_sy 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(ObdCode::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(ObdCode::CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control fields not supported"); - } + (void)blockSize; + (void)minSeparationTime; break; } #endif /* EFI_UNIT_TEST */ @@ -359,12 +327,7 @@ can_msg_t CanStreamerState::streamReceiveTimeout(size_t* np, uint8_t* rxbuf, can } *np -= availableBufferSpace; -#ifdef SERIAL_CAN_DEBUG - efiPrintf("* ret: %d %d (%d)", i, *np, availableBufferSpace); - for (int j = 0; j < i; j++) { - efiPrintf("* [%d]: %02x", j, rxbuf[j]); - } -#endif /* SERIAL_CAN_DEBUG */ + return CAN_MSG_OK; } @@ -387,11 +350,12 @@ void CanTsListener::decodeFrame(const CANRxFrame& frame, efitick_t /*nowNt*/) { #if HAL_USE_CAN -void CanStreamer::init() { +void CanStreamer::init(uint32_t rxId) { + listener.init(rxId); registerCanListener(listener); } -can_msg_t CanStreamer::transmit(canmbx_t /*mailbox*/, const CanTxMessage* /*ctfp*/, can_sysinterval_t /*timeout*/) { +can_msg_t CanStreamer::transmit(uint32_t /*eid*/, canmbx_t /*mailbox*/, const CanTxMessage* /*ctfp*/, can_sysinterval_t /*timeout*/) { // we do nothing here - see CanTxMessage::~CanTxMessage() return CAN_MSG_OK; } @@ -406,8 +370,9 @@ can_msg_t CanStreamer::receive(canmbx_t /*mailbox*/, CANRxFrame* crfp, can_sysin return CAN_MSG_TIMEOUT; } -void canStreamInit(void) { - streamer.init(); +void canStreamInit(uint32_t rxId, uint32_t txId, CanBusIndex busIndex) { + streamer.init(rxId); + state.init(txId, busIndex); } msg_t canStreamAddToTxTimeout(size_t* np, const uint8_t* txbuf, sysinterval_t timeout) { diff --git a/firmware/console/binary/serial_can.h b/firmware/console/binary/serial_can.h index 2c80148a24..4d83d3f971 100644 --- a/firmware/console/binary/serial_can.h +++ b/firmware/console/binary/serial_can.h @@ -55,7 +55,7 @@ class IsoTpFrameHeader { // 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 transmit(uint32_t eid, 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; }; @@ -64,20 +64,24 @@ class CanStreamerState { fifo_buffer rxFifoBuf; fifo_buffer txFifoBuf; -#if defined(TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME) - // used to restore the original packet with CRC - uint8_t tmpRxBuf[13]; -#endif + // used for multi-frame ISO-TP packets int waitingForNumBytes = 0; int waitingForFrameIndex = 0; ICanStreamer* streamer; + uint32_t txId; + CanBusIndex busIndex; public: CanStreamerState(ICanStreamer* s) - : streamer(s) {} + : streamer(s), txId(0), busIndex(CanBusIndex::Bus0) {} + + void init(uint32_t txIdValue, CanBusIndex busIndexValue) { + this->txId = txIdValue; + this->busIndex = busIndexValue; + } 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); @@ -111,7 +115,15 @@ class CanRxMessage { class CanTsListener : public CanListener { public: CanTsListener() - : CanListener(CAN_ECU_SERIAL_RX_ID) {} + : CanListener(0) {} + + void init(uint32_t idValue) { + m_id = idValue; + } + + bool acceptFrame(CanBusIndex /*busIndex*/, const CANRxFrame& frame) const override { + return CAN_ID(frame) == m_id; + } void decodeFrame(const CANRxFrame& frame, efitick_t nowNt) override; @@ -120,19 +132,20 @@ class CanTsListener : public CanListener { } protected: + uint32_t m_id = 0; fifo_buffer_sync rxFifo; }; #if HAL_USE_CAN class CanStreamer : public ICanStreamer { public: - void init(); + void init(uint32_t rxId); - virtual can_msg_t transmit(canmbx_t mailbox, const CanTxMessage* ctfp, can_sysinterval_t timeout) override; + virtual can_msg_t transmit(uint32_t eid, 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); +void canStreamInit(uint32_t rxId, uint32_t txId, CanBusIndex busIndex); // we don't have canStreamSendTimeout() because we need to "bufferize" the stream and send it in fixed-length packets msg_t canStreamAddToTxTimeout(size_t* np, const uint8_t* txbuf, sysinterval_t timeout); diff --git a/firmware/console/binary/ts_can_channel.cpp b/firmware/console/binary/ts_can_channel.cpp index 5c6960baac..40253e11be 100644 --- a/firmware/console/binary/ts_can_channel.cpp +++ b/firmware/console/binary/ts_can_channel.cpp @@ -101,7 +101,7 @@ static CanTsThread canTsThread; void startCanConsole() { canTsThread.startThread(); - canStreamInit(); + canStreamInit(CAN_ECU_SERIAL_RX_ID, CAN_ECU_SERIAL_TX_ID, CanBusIndex::Bus0); } #endif // EFI_CAN_SERIAL