blob: acecec44fd6b635f51d0343fcc5035b3bc2fa6e4 [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/Relay.h"
9
10#include "HALInitializer.h"
11#include "PortsInternal.h"
12#include "hal/handles/IndexedHandleResource.h"
13#include "mockdata/RelayDataInternal.h"
14
15using namespace hal;
16
17namespace {
18struct Relay {
19 uint8_t channel;
20 bool fwd;
21};
22} // namespace
23
24static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
25 HAL_HandleEnum::Relay>* relayHandles;
26
27namespace hal {
28namespace init {
29void InitializeRelay() {
30 static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
31 HAL_HandleEnum::Relay>
32 rH;
33 relayHandles = &rH;
34}
35} // namespace init
36} // namespace hal
37
38extern "C" {
39HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
40 int32_t* status) {
41 hal::init::CheckInit();
42 if (*status != 0) return HAL_kInvalidHandle;
43
44 int16_t channel = getPortHandleChannel(portHandle);
45 if (channel == InvalidHandleIndex) {
46 *status = PARAMETER_OUT_OF_RANGE;
47 return HAL_kInvalidHandle;
48 }
49
50 if (!fwd) channel += kNumRelayHeaders; // add 4 to reverse channels
51
52 auto handle = relayHandles->Allocate(channel, status);
53
54 if (*status != 0)
55 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
56
57 auto port = relayHandles->Get(handle);
58 if (port == nullptr) { // would only occur on thread issue.
59 *status = HAL_HANDLE_ERROR;
60 return HAL_kInvalidHandle;
61 }
62
63 if (!fwd) {
64 // Subtract number of headers to put channel in range
65 channel -= kNumRelayHeaders;
66
67 port->fwd = false; // set to reverse
68
69 SimRelayData[channel].initializedReverse = true;
70 } else {
71 port->fwd = true; // set to forward
72 SimRelayData[channel].initializedForward = true;
73 }
74
75 port->channel = static_cast<uint8_t>(channel);
76
77 return handle;
78}
79
80void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle) {
81 auto port = relayHandles->Get(relayPortHandle);
82 relayHandles->Free(relayPortHandle);
83 if (port == nullptr) return;
84 if (port->fwd)
85 SimRelayData[port->channel].initializedForward = false;
86 else
87 SimRelayData[port->channel].initializedReverse = false;
88}
89
90HAL_Bool HAL_CheckRelayChannel(int32_t channel) {
91 // roboRIO only has 4 headers, and the FPGA has
Austin Schuh1e69f942020-11-14 15:06:14 -080092 // separate functions for forward and reverse,
93 // instead of separate channel IDs
Brian Silverman8fce7482020-01-05 13:18:21 -080094 return channel < kNumRelayHeaders && channel >= 0;
95}
96
97void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
98 int32_t* status) {
99 auto port = relayHandles->Get(relayPortHandle);
100 if (port == nullptr) {
101 *status = HAL_HANDLE_ERROR;
102 return;
103 }
104 if (port->fwd)
105 SimRelayData[port->channel].forward = on;
106 else
107 SimRelayData[port->channel].reverse = on;
108}
109
110HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status) {
111 auto port = relayHandles->Get(relayPortHandle);
112 if (port == nullptr) {
113 *status = HAL_HANDLE_ERROR;
114 return false;
115 }
116 if (port->fwd)
117 return SimRelayData[port->channel].forward;
118 else
119 return SimRelayData[port->channel].reverse;
120}
121} // extern "C"