-
-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(hardware): revised ntcan plugin
- Loading branch information
Showing
6 changed files
with
289 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
hardware_integration/include/isobus/hardware_integration/ntcan_plugin.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
//================================================================================================ | ||
/// @file ntcan_plugin.hpp | ||
/// | ||
/// @brief An interface for using a ESD NTCAN 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 | ||
/// @author Daan Steenbergen | ||
/// | ||
/// @copyright 2024 The Open-Agriculture Developers | ||
//================================================================================================ | ||
#ifndef NTCAN_PLUGIN_HPP | ||
#define NTCAN_PLUGIN_HPP | ||
|
||
#include <string> | ||
#include "ntcan.h" | ||
|
||
#include "isobus/hardware_integration/can_hardware_plugin.hpp" | ||
#include "isobus/isobus/can_hardware_abstraction.hpp" | ||
#include "isobus/isobus/can_message_frame.hpp" | ||
|
||
namespace isobus | ||
{ | ||
/// @brief A CAN Driver for ESD NTCAN Devices | ||
class NTCANPlugin : public CANHardwarePlugin | ||
{ | ||
public: | ||
/// @brief Constructor for the ESD NTCAN CAN driver | ||
/// @param[in] channel The logical net number assigned to the physical CAN port to use. | ||
/// @param[in] baudrate The baudrate to use for the CAN connection. | ||
explicit NTCANPlugin(int channel, int baudrate = NTCAN_BAUD_250); | ||
|
||
/// @brief The destructor for NTCANPlugin | ||
virtual ~NTCANPlugin() = default; | ||
|
||
/// @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::CANMessageFrame &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::CANMessageFrame &canFrame) override; | ||
|
||
/// @brief Changes previously set configuration parameters. Only works if the device is not open. | ||
/// @param[in] channel The logical net number assigned to the physical CAN port to use. | ||
/// @param[in] baudrate The baudrate to use for the CAN connection. | ||
/// @returns True if the configuration was changed, otherwise false (if the device is open false will be returned) | ||
bool reconfigure(int channel, int baudrate = NTCAN_BAUD_250); | ||
|
||
private: | ||
int net; ///< The logical net number assigned to the physical CAN port to use. | ||
int baudrate; ///< The baudrate to use for the CAN connection. | ||
std::uint64_t timestampFreq; ///< The frequency of the timestamp | ||
std::uint64_t timestampOffset; ///< The offset of the timestamps | ||
NTCAN_HANDLE handle = NTCAN_NO_HANDLE; ///< The handle as defined in the NTCAN driver API | ||
NTCAN_RESULT openResult = NTCAN_SUCCESS; ///< Stores the result of the call to begin CAN communication. Used for is_valid check later. | ||
}; | ||
} | ||
|
||
#endif // NTCAN_PLUGIN_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
//================================================================================================ | ||
/// @file ntcan_plugin.cpp | ||
/// | ||
/// @brief An interface for using a ESD NTCAN 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 | ||
/// @author Daan Steenbergen | ||
/// | ||
/// @copyright 2024 The Open-Agriculture Developers | ||
//================================================================================================ | ||
|
||
#include "isobus/hardware_integration/ntcan_plugin.hpp" | ||
#include "isobus/isobus/can_stack_logger.hpp" | ||
|
||
#include <chrono> | ||
#include <thread> | ||
|
||
namespace isobus | ||
{ | ||
NTCANPlugin::NTCANPlugin(int channel, int baudrate) : | ||
net(channel), | ||
baudrate(baudrate) | ||
{ | ||
} | ||
|
||
bool NTCANPlugin::get_is_valid() const | ||
{ | ||
return (NTCAN_SUCCESS == openResult) && (NTCAN_NO_HANDLE != handle); | ||
} | ||
|
||
void NTCANPlugin::close() | ||
{ | ||
canClose(handle); | ||
handle = NTCAN_NO_HANDLE; | ||
} | ||
|
||
void NTCANPlugin::open() | ||
{ | ||
if (NTCAN_NO_HANDLE != handle) | ||
{ | ||
isobus::CANStackLogger::error("[NTCAN]: Attempting to open a connection that is already open"); | ||
} | ||
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); | ||
|
||
if (NTCAN_SUCCESS != openResult) | ||
{ | ||
isobus::CANStackLogger::error("[NTCAN]: Error trying to open the connection"); | ||
return; | ||
} | ||
|
||
CAN_IF_STATUS status{ 0 }; | ||
|
||
openResult = canSetBaudrate(handle, baudrate); | ||
if (NTCAN_SUCCESS != openResult) | ||
{ | ||
isobus::CANStackLogger::error("[NTCAN]: Error trying to set the baudrate"); | ||
close(); | ||
return; | ||
} | ||
|
||
openResult = canStatus(handle, &status); | ||
if (NTCAN_SUCCESS != openResult) | ||
{ | ||
isobus::CANStackLogger::error("[NTCAN]: Error trying to get the status"); | ||
close(); | ||
return; | ||
} | ||
|
||
if (NTCAN_FEATURE_TIMESTAMP == (status.features & NTCAN_FEATURE_TIMESTAMP)) | ||
{ | ||
std::uint64_t timestamp = 0; | ||
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(); | ||
long long millis = std::chrono::duration_cast<std::chrono::microseconds>(unix).count(); | ||
timestampOffset = millis - timestamp; | ||
} | ||
} | ||
|
||
std::int32_t ids = (1 << 11); | ||
openResult = canIdRegionAdd(handle, 0, &ids); | ||
if (NTCAN_SUCCESS == openResult && ids != (1 << 11)) | ||
{ | ||
openResult = NTCAN_INSUFFICIENT_RESOURCES; | ||
isobus::CANStackLogger::error("[NTCAN]: Error trying to add the standard ID region"); | ||
close(); | ||
return; | ||
} | ||
|
||
ids = (1 << 29); | ||
openResult = canIdRegionAdd(handle, NTCAN_20B_BASE, &ids); | ||
if (NTCAN_SUCCESS == openResult && ids != (1 << 29)) | ||
{ | ||
openResult = NTCAN_INSUFFICIENT_RESOURCES; | ||
isobus::CANStackLogger::error("[NTCAN]: Error trying to add the extended ID region"); | ||
close(); | ||
return; | ||
} | ||
} | ||
|
||
bool NTCANPlugin::read_frame(isobus::CANMessageFrame &canFrame) | ||
{ | ||
NTCAN_RESULT result; | ||
CMSG_T msgCanMessage{ 0 }; | ||
bool retVal = false; | ||
std::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 & ((1 << 29) - 1)); | ||
canFrame.isExtendedFrame = (NTCAN_20B_BASE == (msgCanMessage.id & NTCAN_20B_BASE)); | ||
canFrame.timestamp_us = msgCanMessage.timestamp * 1000000 / timestampFreq + timestampOffset; | ||
retVal = true; | ||
} | ||
else | ||
{ | ||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); | ||
} | ||
return retVal; | ||
} | ||
|
||
bool NTCANPlugin::write_frame(const isobus::CANMessageFrame &canFrame) | ||
{ | ||
NTCAN_RESULT result; | ||
CMSG_T msgCanMessage{ 0 }; | ||
std::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); | ||
} | ||
|
||
bool NTCANPlugin::reconfigure(int channel, int baudrate) | ||
{ | ||
bool retVal = false; | ||
|
||
if (!get_is_valid()) | ||
{ | ||
net = channel; | ||
this->baudrate = baudrate; | ||
retVal = true; | ||
} | ||
return retVal; | ||
} | ||
} // namespace isobus |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters