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