-
-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
requires you to set the 'VSCAN_API_DIR' environment variable to the API SDK directory that contains the `.h`, `.lib` files. Furthermore, you need to put `vs_can_api.dll` in the same directory as the executable.
- Loading branch information
Showing
6 changed files
with
304 additions
and
0 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
74 changes: 74 additions & 0 deletions
74
hardware_integration/include/isobus/hardware_integration/vscan_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,74 @@ | ||
//================================================================================================ | ||
/// @file vscan_plugin.hpp | ||
/// | ||
/// @brief An interface for using a VSCOM VSCAN driver. | ||
/// @attention Use of the VSCAN 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 Daan Steenbergen | ||
/// | ||
/// @copyright 2025 The Open-Agriculture Developers | ||
//================================================================================================ | ||
#ifndef VSCAN_PLUGIN_HPP | ||
#define VSCAN_PLUGIN_HPP | ||
|
||
#include <string> | ||
#include "vs_can_api.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 VSCOM VSCAN Devices | ||
class VSCANPlugin : public CANHardwarePlugin | ||
{ | ||
public: | ||
/// @brief Constructor for the VSCOM VSCAN CAN driver | ||
/// @param[in] channel The COM port or IP address of the VSCAN device to use. | ||
/// @param[in] baudrate The baudrate to use for the CAN connection. | ||
VSCANPlugin(std::string channel, void *baudrate = VSCAN_SPEED_250K); | ||
|
||
/// @brief The destructor for VSCANPlugin | ||
virtual ~VSCANPlugin() = 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 COM port or IP address of the VSCAN device 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(std::string channel, void *baudrate = VSCAN_SPEED_250K); | ||
|
||
private: | ||
/// @brief Parses the error from the status code | ||
/// @param[in] status The status code to parse | ||
/// @returns The error message | ||
std::string parse_error_from_status(VSCAN_STATUS status); | ||
|
||
std::string channel; ///< The COM port or IP address of the VSCAN device to use. | ||
void *baudrate; ///< The baudrate to use for the CAN connection. | ||
VSCAN_HANDLE handle; ///< The handle as defined in the NTCAN driver API | ||
VSCAN_STATUS status = VSCAN_ERR_OK; ///< 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
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,161 @@ | ||
//================================================================================================ | ||
/// @file vscan_plugin.cpp | ||
/// | ||
/// @brief An interface for using a VSCOM VSCAN driver. | ||
/// @attention Use of the VSCAN 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 Daan Steenbergen | ||
/// | ||
/// @copyright 2025 The Open-Agriculture Developers | ||
//================================================================================================ | ||
|
||
#include "isobus/hardware_integration/vscan_plugin.hpp" | ||
#include "isobus/isobus/can_stack_logger.hpp" | ||
|
||
#include <chrono> | ||
#include <thread> | ||
|
||
namespace isobus | ||
{ | ||
VSCANPlugin::VSCANPlugin(std::string channel, void *baudrate) : | ||
channel(channel), | ||
baudrate(baudrate) | ||
{ | ||
} | ||
|
||
bool VSCANPlugin::get_is_valid() const | ||
{ | ||
return (VSCAN_ERR_OK == status) && (handle > 0); | ||
} | ||
|
||
void VSCANPlugin::close() | ||
{ | ||
VSCAN_Close(handle); | ||
handle = 0; | ||
} | ||
|
||
void VSCANPlugin::open() | ||
{ | ||
if (get_is_valid()) | ||
{ | ||
LOG_ERROR("[VSCAN]: Attempting to open a connection that is already open"); | ||
return; | ||
} | ||
|
||
VSCAN_API_VERSION version; | ||
status = VSCAN_Ioctl(0, VSCAN_IOCTL_GET_API_VERSION, &version); | ||
if (status != VSCAN_ERR_OK) | ||
{ | ||
LOG_ERROR("[VSCAN] Failed to get API version: %s, trying to continue anyway", parse_error_from_status(status).c_str()); | ||
} | ||
|
||
LOG_DEBUG("[VSCAN] API Version %d.%d.%d", version.Major, version.Minor, version.SubMinor); | ||
|
||
// We create a buffer to guarantee the content to be non-const | ||
std::vector<char> channelBuffer(channel.begin(), channel.end()); | ||
channelBuffer.push_back('\0'); | ||
handle = VSCAN_Open(channelBuffer.data(), VSCAN_MODE_NORMAL); | ||
if (handle <= 0) | ||
{ | ||
LOG_ERROR("[VSCAN]: Error trying to open the connection: %s", parse_error_from_status(handle).c_str()); | ||
return; | ||
} | ||
|
||
status = VSCAN_Ioctl(handle, VSCAN_IOCTL_SET_SPEED, baudrate); | ||
if (VSCAN_ERR_OK != status) | ||
{ | ||
LOG_ERROR("[VSCAN]: Error trying to set the baudrate: %s", parse_error_from_status(status).c_str()); | ||
close(); | ||
return; | ||
} | ||
|
||
status = VSCAN_Ioctl(handle, VSCAN_IOCTL_SET_BLOCKING_READ, VSCAN_IOCTL_ON); | ||
if (VSCAN_ERR_OK != status) | ||
{ | ||
LOG_ERROR("[VSCAN]: Error trying to set blocking read mode: %s", parse_error_from_status(status).c_str()); | ||
close(); | ||
return; | ||
} | ||
} | ||
|
||
bool VSCANPlugin::read_frame(CANMessageFrame &canFrame) | ||
{ | ||
VSCAN_MSG message; | ||
DWORD rv; | ||
bool retVal = false; | ||
|
||
status = VSCAN_Read(handle, &message, 1, &rv); | ||
|
||
if (VSCAN_ERR_OK == status && rv) | ||
{ | ||
canFrame.dataLength = message.Size; | ||
memcpy(canFrame.data, message.Data, message.Size); | ||
canFrame.identifier = message.Id; | ||
canFrame.isExtendedFrame = (message.Flags & VSCAN_FLAGS_EXTENDED); | ||
retVal = true; | ||
} | ||
else | ||
{ | ||
LOG_ERROR("[VSCAN]: Error trying to read a frame: %s, closing connection", parse_error_from_status(status).c_str()); | ||
close(); | ||
} | ||
|
||
return retVal; | ||
} | ||
|
||
bool VSCANPlugin::write_frame(const CANMessageFrame &canFrame) | ||
{ | ||
VSCAN_MSG message; | ||
DWORD rv; | ||
bool retVal = false; | ||
|
||
message.Id = canFrame.identifier; | ||
message.Size = canFrame.dataLength; | ||
memcpy(message.Data, canFrame.data, message.Size); | ||
message.Flags = canFrame.isExtendedFrame ? VSCAN_FLAGS_EXTENDED : VSCAN_FLAGS_STANDARD; | ||
|
||
status = VSCAN_Write(handle, &message, 1, &rv); | ||
|
||
if (VSCAN_ERR_OK == status && rv) | ||
{ | ||
status = VSCAN_Flush(handle); | ||
if (VSCAN_ERR_OK == status) | ||
{ | ||
retVal = true; | ||
} | ||
else | ||
{ | ||
LOG_ERROR("[VSCAN]: Error trying to flush the write buffer: %s, closing connection", parse_error_from_status(status).c_str()); | ||
close(); | ||
} | ||
} | ||
else | ||
{ | ||
LOG_ERROR("[VSCAN]: Error trying to write a frame: %s, closing connection", parse_error_from_status(status).c_str()); | ||
close(); | ||
} | ||
|
||
return retVal; | ||
} | ||
|
||
bool VSCANPlugin::reconfigure(std::string channel, void *baudrate) | ||
{ | ||
bool retVal = false; | ||
|
||
if (!get_is_valid()) | ||
{ | ||
this->channel = channel; | ||
this->baudrate = baudrate; | ||
retVal = true; | ||
} | ||
return retVal; | ||
} | ||
|
||
std::string VSCANPlugin::parse_error_from_status(VSCAN_STATUS status) | ||
{ | ||
char errorBuffer[256] = { 0 }; | ||
VSCAN_GetErrorString(status, errorBuffer, sizeof(errorBuffer)); | ||
return std::string(errorBuffer); | ||
} | ||
} | ||
// 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