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