From 3a33e59b86a51bdad88aef99c588b34b60ca168b Mon Sep 17 00:00:00 2001 From: rusefillc Date: Wed, 8 Dec 2021 12:01:28 -0500 Subject: [PATCH] rusEFI console ISO-TP via PCAN #3667 --- firmware/console/binary/serial_can.cpp | 7 +- firmware/console/binary/serial_can.h | 2 +- firmware/controllers/can/can.h | 7 +- firmware/hw_layer/drivers/can/can_msg_tx.cpp | 13 +- firmware/hw_layer/drivers/can/can_msg_tx.h | 13 +- unit_tests/tests/test_can_serial.cpp | 175 +++++++++++++++++++ 6 files changed, 199 insertions(+), 18 deletions(-) diff --git a/firmware/console/binary/serial_can.cpp b/firmware/console/binary/serial_can.cpp index 7ace7c632d..766493aa4d 100644 --- a/firmware/console/binary/serial_can.cpp +++ b/firmware/console/binary/serial_can.cpp @@ -13,16 +13,15 @@ #include "pch.h" #include "os_access.h" #include "crc.h" - -#if HAL_USE_CAN - #include "serial_can.h" #include "can.h" #include "can_msg_tx.h" +#if HAL_USE_CAN static CanStreamer streamer; static CanStreamerState state(&streamer); static CanTsListener listener; +#endif // HAL_USE_CAN int CanStreamerState::sendFrame(const IsoTpFrameHeader & header, const uint8_t *data, int num, can_sysinterval_t timeout) { int dlc = 8; // standard 8 bytes @@ -320,6 +319,8 @@ void CanTsListener::decodeFrame(const CANRxFrame& frame, efitick_t /*nowNt*/) { } } +#if HAL_USE_CAN + void CanStreamer::init() { registerCanListener(listener); } diff --git a/firmware/console/binary/serial_can.h b/firmware/console/binary/serial_can.h index e4adcb0bad..7c5ef3e81b 100644 --- a/firmware/console/binary/serial_can.h +++ b/firmware/console/binary/serial_can.h @@ -12,7 +12,7 @@ #include "can_listener.h" #include "can_msg_tx.h" -#if !EFI_UNIT_TEST +#if EFI_PROD_CODE #define can_msg_t msg_t #define can_sysinterval_t sysinterval_t #define CAN_MSG_OK MSG_OK diff --git a/firmware/controllers/can/can.h b/firmware/controllers/can/can.h index e3f5a3c303..028c74f4de 100644 --- a/firmware/controllers/can/can.h +++ b/firmware/controllers/can/can.h @@ -7,9 +7,12 @@ #pragma once -#if EFI_UNIT_TEST +#if ! EFI_PROD_CODE #include "can_mocks.h" -#else +#endif // EFI_PROD_CODE + + +#if !EFI_UNIT_TEST #include "hal.h" #endif // EFI_UNIT_TEST diff --git a/firmware/hw_layer/drivers/can/can_msg_tx.cpp b/firmware/hw_layer/drivers/can/can_msg_tx.cpp index d929b4500b..cb544a9bd6 100644 --- a/firmware/hw_layer/drivers/can/can_msg_tx.cpp +++ b/firmware/hw_layer/drivers/can/can_msg_tx.cpp @@ -78,10 +78,6 @@ void CanTxMessage::setDlc(uint8_t dlc) { m_frame.DLC = dlc; } -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; @@ -101,10 +97,11 @@ CanTxMessage::~CanTxMessage() { } -uint8_t& CanTxMessage::operator[](size_t index) { - return m_data8[index]; -} - void CanTxMessage::setDlc(uint8_t) { } #endif // EFI_CAN_SUPPORT + +uint8_t& CanTxMessage::operator[](size_t index) { + return m_frame.data8[index]; +} + diff --git a/firmware/hw_layer/drivers/can/can_msg_tx.h b/firmware/hw_layer/drivers/can/can_msg_tx.h index 3422d0b042..350cdd8059 100644 --- a/firmware/hw_layer/drivers/can/can_msg_tx.h +++ b/firmware/hw_layer/drivers/can/can_msg_tx.h @@ -13,6 +13,7 @@ #include #include "os_access.h" +#include "can.h" /** * Represent a message to be transmitted over CAN. @@ -58,12 +59,16 @@ public: void setDlc(uint8_t dlc); +//#if ! EFI_SIMULATOR + const CANTxFrame *getFrame() const { + return &m_frame; + } +//#endif // EFI_SIMULATOR + protected: -#if EFI_CAN_SUPPORT +//#if ! EFI_SIMULATOR CANTxFrame m_frame; -#else // not EFI_CAN_SUPPORT - uint8_t m_data8[8]; -#endif // EFI_CAN_SUPPORT +//#endif // EFI_SIMULATOR private: #if EFI_CAN_SUPPORT diff --git a/unit_tests/tests/test_can_serial.cpp b/unit_tests/tests/test_can_serial.cpp index b28b04f643..d03c298ab1 100644 --- a/unit_tests/tests/test_can_serial.cpp +++ b/unit_tests/tests/test_can_serial.cpp @@ -1,3 +1,178 @@ +/* + * @file test_can_serial.cpp + * + * Created on: Nov 26, 2020 + * @author andreika + * @author Andrey Belomutskiy, (c) 2012-2020 + */ + +#include +#include + +#include "pch.h" +#include "engine_test_helper.h" +#include "serial_can.h" + + +using namespace std::string_literals; + +class TestCanStreamer : public ICanStreamer { +public: + virtual can_msg_t transmit(canmbx_t mailbox, const CanTxMessage *ctfp, can_sysinterval_t timeout) override { + const CANTxFrame * frame = ctfp->getFrame(); + // invoke copy constructor to clone frame + CANTxFrame localCopy = *frame; + localCopy.DLC = 8; + ctfList.emplace_back(localCopy); + return CAN_MSG_OK; + } + + virtual can_msg_t receive(canmbx_t mailbox, CANRxFrame *crfp, can_sysinterval_t timeout) override { + *crfp = *crfList.begin(); + crfList.pop_front(); + return CAN_MSG_OK; + } + + template + void checkFrame(const T & frame, const std::string & bytes) { + EXPECT_EQ(bytes.size(), frame.DLC); + for (size_t i = 0; i < bytes.size(); i++) { + EXPECT_EQ(bytes[i], frame.data8[i]) << "Frame byte #" << i << " differs!"; + } + } + +public: + std::list ctfList; + std::list crfList; +}; + +class TestCanStreamerState : public CanStreamerState { +public: + TestCanStreamerState() : CanStreamerState(&streamer) {} + + void test(const std::vector & dataList, const std::vector & frames, int fifoLeftoverSize, const std::vector & receiveChunks) { + size_t totalSize = 0; + std::string totalData; + for (auto data : dataList) { + size_t np = data.size(); + + totalSize += np; + totalData += data; + + streamAddToTxTimeout(&np, (uint8_t *)data.c_str(), 0); + } + + // check the FIFO buf size + EXPECT_EQ(fifoLeftoverSize, txFifoBuf.getCount()); + + // send the rest + streamFlushTx(0); + + // check if correct the TX frames were sent + EXPECT_EQ(frames.size(), streamer.ctfList.size()); + + auto it1 = streamer.ctfList.begin(); + auto it2 = frames.begin(); + for (; it1 != streamer.ctfList.end() && it2 != frames.end(); it1++, it2++) { + streamer.checkFrame(*it1, *it2); + } + + // copy transmitted data back into the receive buffer + for (auto f : streamer.ctfList) { + CANRxFrame rf; + rf.DLC = f.DLC; + rf.RTR = f.RTR; + rf.IDE = f.IDE; + rf.EID = f.EID; + rf.data64[0] = f.data64[0]; + streamer.crfList.push_back(rf); + } + + size_t totalReceivedSize = 0; + std::string totalReceivedData; + for (size_t chunkSize : receiveChunks) { + size_t nr = chunkSize; + uint8_t rxbuf[256]; + streamReceiveTimeout(&nr, rxbuf, 0); + EXPECT_EQ(nr, chunkSize); + totalReceivedSize += nr; + totalReceivedData += std::string((const char *)rxbuf, nr); + } + // we should receive the same amount of bytes that we've sent + EXPECT_EQ(totalSize, totalReceivedSize); + // check the data + for (size_t i = 0; i < totalSize; i++) { + EXPECT_EQ(totalData[i], totalReceivedData[i]) << "Rcv. byte #" << i << " differs!"; + } + } + +protected: + TestCanStreamer streamer; +}; + +TEST(testCanSerial, test1Frame) { + /* + { + TestCanStreamerState state; + state.test({ "1" }, { "\x01"s "1\0\0\0\0\0\0"s }, 1, { 1 }); // 1 byte -> 1 frame, 1 byte in FIFO + } + { + TestCanStreamerState state; + state.test({ "0123456" }, { "\x07"s "0123456"s }, 0, { 7 }); // 7 bytes -> 1 8-byte frame + } + { + TestCanStreamerState state; + state.test({ "0123456" }, { "\x07"s "0123456"s }, 0, { 1, 1, 1, 1, 1, 1, 1 }); // 7 bytes -> 1 8-byte frame, split receive test + } + { + TestCanStreamerState state; + state.test({ "0123456" }, { "\x07"s "0123456"s }, 0, { 3, 4 }); // 7 bytes -> 1 8-byte frame, split receive test + } + { + TestCanStreamerState state; + state.test({ "0", "1", "2", "3", "4", "5", "6" }, { "\x07"s "0123456"s }, 0, { 7 }); // 7 bytes separately -> 1 8-byte frame + } +*/ +} + +/* +TEST(testCanSerial, test2Frames) { + { + TestCanStreamerState state; + state.test({ "01234567" }, { "\x07"s "0123456"s, "\x01"s "7\0\0\0\0\0\0"s }, 1, { 8 }); // 8 bytes -> 2 8-byte frames, 1 byte in FIFO + } + { + TestCanStreamerState state; + state.test({ "0123456ABCDEFG" }, { "\x07"s "0123456"s, "\x07"s "ABCDEFG"s }, 0, { 14 }); // 14 bytes -> 2 8-byte frames, empty FIFO + } + { + TestCanStreamerState state; + state.test({ "0123456ABCDEFG" }, { "\x07"s "0123456"s, "\x07"s "ABCDEFG"s }, 0, { 6, 1, 1, 6 }); // 14 bytes -> 2 8-byte frames, empty FIFO, split receive test + } +} + +TEST(testCanSerial, testIrregularSplits) { + { + TestCanStreamerState state; + state.test({ "012", "3456ABCDEFG" }, { "\x07"s "0123456"s, "\x07"s "ABCDEFG"s }, 0, { 7, 7 }); // 14 bytes -> 2 8-byte frames, empty FIFO + } + { + TestCanStreamerState state; + state.test({ "0123456ABC", "DEFG" }, { "\x07"s "0123456"s, "\x07"s "ABCDEFG"s }, 0, { 14 }); // 14 bytes -> 2 8-byte frames, empty FIFO + } +} + +TEST(testCanSerial, testLongMessage) { + { + TestCanStreamerState state; + state.test({ "abcdefghijklmnopqrstuvwxyz" }, { + "\x07"s "abcdefg"s, + "\x07"s "hijklmn"s, + "\x07"s "opqrstu"s, + "\x05"s "vwxyz\0\0"s }, 5, { 26 }); // 26 bytes -> 4 8-byte frames, 5 bytes left in FIFO + } +} +*/