AgIsoStack++
A control-function-focused implementation of the major ISOBUS and J1939 protocols
Loading...
Searching...
No Matches
innomaker_usb2can_windows_plugin.cpp
Go to the documentation of this file.
1//================================================================================================
12//================================================================================================
13
16#include "isobus/utility/to_string.hpp"
17
18#include <thread>
19
20namespace isobus
21{
22 std::unique_ptr<InnoMakerUsb2CanLib> InnoMakerUSB2CANWindowsPlugin::driverInstance = nullptr;
23
25 channel(channel),
26 baudrate(baudrate)
27 {
28 if (nullptr == driverInstance)
29 {
30 driverInstance = std::unique_ptr<InnoMakerUsb2CanLib>(new InnoMakerUsb2CanLib());
31 driverInstance->setup();
32 driverInstance->scanInnoMakerDevice();
33 }
34 txContexts = std::unique_ptr<InnoMakerUsb2CanLib::innomaker_can>(new InnoMakerUsb2CanLib::innomaker_can());
35 }
36
41
43 {
44 return nullptr != driverInstance->getInnoMakerDevice(channel) && driverInstance->getInnoMakerDevice(channel)->isOpen;
45 }
46
48 {
49 InnoMakerUsb2CanLib::InnoMakerDevice *device = driverInstance->getInnoMakerDevice(channel);
50
51 if (nullptr != device && device->isOpen)
52 {
53 driverInstance->urbResetDevice(device);
54 driverInstance->closeInnoMakerDevice(device);
55
56 // Check if all channels are closed and if so, close the driver instance
57 bool allChannelsClosed = true;
58 for (int i = 0; i < driverInstance->getInnoMakerDeviceCount(); i++)
59 {
60 if (nullptr != driverInstance->getInnoMakerDevice(i) &&
61 driverInstance->getInnoMakerDevice(i)->isOpen)
62 {
63 allChannelsClosed = false;
64 break;
65 }
66 }
67 if (allChannelsClosed)
68 {
69 LOG_INFO("[InnoMaker-Windows] All channels closed, closing driver instance");
70 driverInstance->setdown();
71 driverInstance = nullptr;
72 }
73 }
74 }
75
77 {
78 InnoMakerUsb2CanLib::InnoMakerDevice *device = driverInstance->getInnoMakerDevice(channel);
79
80 if (nullptr != device)
81 {
82 driverInstance->urbResetDevice(device);
83 driverInstance->closeInnoMakerDevice(device);
84
85 // Reset tx buffer according to the documentation
86 for (int i = 0; i < driverInstance->innomaker_MAX_TX_URBS; i++)
87 {
88 txContexts->tx_context[i].echo_id = driverInstance->innomaker_MAX_TX_URBS;
89 }
90
91 InnoMakerUsb2CanLib::Innomaker_device_bittming bitTiming;
92 switch (baudrate)
93 {
94 case B20k:
95 {
96 bitTiming.prop_seg = 6;
97 bitTiming.phase_seg1 = 7;
98 bitTiming.phase_seg2 = 2;
99 bitTiming.sjw = 1;
100 bitTiming.brp = 150;
101 }
102 break;
103 case B33k3:
104 {
105 bitTiming.prop_seg = 3;
106 bitTiming.phase_seg1 = 3;
107 bitTiming.phase_seg2 = 1;
108 bitTiming.sjw = 1;
109 bitTiming.brp = 180;
110 }
111 break;
112 case B40k:
113 {
114 bitTiming.prop_seg = 6;
115 bitTiming.phase_seg1 = 7;
116 bitTiming.phase_seg2 = 2;
117 bitTiming.sjw = 1;
118 bitTiming.brp = 75;
119 }
120 break;
121 case B50k:
122 {
123 bitTiming.prop_seg = 6;
124 bitTiming.phase_seg1 = 7;
125 bitTiming.phase_seg2 = 2;
126 bitTiming.sjw = 1;
127 bitTiming.brp = 60;
128 }
129 break;
130 case B66k6:
131 {
132 bitTiming.prop_seg = 3;
133 bitTiming.phase_seg1 = 3;
134 bitTiming.phase_seg2 = 1;
135 bitTiming.sjw = 1;
136 bitTiming.brp = 90;
137 }
138 break;
139 case B80k:
140 {
141 bitTiming.prop_seg = 3;
142 bitTiming.phase_seg1 = 3;
143 bitTiming.phase_seg2 = 1;
144 bitTiming.sjw = 1;
145 bitTiming.brp = 75;
146 }
147 break;
148 case B83k3:
149 {
150 bitTiming.prop_seg = 3;
151 bitTiming.phase_seg1 = 3;
152 bitTiming.phase_seg2 = 1;
153 bitTiming.sjw = 1;
154 bitTiming.brp = 72;
155 }
156 break;
157 case B100k:
158 {
159 bitTiming.prop_seg = 6;
160 bitTiming.phase_seg1 = 7;
161 bitTiming.phase_seg2 = 2;
162 bitTiming.sjw = 1;
163 bitTiming.brp = 30;
164 }
165 break;
166 case B125k:
167 {
168 bitTiming.prop_seg = 6;
169 bitTiming.phase_seg1 = 7;
170 bitTiming.phase_seg2 = 2;
171 bitTiming.sjw = 1;
172 bitTiming.brp = 24;
173 }
174 break;
175 case B200k:
176 {
177 bitTiming.prop_seg = 6;
178 bitTiming.phase_seg1 = 7;
179 bitTiming.phase_seg2 = 2;
180 bitTiming.sjw = 1;
181 bitTiming.brp = 15;
182 }
183 break;
184 case B250k:
185 {
186 bitTiming.prop_seg = 6;
187 bitTiming.phase_seg1 = 7;
188 bitTiming.phase_seg2 = 2;
189 bitTiming.sjw = 1;
190 bitTiming.brp = 12;
191 }
192 break;
193 case B400k:
194 {
195 bitTiming.prop_seg = 3;
196 bitTiming.phase_seg1 = 3;
197 bitTiming.phase_seg2 = 1;
198 bitTiming.sjw = 1;
199 bitTiming.brp = 15;
200 }
201 break;
202 case B500k:
203 {
204 bitTiming.prop_seg = 6;
205 bitTiming.phase_seg1 = 7;
206 bitTiming.phase_seg2 = 2;
207 bitTiming.sjw = 1;
208 bitTiming.brp = 6;
209 }
210 break;
211 case B666k:
212 {
213 bitTiming.prop_seg = 3;
214 bitTiming.phase_seg1 = 3;
215 bitTiming.phase_seg2 = 2;
216 bitTiming.sjw = 1;
217 bitTiming.brp = 8;
218 }
219 break;
220 case B800k:
221 {
222 bitTiming.prop_seg = 7;
223 bitTiming.phase_seg1 = 8;
224 bitTiming.phase_seg2 = 4;
225 bitTiming.sjw = 1;
226 bitTiming.brp = 3;
227 }
228 break;
229 case B1000k:
230 {
231 bitTiming.prop_seg = 5;
232 bitTiming.phase_seg1 = 6;
233 bitTiming.phase_seg2 = 4;
234 bitTiming.sjw = 1;
235 bitTiming.brp = 3;
236 }
237 break;
238
239 default:
240 {
241 LOG_ERROR("[InnoMaker-Windows] Unsupported baudrate with index " + isobus::to_string(baudrate) + " in InnoMakerUSB2CANWindowsPlugin::Baudrate enum.");
242 return;
243 }
244 break;
245 }
246 driverInstance->urbSetupDevice(device, CAN_MODE, bitTiming);
247 driverInstance->openInnoMakerDevice(device);
248 }
249 else
250 {
251 LOG_ERROR("[InnoMaker-Windows] No device found on channel " + isobus::to_string(channel));
252 }
253 }
254
256 {
257 InnoMakerUsb2CanLib::InnoMakerDevice *device = driverInstance->getInnoMakerDevice(channel);
258
259 if (nullptr == device)
260 {
261 return false;
262 }
263 BYTE receiveBuffer[sizeof(InnoMakerUsb2CanLib::innomaker_host_frame)];
264 bool success = driverInstance->recvInnoMakerDeviceBuf(device, receiveBuffer, sizeof(InnoMakerUsb2CanLib::innomaker_host_frame), 0xFFFFFFFF);
265 if (!success)
266 {
267 // Most likely a timeout
268 return false;
269 }
270 InnoMakerUsb2CanLib::innomaker_host_frame frame;
271 memcpy(&frame, receiveBuffer, sizeof(InnoMakerUsb2CanLib::innomaker_host_frame));
272
273 if (0xFFFFFFFF != frame.echo_id)
274 {
275 InnoMakerUsb2CanLib::innomaker_tx_context *txc = driverInstance->innomaker_get_tx_context(txContexts.get(), frame.echo_id);
276 if (nullptr == txc)
277 {
278 LOG_WARNING("[InnoMaker-Windows] Received frame with bad echo ID: " + isobus::to_string(static_cast<int>(frame.echo_id)));
279 return false;
280 }
281 driverInstance->innomaker_free_tx_context(txc);
282
284 return false;
285 }
286
287 canFrame.dataLength = frame.can_dlc;
288 canFrame.isExtendedFrame = frame.can_id & CAN_EFF_FLAG;
289 if (canFrame.isExtendedFrame)
290 {
291 canFrame.identifier = frame.can_id & CAN_EFF_MASK;
292 }
293 else
294 {
295 canFrame.identifier = frame.can_id & CAN_SFF_MASK;
296 }
297 canFrame.timestamp_us = frame.timestamp_us;
298 memcpy(canFrame.data, frame.data, canFrame.dataLength);
299 return true;
300 }
301
303 {
304 InnoMakerUsb2CanLib::InnoMakerDevice *device = driverInstance->getInnoMakerDevice(channel);
305 if (nullptr == device)
306 {
307 return false;
308 }
309
310 InnoMakerUsb2CanLib::innomaker_tx_context *txc = driverInstance->innomaker_alloc_tx_context(txContexts.get());
311 if (0xFF == txc->echo_id)
312 {
313 LOG_DEBUG("[InnoMaker-Windows] No free transmission context");
314 return false;
315 }
316
317 InnoMakerUsb2CanLib::innomaker_host_frame frame;
318 memset(&frame, 0, sizeof(InnoMakerUsb2CanLib::innomaker_host_frame));
319
320 frame.echo_id = txc->echo_id;
321 frame.can_dlc = canFrame.dataLength;
322 frame.can_id = canFrame.identifier;
323 memcpy(frame.data, canFrame.data, canFrame.dataLength);
324
325 if (canFrame.isExtendedFrame)
326 {
327 frame.can_id |= CAN_EFF_FLAG;
328 }
329
330 BYTE sendBuffer[sizeof(InnoMakerUsb2CanLib::innomaker_host_frame)];
331 memcpy(sendBuffer, &frame, sizeof(InnoMakerUsb2CanLib::innomaker_host_frame));
332
333 bool success = driverInstance->sendInnoMakerDeviceBuf(device, sendBuffer, sizeof(InnoMakerUsb2CanLib::innomaker_host_frame), 10);
334 if (!success)
335 {
336 LOG_WARNING("[InnoMaker-Windows] Failed to send frame");
337 driverInstance->innomaker_free_tx_context(txc);
338 }
339 return success;
340 }
341}
A class that acts as a logging sink. The intent is that someone could make their own derived class of...
A CAN frame for interfacing with a hardware layer, like socket CAN or other interface.
std::uint8_t dataLength
The length of the data used in the frame.
std::uint32_t identifier
The 32 bit identifier of the frame.
std::uint64_t timestamp_us
A microsecond timestamp.
bool isExtendedFrame
Denotes if the frame is extended format.
std::uint8_t data[8]
The data payload of the frame.
static constexpr std::uint32_t CAN_EFF_MASK
The mask for extended frames.
static constexpr std::uint32_t CAN_SFF_MASK
The mask for standard frames.
InnoMakerUSB2CANWindowsPlugin(int channel, Baudrate baudrate=B250k)
Constructor for the Windows version of the InnoMaker USB2CAN Windows CAN driver.
std::unique_ptr< InnoMakerUsb2CanLib::innomaker_can > txContexts
Stores Tx tickets for the driver.
bool write_frame(const isobus::CANMessageFrame &canFrame) override
Writes a frame to the bus (synchronous)
static std::unique_ptr< InnoMakerUsb2CanLib > driverInstance
The driver itself.
Baudrate
The baudrates supported by the InnoMaker USB2CAN device.
void open() override
Connects to the hardware you specified in the constructor's channel argument.
const int channel
Stores the channel associated with this object.
static constexpr std::uint32_t CAN_EFF_FLAG
Set if the frame is extended.
virtual ~InnoMakerUSB2CANWindowsPlugin()
The destructor for InnoMakerUSB2CANWindowsPlugin.
bool read_frame(isobus::CANMessageFrame &canFrame) override
Returns a frame from the hardware (synchronous), or false if no frame can be read.
void close() override
Closes the connection to the hardware.
const std::uint32_t baudrate
Stores the baud rate associated with this object.
static constexpr InnoMakerUsb2CanLib::UsbCanMode CAN_MODE
The mode to use for the CAN device.
bool get_is_valid() const override
Returns if the connection with the hardware is valid.
An interface for using an InnoMaker USB2CAN device.
This namespace encompasses all of the ISO11783 stack's functionality to reduce global namespace pollu...