1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <stdint.h>
#include <hal/CANAPI.h>
namespace frc {
struct CANData {
/** Contents of the CAN packet. */
uint8_t data[8];
/** Length of packet in bytes. */
int32_t length;
/** CAN frame timestamp in milliseconds. */
uint64_t timestamp;
};
/**
* High level class for interfacing with CAN devices conforming to
* the standard CAN spec.
*
* No packets that can be sent gets blocked by the RoboRIO, so all methods
* work identically in all robot modes.
*
* All methods are thread save, however the buffer objects passed in
* by the user need to not be modified for the duration of their calls.
*/
class CAN {
public:
/**
* Create a new CAN communication interface with the specific device ID.
* This uses the team manufacturer and device types.
* The device ID is 6 bits (0-63)
*
* @param deviceId The device id
*/
explicit CAN(int deviceId);
/**
* Create a new CAN communication interface with a specific device ID,
* manufacturer and device type. The device ID is 6 bits, the
* manufacturer is 8 bits, and the device type is 5 bits.
*
* @param deviceId The device ID
* @param deviceManufacturer The device manufacturer
* @param deviceType The device type
*/
CAN(int deviceId, int deviceManufacturer, int deviceType);
CAN(CAN&&) = default;
CAN& operator=(CAN&&) = default;
/**
* Write a packet to the CAN device with a specific ID. This ID is 10 bits.
*
* @param data The data to write (8 bytes max)
* @param length The data length to write
* @param apiId The API ID to write.
*/
void WritePacket(const uint8_t* data, int length, int apiId);
/**
* Write a repeating packet to the CAN device with a specific ID. This ID is
* 10 bits. The RoboRIO will automatically repeat the packet at the specified
* interval
*
* @param data The data to write (8 bytes max)
* @param length The data length to write
* @param apiId The API ID to write.
* @param repeatMs The period to repeat the packet at.
*/
void WritePacketRepeating(const uint8_t* data, int length, int apiId,
int repeatMs);
/**
* Write an RTR frame to the CAN device with a specific ID. This ID is 10
* bits. The length by spec must match what is returned by the responding
* device
*
* @param length The length to request (0 to 8)
* @param apiId The API ID to write.
*/
void WriteRTRFrame(int length, int apiId);
/**
* Write a packet to the CAN device with a specific ID. This ID is 10 bits.
*
* @param data The data to write (8 bytes max)
* @param length The data length to write
* @param apiId The API ID to write.
*/
int WritePacketNoError(const uint8_t* data, int length, int apiId);
/**
* Write a repeating packet to the CAN device with a specific ID. This ID is
* 10 bits. The RoboRIO will automatically repeat the packet at the specified
* interval
*
* @param data The data to write (8 bytes max)
* @param length The data length to write
* @param apiId The API ID to write.
* @param repeatMs The period to repeat the packet at.
*/
int WritePacketRepeatingNoError(const uint8_t* data, int length, int apiId,
int repeatMs);
/**
* Write an RTR frame to the CAN device with a specific ID. This ID is 10
* bits. The length by spec must match what is returned by the responding
* device
*
* @param length The length to request (0 to 8)
* @param apiId The API ID to write.
*/
int WriteRTRFrameNoError(int length, int apiId);
/**
* Stop a repeating packet with a specific ID. This ID is 10 bits.
*
* @param apiId The API ID to stop repeating
*/
void StopPacketRepeating(int apiId);
/**
* Read a new CAN packet. This will only return properly once per packet
* received. Multiple calls without receiving another packet will return
* false.
*
* @param apiId The API ID to read.
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
bool ReadPacketNew(int apiId, CANData* data);
/**
* Read a CAN packet. The will continuously return the last packet received,
* without accounting for packet age.
*
* @param apiId The API ID to read.
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
bool ReadPacketLatest(int apiId, CANData* data);
/**
* Read a CAN packet. The will return the last packet received until the
* packet is older then the requested timeout. Then it will return false.
*
* @param apiId The API ID to read.
* @param timeoutMs The timeout time for the packet
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
bool ReadPacketTimeout(int apiId, int timeoutMs, CANData* data);
/**
* Reads the current value of the millisecond-resolution timer that CANData
* timestamps are based on
*
* @return Current value of timer used as a base time for CANData timestamps
* in milliseconds
*/
static uint64_t GetTimestampBaseTime();
/// Team manufacturer.
static constexpr HAL_CANManufacturer kTeamManufacturer = HAL_CAN_Man_kTeamUse;
/// Team device type.
static constexpr HAL_CANDeviceType kTeamDeviceType =
HAL_CAN_Dev_kMiscellaneous;
private:
hal::Handle<HAL_CANHandle, HAL_CleanCAN> m_handle;
};
} // namespace frc