Skip to content

Commit 4b9c79b

Browse files
Merge pull request #5 from unofficial-rev-port/SocketCAN
Add SocketCAN functionality
2 parents 6576ec7 + 13e3871 commit 4b9c79b

35 files changed

+1007
-28
lines changed

.vscode/settings.json

+16-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,22 @@
6868
"iterator": "cpp",
6969
"sstream": "cpp",
7070
"cctype": "cpp",
71-
"concepts": "cpp"
71+
"concepts": "cpp",
72+
"inet.h": "c",
73+
"cwctype": "cpp",
74+
"array": "cpp",
75+
"hash_map": "cpp",
76+
"*.tcc": "cpp",
77+
"bitset": "cpp",
78+
"complex": "cpp",
79+
"condition_variable": "cpp",
80+
"memory_resource": "cpp",
81+
"numeric": "cpp",
82+
"optional": "cpp",
83+
"random": "cpp",
84+
"set": "cpp",
85+
"string_view": "cpp",
86+
"cinttypes": "cpp"
7287
},
7388
"C_Cpp.default.configurationProvider": "vscode-wpilib",
7489
"C_Cpp.errorSquiggles": "enabled"

.wpilib/wpilib_preferences.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"enableCppIntellisense": true,
33
"currentLanguage": "cpp",
4-
"projectYear": "Beta2020-2",
4+
"projectYear": "2020",
55
"teamNumber": 9999
6-
}
6+
}

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ The output is placed at `~\releases\maven\release\com\revrobotics\usb\CANBridge-
6363
6. Add release notes to the draft release
6464
7. Publish the draft release
6565

66+
## Linux
67+
68+
> [!NOTE]
69+
>
70+
> This branch is a work in progress, testing does show that it does work, however this still might be some issues. If you do run across those issues, please create an issue so we can diagnose.
71+
72+
The latest firmware version will work with Linux if the `SocketCAN` and `gs_usb` drivers are enabled. The following udev rule will work to enable this:
73+
74+
Create a new file named and located at: `/etc/udev/rules.d/99-canbridge.rules`
75+
76+
```text
77+
ACTION=="add", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a30e", RUN+="/sbin/modprobe gs_usb" RUN+="/bin/sh -c 'echo 0483 a30e > /sys/bus/usb/drivers/gs_usb/new_id'"
78+
```
79+
6680
## Changelog
6781

6882
The SDK Changelog can be viewed with [Changelog.md](Changelog.md).

src/main/native/cpp/CANBridge.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 REV Robotics
2+
* Copyright (c) 2019 - 2020 REV Robotics
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions are met:
@@ -45,6 +45,10 @@
4545

4646
#include "rev/Drivers/SerialPort/SerialDriver.h"
4747

48+
#ifdef __linux__
49+
#include "rev/Drivers/SocketCAN/SocketCANDriver.h"
50+
#endif
51+
4852
#include <hal/simulation/CanData.h>
4953
#include <hal/CAN.h>
5054

@@ -61,7 +65,9 @@ static const std::vector<rev::usb::CANDriver*> CANDriverList = {
6165
#ifdef _WIN32
6266
new rev::usb::CandleWinUSBDriver(),
6367
#endif
64-
new rev::usb::SerialDriver()
68+
#ifdef __linux__
69+
new rev::usb::SocketCANDriver(),
70+
#endif
6571
};
6672

6773
static std::vector<std::pair<std::unique_ptr<rev::usb::CANDevice>, rev::usb::CANBridge_CANFilter>> CANDeviceList = {};
@@ -312,3 +318,4 @@ void CANBridge_UnregisterDeviceFromHAL(const char* descriptor)
312318
}
313319

314320

321+

src/main/native/cpp/CANBridgeUtils.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 REV Robotics
2+
* Copyright (c) 2019 - 2020 REV Robotics
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions are met:

src/main/native/cpp/Drivers/CandleWinUSB/CandleWinUSBDevice.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 REV Robotics
2+
* Copyright (c) 2019 - 2020 REV Robotics
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions are met:

src/main/native/cpp/Drivers/CandleWinUSB/CandleWinUSBDriver.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 REV Robotics
2+
* Copyright (c) 2019 - 2020 REV Robotics
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions are met:

src/main/native/cpp/Drivers/Serial/SerialDevice.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 REV Robotics
2+
* Copyright (c) 2019 - 2020 REV Robotics
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions are met:

src/main/native/cpp/Drivers/Serial/SerialDriver.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 REV Robotics
2+
* Copyright (c) 2019 - 2020 REV Robotics
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions are met:

src/main/native/cpp/Drivers/Serial/SerialMessage.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 REV Robotics
2+
* Copyright (c) 2019 - 2020 REV Robotics
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions are met:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#ifdef __linux__
2+
3+
#include "rev/Drivers/SocketCAN/SocketCANDevice.h"
4+
5+
#include <map>
6+
#include <string>
7+
#include <thread>
8+
9+
#include <hal/simulation/CanData.h>
10+
#include <hal/CAN.h>
11+
12+
namespace rev {
13+
namespace usb {
14+
15+
SocketCANDevice::SocketCANDevice(std::string port) :
16+
m_thread(port) {
17+
m_descriptor = port;
18+
// TODO: Get the name of the device, for now just hardcode the name
19+
m_name = "SocketCAN Device";
20+
m_thread.Start();
21+
}
22+
23+
SocketCANDevice::~SocketCANDevice() {
24+
m_thread.Stop();
25+
}
26+
27+
std::string SocketCANDevice::GetName() const {
28+
return m_name;
29+
}
30+
31+
std::string SocketCANDevice::GetDescriptor() const {
32+
return m_descriptor;
33+
}
34+
35+
int SocketCANDevice::GetNumberOfErrors() {
36+
return m_thread.GetNumberOfErrors();
37+
}
38+
39+
int SocketCANDevice::GetId() const {
40+
return 0;
41+
}
42+
43+
CANStatus SocketCANDevice::SendCANMessage(const CANMessage& msg, int periodMs) {
44+
m_thread.EnqueueMessage(msg, periodMs);
45+
return m_thread.GetLastThreadError();
46+
}
47+
48+
CANStatus SocketCANDevice::ReceiveCANMessage(std::shared_ptr<CANMessage>& msg, uint32_t messageID, uint32_t messageMask) {
49+
CANStatus status = CANStatus::kTimeout;
50+
51+
// parse through the keys, find the messges the match, and return it
52+
// The first in the message id, then the messages
53+
std::map<uint32_t, std::shared_ptr<CANMessage>> messages;
54+
m_thread.ReceiveMessage(messages);
55+
std::shared_ptr<CANMessage> mostRecent;
56+
for (auto& m : messages) {
57+
if (
58+
CANBridge_ProcessMask({m.second->GetMessageId(), 0}, m.first)
59+
&& CANBridge_ProcessMask({messageID, messageMask}, m.first)
60+
&& (!mostRecent || m.second->GetTimestampUs() > mostRecent->GetTimestampUs())
61+
) {
62+
mostRecent = m.second;
63+
status = CANStatus::kOk;
64+
}
65+
}
66+
67+
if (status == CANStatus::kOk) {
68+
msg = mostRecent;
69+
status = m_thread.GetLastThreadError();
70+
} else {
71+
status = CANStatus::kError;
72+
}
73+
74+
75+
return status;
76+
}
77+
78+
CANStatus SocketCANDevice::OpenStreamSession(uint32_t* sessionHandle, CANBridge_CANFilter filter, uint32_t maxSize) {
79+
CANStatus stat = CANStatus::kOk;
80+
m_thread.OpenStream(sessionHandle, filter, maxSize, &stat);
81+
return m_thread.GetLastThreadError();
82+
}
83+
84+
CANStatus SocketCANDevice::CloseStreamSession(uint32_t sessionHandle) {
85+
m_thread.CloseStream(sessionHandle);
86+
return m_thread.GetLastThreadError();
87+
}
88+
89+
CANStatus SocketCANDevice::ReadStreamSession(uint32_t sessionHandle, struct HAL_CANStreamMessage* msgs, uint32_t messagesToRead, uint32_t* messagesRead) {
90+
m_thread.ReadStream(sessionHandle, msgs, messagesToRead, messagesRead);
91+
return m_thread.GetLastThreadError();
92+
}
93+
94+
CANStatus SocketCANDevice::GetCANDetailStatus(float* percentBusUtilization, uint32_t* busOff, uint32_t* txFull, uint32_t* receiveErr, uint32_t* transmitErr) {
95+
rev::usb::CANStatusDetails details;
96+
m_thread.GetCANStatus(&details);
97+
*percentBusUtilization = 0.0f;
98+
*busOff = details.busOffCount;
99+
*txFull = details.txFullCount;
100+
*receiveErr = details.receiveErrCount;
101+
*transmitErr = details.transmitErrCount;
102+
return m_thread.GetLastThreadError();
103+
}
104+
105+
CANStatus SocketCANDevice::GetCANDetailStatus(float* percentBusUtilization, uint32_t* busOff, uint32_t* txFull, uint32_t* receiveErr, uint32_t* transmitErr, uint32_t* lastErrorTime) {
106+
return GetCANDetailStatus(percentBusUtilization, busOff, txFull, receiveErr, transmitErr);
107+
}
108+
109+
bool SocketCANDevice::IsConnected() {
110+
// Implementation
111+
return true;
112+
}
113+
114+
} // namespace usb
115+
} // namespace rev
116+
117+
118+
#else
119+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2019 - 2020 REV Robotics
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are met:
6+
*
7+
* 1. Redistributions of source code must retain the above copyright notice,
8+
* this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
* 3. Neither the name of REV Robotics nor the names of its
13+
* contributors may be used to endorse or promote products derived from
14+
* this software without specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
*/
28+
29+
#ifdef __linux__
30+
31+
#include "rev/Drivers/SocketCAN/SocketCANDriver.h"
32+
#include "rev/Drivers/SocketCAN/SocketCANDevice.h"
33+
34+
#include <map>
35+
#include <iostream>
36+
#include <memory>
37+
38+
#include <net/if.h>
39+
40+
namespace rev {
41+
namespace usb {
42+
43+
std::vector<CANDeviceDetail> SocketCANDriver::GetDevices()
44+
{
45+
std::vector<CANDeviceDetail> retval;
46+
47+
// TODO: Better way of doing this?
48+
// find canx or vcanx interface names
49+
struct if_nameindex *if_nidxs, *intf;
50+
51+
if_nidxs = if_nameindex();
52+
if ( if_nidxs != NULL )
53+
{
54+
for (intf = if_nidxs; intf->if_index != 0 || intf->if_name != NULL; intf++)
55+
{
56+
char* buf = intf->if_name;
57+
58+
// Not possible can name, protect later compares
59+
if (strnlen(buf, 4) < 4) {
60+
continue;
61+
}
62+
63+
// possibly vcanx
64+
if (buf[0] == 'v') {
65+
buf++;
66+
}
67+
68+
if (strncmp(buf, "can", 3) == 0) {
69+
std::string ifnameStr = std::string(intf->if_name);
70+
retval.push_back( {ifnameStr, ifnameStr, this->GetName()} );
71+
}
72+
}
73+
74+
if_freenameindex(if_nidxs);
75+
}
76+
77+
return retval;
78+
}
79+
80+
std::unique_ptr<CANDevice> SocketCANDriver::CreateDeviceFromDescriptor(const char* descriptor)
81+
{
82+
try {
83+
return std::make_unique<SocketCANDevice>(descriptor);
84+
} catch(...) {
85+
// do nothing if it failed
86+
}
87+
return std::unique_ptr<CANDevice>(nullptr);
88+
}
89+
} // namespace usb
90+
} // namespace rev
91+
92+
#else
93+
typedef int __ISOWarning__CLEAR_;
94+
#endif // _WIN32

src/main/native/cpp/ThreadUtils.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019 REV Robotics
2+
* Copyright (c) 2019 - 2020 REV Robotics
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions are met:

0 commit comments

Comments
 (0)