From bdc84b7878d250e87809e120591d7ba00ace5903 Mon Sep 17 00:00:00 2001 From: Alex Cole Date: Thu, 2 Mar 2023 14:45:09 +0000 Subject: [PATCH 1/3] First attempt at an NTCAN implementation. --- .../ntcan_fifo_plugin.hpp | 64 ++++++++ .../src/ntcan_fifo_plugin.cpp | 154 ++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 hardware_integration/include/isobus/hardware_integration/ntcan_fifo_plugin.hpp create mode 100644 hardware_integration/src/ntcan_fifo_plugin.cpp diff --git a/hardware_integration/include/isobus/hardware_integration/ntcan_fifo_plugin.hpp b/hardware_integration/include/isobus/hardware_integration/ntcan_fifo_plugin.hpp new file mode 100644 index 00000000..f19c8b89 --- /dev/null +++ b/hardware_integration/include/isobus/hardware_integration/ntcan_fifo_plugin.hpp @@ -0,0 +1,64 @@ +//================================================================================================ +/// @file ntcan_fifo_plugin.hpp +/// +/// @brief An interface for using a ESD NTCAN FIFO driver. +/// @attention Use of the NTCAN driver is governed in part by their license, and requires you +/// to install their driver first, which in-turn requires you to agree to their terms and conditions. +/// @author Alex "Y_Less" Cole +/// +/// @copyright 2023 Alex "Y_Less" Cole +//================================================================================================ +#ifndef NTCAN_FIFO_PLUGIN_HPP +#define NTCAN_FIFO_PLUGIN_HPP + +#include + +#include +#include "isobus/hardware_integration/can_hardware_plugin.hpp" +#include "isobus/isobus/can_frame.hpp" +#include "isobus/isobus/can_hardware_abstraction.hpp" + +//================================================================================================ +/// @class NTCANPlugin +/// +/// @brief A CAN Driver for ESD NTCAN FIFO Devices +//================================================================================================ +class NTCANFIFOPlugin : public CANHardwarePlugin +{ +public: + /// @brief Constructor for the ESD NTCAN FIFO CAN driver + /// @param[in] channel The logical net number assigned to the physical CAN port to use. + explicit NTCANFIFOPlugin(int channel); + + /// @brief The destructor for NTCANFIFOPlugin + virtual ~NTCANFIFOPlugin(); + + /// @brief Returns if the connection with the hardware is valid + /// @returns `true` if connected, `false` if not connected + bool get_is_valid() const override; + + /// @brief Closes the connection to the hardware + void close() override; + + /// @brief Connects to the hardware you specified in the constructor's channel argument + void open() override; + + /// @brief Returns a frame from the hardware (synchronous), or `false` if no frame can be read. + /// @param[in, out] canFrame The CAN frame that was read + /// @returns `true` if a CAN frame was read, otherwise `false` + bool read_frame(isobus::HardwareInterfaceCANFrame &canFrame) override; + + /// @brief Writes a frame to the bus (synchronous) + /// @param[in] canFrame The frame to write to the bus + /// @returns `true` if the frame was written, otherwise `false` + bool write_frame(const isobus::HardwareInterfaceCANFrame &canFrame) override; + +private: + int net; + uint64_t timestampFreq; + uint64_t timestampOff; + NTCAN_HANDLE handle; ///< The handle as defined in the NTCAN FIFO driver API + NTCAN_RESULT openResult; ///< Stores the result of the call to begin CAN communication. Used for is_valid check later. +}; + +#endif // NTCAN_FIFO_PLUGIN_HPP diff --git a/hardware_integration/src/ntcan_fifo_plugin.cpp b/hardware_integration/src/ntcan_fifo_plugin.cpp new file mode 100644 index 00000000..6582c5a3 --- /dev/null +++ b/hardware_integration/src/ntcan_fifo_plugin.cpp @@ -0,0 +1,154 @@ +//================================================================================================ +/// @file ntcan_fifo_plugin.cpp +/// +/// @brief An interface for using a ESD NTCAN FIFO driver. +/// @attention Use of the NTCAN driver is governed in part by their license, and requires you +/// to install their driver first, which in-turn requires you to agree to their terms and conditions. +/// @author Alex "Y_Less" Cole +/// +/// @copyright 2023 Alex "Y_Less" Cole +//================================================================================================ + +#include "isobus/hardware_integration/ntcan_fifo_plugin.hpp" +#include "isobus/isobus/can_stack_logger.hpp" + +#include +#include + +NTCANFIFOPlugin::NTCANFIFOPlugin(int channel) : + net(channel), + timestampFreq(1), + timestamp(0), + unix(std::chrono::system_clock::now()), + openResult(NTCAN_SUCCESS) +{ +} + +NTCANFIFOPlugin::~NTCANFIFOPlugin() +{ +} + +bool NTCANFIFOPlugin::get_is_valid() const +{ + return (NTCAN_SUCCESS == openResult); +} + +void NTCANFIFOPlugin::close() +{ + canClose(handle); +} + +void NTCANFIFOPlugin::open() +{ + uint32_t mode = 0; + int32_t txQueueSize = 8; + int32_t rxQueueSize = 8; + int32_t txTimeOut = 100; + int32_t rxTimeOut = 1000; + CAN_IF_STATUS status {0}; + uint64_t timestamp = 0; + int ids; + + openResult = canOpen(net, mode, txQueueSize, rxQueueSize, txTimeOut, rxTimeOut, &handle); + + if (NTCAN_SUCCESS == openResult) + { + openResult = canSetBaudrate(handle, NTCAN_BAUD_250); + + if (NTCAN_SUCCESS == openResult) + { + openResult = canStatus(handle, NTCAN_FEATURE_TIMESTAMP, &status); + } + + if (NTCAN_FEATURE_TIMESTAMP == status.features & NTCAN_FEATURE_TIMESTAMP) + { + if (NTCAN_SUCCESS == openResult) + { + openResult = canIoctl(handle, NTCAN_IOCTL_GET_TIMESTAMP_FREQ, ×tampFreq); + } + + if (NTCAN_SUCCESS == openResult) + { + openResult = canIoctl(handle, NTCAN_IOCTL_GET_TIMESTAMP, ×tamp); + } + + if (NTCAN_SUCCESS == openResult) + { + auto now = std::chrono::system_clock::now(); + auto unix = now.time_since_epoch(); + uint64_t millis = std::chrono::duration_cast(since_epoch); + timestampOff = millis - timestamp; + } + } + + if (NTCAN_SUCCESS == openResult) + { + ids = 0x800; + openResult = canIdRegionAdd(handle, 0, &ids); + if (NTCAN_SUCCESS == openResult && ids != 0x800) + { + openResult = NTCAN_INSUFFICIENT_RESOURCES; + } + } + + if (NTCAN_SUCCESS == openResult) + { + ids = 0x20000000; + openResult = canIdRegionAdd(handle, 0 | NTCAN_20B_BASE, &ids); + if (NTCAN_SUCCESS == openResult && ids != 0x20000000) + { + openResult = NTCAN_INSUFFICIENT_RESOURCES; + } + } + + if (NTCAN_SUCCESS != openResult) + { + isobus::CANStackLogger::CAN_stack_log(isobus::CANStackLogger::LoggingLevel::Critical, "[NTCAN]: Error trying to connect to NTCAN driver"); + canClose(handle); + } + } + else + { + isobus::CANStackLogger::CAN_stack_log(isobus::CANStackLogger::LoggingLevel::Critical, "[NTCAN]: Error trying to connect to NTCAN driver"); + } +} + +bool NTCANFIFOPlugin::read_frame(isobus::HardwareInterfaceCANFrame &canFrame) +{ + NTCAN_RESULT result; + CMSG_T msgCanMessage {0}; + bool retVal = false; + int32_t count = 1; + + result = canReadT(handle, &msgCanMessage, &count, nullptr); + + if (NTCAN_SUCCESS == result && 1 == count) + { + canFrame.dataLength = msgCanMessage.len; + memcpy(canFrame.data, msgCanMessage.data, msgCanMessage.len); + canFrame.identifier = msgCanMessage.id & 0x1FFFFFFF; + canFrame.isExtendedFrame = (NTCAN_20B_BASE == msgCanMessage.id & NTCAN_20B_BASE); + canFrame.timestamp_us = msgCanMessage.timestamp * 1000000 / timestampFreq + timestampOff; + retVal = true; + } + else + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + return retVal; +} + +bool NTCANFIFOPlugin::write_frame(const isobus::HardwareInterfaceCANFrame &canFrame) +{ + NTCAN_RESULT result; + CMSG_T msgCanMessage {0}; + int32_t count = 1; + + msgCanMessage.id = canFrame.isExtendedFrame ? canFrame.identifier | NTCAN_20B_BASE : canFrame.identifier; + msgCanMessage.len = canFrame.dataLength; + memcpy(msgCanMessage.data, canFrame.data, canFrame.dataLength); + + result = canWriteT(handle, &msgCanMessage, &count, nullptr); + + return (NTCAN_SUCCESS == result && 1 == count); +} From 9d95a068e8bfd6ba80c957d1b67f96026b2ddd9c Mon Sep 17 00:00:00 2001 From: Alex Cole Date: Fri, 3 Mar 2023 02:01:14 +0000 Subject: [PATCH 2/3] Finish ESD CAN v0.1. --- hardware_integration/lib/README.md | 8 ++++++++ hardware_integration/src/ntcan_fifo_plugin.cpp | 14 +++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/hardware_integration/lib/README.md b/hardware_integration/lib/README.md index 10bd89b1..69a31d6a 100644 --- a/hardware_integration/lib/README.md +++ b/hardware_integration/lib/README.md @@ -6,3 +6,11 @@ Please read the End User License Agreement of the company PEAK-System Technik Gm www.peak-system.com/quick/eula Use of the PEAK driver libraries is governed by their EULA. + +### ESD NTCAN FIFO Driver + +Please read the End User License Agreement of the company esd electronics GmbH at: +https://esd.eu/en/products/can-tools + +You must install their driver and SDK to use this backend. + diff --git a/hardware_integration/src/ntcan_fifo_plugin.cpp b/hardware_integration/src/ntcan_fifo_plugin.cpp index 6582c5a3..65403fca 100644 --- a/hardware_integration/src/ntcan_fifo_plugin.cpp +++ b/hardware_integration/src/ntcan_fifo_plugin.cpp @@ -18,8 +18,8 @@ NTCANFIFOPlugin::NTCANFIFOPlugin(int channel) : net(channel), timestampFreq(1), - timestamp(0), - unix(std::chrono::system_clock::now()), + timestampOff(0), + handle(0), openResult(NTCAN_SUCCESS) { } @@ -57,10 +57,10 @@ void NTCANFIFOPlugin::open() if (NTCAN_SUCCESS == openResult) { - openResult = canStatus(handle, NTCAN_FEATURE_TIMESTAMP, &status); + openResult = canStatus(handle, &status); } - if (NTCAN_FEATURE_TIMESTAMP == status.features & NTCAN_FEATURE_TIMESTAMP) + if (NTCAN_FEATURE_TIMESTAMP == (status.features & NTCAN_FEATURE_TIMESTAMP)) { if (NTCAN_SUCCESS == openResult) { @@ -76,7 +76,7 @@ void NTCANFIFOPlugin::open() { auto now = std::chrono::system_clock::now(); auto unix = now.time_since_epoch(); - uint64_t millis = std::chrono::duration_cast(since_epoch); + uint64_t millis = std::chrono::duration_cast(unix).count(); timestampOff = millis - timestamp; } } @@ -126,8 +126,8 @@ bool NTCANFIFOPlugin::read_frame(isobus::HardwareInterfaceCANFrame &canFrame) { canFrame.dataLength = msgCanMessage.len; memcpy(canFrame.data, msgCanMessage.data, msgCanMessage.len); - canFrame.identifier = msgCanMessage.id & 0x1FFFFFFF; - canFrame.isExtendedFrame = (NTCAN_20B_BASE == msgCanMessage.id & NTCAN_20B_BASE); + canFrame.identifier = (msgCanMessage.id & 0x1FFFFFFF); + canFrame.isExtendedFrame = (NTCAN_20B_BASE == (msgCanMessage.id & NTCAN_20B_BASE)); canFrame.timestamp_us = msgCanMessage.timestamp * 1000000 / timestampFreq + timestampOff; retVal = true; } From 34727631263748ca07d5f6e1261e428d9cf687cf Mon Sep 17 00:00:00 2001 From: Alex Cole Date: Sat, 4 Mar 2023 04:18:25 +0000 Subject: [PATCH 3/3] Fix a few PR suggestions: - Prefix types with `std::`. - Comment `| 0`. - Still using explicit width types, because they're what the API takes (and none are exposed outside the plugin). - Not a suggestion, but I switched to using `<< 11` and `<< 29` instead of more magic numbers to make it slightly clearer that those numbers are to do with CAN 11- and 29-bit identifiers. - Reduced some scopes. --- .../ntcan_fifo_plugin.hpp | 6 +-- .../src/ntcan_fifo_plugin.cpp | 43 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/hardware_integration/include/isobus/hardware_integration/ntcan_fifo_plugin.hpp b/hardware_integration/include/isobus/hardware_integration/ntcan_fifo_plugin.hpp index f19c8b89..3022270f 100644 --- a/hardware_integration/include/isobus/hardware_integration/ntcan_fifo_plugin.hpp +++ b/hardware_integration/include/isobus/hardware_integration/ntcan_fifo_plugin.hpp @@ -31,7 +31,7 @@ class NTCANFIFOPlugin : public CANHardwarePlugin explicit NTCANFIFOPlugin(int channel); /// @brief The destructor for NTCANFIFOPlugin - virtual ~NTCANFIFOPlugin(); + virtual ~NTCANFIFOPlugin() = default; /// @brief Returns if the connection with the hardware is valid /// @returns `true` if connected, `false` if not connected @@ -55,8 +55,8 @@ class NTCANFIFOPlugin : public CANHardwarePlugin private: int net; - uint64_t timestampFreq; - uint64_t timestampOff; + std::uint64_t timestampFreq; + std::uint64_t timestampOff; NTCAN_HANDLE handle; ///< The handle as defined in the NTCAN FIFO driver API NTCAN_RESULT openResult; ///< Stores the result of the call to begin CAN communication. Used for is_valid check later. }; diff --git a/hardware_integration/src/ntcan_fifo_plugin.cpp b/hardware_integration/src/ntcan_fifo_plugin.cpp index 65403fca..16efc0da 100644 --- a/hardware_integration/src/ntcan_fifo_plugin.cpp +++ b/hardware_integration/src/ntcan_fifo_plugin.cpp @@ -24,10 +24,6 @@ NTCANFIFOPlugin::NTCANFIFOPlugin(int channel) : { } -NTCANFIFOPlugin::~NTCANFIFOPlugin() -{ -} - bool NTCANFIFOPlugin::get_is_valid() const { return (NTCAN_SUCCESS == openResult); @@ -40,19 +36,20 @@ void NTCANFIFOPlugin::close() void NTCANFIFOPlugin::open() { - uint32_t mode = 0; - int32_t txQueueSize = 8; - int32_t rxQueueSize = 8; - int32_t txTimeOut = 100; - int32_t rxTimeOut = 1000; - CAN_IF_STATUS status {0}; - uint64_t timestamp = 0; - int ids; + { + std::uint32_t mode = 0; + std::int32_t txQueueSize = 8; + std::int32_t rxQueueSize = 8; + std::int32_t txTimeOut = 100; + std::int32_t rxTimeOut = 1000; - openResult = canOpen(net, mode, txQueueSize, rxQueueSize, txTimeOut, rxTimeOut, &handle); + openResult = canOpen(net, mode, txQueueSize, rxQueueSize, txTimeOut, rxTimeOut, &handle); + } if (NTCAN_SUCCESS == openResult) { + CAN_IF_STATUS status {0}; + openResult = canSetBaudrate(handle, NTCAN_BAUD_250); if (NTCAN_SUCCESS == openResult) @@ -62,6 +59,7 @@ void NTCANFIFOPlugin::open() if (NTCAN_FEATURE_TIMESTAMP == (status.features & NTCAN_FEATURE_TIMESTAMP)) { + std::uint64_t timestamp = 0; if (NTCAN_SUCCESS == openResult) { openResult = canIoctl(handle, NTCAN_IOCTL_GET_TIMESTAMP_FREQ, ×tampFreq); @@ -76,16 +74,16 @@ void NTCANFIFOPlugin::open() { auto now = std::chrono::system_clock::now(); auto unix = now.time_since_epoch(); - uint64_t millis = std::chrono::duration_cast(unix).count(); + long long millis = std::chrono::duration_cast(unix).count(); timestampOff = millis - timestamp; } } if (NTCAN_SUCCESS == openResult) { - ids = 0x800; + std::int32_t ids = (1 << 11); openResult = canIdRegionAdd(handle, 0, &ids); - if (NTCAN_SUCCESS == openResult && ids != 0x800) + if (NTCAN_SUCCESS == openResult && ids != (1 << 11)) { openResult = NTCAN_INSUFFICIENT_RESOURCES; } @@ -93,9 +91,10 @@ void NTCANFIFOPlugin::open() if (NTCAN_SUCCESS == openResult) { - ids = 0x20000000; + std::int32_t ids = (1 << 29); + // Address 0, with the wide address flag. openResult = canIdRegionAdd(handle, 0 | NTCAN_20B_BASE, &ids); - if (NTCAN_SUCCESS == openResult && ids != 0x20000000) + if (NTCAN_SUCCESS == openResult && ids != (1 << 29)) { openResult = NTCAN_INSUFFICIENT_RESOURCES; } @@ -118,7 +117,7 @@ bool NTCANFIFOPlugin::read_frame(isobus::HardwareInterfaceCANFrame &canFrame) NTCAN_RESULT result; CMSG_T msgCanMessage {0}; bool retVal = false; - int32_t count = 1; + std::int32_t count = 1; result = canReadT(handle, &msgCanMessage, &count, nullptr); @@ -126,7 +125,7 @@ bool NTCANFIFOPlugin::read_frame(isobus::HardwareInterfaceCANFrame &canFrame) { canFrame.dataLength = msgCanMessage.len; memcpy(canFrame.data, msgCanMessage.data, msgCanMessage.len); - canFrame.identifier = (msgCanMessage.id & 0x1FFFFFFF); + canFrame.identifier = (msgCanMessage.id & ((1 << 29) - 1)); canFrame.isExtendedFrame = (NTCAN_20B_BASE == (msgCanMessage.id & NTCAN_20B_BASE)); canFrame.timestamp_us = msgCanMessage.timestamp * 1000000 / timestampFreq + timestampOff; retVal = true; @@ -142,9 +141,9 @@ bool NTCANFIFOPlugin::write_frame(const isobus::HardwareInterfaceCANFrame &canFr { NTCAN_RESULT result; CMSG_T msgCanMessage {0}; - int32_t count = 1; + std::int32_t count = 1; - msgCanMessage.id = canFrame.isExtendedFrame ? canFrame.identifier | NTCAN_20B_BASE : canFrame.identifier; + msgCanMessage.id = canFrame.isExtendedFrame ? (canFrame.identifier | NTCAN_20B_BASE) : canFrame.identifier; msgCanMessage.len = canFrame.dataLength; memcpy(msgCanMessage.data, canFrame.data, canFrame.dataLength);