Files
allwpilib/hal/lib/athena/Relay.cpp

132 lines
3.5 KiB
C++
Raw Normal View History

/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2016. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "HAL/Relay.h"
#include "DigitalInternal.h"
2016-07-02 23:19:14 -07:00
#include "PortsInternal.h"
2016-06-29 18:58:14 -07:00
#include "handles/IndexedHandleResource.h"
using namespace hal;
2016-06-29 18:58:14 -07:00
namespace {
struct Relay {
uint8_t pin;
bool fwd;
};
}
2016-07-02 23:19:14 -07:00
static IndexedHandleResource<HalRelayHandle, Relay, kNumRelayPins,
2016-06-29 18:58:14 -07:00
HalHandleEnum::Relay>
relayHandles;
// Create a mutex to protect changes to the relay values
static priority_recursive_mutex digitalRelayMutex;
extern "C" {
2016-06-29 18:58:14 -07:00
HalRelayHandle initializeRelayPort(HalPortHandle port_handle, uint8_t fwd,
int32_t* status) {
initializeDigital(status);
2016-06-29 18:58:14 -07:00
if (*status != 0) return HAL_INVALID_HANDLE;
int16_t pin = getPortHandlePin(port_handle);
if (pin == InvalidHandleIndex) {
*status = PARAMETER_OUT_OF_RANGE;
2016-06-29 18:58:14 -07:00
return HAL_INVALID_HANDLE;
}
2016-07-02 23:19:14 -07:00
if (!fwd) pin += kNumRelayHeaders; // add 4 to reverse pins
2016-06-29 18:58:14 -07:00
auto handle = relayHandles.Allocate(pin, status);
if (*status != 0)
return HAL_INVALID_HANDLE; // failed to allocate. Pass error back.
auto port = relayHandles.Get(handle);
if (port == nullptr) { // would only occur on thread issue.
*status = HAL_HANDLE_ERROR;
2016-06-29 18:58:14 -07:00
return HAL_INVALID_HANDLE;
}
2016-06-29 18:58:14 -07:00
if (!fwd) {
2016-07-02 23:19:14 -07:00
pin -= kNumRelayHeaders; // subtract number of headers to put pin in range.
port->fwd = false; // set to reverse
2016-06-29 18:58:14 -07:00
} else {
port->fwd = true; // set to forward
}
2016-06-29 18:58:14 -07:00
port->pin = static_cast<uint8_t>(pin);
return handle;
}
void freeRelayPort(HalRelayHandle relay_port_handle) {
// no status, so no need to check for a proper free.
relayHandles.Free(relay_port_handle);
}
bool checkRelayChannel(uint8_t pin) {
2016-07-02 23:19:14 -07:00
// roboRIO only has 4 headers, and the FPGA has
// seperate functions for forward and reverse,
// instead of seperate pin IDs
return pin < kNumRelayHeaders;
}
/**
* Set the state of a relay.
2016-06-29 18:58:14 -07:00
* Set the state of a relay output.
*/
2016-06-29 18:58:14 -07:00
void setRelay(HalRelayHandle relay_port_handle, bool on, int32_t* status) {
auto port = relayHandles.Get(relay_port_handle);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
2016-06-29 18:58:14 -07:00
std::lock_guard<priority_recursive_mutex> sync(digitalRelayMutex);
uint8_t relays = 0;
if (port->fwd) {
relays = relaySystem->readValue_Forward(status);
} else {
relays = relaySystem->readValue_Reverse(status);
}
2016-06-29 18:58:14 -07:00
if (*status != 0) return; // bad status read
if (on) {
relays |= 1 << port->pin;
} else {
relays &= ~(1 << port->pin);
}
2016-06-29 18:58:14 -07:00
if (port->fwd) {
relaySystem->writeValue_Forward(relays, status);
} else {
relaySystem->writeValue_Reverse(relays, status);
}
}
/**
2016-06-29 18:58:14 -07:00
* Get the current state of the relay channel
*/
2016-06-29 18:58:14 -07:00
bool getRelay(HalRelayHandle relay_port_handle, int32_t* status) {
auto port = relayHandles.Get(relay_port_handle);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}
2016-06-29 18:58:14 -07:00
uint8_t relays = 0;
if (port->fwd) {
relays = relaySystem->readValue_Forward(status);
} else {
relays = relaySystem->readValue_Reverse(status);
}
return (relays & (1 << port->pin)) != 0;
}
}