blob: 0f190a5670a5603476af813633e24cb045bbd835 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
2
3#include "ctre/CtreCanNode.h"
4#include "FRC_NetworkCommunication/CANSessionMux.h"
5#include <string.h> // memset
6#include <unistd.h> // usleep
7
8static const UINT32 kFullMessageIDMask = 0x1fffffff;
9
10CtreCanNode::CtreCanNode(UINT8 deviceNumber)
11{
12 _deviceNumber = deviceNumber;
13}
14CtreCanNode::~CtreCanNode()
15{
16}
17void CtreCanNode::RegisterRx(uint32_t arbId)
18{
19 /* no need to do anything, we just use new API to poll last received message */
20}
Brian Silverman1a675112016-02-20 20:42:49 -050021/**
22 * Schedule a CAN Frame for periodic transmit.
23 * @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
24 * @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
25 * @param dlc Number of bytes to transmit (0 to 8).
26 * @param initialFrame Ptr to the frame data to schedule for transmitting. Passing null will result
27 * in defaulting to zero data value.
28 */
29void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs, uint32_t dlc, const uint8_t * initialFrame)
Brian Silverman26e4e522015-12-17 01:56:40 -050030{
31 int32_t status = 0;
Brian Silverman1a675112016-02-20 20:42:49 -050032 if(dlc > 8)
33 dlc = 8;
Brian Silverman26e4e522015-12-17 01:56:40 -050034 txJob_t job = {0};
35 job.arbId = arbId;
36 job.periodMs = periodMs;
Brian Silverman1a675112016-02-20 20:42:49 -050037 job.dlc = dlc;
38 if(initialFrame){
39 /* caller wants to specify original data */
40 memcpy(job.toSend, initialFrame, dlc);
41 }
Brian Silverman26e4e522015-12-17 01:56:40 -050042 _txJobs[arbId] = job;
43 FRC_NetworkCommunication_CANSessionMux_sendMessage( job.arbId,
44 job.toSend,
Brian Silverman1a675112016-02-20 20:42:49 -050045 job.dlc,
Brian Silverman26e4e522015-12-17 01:56:40 -050046 job.periodMs,
47 &status);
48}
Brian Silverman1a675112016-02-20 20:42:49 -050049/**
50 * Schedule a CAN Frame for periodic transmit. Assume eight byte DLC and zero value for initial transmission.
51 * @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
52 * @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
53 */
54void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs)
55{
56 RegisterTx(arbId,periodMs, 8, 0);
57}
58/**
59 * Remove a CAN frame Arbid to stop transmission.
60 * @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
61 */
62void CtreCanNode::UnregisterTx(uint32_t arbId)
63{
64 /* set period to zero */
65 ChangeTxPeriod(arbId, 0);
66 /* look and remove */
67 txJobs_t::iterator iter = _txJobs.find(arbId);
68 if(iter != _txJobs.end()) {
69 _txJobs.erase(iter);
70 }
71}
Brian Silverman26e4e522015-12-17 01:56:40 -050072timespec diff(const timespec & start, const timespec & end)
73{
74 timespec temp;
75 if ((end.tv_nsec-start.tv_nsec)<0) {
76 temp.tv_sec = end.tv_sec-start.tv_sec-1;
77 temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
78 } else {
79 temp.tv_sec = end.tv_sec-start.tv_sec;
80 temp.tv_nsec = end.tv_nsec-start.tv_nsec;
81 }
82 return temp;
83}
84CTR_Code CtreCanNode::GetRx(uint32_t arbId,uint8_t * dataBytes, uint32_t timeoutMs)
85{
86 CTR_Code retval = CTR_OKAY;
87 int32_t status = 0;
88 uint8_t len = 0;
89 uint32_t timeStamp;
90 /* cap timeout at 999ms */
91 if(timeoutMs > 999)
92 timeoutMs = 999;
93 FRC_NetworkCommunication_CANSessionMux_receiveMessage(&arbId,kFullMessageIDMask,dataBytes,&len,&timeStamp,&status);
94 if(status == 0){
95 /* fresh update */
96 rxEvent_t & r = _rxRxEvents[arbId]; /* lookup entry or make a default new one with all zeroes */
97 clock_gettime(2,&r.time); /* fill in time */
98 memcpy(r.bytes, dataBytes, 8); /* fill in databytes */
99 }else{
100 /* did not get the message */
101 rxRxEvents_t::iterator i = _rxRxEvents.find(arbId);
102 if(i == _rxRxEvents.end()){
103 /* we've never gotten this mesage */
104 retval = CTR_RxTimeout;
105 /* fill caller's buffer with zeros */
106 memset(dataBytes,0,8);
107 }else{
108 /* we've gotten this message before but not recently */
109 memcpy(dataBytes,i->second.bytes,8);
110 /* get the time now */
111 struct timespec temp;
112 clock_gettime(2,&temp); /* get now */
113 /* how long has it been? */
114 temp = diff(i->second.time,temp); /* temp = now - last */
115 if(temp.tv_sec > 0){
116 retval = CTR_RxTimeout;
117 }else if(temp.tv_nsec > ((int32_t)timeoutMs*1000*1000)){
118 retval = CTR_RxTimeout;
119 }else {
120 /* our last update was recent enough */
121 }
122 }
123 }
124
125 return retval;
126}
127void CtreCanNode::FlushTx(uint32_t arbId)
128{
129 int32_t status = 0;
130 txJobs_t::iterator iter = _txJobs.find(arbId);
131 if(iter != _txJobs.end())
132 FRC_NetworkCommunication_CANSessionMux_sendMessage( iter->second.arbId,
133 iter->second.toSend,
Brian Silverman1a675112016-02-20 20:42:49 -0500134 iter->second.dlc,
Brian Silverman26e4e522015-12-17 01:56:40 -0500135 iter->second.periodMs,
136 &status);
137}
Brian Silverman1a675112016-02-20 20:42:49 -0500138/**
139 * Change the transmit period of an already scheduled CAN frame.
140 * This keeps the frame payload contents the same without caller having to perform
141 * a read-modify-write.
142 * @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
143 * @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
144 * @return true if scheduled job was found and updated, false if there was no preceding job for the specified arbID.
145 */
146bool CtreCanNode::ChangeTxPeriod(uint32_t arbId, uint32_t periodMs)
147{
148 int32_t status = 0;
149 /* lookup the data bytes and period for this message */
150 txJobs_t::iterator iter = _txJobs.find(arbId);
151 if(iter != _txJobs.end()) {
152 /* modify th periodMs */
153 iter->second.periodMs = periodMs;
154 /* reinsert into scheduler with the same data bytes, only the period changed. */
155 FRC_NetworkCommunication_CANSessionMux_sendMessage( iter->second.arbId,
156 iter->second.toSend,
157 iter->second.dlc,
158 iter->second.periodMs,
159 &status);
160 return true;
161 }
162 return false;
163}
Brian Silverman26e4e522015-12-17 01:56:40 -0500164