blob: f27f5da82d1d06ac7b6edccb52b59a9431647024 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -08002/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
Brian Silverman41cdd3e2019-01-19 19:48:58 -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
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;
Brian Silverman41cdd3e2019-01-19 19:48:58 -080037
38/* encoder/decoders */
39union PdpStatus1 {
40 uint8_t data[8];
41 struct Bits {
42 unsigned chan1_h8 : 8;
43 unsigned chan2_h6 : 6;
44 unsigned chan1_l2 : 2;
45 unsigned chan3_h4 : 4;
46 unsigned chan2_l4 : 4;
47 unsigned chan4_h2 : 2;
48 unsigned chan3_l6 : 6;
49 unsigned chan4_l8 : 8;
50 unsigned chan5_h8 : 8;
51 unsigned chan6_h6 : 6;
52 unsigned chan5_l2 : 2;
53 unsigned reserved4 : 4;
54 unsigned chan6_l4 : 4;
55 } bits;
56};
57
58union PdpStatus2 {
59 uint8_t data[8];
60 struct Bits {
61 unsigned chan7_h8 : 8;
62 unsigned chan8_h6 : 6;
63 unsigned chan7_l2 : 2;
64 unsigned chan9_h4 : 4;
65 unsigned chan8_l4 : 4;
66 unsigned chan10_h2 : 2;
67 unsigned chan9_l6 : 6;
68 unsigned chan10_l8 : 8;
69 unsigned chan11_h8 : 8;
70 unsigned chan12_h6 : 6;
71 unsigned chan11_l2 : 2;
72 unsigned reserved4 : 4;
73 unsigned chan12_l4 : 4;
74 } bits;
75};
76
77union PdpStatus3 {
78 uint8_t data[8];
79 struct Bits {
80 unsigned chan13_h8 : 8;
81 unsigned chan14_h6 : 6;
82 unsigned chan13_l2 : 2;
83 unsigned chan15_h4 : 4;
84 unsigned chan14_l4 : 4;
85 unsigned chan16_h2 : 2;
86 unsigned chan15_l6 : 6;
87 unsigned chan16_l8 : 8;
88 unsigned internalResBattery_mOhms : 8;
89 unsigned busVoltage : 8;
90 unsigned temp : 8;
91 } bits;
92};
93
94union PdpStatusEnergy {
95 uint8_t data[8];
96 struct Bits {
97 unsigned TmeasMs_likelywillbe20ms_ : 8;
98 unsigned TotalCurrent_125mAperunit_h8 : 8;
99 unsigned Power_125mWperunit_h4 : 4;
100 unsigned TotalCurrent_125mAperunit_l4 : 4;
101 unsigned Power_125mWperunit_m8 : 8;
102 unsigned Energy_125mWPerUnitXTmeas_h4 : 4;
103 unsigned Power_125mWperunit_l4 : 4;
104 unsigned Energy_125mWPerUnitXTmeas_mh8 : 8;
105 unsigned Energy_125mWPerUnitXTmeas_ml8 : 8;
106 unsigned Energy_125mWPerUnitXTmeas_l8 : 8;
107 } bits;
108};
109
Brian Silverman60246092019-03-02 13:29:58 -0800110static wpi::mutex pdpHandleMutex;
111static HAL_PDPHandle pdpHandles[kNumPDPModules];
112
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800113namespace hal {
114namespace init {
Brian Silverman60246092019-03-02 13:29:58 -0800115void InitializePDP() {
116 for (int i = 0; i < kNumPDPModules; i++) {
117 pdpHandles[i] = HAL_kInvalidHandle;
118 }
119}
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800120} // namespace init
121} // namespace hal
122
123extern "C" {
124
125HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status) {
126 hal::init::CheckInit();
127 if (!HAL_CheckPDPModule(module)) {
128 *status = PARAMETER_OUT_OF_RANGE;
129 return HAL_kInvalidHandle;
130 }
131
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800132 std::scoped_lock lock(pdpHandleMutex);
Brian Silverman60246092019-03-02 13:29:58 -0800133
134 if (pdpHandles[module] != HAL_kInvalidHandle) {
135 *status = 0;
136 return pdpHandles[module];
137 }
138
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800139 auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
140
141 if (*status != 0) {
142 HAL_CleanCAN(handle);
143 return HAL_kInvalidHandle;
144 }
145
Brian Silverman60246092019-03-02 13:29:58 -0800146 pdpHandles[module] = handle;
147
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800148 return handle;
149}
150
Brian Silverman60246092019-03-02 13:29:58 -0800151void HAL_CleanPDP(HAL_PDPHandle handle) {
152 HAL_CleanCAN(handle);
153
154 for (int i = 0; i < kNumPDPModules; i++) {
155 if (pdpHandles[i] == handle) {
156 pdpHandles[i] = HAL_kInvalidHandle;
157 return;
158 }
159 }
160}
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800161
162HAL_Bool HAL_CheckPDPModule(int32_t module) {
163 return module < kNumPDPModules && module >= 0;
164}
165
166HAL_Bool HAL_CheckPDPChannel(int32_t channel) {
167 return channel < kNumPDPChannels && channel >= 0;
168}
169
170double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
171 PdpStatus3 pdpStatus;
172 int32_t length = 0;
173 uint64_t receivedTimestamp = 0;
174
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800175 HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
176 &receivedTimestamp, TimeoutMs, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800177
178 return pdpStatus.bits.temp * 1.03250836957542 - 67.8564500484966;
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
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800186 HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
187 &receivedTimestamp, TimeoutMs, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800188
189 return pdpStatus.bits.busVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
190}
191
192double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
193 int32_t* status) {
194 if (!HAL_CheckPDPChannel(channel)) {
195 *status = PARAMETER_OUT_OF_RANGE;
196 return 0;
197 }
198
199 int32_t length = 0;
200 uint64_t receivedTimestamp = 0;
201
202 double raw = 0;
203
204 if (channel <= 5) {
205 PdpStatus1 pdpStatus;
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800206 HAL_ReadCANPacketTimeout(handle, Status1, pdpStatus.data, &length,
207 &receivedTimestamp, TimeoutMs, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800208 switch (channel) {
209 case 0:
210 raw = (static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
211 pdpStatus.bits.chan1_l2;
212 break;
213 case 1:
214 raw = (static_cast<uint32_t>(pdpStatus.bits.chan2_h6) << 4) |
215 pdpStatus.bits.chan2_l4;
216 break;
217 case 2:
218 raw = (static_cast<uint32_t>(pdpStatus.bits.chan3_h4) << 6) |
219 pdpStatus.bits.chan3_l6;
220 break;
221 case 3:
222 raw = (static_cast<uint32_t>(pdpStatus.bits.chan4_h2) << 8) |
223 pdpStatus.bits.chan4_l8;
224 break;
225 case 4:
226 raw = (static_cast<uint32_t>(pdpStatus.bits.chan5_h8) << 2) |
227 pdpStatus.bits.chan5_l2;
228 break;
229 case 5:
230 raw = (static_cast<uint32_t>(pdpStatus.bits.chan6_h6) << 4) |
231 pdpStatus.bits.chan6_l4;
232 break;
233 }
234 } else if (channel <= 11) {
235 PdpStatus2 pdpStatus;
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800236 HAL_ReadCANPacketTimeout(handle, Status2, pdpStatus.data, &length,
237 &receivedTimestamp, TimeoutMs, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800238 switch (channel) {
239 case 6:
240 raw = (static_cast<uint32_t>(pdpStatus.bits.chan7_h8) << 2) |
241 pdpStatus.bits.chan7_l2;
242 break;
243 case 7:
244 raw = (static_cast<uint32_t>(pdpStatus.bits.chan8_h6) << 4) |
245 pdpStatus.bits.chan8_l4;
246 break;
247 case 8:
248 raw = (static_cast<uint32_t>(pdpStatus.bits.chan9_h4) << 6) |
249 pdpStatus.bits.chan9_l6;
250 break;
251 case 9:
252 raw = (static_cast<uint32_t>(pdpStatus.bits.chan10_h2) << 8) |
253 pdpStatus.bits.chan10_l8;
254 break;
255 case 10:
256 raw = (static_cast<uint32_t>(pdpStatus.bits.chan11_h8) << 2) |
257 pdpStatus.bits.chan11_l2;
258 break;
259 case 11:
260 raw = (static_cast<uint32_t>(pdpStatus.bits.chan12_h6) << 4) |
261 pdpStatus.bits.chan12_l4;
262 break;
263 }
264 } else {
265 PdpStatus3 pdpStatus;
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800266 HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
267 &receivedTimestamp, TimeoutMs, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800268 switch (channel) {
269 case 12:
270 raw = (static_cast<uint32_t>(pdpStatus.bits.chan13_h8) << 2) |
271 pdpStatus.bits.chan13_l2;
272 break;
273 case 13:
274 raw = (static_cast<uint32_t>(pdpStatus.bits.chan14_h6) << 4) |
275 pdpStatus.bits.chan14_l4;
276 break;
277 case 14:
278 raw = (static_cast<uint32_t>(pdpStatus.bits.chan15_h4) << 6) |
279 pdpStatus.bits.chan15_l6;
280 break;
281 case 15:
282 raw = (static_cast<uint32_t>(pdpStatus.bits.chan16_h2) << 8) |
283 pdpStatus.bits.chan16_l8;
284 break;
285 }
286 }
287
288 /* convert to amps */
289 return raw * 0.125; /* 7.3 fixed pt value in Amps */
290}
291
292double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
293 PdpStatusEnergy pdpStatus;
294 int32_t length = 0;
295 uint64_t receivedTimestamp = 0;
296
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800297 HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
298 &receivedTimestamp, TimeoutMs, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800299
300 uint32_t raw;
301 raw = pdpStatus.bits.TotalCurrent_125mAperunit_h8;
302 raw <<= 4;
303 raw |= pdpStatus.bits.TotalCurrent_125mAperunit_l4;
304 return 0.125 * raw; /* 7.3 fixed pt value in Amps */
305}
306
307double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
308 PdpStatusEnergy pdpStatus;
309 int32_t length = 0;
310 uint64_t receivedTimestamp = 0;
311
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800312 HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
313 &receivedTimestamp, TimeoutMs, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800314
315 uint32_t raw;
316 raw = pdpStatus.bits.Power_125mWperunit_h4;
317 raw <<= 8;
318 raw |= pdpStatus.bits.Power_125mWperunit_m8;
319 raw <<= 4;
320 raw |= pdpStatus.bits.Power_125mWperunit_l4;
321 return 0.125 * raw; /* 7.3 fixed pt value in Watts */
322}
323
324double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
325 PdpStatusEnergy pdpStatus;
326 int32_t length = 0;
327 uint64_t receivedTimestamp = 0;
328
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800329 HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
330 &receivedTimestamp, TimeoutMs, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800331
332 uint32_t raw;
333 raw = pdpStatus.bits.Energy_125mWPerUnitXTmeas_h4;
334 raw <<= 8;
335 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_mh8;
336 raw <<= 8;
337 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_ml8;
338 raw <<= 8;
339 raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_l8;
340
341 double energyJoules = 0.125 * raw; /* mW integrated every TmeasMs */
342 energyJoules *= 0.001; /* convert from mW to W */
343 energyJoules *=
344 pdpStatus.bits
345 .TmeasMs_likelywillbe20ms_; /* multiplied by TmeasMs = joules */
346 return 0.125 * raw;
347}
348
349void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
350 uint8_t pdpControl[] = {0x40}; /* only bit set is ResetEnergy */
351 HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
352}
353
354void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {
355 uint8_t pdpControl[] = {0x80}; /* only bit set is ClearStickyFaults */
356 HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
357}
358
359} // extern "C"