From 2c80b8cf196b792615719f4a0683950e3393f936 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 3 Jul 2022 05:25:24 -0700 Subject: [PATCH] implement CAN driver for simulator (#4312) * stub simulator CAN driver * comments * CAN sensor * maybe implement? * s * fix * tx and rx actually work!?!?! * check_can_isr * modify chibios * Sim has no CAN on Windows (for now?) * safer init/deinit, enable assertions * smarter handling of missing CAN device * better guards * guards for windows --- firmware/ChibiOS | 2 +- firmware/config/engines/custom_engine.cpp | 4 - firmware/config/engines/honda_600.cpp | 4 - firmware/console/binary/serial_can.h | 2 +- firmware/controllers/can/can.h | 2 +- firmware/controllers/can/can_tx.cpp | 2 + firmware/controllers/can/can_verbose.cpp | 3 + firmware/hw_layer/drivers/can/can_hw.cpp | 15 +- firmware/hw_layer/drivers/can/can_hw.h | 2 +- firmware/init/sensor/init_can_sensors.cpp | 4 +- firmware/init/sensor/init_sensors.cpp | 2 +- simulator/Makefile | 6 +- simulator/chconf.h | 4 +- simulator/halconf.h | 2 +- simulator/simulator/can/hal_can_lld.cpp | 303 +++++++++++++++++++ simulator/simulator/can/hal_can_lld.h | 194 ++++++++++++ simulator/simulator/efifeatures.h | 6 +- simulator/simulator/global.h | 1 + simulator/simulator/mpu_util.h | 7 + simulator/simulator/rusEfiFunctionalTest.cpp | 22 ++ 20 files changed, 566 insertions(+), 21 deletions(-) create mode 100644 simulator/simulator/can/hal_can_lld.cpp create mode 100644 simulator/simulator/can/hal_can_lld.h create mode 100644 simulator/simulator/mpu_util.h diff --git a/firmware/ChibiOS b/firmware/ChibiOS index eed346d57f..4a81e00519 160000 --- a/firmware/ChibiOS +++ b/firmware/ChibiOS @@ -1 +1 @@ -Subproject commit eed346d57f80efd78bd4130c7088066a1169d495 +Subproject commit 4a81e00519e4b592176d974c37abc6249ab5294b diff --git a/firmware/config/engines/custom_engine.cpp b/firmware/config/engines/custom_engine.cpp index 2316bdaa55..9e52c98db1 100644 --- a/firmware/config/engines/custom_engine.cpp +++ b/firmware/config/engines/custom_engine.cpp @@ -187,10 +187,6 @@ void setFrankensoConfiguration() { // todo: 8.2 or 10k? engineConfiguration->vbattDividerCoeff = ((float) (10 + 33)) / 10 * 2; - -#if EFI_CAN_SUPPORT - enableFrankensoCan(); -#endif /* EFI_CAN_SUPPORT */ } /** diff --git a/firmware/config/engines/honda_600.cpp b/firmware/config/engines/honda_600.cpp index 7090f78b89..4887430ca4 100644 --- a/firmware/config/engines/honda_600.cpp +++ b/firmware/config/engines/honda_600.cpp @@ -125,9 +125,5 @@ void setHonda600() { // todo: 8.2 or 10k? engineConfiguration->vbattDividerCoeff = ((float) (10 + 33)) / 10 * 2; - -#if EFI_CAN_SUPPORT - enableFrankensoCan(); -#endif /* EFI_CAN_SUPPORT */ } diff --git a/firmware/console/binary/serial_can.h b/firmware/console/binary/serial_can.h index 36ae34430d..64039ca14a 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_PROD_CODE +#if EFI_PROD_CODE | EFI_SIMULATOR #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 76219ca792..380ff31c57 100644 --- a/firmware/controllers/can/can.h +++ b/firmware/controllers/can/can.h @@ -7,7 +7,7 @@ #pragma once -#if !EFI_PROD_CODE || !EFI_CAN_SUPPORT +#if EFI_UNIT_TEST || !EFI_CAN_SUPPORT #include "can_mocks.h" #endif // EFI_PROD_CODE diff --git a/firmware/controllers/can/can_tx.cpp b/firmware/controllers/can/can_tx.cpp index c967d853db..f37045624e 100644 --- a/firmware/controllers/can/can_tx.cpp +++ b/firmware/controllers/can/can_tx.cpp @@ -56,9 +56,11 @@ void CanWrite::PeriodicTask(efitime_t nowNt) { updateDash(cycle); #endif /* DISABLE_CAN_UPDATE_DASH */ +#if EFI_WIDEBAND_FIRMWARE_UPDATE if (engineConfiguration->enableAemXSeries && cycle.isInterval(CI::_50ms)) { sendWidebandInfo(); } +#endif cycleCount++; } diff --git a/firmware/controllers/can/can_verbose.cpp b/firmware/controllers/can/can_verbose.cpp index a47e38dd84..3bb740ff2e 100644 --- a/firmware/controllers/can/can_verbose.cpp +++ b/firmware/controllers/can/can_verbose.cpp @@ -98,7 +98,10 @@ static void populateFrame(Sensors1& msg) { msg.aux1 = Sensor::getOrZero(SensorType::AuxTemp1) + PACK_ADD_TEMPERATURE; msg.aux2 = Sensor::getOrZero(SensorType::AuxTemp2) + PACK_ADD_TEMPERATURE; +#if HAL_USE_ADC msg.mcuTemp = getMCUInternalTemperature(); +#endif + msg.fuelLevel = Sensor::getOrZero(SensorType::FuelLevel); } diff --git a/firmware/hw_layer/drivers/can/can_hw.cpp b/firmware/hw_layer/drivers/can/can_hw.cpp index 68474a6f99..4e62a8178a 100644 --- a/firmware/hw_layer/drivers/can/can_hw.cpp +++ b/firmware/hw_layer/drivers/can/can_hw.cpp @@ -24,6 +24,8 @@ static bool isCanEnabled = false; +#if EFI_PROD_CODE + // Values below calculated with http://www.bittiming.can-wiki.info/ // Pick ST micro bxCAN // Clock rate of 42mhz for f4, 54mhz for f7, 80mhz for h7 @@ -120,6 +122,15 @@ static const CANConfig canConfig1000 = { }; #endif +#else // not EFI_PROD_CODE +// Nothing to actually set for the simulator's CAN config. +// It's impossible to set CAN bitrate from userspace, so we can't set it. +static const CANConfig canConfig100; +static const CANConfig canConfig250; +static const CANConfig canConfig500; +static const CANConfig canConfig1000; +#endif + class CanRead final : protected ThreadController { public: CanRead(size_t index) @@ -238,11 +249,13 @@ void startCanPins() { return; } +#if EFI_PROD_CODE efiSetPadModeIfConfigurationChanged("CAN TX", canTxPin, PAL_MODE_ALTERNATE(EFI_CAN_TX_AF)); efiSetPadModeIfConfigurationChanged("CAN RX", canRxPin, PAL_MODE_ALTERNATE(EFI_CAN_RX_AF)); efiSetPadModeIfConfigurationChanged("CAN2 TX", can2TxPin, PAL_MODE_ALTERNATE(EFI_CAN_TX_AF)); efiSetPadModeIfConfigurationChanged("CAN2 RX", can2RxPin, PAL_MODE_ALTERNATE(EFI_CAN_RX_AF)); +#endif // EFI_PROD_CODE } static const CANConfig * findConfig(can_baudrate_e rate) { @@ -262,7 +275,7 @@ static const CANConfig * findConfig(can_baudrate_e rate) { } } -void initCan(void) { +void initCan() { addConsoleAction("caninfo", canInfo); isCanEnabled = false; diff --git a/firmware/hw_layer/drivers/can/can_hw.h b/firmware/hw_layer/drivers/can/can_hw.h index 2c6ee89c14..8674267009 100644 --- a/firmware/hw_layer/drivers/can/can_hw.h +++ b/firmware/hw_layer/drivers/can/can_hw.h @@ -9,7 +9,7 @@ #include "efifeatures.h" -void initCan(void); +void initCan(); void setCanType(int type); void setCanVss(int type); diff --git a/firmware/init/sensor/init_can_sensors.cpp b/firmware/init/sensor/init_can_sensors.cpp index dd80ed113c..e85eac7fdd 100644 --- a/firmware/init/sensor/init_can_sensors.cpp +++ b/firmware/init/sensor/init_can_sensors.cpp @@ -7,7 +7,7 @@ #include "pch.h" -#if EFI_CAN_SUPPORT +#if EFI_PROD_CODE && EFI_CAN_SUPPORT #include "can_sensor.h" #include "can.h" @@ -50,4 +50,4 @@ void initCanSensors() { registerCanSensor(obdTpsSensor); } } -#endif // EFI_CAN_SUPPORT +#endif // EFI_PROD_CODE && EFI_CAN_SUPPORT diff --git a/firmware/init/sensor/init_sensors.cpp b/firmware/init/sensor/init_sensors.cpp index 2ab97314b9..3df43e699e 100644 --- a/firmware/init/sensor/init_sensors.cpp +++ b/firmware/init/sensor/init_sensors.cpp @@ -46,7 +46,7 @@ static void deInitOldAnalogInputs() { } void initNewSensors() { -#if EFI_CAN_SUPPORT +#if EFI_PROD_CODE && EFI_CAN_SUPPORT initCanSensors(); #endif diff --git a/simulator/Makefile b/simulator/Makefile index 4a39ff5e2a..94d563583c 100644 --- a/simulator/Makefile +++ b/simulator/Makefile @@ -46,8 +46,9 @@ ifeq ($(USE_OPT),) # USE_OPT += -O0 -g ifeq ($(OS),Windows_NT) + USE_OPT += -DEFI_SIM_IS_WINDOWS=1 else - USE_OPT += -m32 + USE_OPT += -m32 -DEFI_SIM_IS_WINDOWS=0 endif endif @@ -157,6 +158,7 @@ include $(PROJECT_DIR)/common.mk # setting. CSRC = $(ALLCSRC) \ + # C++ sources that can be compiled in ARM or THUMB mode depending on the global # setting. CPPSRC = $(ALLCPPSRC) \ @@ -167,6 +169,7 @@ CPPSRC = $(ALLCPPSRC) \ $(CONSOLE_SRC_CPP) \ $(DEV_SIMULATOR_SRC_CPP) \ simulator/rusEfiFunctionalTest.cpp \ + simulator/can/hal_can_lld.cpp \ simulator/framework.cpp \ simulator/boards.cpp \ $(TEST_SRC_CPP) \ @@ -183,6 +186,7 @@ INCDIR = . \ $(PROJECT_DIR)/hw_layer/drivers/can \ ${CHIBIOS}/os/various \ $(CHIBIOS)/os/hal/lib/streams \ + simulator/can \ simulator # List ASM source files here diff --git a/simulator/chconf.h b/simulator/chconf.h index 1482cc4b25..f344c3fbcf 100644 --- a/simulator/chconf.h +++ b/simulator/chconf.h @@ -533,7 +533,7 @@ * @note The default is @p FALSE. */ #if !defined(CH_DBG_ENABLE_CHECKS) -#define CH_DBG_ENABLE_CHECKS FALSE +#define CH_DBG_ENABLE_CHECKS TRUE #endif /** @@ -545,7 +545,7 @@ * @note The default is @p FALSE. */ #if !defined(CH_DBG_ENABLE_ASSERTS) -#define CH_DBG_ENABLE_ASSERTS FALSE +#define CH_DBG_ENABLE_ASSERTS TRUE #endif /** diff --git a/simulator/halconf.h b/simulator/halconf.h index 41050b462c..11b6acbc9b 100644 --- a/simulator/halconf.h +++ b/simulator/halconf.h @@ -58,7 +58,7 @@ * @brief Enables the CAN subsystem. */ #if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) -#define HAL_USE_CAN FALSE +#define HAL_USE_CAN !EFI_SIM_IS_WINDOWS #endif /** diff --git a/simulator/simulator/can/hal_can_lld.cpp b/simulator/simulator/can/hal_can_lld.cpp new file mode 100644 index 0000000000..a13ad49f77 --- /dev/null +++ b/simulator/simulator/can/hal_can_lld.cpp @@ -0,0 +1,303 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file hal_can_lld.c + * @brief PLATFORM CAN subsystem low level driver source. + * + * @addtogroup CAN + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_CAN == TRUE) || defined(__DOXYGEN__) + +#include +#include +#include + +#include +#include + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief CAN1 driver identifier. + */ +CANDriver CAND1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level CAN driver initialization. + * + * @notapi + */ +void can_lld_init(void) { + /* Driver initialization.*/ + canObjectInit(&CAND1); + + CAND1.sock = -1; +} + +static std::vector instances; + +/** + * @brief Configures and activates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_start(CANDriver *canp) { + (void)canp; + + // Check that this device is not already started + osalDbgCheck(canp->sock <= 0); + + // Check that a name is set + osalDbgCheck(canp->deviceName != nullptr); + + // create socket + int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW); + + if (sock < 0) { + // TODO: handle + return; + } + + sockaddr_can addr; + + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + + { + // Determine index of the CAN device with the requested name + ifreq ifr; + strcpy(ifr.ifr_name, canp->deviceName); + ioctl(sock, SIOCGIFINDEX, &ifr); + addr.can_ifindex = ifr.ifr_ifindex; + } + + if (bind(sock, (sockaddr*)&addr, sizeof(addr)) < 0) { + // TODO: handle + return; + } + + canp->sock = sock; + + // Initialize the rx queue + canp->rx = new std::queue; + + // Add this instance so it will have receive listened to by the "interrupt handler" + instances.push_back(canp); + + // TODO: can we even set bitrate from userspace? +} + +/** + * @brief Deactivates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_stop(CANDriver *canp) { + (void)canp; + + // Remove from the "interrupt handler" list + std::remove(instances.begin(), instances.end(), canp); + + // Close the socket. + close(canp->sock); + canp->sock = -1; + + // Free the rx queue + delete reinterpret_cast*>(canp->rx); +} + +/** + * @brief Determines whether a frame can be transmitted. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @return The queue space availability. + * @retval false no space in the transmit queue. + * @retval true transmit slot available. + * + * @notapi + */ +bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { + (void)canp; + (void)mailbox; + + // The queue is practically infinitely deep, so it is always safe to call can_lld_transmit. + // Therefore, just return whether or not the CAN interface actually got initialized + return canp->sock >= 0; +} + +/** + * @brief Inserts a frame into the transmit queue. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] ctfp pointer to the CAN frame to be transmitted + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @notapi + */ +void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp) { + (void)mailbox; + + can_frame frame; + + memcpy(frame.data, ctfp->data8, 8); + frame.can_dlc = ctfp->DLC; + + frame.can_id = ctfp->IDE ? ctfp->EID : ctfp->SID; + // bit 31 is 1 for extended, 0 for standard + frame.can_id |= ctfp->IDE ? (1 << 31) : 0; + + int res = write(canp->sock, &frame, sizeof(frame)); + + if (res != sizeof(frame)) { + // TODO: handle err + return; + } +} + +/** + * @brief Determines whether a frame has been received. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @return The queue space availability. + * @retval false no space in the transmit queue. + * @retval true transmit slot available. + * + * @notapi + */ +bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) { + (void)mailbox; + + // CAN init failed, claim that the queue is full. + if (canp->sock < 0) { + return false; + } + + return !reinterpret_cast*>(canp->rx)->empty(); +} + +bool check_can_isr() { + bool intOccured = false; + + for (auto canp : instances) { + can_frame frame; + + // nonblocking read so it fails instantly in case no frame is queued + int result = recv(canp->sock, &frame, sizeof(frame), MSG_DONTWAIT); + + // no frame received, nothing to do + if (result != sizeof(frame)) { + continue; + } + + intOccured = true; + + CH_IRQ_PROLOGUE(); + reinterpret_cast*>(canp->rx)->push(frame); + _can_rx_full_isr(canp, 0); + CH_IRQ_EPILOGUE(); + } + + return intOccured; +} + +/** + * @brief Receives a frame from the input queue. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * @param[out] crfp pointer to the buffer where the CAN frame is copied + * + * @notapi + */ +void can_lld_receive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *crfp) { + (void)mailbox; + + auto queue = reinterpret_cast*>(canp->rx); + + can_frame frame = queue->front(); + queue->pop(); + + crfp->DLC = frame.can_dlc; + + memcpy(crfp->data8, frame.data, crfp->DLC); + + // If <8 byte packet, pad with zeroes to avoid spilling stack state or garbage data from the returned frame + if (crfp->DLC < 8) { + memset(crfp->data8 + crfp->DLC, 0, 8 - crfp->DLC); + } + + // SID bits overlap with EID, no reason to copy both, but mask off err/rtr/etc bits + crfp->EID = CAN_ERR_MASK & frame.can_id; + + crfp->IDE = (frame.can_id & CAN_EFF_FLAG) != 0; +} + +/** + * @brief Tries to abort an ongoing transmission. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number + * + * @notapi + */ +void can_lld_abort(CANDriver *canp, + canmbx_t mailbox) { + (void)canp; + (void)mailbox; +} + +#endif /* HAL_USE_CAN == TRUE */ + +/** @} */ diff --git a/simulator/simulator/can/hal_can_lld.h b/simulator/simulator/can/hal_can_lld.h new file mode 100644 index 0000000000..a3167820bc --- /dev/null +++ b/simulator/simulator/can/hal_can_lld.h @@ -0,0 +1,194 @@ +#ifndef HAL_CAN_LLD_H +#define HAL_CAN_LLD_H + +#if HAL_USE_CAN || defined(__DOXYGEN__) + +/** + * @brief This switch defines whether the driver implementation supports + * a low power switch mode with automatic an wakeup feature. + */ +#define CAN_SUPPORTS_SLEEP FALSE + +/** + * @brief This implementation supports three transmit mailboxes. + */ +#define CAN_TX_MAILBOXES 1 + +/** + * @brief This implementation supports two receive mailboxes. + */ +#define CAN_RX_MAILBOXES 1 + +#define CAN_BTR_BRP(n) (n) /**< @brief BRP field macro.*/ +#define CAN_BTR_TS1(n) ((n) << 16) /**< @brief TS1 field macro.*/ +#define CAN_BTR_TS2(n) ((n) << 20) /**< @brief TS2 field macro.*/ +#define CAN_BTR_SJW(n) ((n) << 24) /**< @brief SJW field macro.*/ + +#define CAN_IDE_STD 0 /**< @brief Standard id. */ +#define CAN_IDE_EXT 1 /**< @brief Extended id. */ + +#define CAN_RTR_DATA 0 /**< @brief Data frame. */ +#define CAN_RTR_REMOTE 1 /**< @brief Remote frame. */ + + +typedef uint32_t canmbx_t; + +typedef struct CANDriver CANDriver; + +typedef struct { } CANConfig; + +struct CANDriver { + /** + * @brief Driver state. + */ + canstate_t state; + /** + * @brief Current configuration data. + */ + const CANConfig *config; + /** + * @brief Transmission threads queue. + */ + threads_queue_t txqueue; + /** + * @brief Receive threads queue. + */ + threads_queue_t rxqueue; +#if (CAN_ENFORCE_USE_CALLBACKS == FALSE) || defined(__DOXYGEN__) + /** + * @brief One or more frames become available. + * @note After broadcasting this event it will not be broadcasted again + * until the received frames queue has been completely emptied. It + * is not broadcasted for each received frame. It is + * responsibility of the application to empty the queue by + * repeatedly invoking @p canReceive() when listening to this event. + * This behavior minimizes the interrupt served by the system + * because CAN traffic. + * @note The flags associated to the listeners will indicate which + * receive mailboxes become non-empty. + */ + event_source_t rxfull_event; + /** + * @brief One or more transmission mailbox become available. + * @note The flags associated to the listeners will indicate which + * transmit mailboxes become empty. + * @note The upper 16 bits are transmission error flags associated + * to the transmit mailboxes. + */ + event_source_t txempty_event; + /** + * @brief A CAN bus error happened. + * @note The flags associated to the listeners will indicate that + * receive error(s) have occurred. + * @note In this implementation the upper 16 bits are filled with the + * unprocessed content of the ESR register. + */ + event_source_t error_event; +#else /* CAN_ENFORCE_USE_CALLBACKS == TRUE */ + /** + * @brief One or more frames become available. + * @note After calling this function it will not be called again + * until the received frames queue has been completely emptied. It + * is not called for each received frame. It is + * responsibility of the application to empty the queue by + * repeatedly invoking @p chTryReceiveI(). + * This behavior minimizes the interrupt served by the system + * because CAN traffic. + */ + can_callback_t rxfull_cb; + /** + * @brief One or more transmission mailbox become available. + * @note The flags associated to the callback will indicate which + * transmit mailboxes become empty. + */ + can_callback_t txempty_cb; + /** + * @brief A CAN bus error happened. + */ + can_callback_t error_cb; +#endif + + const char* deviceName; + + int sock; + + // This contains a std::queue of received frames + void* rx; +}; + +typedef struct { + struct { + uint8_t DLC:4; /**< @brief Data length. */ + uint8_t RTR:1; /**< @brief Frame type. */ + uint8_t IDE:1; /**< @brief Identifier type. */ + }; + union { + struct { + uint32_t SID:11; /**< @brief Standard identifier.*/ + }; + struct { + uint32_t EID:29; /**< @brief Extended identifier.*/ + }; + }; + union { + uint8_t data8[8]; /**< @brief Frame data. */ + uint16_t data16[4]; /**< @brief Frame data. */ + uint32_t data32[2]; /**< @brief Frame data. */ + uint64_t data64[1]; /**< @brief Frame data. */ + }; +} CANTxFrame; + +typedef struct { + struct { + uint8_t FMI; /**< @brief Filter id. */ + uint16_t TIME; /**< @brief Time stamp. */ + }; + struct { + uint8_t DLC:4; /**< @brief Data length. */ + uint8_t RTR:1; /**< @brief Frame type. */ + uint8_t IDE:1; /**< @brief Identifier type. */ + }; + union { + struct { + uint32_t SID:11; /**< @brief Standard identifier.*/ + }; + struct { + uint32_t EID:29; /**< @brief Extended identifier.*/ + }; + }; + union { + uint8_t data8[8]; /**< @brief Frame data. */ + uint16_t data16[4]; /**< @brief Frame data. */ + uint32_t data32[2]; /**< @brief Frame data. */ + uint64_t data64[1]; /**< @brief Frame data. */ + }; +} CANRxFrame; + +extern CANDriver CAND1; + +#ifdef __cplusplus +extern "C" { +#endif + void can_lld_init(void); + void can_lld_start(CANDriver *canp); + void can_lld_stop(CANDriver *canp); + bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox); + void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *crfp); + bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox); + void can_lld_receive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *ctfp); + void can_lld_abort(CANDriver *canp, + canmbx_t mailbox); + + // Called from _sim_check_for_interrupts + bool check_can_isr(void); +#ifdef __cplusplus +} +#endif + +#endif // HAL_USE_CAN + +#endif // HAL_CAN_LLD_H diff --git a/simulator/simulator/efifeatures.h b/simulator/simulator/efifeatures.h index f31af10c53..fb7296498b 100644 --- a/simulator/simulator/efifeatures.h +++ b/simulator/simulator/efifeatures.h @@ -96,7 +96,11 @@ #define EFI_MAIN_RELAY_CONTROL FALSE #define EFI_HIP_9011 TRUE #define EFI_CJ125 TRUE -#define EFI_CAN_SUPPORT FALSE + +// Simulator supports real CAN, but not on Windows (yet?) +#define EFI_CAN_SUPPORT !EFI_SIM_IS_WINDOWS + +#define EFI_WIDEBAND_FIRMWARE_UPDATE TRUE #define EFI_MAX_31855 FALSE #define EFI_ELECTRONIC_THROTTLE_BODY TRUE diff --git a/simulator/simulator/global.h b/simulator/simulator/global.h index 3cb5ed3905..e5c331cd8c 100644 --- a/simulator/simulator/global.h +++ b/simulator/simulator/global.h @@ -22,6 +22,7 @@ #include "chprintf.h" #include "cli_registry.h" #include "eficonsole.h" +#include #endif /* __cplusplus */ #define hasOsPanicError() (FALSE) diff --git a/simulator/simulator/mpu_util.h b/simulator/simulator/mpu_util.h new file mode 100644 index 0000000000..40764e1402 --- /dev/null +++ b/simulator/simulator/mpu_util.h @@ -0,0 +1,7 @@ +#pragma once + +#if HAL_USE_CAN +CANDriver* detectCanDevice(brain_pin_e pinRx, brain_pin_e pinTx); +bool isValidCanTxPin(brain_pin_e) { return true; } +bool isValidCanRxPin(brain_pin_e) { return true; } +#endif // HAL_USE_CAN diff --git a/simulator/simulator/rusEfiFunctionalTest.cpp b/simulator/simulator/rusEfiFunctionalTest.cpp index 1b9ab2483a..c8338b03f7 100644 --- a/simulator/simulator/rusEfiFunctionalTest.cpp +++ b/simulator/simulator/rusEfiFunctionalTest.cpp @@ -24,6 +24,7 @@ #include "memstreams.h" #include #include "rusefi_lua.h" +#include "can_hw.h" #define DEFAULT_SIM_RPM 1200 #define DEFAULT_SNIFFER_THR 2500 @@ -115,6 +116,15 @@ void rusEfiFunctionalTest(void) { startSerialChannels(); + engineConfiguration->enableVerboseCanTx = true; + +#if HAL_USE_CAN + // Set CAN device name + CAND1.deviceName = "can0"; + + initCan(); +#endif // HAL_USE_CAN + startLua(); extern bool main_loop_started; @@ -150,3 +160,15 @@ void logMsg(const char *format, ...) { // // fclose(fp); } + +#if HAL_USE_CAN +static bool didInitCan = false; +CANDriver* detectCanDevice(brain_pin_e pinRx, brain_pin_e pinTx) { + if (didInitCan) { + return nullptr; + } + + didInitCan = true; + return &CAND1; +} +#endif // HAL_USE_CAN