blob: 22ea8c1fc32f108090b8b57e1373e8468be987d6 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
3/* 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
10#include <memory>
11
Brian Silverman60246092019-03-02 13:29:58 -080012#include <wpi/mutex.h>
13
Brian Silverman41cdd3e2019-01-19 19:48:58 -080014#include "HALInitializer.h"
15#include "PortsInternal.h"
16#include "hal/CANAPI.h"
17#include "hal/Errors.h"
18#include "hal/Ports.h"
19#include "hal/handles/IndexedHandleResource.h"
20
21using namespace hal;
22
23static constexpr HAL_CANManufacturer manufacturer =
24 HAL_CANManufacturer::HAL_CAN_Man_kCTRE;
25
26static constexpr HAL_CANDeviceType deviceType =
27 HAL_CANDeviceType::HAL_CAN_Dev_kPowerDistribution;
28
29static constexpr int32_t Status1 = 0x50;
30static constexpr int32_t Status2 = 0x51;
31static constexpr int32_t Status3 = 0x52;
32static constexpr int32_t StatusEnergy = 0x5D;
33
34static constexpr int32_t Control1 = 0x70;
35
36static constexpr int32_t TimeoutMs = 100;
37static constexpr int32_t StatusPeriodMs = 25;
38
39/* encoder/decoders */
40union PdpStatus1 {
41 uint8_t data[8];
42 struct Bits {
43 unsigned chan1_h8 : 8;
44 unsigned chan2_h6 : 6;
45 unsigned chan1_l2 : 2;
46 unsigned chan3_h4 : 4;
47 unsigned chan2_l4 : 4;
48 unsigned chan4_h2 : 2;
49 unsigned chan3_l6 : 6;
50 unsigned chan4_l8 : 8;
51 unsigned chan5_h8 : 8;
52 unsigned chan6_h6 : 6;
53 unsigned chan5_l2 : 2;
54 unsigned reserved4 : 4;
55 unsigned chan6_l4 : 4;
56 } bits;
57};
58
59union PdpStatus2 {
60 uint8_t data[8];
61 struct Bits {
62 unsigned chan7_h8 : 8;
63 unsigned chan8_h6 : 6;
64 unsigned chan7_l2 : 2;
65 unsigned chan9_h4 : 4;
66 unsigned chan8_l4 : 4;
67 unsigned chan10_h2 : 2;
68 unsigned chan9_l6 : 6;
69 unsigned chan10_l8 : 8;
70 unsigned chan11_h8 : 8;
71 unsigned chan12_h6 : 6;
72 unsigned chan11_l2 : 2;
73 unsigned reserved4 : 4;
74 unsigned chan12_l4 : 4;
75 } bits;
76};
77
78union PdpStatus3 {
79 uint8_t data[8];
80 struct Bits {
81 unsigned chan13_h8 : 8;
82 unsigned chan14_h6 : 6;
83 unsigned chan13_l2 : 2;
84 unsigned chan15_h4 : 4;
85 unsigned chan14_l4 : 4;
86 unsigned chan16_h2 : 2;
87 unsigned chan15_l6 : 6;
88 unsigned chan16_l8 : 8;
89 unsigned internalResBattery_mOhms : 8;
90 unsigned busVoltage : 8;
91 unsigned temp : 8;
92 } bits;
93};
94
95union PdpStatusEnergy {
96 uint8_t data[8];
97 struct Bits {
98 unsigned TmeasMs_likelywillbe20ms_ : 8;
99 unsigned TotalCurrent_125mAperunit_h8 : 8;
100 unsigned Power_125mWperunit_h4 : 4;
101 unsigned TotalCurrent_125mAperunit_l4 : 4;
102 unsigned Power_125mWperunit_m8 : 8;
103 unsigned Energy_125mWPerUnitXTmeas_h4 : 4;
104 unsigned Power_125mWperunit_l4 : 4;
105 unsigned Energy_125mWPerUnitXTmeas_mh8 : 8;
106 unsigned Energy_125mWPerUnitXTmeas_ml8 : 8;
107 unsigned Energy_125mWPerUnitXTmeas_l8 : 8;
108 } bits;
109};
110
Brian Silverman60246092019-03-02 13:29:58 -0800111static wpi::mutex pdpHandleMutex;
112static HAL_PDPHandle pdpHandles[kNumPDPModules];
113
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800114namespace hal {
115namespace init {
Brian Silverman60246092019-03-02 13:29:58 -0800116void InitializePDP() {
117 for (int i = 0; i < kNumPDPModules; i++) {
118 pdpHandles[i] = HAL_kInvalidHandle;
119 }
120}
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800121} // namespace init
122} // namespace hal
123
124extern "C" {
125
126HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status) {
127 hal::init::CheckInit();
128 if (!HAL_CheckPDPModule(module)) {
129 *status = PARAMETER_OUT_OF_RANGE;
130 return HAL_kInvalidHandle;
131 }
132
Brian Silverman60246092019-03-02 13:29:58 -0800133 std::lock_guard<wpi::mutex> lock(pdpHandleMutex);
134
135 if (pdpHandles[module] != HAL_kInvalidHandle) {
136 *status = 0;
137 return pdpHandles[module];
138 }
139
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800140 auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
141
142 if (*status != 0) {
143 HAL_CleanCAN(handle);
144 return HAL_kInvalidHandle;
145 }
146
Brian Silverman60246092019-03-02 13:29:58 -0800147 pdpHandles[module] = handle;
148
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800149 return handle;
150}
151
Brian Silverman60246092019-03-02 13:29:58 -0800152void HAL_CleanPDP(HAL_PDPHandle handle) {
153 HAL_CleanCAN(handle);
154
155 for (int i = 0; i < kNumPDPModules; i++) {
156 if (pdpHandles[i] == handle) {
157 pdpHandles[i] = HAL_kInvalidHandle;
158 return;
159 }
160 }
161}
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800162
163HAL_Bool HAL_CheckPDPModule(int32_t module) {
164 return module < kNumPDPModules && module >= 0;
165}
166
167HAL_Bool HAL_CheckPDPChannel(int32_t channel) {
168 return channel < kNumPDPChannels && channel >= 0;
169}
170
171double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
172 PdpStatus3 pdpStatus;
173 int32_t length = 0;
174 uint64_t receivedTimestamp = 0;
175
176 HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
177 &receivedTimestamp, TimeoutMs, StatusPeriodMs,
178 status);
179
180 return pdpStatus.bits.temp * 1.03250836957542 - 67.8564500484966;
181}
182
183double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
184 PdpStatus3 pdpStatus;
185 int32_t length = 0;
186 uint64_t receivedTimestamp = 0;
187
188 HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
189 &receivedTimestamp, TimeoutMs, StatusPeriodMs,
190 status);
191
192 return pdpStatus.bits.busVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
193}
194
195double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
196 int32_t* status) {
197 if (!HAL_CheckPDPChannel(channel)) {
198 *status = PARAMETER_OUT_OF_RANGE;
199 return 0;
200 }
201
202 int32_t length = 0;
203 uint64_t receivedTimestamp = 0;
204
205 double raw = 0;
206
207 if (channel <= 5) {
208 PdpStatus1 pdpStatus;
209 HAL_ReadCANPeriodicPacket(handle, Status1, pdpStatus.data, &length,
210 &receivedTimestamp, TimeoutMs, StatusPeriodMs,
211 status);
212 switch (channel) {
213 case 0:
214 raw = (static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
215 pdpStatus.bits.chan1_l2;
216 break;
217 case 1:
218 raw = (static_cast<uint32_t>(pdpStatus.bits.chan2_h6) << 4) |
219 pdpStatus.bits.chan2_l4;
220 break;
221 case 2:
222 raw = (static_cast<uint32_t>(pdpStatus.bits.chan3_h4) << 6) |
223 pdpStatus.bits.chan3_l6;
224 break;
225 case 3:
226 raw = (static_cast<uint32_t>(pdpStatus.bits.chan4_h2) << 8) |
227 pdpStatus.bits.chan4_l8;
228 break;
229 case 4:
230 raw = (static_cast<uint32_t>(pdpStatus.bits.chan5_h8) << 2) |
231 pdpStatus.bits.chan5_l2;
232 break;
233 case 5:
234 raw = (static_cast<uint32_t>(pdpStatus.bits.chan6_h6) << 4) |
235 pdpStatus.bits.chan6_l4;
236 break;
237 }
238 } else if (channel <= 11) {
239 PdpStatus2 pdpStatus;
240 HAL_ReadCANPeriodicPacket(handle, Status2, pdpStatus.data, &length,
241 &receivedTimestamp, TimeoutMs, StatusPeriodMs,
242 status);
243 switch (channel) {
244 case 6:
245 raw = (static_cast<uint32_t>(pdpStatus.bits.chan7_h8) << 2) |
246 pdpStatus.bits.chan7_l2;
247 break;
248 case 7:
249 raw = (static_cast<uint32_t>(pdpStatus.bits.chan8_h6) << 4) |
250 pdpStatus.bits.chan8_l4;
251 break;
252 case 8:
253 raw = (static_cast<uint32_t>(pdpStatus.bits.chan9_h4) << 6) |
254 pdpStatus.bits.chan9_l6;
255 break;
256 case 9:
257 raw = (static_cast<uint32_t>(pdpStatus.bits.chan10_h2) << 8) |
258 pdpStatus.bits.chan10_l8;
259 break;
260 case 10:
261 raw = (static_cast<uint32_t>(pdpStatus.bits.chan11_h8) << 2) |
262 pdpStatus.bits.chan11_l2;
263 break;
264 case 11:
265 raw = (static_cast<uint32_t>(pdpStatus.bits.chan12_h6) << 4) |
266 pdpStatus.bits.chan12_l4;
267 break;
268 }
269 } else {
270 PdpStatus3 pdpStatus;
271 HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
272 &receivedTimestamp, TimeoutMs, StatusPeriodMs,
273 status);
274 switch (channel) {
275 case 12:
276 raw = (static_cast<uint32_t>(pdpStatus.bits.chan13_h8) << 2) |
277 pdpStatus.bits.chan13_l2;
278 break;
279 case 13:
280 raw = (static_cast<uint32_t>(pdpStatus.bits.chan14_h6) << 4) |
281 pdpStatus.bits.chan14_l4;
282 break;
283 case 14:
284 raw = (static_cast<uint32_t>(pdpStatus.bits.chan15_h4) << 6) |
285 pdpStatus.bits.chan15_l6;
286 break;
287 case 15:
288 raw = (static_cast<uint32_t>(pdpStatus.bits.chan16_h2) << 8) |
289 pdpStatus.bits.chan16_l8;
290 break;
291 }
292 }
293
294 /* convert to amps */
295 return raw * 0.125; /* 7.3 fixed pt value in Amps */
296}
297
298double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
299 PdpStatusEnergy pdpStatus;
300 int32_t length = 0;
301 uint64_t receivedTimestamp = 0;
302
303 HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
304 &receivedTimestamp, TimeoutMs, StatusPeriodMs,
305 status);
306
307 uint32_t raw;
308 raw = pdpStatus.bits.TotalCurrent_125mAperunit_h8;
309 raw <<= 4;
310 raw |= pdpStatus.bits.TotalCurrent_125mAperunit_l4;
311 return 0.125 * raw; /* 7.3 fixed pt value in Amps */
312}
313
314double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
315 PdpStatusEnergy pdpStatus;
316 int32_t length = 0;
317 uint64_t receivedTimestamp = 0;
318
319 HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
320 &receivedTimestamp, TimeoutMs, StatusPeriodMs,
321 status);
322
323 uint32_t raw;
324 raw = pdpStatus.bits.Power_125mWperunit_h4;
325 raw <<= 8;
326 raw |= pdpStatus.bits.Power_125mWperunit_m8;
327 raw <<= 4;
328 raw |= pdpStatus.bits.Power_125mWperunit_l4;
329 return 0.125 * raw; /* 7.3 fixed pt value in Watts */
330}
331
332double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
333 PdpStatusEnergy pdpStatus;
334 int32_t length = 0;
335 uint64_t receivedTimestamp = 0;
336
337 HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
338 &receivedTimestamp, TimeoutMs, StatusPeriodMs,
339 status);
340
341 uint32_t raw;
342 raw = pdpStatus.bits.Energy_125mWPerUnitXTmeas_h4;
343 raw <<= 8;
344 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_mh8;
345 raw <<= 8;
346 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_ml8;
347 raw <<= 8;
348 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_l8;
349
350 double energyJoules = 0.125 * raw; /* mW integrated every TmeasMs */
351 energyJoules *= 0.001; /* convert from mW to W */
352 energyJoules *=
353 pdpStatus.bits
354 .TmeasMs_likelywillbe20ms_; /* multiplied by TmeasMs = joules */
355 return 0.125 * raw;
356}
357
358void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
359 uint8_t pdpControl[] = {0x40}; /* only bit set is ResetEnergy */
360 HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
361}
362
363void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {
364 uint8_t pdpControl[] = {0x80}; /* only bit set is ClearStickyFaults */
365 HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
366}
367
368} // extern "C"