blob: 4dfcdaf2a4d16f0ef8287588fa4884523d89a3e1 [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "hal/Relay.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <string>
8
Brian Silverman8fce7482020-01-05 13:18:21 -08009#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070010#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080011#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;
Austin Schuh812d0d12021-11-04 20:16:48 -070021 std::string previousAllocation;
Brian Silverman8fce7482020-01-05 13:18:21 -080022};
23} // namespace
24
25static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
26 HAL_HandleEnum::Relay>* relayHandles;
27
Austin Schuh812d0d12021-11-04 20:16:48 -070028namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080029void InitializeRelay() {
30 static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
31 HAL_HandleEnum::Relay>
32 rH;
33 relayHandles = &rH;
34}
Austin Schuh812d0d12021-11-04 20:16:48 -070035} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080036
37extern "C" {
38HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
Austin Schuh812d0d12021-11-04 20:16:48 -070039 const char* allocationLocation,
Brian Silverman8fce7482020-01-05 13:18:21 -080040 int32_t* status) {
41 hal::init::CheckInit();
Austin Schuh812d0d12021-11-04 20:16:48 -070042 if (*status != 0) {
Brian Silverman8fce7482020-01-05 13:18:21 -080043 return HAL_kInvalidHandle;
44 }
45
Austin Schuh812d0d12021-11-04 20:16:48 -070046 int16_t channel = getPortHandleChannel(portHandle);
47 if (channel == InvalidHandleIndex || channel >= kNumRelayChannels) {
48 *status = RESOURCE_OUT_OF_RANGE;
49 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Relay", 0,
50 kNumRelayChannels, channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080051 return HAL_kInvalidHandle;
52 }
53
54 if (!fwd) {
Austin Schuh812d0d12021-11-04 20:16:48 -070055 channel += kNumRelayHeaders; // add 4 to reverse channels
56 }
57
58 HAL_RelayHandle handle;
59 auto port = relayHandles->Allocate(channel, &handle, status);
60
61 if (*status != 0) {
62 if (port) {
63 hal::SetLastErrorPreviouslyAllocated(status, "Relay", channel,
64 port->previousAllocation);
65 } else {
66 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Relay", 0,
67 kNumRelayChannels, channel);
68 }
69 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
70 }
71
72 if (!fwd) {
Brian Silverman8fce7482020-01-05 13:18:21 -080073 // Subtract number of headers to put channel in range
74 channel -= kNumRelayHeaders;
75
76 port->fwd = false; // set to reverse
77
78 SimRelayData[channel].initializedReverse = true;
79 } else {
80 port->fwd = true; // set to forward
81 SimRelayData[channel].initializedForward = true;
82 }
83
84 port->channel = static_cast<uint8_t>(channel);
Austin Schuh812d0d12021-11-04 20:16:48 -070085 port->previousAllocation = allocationLocation ? allocationLocation : "";
Brian Silverman8fce7482020-01-05 13:18:21 -080086
87 return handle;
88}
89
90void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle) {
91 auto port = relayHandles->Get(relayPortHandle);
92 relayHandles->Free(relayPortHandle);
Austin Schuh812d0d12021-11-04 20:16:48 -070093 if (port == nullptr) {
94 return;
95 }
96 if (port->fwd) {
Brian Silverman8fce7482020-01-05 13:18:21 -080097 SimRelayData[port->channel].initializedForward = false;
Austin Schuh812d0d12021-11-04 20:16:48 -070098 } else {
Brian Silverman8fce7482020-01-05 13:18:21 -080099 SimRelayData[port->channel].initializedReverse = false;
Austin Schuh812d0d12021-11-04 20:16:48 -0700100 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800101}
102
103HAL_Bool HAL_CheckRelayChannel(int32_t channel) {
104 // roboRIO only has 4 headers, and the FPGA has
Austin Schuh1e69f942020-11-14 15:06:14 -0800105 // separate functions for forward and reverse,
106 // instead of separate channel IDs
Brian Silverman8fce7482020-01-05 13:18:21 -0800107 return channel < kNumRelayHeaders && channel >= 0;
108}
109
110void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
111 int32_t* status) {
112 auto port = relayHandles->Get(relayPortHandle);
113 if (port == nullptr) {
114 *status = HAL_HANDLE_ERROR;
115 return;
116 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700117 if (port->fwd) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800118 SimRelayData[port->channel].forward = on;
Austin Schuh812d0d12021-11-04 20:16:48 -0700119 } else {
Brian Silverman8fce7482020-01-05 13:18:21 -0800120 SimRelayData[port->channel].reverse = on;
Austin Schuh812d0d12021-11-04 20:16:48 -0700121 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800122}
123
124HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status) {
125 auto port = relayHandles->Get(relayPortHandle);
126 if (port == nullptr) {
127 *status = HAL_HANDLE_ERROR;
128 return false;
129 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700130 if (port->fwd) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800131 return SimRelayData[port->channel].forward;
Austin Schuh812d0d12021-11-04 20:16:48 -0700132 } else {
Brian Silverman8fce7482020-01-05 13:18:21 -0800133 return SimRelayData[port->channel].reverse;
Austin Schuh812d0d12021-11-04 20:16:48 -0700134 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800135}
136} // extern "C"