blob: f60e88155149dabc72d5163d512d5499329da406 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
Austin Schuh1e69f942020-11-14 15:06:14 -08002/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
Brian Silverman8fce7482020-01-05 13:18:21 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "hal/PDP.h"
9
Brian Silverman8fce7482020-01-05 13:18:21 -080010#include <wpi/mutex.h>
11
12#include "HALInitializer.h"
13#include "PortsInternal.h"
14#include "hal/CANAPI.h"
15#include "hal/Errors.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080016
17using namespace hal;
18
19static constexpr HAL_CANManufacturer manufacturer =
20 HAL_CANManufacturer::HAL_CAN_Man_kCTRE;
21
22static constexpr HAL_CANDeviceType deviceType =
23 HAL_CANDeviceType::HAL_CAN_Dev_kPowerDistribution;
24
25static constexpr int32_t Status1 = 0x50;
26static constexpr int32_t Status2 = 0x51;
27static constexpr int32_t Status3 = 0x52;
28static constexpr int32_t StatusEnergy = 0x5D;
29
30static constexpr int32_t Control1 = 0x70;
31
32static constexpr int32_t TimeoutMs = 100;
33
34/* encoder/decoders */
35union PdpStatus1 {
36 uint8_t data[8];
37 struct Bits {
38 unsigned chan1_h8 : 8;
39 unsigned chan2_h6 : 6;
40 unsigned chan1_l2 : 2;
41 unsigned chan3_h4 : 4;
42 unsigned chan2_l4 : 4;
43 unsigned chan4_h2 : 2;
44 unsigned chan3_l6 : 6;
45 unsigned chan4_l8 : 8;
46 unsigned chan5_h8 : 8;
47 unsigned chan6_h6 : 6;
48 unsigned chan5_l2 : 2;
49 unsigned reserved4 : 4;
50 unsigned chan6_l4 : 4;
51 } bits;
52};
53
54union PdpStatus2 {
55 uint8_t data[8];
56 struct Bits {
57 unsigned chan7_h8 : 8;
58 unsigned chan8_h6 : 6;
59 unsigned chan7_l2 : 2;
60 unsigned chan9_h4 : 4;
61 unsigned chan8_l4 : 4;
62 unsigned chan10_h2 : 2;
63 unsigned chan9_l6 : 6;
64 unsigned chan10_l8 : 8;
65 unsigned chan11_h8 : 8;
66 unsigned chan12_h6 : 6;
67 unsigned chan11_l2 : 2;
68 unsigned reserved4 : 4;
69 unsigned chan12_l4 : 4;
70 } bits;
71};
72
73union PdpStatus3 {
74 uint8_t data[8];
75 struct Bits {
76 unsigned chan13_h8 : 8;
77 unsigned chan14_h6 : 6;
78 unsigned chan13_l2 : 2;
79 unsigned chan15_h4 : 4;
80 unsigned chan14_l4 : 4;
81 unsigned chan16_h2 : 2;
82 unsigned chan15_l6 : 6;
83 unsigned chan16_l8 : 8;
84 unsigned internalResBattery_mOhms : 8;
85 unsigned busVoltage : 8;
86 unsigned temp : 8;
87 } bits;
88};
89
90union PdpStatusEnergy {
91 uint8_t data[8];
92 struct Bits {
93 unsigned TmeasMs_likelywillbe20ms_ : 8;
94 unsigned TotalCurrent_125mAperunit_h8 : 8;
95 unsigned Power_125mWperunit_h4 : 4;
96 unsigned TotalCurrent_125mAperunit_l4 : 4;
97 unsigned Power_125mWperunit_m8 : 8;
98 unsigned Energy_125mWPerUnitXTmeas_h4 : 4;
99 unsigned Power_125mWperunit_l4 : 4;
100 unsigned Energy_125mWPerUnitXTmeas_mh8 : 8;
101 unsigned Energy_125mWPerUnitXTmeas_ml8 : 8;
102 unsigned Energy_125mWPerUnitXTmeas_l8 : 8;
103 } bits;
104};
105
106static wpi::mutex pdpHandleMutex;
107static HAL_PDPHandle pdpHandles[kNumPDPModules];
108
109namespace hal {
110namespace init {
111void InitializePDP() {
112 for (int i = 0; i < kNumPDPModules; i++) {
113 pdpHandles[i] = HAL_kInvalidHandle;
114 }
115}
116} // namespace init
117} // namespace hal
118
119extern "C" {
120
121HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status) {
122 hal::init::CheckInit();
123 if (!HAL_CheckPDPModule(module)) {
124 *status = PARAMETER_OUT_OF_RANGE;
125 return HAL_kInvalidHandle;
126 }
127
128 std::scoped_lock lock(pdpHandleMutex);
129
130 if (pdpHandles[module] != HAL_kInvalidHandle) {
131 *status = 0;
132 return pdpHandles[module];
133 }
134
135 auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
136
137 if (*status != 0) {
138 HAL_CleanCAN(handle);
139 return HAL_kInvalidHandle;
140 }
141
142 pdpHandles[module] = handle;
143
144 return handle;
145}
146
147void HAL_CleanPDP(HAL_PDPHandle handle) {
148 HAL_CleanCAN(handle);
149
150 for (int i = 0; i < kNumPDPModules; i++) {
151 if (pdpHandles[i] == handle) {
152 pdpHandles[i] = HAL_kInvalidHandle;
153 return;
154 }
155 }
156}
157
158HAL_Bool HAL_CheckPDPModule(int32_t module) {
159 return module < kNumPDPModules && module >= 0;
160}
161
162HAL_Bool HAL_CheckPDPChannel(int32_t channel) {
163 return channel < kNumPDPChannels && channel >= 0;
164}
165
166double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
167 PdpStatus3 pdpStatus;
168 int32_t length = 0;
169 uint64_t receivedTimestamp = 0;
170
171 HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
172 &receivedTimestamp, TimeoutMs, status);
173
174 if (*status != 0) {
175 return 0;
176 } else {
177 return pdpStatus.bits.temp * 1.03250836957542 - 67.8564500484966;
178 }
179}
180
181double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
182 PdpStatus3 pdpStatus;
183 int32_t length = 0;
184 uint64_t receivedTimestamp = 0;
185
186 HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
187 &receivedTimestamp, TimeoutMs, status);
188
189 if (*status != 0) {
190 return 0;
191 } else {
192 return pdpStatus.bits.busVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
193 }
194}
195
196double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
197 int32_t* status) {
198 if (!HAL_CheckPDPChannel(channel)) {
199 *status = PARAMETER_OUT_OF_RANGE;
200 return 0;
201 }
202
203 int32_t length = 0;
204 uint64_t receivedTimestamp = 0;
205
206 double raw = 0;
207
208 if (channel <= 5) {
209 PdpStatus1 pdpStatus;
210 HAL_ReadCANPacketTimeout(handle, Status1, pdpStatus.data, &length,
211 &receivedTimestamp, TimeoutMs, status);
212 if (*status != 0) {
213 return 0;
214 }
215 switch (channel) {
216 case 0:
217 raw = (static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
218 pdpStatus.bits.chan1_l2;
219 break;
220 case 1:
221 raw = (static_cast<uint32_t>(pdpStatus.bits.chan2_h6) << 4) |
222 pdpStatus.bits.chan2_l4;
223 break;
224 case 2:
225 raw = (static_cast<uint32_t>(pdpStatus.bits.chan3_h4) << 6) |
226 pdpStatus.bits.chan3_l6;
227 break;
228 case 3:
229 raw = (static_cast<uint32_t>(pdpStatus.bits.chan4_h2) << 8) |
230 pdpStatus.bits.chan4_l8;
231 break;
232 case 4:
233 raw = (static_cast<uint32_t>(pdpStatus.bits.chan5_h8) << 2) |
234 pdpStatus.bits.chan5_l2;
235 break;
236 case 5:
237 raw = (static_cast<uint32_t>(pdpStatus.bits.chan6_h6) << 4) |
238 pdpStatus.bits.chan6_l4;
239 break;
240 }
241 } else if (channel <= 11) {
242 PdpStatus2 pdpStatus;
243 HAL_ReadCANPacketTimeout(handle, Status2, pdpStatus.data, &length,
244 &receivedTimestamp, TimeoutMs, status);
245 if (*status != 0) {
246 return 0;
247 }
248 switch (channel) {
249 case 6:
250 raw = (static_cast<uint32_t>(pdpStatus.bits.chan7_h8) << 2) |
251 pdpStatus.bits.chan7_l2;
252 break;
253 case 7:
254 raw = (static_cast<uint32_t>(pdpStatus.bits.chan8_h6) << 4) |
255 pdpStatus.bits.chan8_l4;
256 break;
257 case 8:
258 raw = (static_cast<uint32_t>(pdpStatus.bits.chan9_h4) << 6) |
259 pdpStatus.bits.chan9_l6;
260 break;
261 case 9:
262 raw = (static_cast<uint32_t>(pdpStatus.bits.chan10_h2) << 8) |
263 pdpStatus.bits.chan10_l8;
264 break;
265 case 10:
266 raw = (static_cast<uint32_t>(pdpStatus.bits.chan11_h8) << 2) |
267 pdpStatus.bits.chan11_l2;
268 break;
269 case 11:
270 raw = (static_cast<uint32_t>(pdpStatus.bits.chan12_h6) << 4) |
271 pdpStatus.bits.chan12_l4;
272 break;
273 }
274 } else {
275 PdpStatus3 pdpStatus;
276 HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
277 &receivedTimestamp, TimeoutMs, status);
278 if (*status != 0) {
279 return 0;
280 }
281 switch (channel) {
282 case 12:
283 raw = (static_cast<uint32_t>(pdpStatus.bits.chan13_h8) << 2) |
284 pdpStatus.bits.chan13_l2;
285 break;
286 case 13:
287 raw = (static_cast<uint32_t>(pdpStatus.bits.chan14_h6) << 4) |
288 pdpStatus.bits.chan14_l4;
289 break;
290 case 14:
291 raw = (static_cast<uint32_t>(pdpStatus.bits.chan15_h4) << 6) |
292 pdpStatus.bits.chan15_l6;
293 break;
294 case 15:
295 raw = (static_cast<uint32_t>(pdpStatus.bits.chan16_h2) << 8) |
296 pdpStatus.bits.chan16_l8;
297 break;
298 }
299 }
300
301 /* convert to amps */
302 return raw * 0.125; /* 7.3 fixed pt value in Amps */
303}
304
305void HAL_GetPDPAllChannelCurrents(HAL_PDPHandle handle, double* currents,
306 int32_t* status) {
307 int32_t length = 0;
308 uint64_t receivedTimestamp = 0;
309 PdpStatus1 pdpStatus;
310 HAL_ReadCANPacketTimeout(handle, Status1, pdpStatus.data, &length,
311 &receivedTimestamp, TimeoutMs, status);
312 if (*status != 0) return;
313 PdpStatus2 pdpStatus2;
314 HAL_ReadCANPacketTimeout(handle, Status2, pdpStatus2.data, &length,
315 &receivedTimestamp, TimeoutMs, status);
316 if (*status != 0) return;
317 PdpStatus3 pdpStatus3;
318 HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus3.data, &length,
319 &receivedTimestamp, TimeoutMs, status);
320 if (*status != 0) return;
321
322 currents[0] = ((static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
323 pdpStatus.bits.chan1_l2) *
324 0.125;
325 currents[1] = ((static_cast<uint32_t>(pdpStatus.bits.chan2_h6) << 4) |
326 pdpStatus.bits.chan2_l4) *
327 0.125;
328 currents[2] = ((static_cast<uint32_t>(pdpStatus.bits.chan3_h4) << 6) |
329 pdpStatus.bits.chan3_l6) *
330 0.125;
331 currents[3] = ((static_cast<uint32_t>(pdpStatus.bits.chan4_h2) << 8) |
332 pdpStatus.bits.chan4_l8) *
333 0.125;
334 currents[4] = ((static_cast<uint32_t>(pdpStatus.bits.chan5_h8) << 2) |
335 pdpStatus.bits.chan5_l2) *
336 0.125;
337 currents[5] = ((static_cast<uint32_t>(pdpStatus.bits.chan6_h6) << 4) |
338 pdpStatus.bits.chan6_l4) *
339 0.125;
340
341 currents[6] = ((static_cast<uint32_t>(pdpStatus2.bits.chan7_h8) << 2) |
342 pdpStatus2.bits.chan7_l2) *
343 0.125;
344 currents[7] = ((static_cast<uint32_t>(pdpStatus2.bits.chan8_h6) << 4) |
345 pdpStatus2.bits.chan8_l4) *
346 0.125;
347 currents[8] = ((static_cast<uint32_t>(pdpStatus2.bits.chan9_h4) << 6) |
348 pdpStatus2.bits.chan9_l6) *
349 0.125;
350 currents[9] = ((static_cast<uint32_t>(pdpStatus2.bits.chan10_h2) << 8) |
351 pdpStatus2.bits.chan10_l8) *
352 0.125;
353 currents[10] = ((static_cast<uint32_t>(pdpStatus2.bits.chan11_h8) << 2) |
354 pdpStatus2.bits.chan11_l2) *
355 0.125;
356 currents[11] = ((static_cast<uint32_t>(pdpStatus2.bits.chan12_h6) << 4) |
357 pdpStatus2.bits.chan12_l4) *
358 0.125;
359
360 currents[12] = ((static_cast<uint32_t>(pdpStatus3.bits.chan13_h8) << 2) |
361 pdpStatus3.bits.chan13_l2) *
362 0.125;
363 currents[13] = ((static_cast<uint32_t>(pdpStatus3.bits.chan14_h6) << 4) |
364 pdpStatus3.bits.chan14_l4) *
365 0.125;
366 currents[14] = ((static_cast<uint32_t>(pdpStatus3.bits.chan15_h4) << 6) |
367 pdpStatus3.bits.chan15_l6) *
368 0.125;
369 currents[15] = ((static_cast<uint32_t>(pdpStatus3.bits.chan16_h2) << 8) |
370 pdpStatus3.bits.chan16_l8) *
371 0.125;
372}
373
374double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
375 PdpStatusEnergy pdpStatus;
376 int32_t length = 0;
377 uint64_t receivedTimestamp = 0;
378
379 HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
380 &receivedTimestamp, TimeoutMs, status);
381 if (*status != 0) {
382 return 0;
383 }
384
385 uint32_t raw;
386 raw = pdpStatus.bits.TotalCurrent_125mAperunit_h8;
387 raw <<= 4;
388 raw |= pdpStatus.bits.TotalCurrent_125mAperunit_l4;
389 return 0.125 * raw; /* 7.3 fixed pt value in Amps */
390}
391
392double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
393 PdpStatusEnergy pdpStatus;
394 int32_t length = 0;
395 uint64_t receivedTimestamp = 0;
396
397 HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
398 &receivedTimestamp, TimeoutMs, status);
399 if (*status != 0) {
400 return 0;
401 }
402
403 uint32_t raw;
404 raw = pdpStatus.bits.Power_125mWperunit_h4;
405 raw <<= 8;
406 raw |= pdpStatus.bits.Power_125mWperunit_m8;
407 raw <<= 4;
408 raw |= pdpStatus.bits.Power_125mWperunit_l4;
409 return 0.125 * raw; /* 7.3 fixed pt value in Watts */
410}
411
412double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
413 PdpStatusEnergy pdpStatus;
414 int32_t length = 0;
415 uint64_t receivedTimestamp = 0;
416
417 HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
418 &receivedTimestamp, TimeoutMs, status);
419 if (*status != 0) {
420 return 0;
421 }
422
423 uint32_t raw;
424 raw = pdpStatus.bits.Energy_125mWPerUnitXTmeas_h4;
425 raw <<= 8;
426 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_mh8;
427 raw <<= 8;
428 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_ml8;
429 raw <<= 8;
430 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_l8;
431
432 double energyJoules = 0.125 * raw; /* mW integrated every TmeasMs */
433 energyJoules *= 0.001; /* convert from mW to W */
434 energyJoules *=
435 pdpStatus.bits
436 .TmeasMs_likelywillbe20ms_; /* multiplied by TmeasMs = joules */
Austin Schuh1e69f942020-11-14 15:06:14 -0800437 return energyJoules;
Brian Silverman8fce7482020-01-05 13:18:21 -0800438}
439
440void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
441 uint8_t pdpControl[] = {0x40}; /* only bit set is ResetEnergy */
442 HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
443}
444
445void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {
446 uint8_t pdpControl[] = {0x80}; /* only bit set is ClearStickyFaults */
447 HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
448}
449
450} // extern "C"