-
-
Notifications
You must be signed in to change notification settings - Fork 93
[HW]: add VSCAN hardware interface #528
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
GwnDaan
wants to merge
2
commits into
Open-Agriculture:main
Choose a base branch
from
GwnDaan:daan/vscan-plugin
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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(const 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(const 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 | ||
| static 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. | ||
|
ad3154 marked this conversation as resolved.
|
||
| 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 hidden or 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 hidden or 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,169 @@ | ||
| //================================================================================================ | ||
| /// @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 <cstring> | ||
| #include <thread> | ||
|
|
||
| namespace isobus | ||
| { | ||
| VSCANPlugin::VSCANPlugin(const 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(const 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) | ||
| { | ||
| // Arbitrary buffer size, should be enough for most error messages | ||
| size_t bufferSize = 256; | ||
| std::vector<char> errorBuffer(bufferSize, 0); | ||
|
|
||
| VSCAN_GetErrorString(status, errorBuffer.data(), bufferSize); | ||
|
|
||
| // Ensure the string is null-terminated, just in case | ||
| errorBuffer[bufferSize - 1] = '\0'; | ||
|
|
||
| return std::string(errorBuffer.data()); | ||
| } | ||
| } | ||
| // namespace isobus |
This file contains hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.