blob: 71880a8d21d450f30d2c0cee51e10fa583b6b3b5 [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/Relay.h"
9
10#include "DigitalInternal.h"
11#include "HALInitializer.h"
12#include "PortsInternal.h"
13#include "hal/handles/IndexedHandleResource.h"
14
15using namespace hal;
16
17namespace {
18
19struct Relay {
20 uint8_t channel;
21 bool fwd;
22};
23
24} // namespace
25
26static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
27 HAL_HandleEnum::Relay>* relayHandles;
28
29// Create a mutex to protect changes to the relay values
30static wpi::mutex digitalRelayMutex;
31
32namespace hal {
33namespace init {
34void InitializeRelay() {
35 static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
36 HAL_HandleEnum::Relay>
37 rH;
38 relayHandles = &rH;
39}
40} // namespace init
41} // namespace hal
42
43extern "C" {
44
45HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
46 int32_t* status) {
47 hal::init::CheckInit();
48 initializeDigital(status);
49
50 if (*status != 0) return HAL_kInvalidHandle;
51
52 int16_t channel = getPortHandleChannel(portHandle);
53 if (channel == InvalidHandleIndex) {
54 *status = PARAMETER_OUT_OF_RANGE;
55 return HAL_kInvalidHandle;
56 }
57
58 if (!fwd) channel += kNumRelayHeaders; // add 4 to reverse channels
59
60 auto handle = relayHandles->Allocate(channel, status);
61
62 if (*status != 0)
63 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
64
65 auto port = relayHandles->Get(handle);
66 if (port == nullptr) { // would only occur on thread issue.
67 *status = HAL_HANDLE_ERROR;
68 return HAL_kInvalidHandle;
69 }
70
71 if (!fwd) {
72 // Subtract number of headers to put channel in range
73 channel -= kNumRelayHeaders;
74
75 port->fwd = false; // set to reverse
76 } else {
77 port->fwd = true; // set to forward
78 }
79
80 port->channel = static_cast<uint8_t>(channel);
81 return handle;
82}
83
84void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle) {
85 // no status, so no need to check for a proper free.
86 relayHandles->Free(relayPortHandle);
87}
88
89HAL_Bool HAL_CheckRelayChannel(int32_t channel) {
90 // roboRIO only has 4 headers, and the FPGA has
91 // seperate functions for forward and reverse,
92 // instead of seperate channel IDs
93 return channel < kNumRelayHeaders && channel >= 0;
94}
95
96void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
97 int32_t* status) {
98 auto port = relayHandles->Get(relayPortHandle);
99 if (port == nullptr) {
100 *status = HAL_HANDLE_ERROR;
101 return;
102 }
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800103 std::scoped_lock lock(digitalRelayMutex);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800104 uint8_t relays = 0;
105 if (port->fwd) {
106 relays = relaySystem->readValue_Forward(status);
107 } else {
108 relays = relaySystem->readValue_Reverse(status);
109 }
110
111 if (*status != 0) return; // bad status read
112
113 if (on) {
114 relays |= 1 << port->channel;
115 } else {
116 relays &= ~(1 << port->channel);
117 }
118
119 if (port->fwd) {
120 relaySystem->writeValue_Forward(relays, status);
121 } else {
122 relaySystem->writeValue_Reverse(relays, status);
123 }
124}
125
126HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status) {
127 auto port = relayHandles->Get(relayPortHandle);
128 if (port == nullptr) {
129 *status = HAL_HANDLE_ERROR;
130 return false;
131 }
132
133 uint8_t relays = 0;
134 if (port->fwd) {
135 relays = relaySystem->readValue_Forward(status);
136 } else {
137 relays = relaySystem->readValue_Reverse(status);
138 }
139
140 return (relays & (1 << port->channel)) != 0;
141}
142
143} // extern "C"