diff --git a/hal/include/HAL/Handles.h b/hal/include/HAL/Handles.h index fa366260e4..57aae1af32 100644 --- a/hal/include/HAL/Handles.h +++ b/hal/include/HAL/Handles.h @@ -24,3 +24,5 @@ typedef HalHandle HalAnalogOutputHandle; typedef HalHandle HalAnalogInputHandle; typedef HalHandle HalAnalogTriggerHandle; + +typedef HalHandle HalRelayHandle; diff --git a/hal/include/HAL/Relay.h b/hal/include/HAL/Relay.h index eda5ece608..4ecf66c741 100644 --- a/hal/include/HAL/Relay.h +++ b/hal/include/HAL/Relay.h @@ -9,11 +9,15 @@ #include -extern "C" { -bool checkRelayChannel(void* digital_port_pointer); +#include "Handles.h" -void setRelayForward(void* digital_port_pointer, bool on, int32_t* status); -void setRelayReverse(void* digital_port_pointer, bool on, int32_t* status); -bool getRelayForward(void* digital_port_pointer, int32_t* status); -bool getRelayReverse(void* digital_port_pointer, int32_t* status); +extern "C" { +HalRelayHandle initializeRelayPort(HalPortHandle port_handle, uint8_t fwd, + int32_t* status); +void freeRelayPort(HalRelayHandle relay_port_handle); + +bool checkRelayChannel(uint8_t pin); + +void setRelay(HalRelayHandle relay_port_handle, bool on, int32_t* status); +bool getRelay(HalRelayHandle relay_port_handle, int32_t* status); } diff --git a/hal/lib/athena/Relay.cpp b/hal/lib/athena/Relay.cpp index 4cd3a3fb5c..804f6ecd58 100644 --- a/hal/lib/athena/Relay.cpp +++ b/hal/lib/athena/Relay.cpp @@ -8,111 +8,125 @@ #include "HAL/Relay.h" #include "DigitalInternal.h" - -static_assert(sizeof(uint32_t) <= sizeof(void*), - "This file shoves uint32_ts into pointers."); +#include "handles/IndexedHandleResource.h" using namespace hal; +namespace { +struct Relay { + uint8_t pin; + bool fwd; +}; +} + +constexpr uint32_t kRelayPins = 8; +constexpr uint32_t kRelayHeaders = kRelayPins / 2; // Number of FPGA ID's + +static IndexedHandleResource + relayHandles; + // Create a mutex to protect changes to the relay values static priority_recursive_mutex digitalRelayMutex; -constexpr uint32_t kRelayPins = 8; - extern "C" { -bool checkRelayChannel(void* digital_port_pointer) { - DigitalPort* port = (DigitalPort*)digital_port_pointer; - return port->pin < kRelayPins; +HalRelayHandle initializeRelayPort(HalPortHandle port_handle, uint8_t fwd, + int32_t* status) { + initializeDigital(status); + + if (*status != 0) return HAL_INVALID_HANDLE; + + int16_t pin = getPortHandlePin(port_handle); + if (pin == InvalidHandleIndex) { + *status = PARAMETER_OUT_OF_RANGE; + return HAL_INVALID_HANDLE; + } + + if (!fwd) pin += kRelayHeaders; // add 4 to reverse pins + + 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 = PARAMETER_OUT_OF_RANGE; + return HAL_INVALID_HANDLE; + } + + if (!fwd) { + pin -= kRelayHeaders; // subtract number of headers to put pin in range. + port->fwd = false; // set to reverse + } else { + port->fwd = true; // set to forward + } + + port->pin = static_cast(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) { + return pin < kRelayHeaders; // roboRIO only has 4 headers, and the FPGA has + // seperate functions for forward and reverse, + // instead of seperate pin IDs } /** - * Check a port to make sure that it is not nullptr and is a valid Relay port. - * - * Sets the status to contain the appropriate error. - * - * @return true if the port passed validation. + * Set the state of a relay. + * Set the state of a relay output. */ -static bool verifyRelayChannel(DigitalPort* port, int32_t* status) { +void setRelay(HalRelayHandle relay_port_handle, bool on, int32_t* status) { + auto port = relayHandles.Get(relay_port_handle); + if (port == nullptr) { + *status = PARAMETER_OUT_OF_RANGE; + return; + } + std::lock_guard sync(digitalRelayMutex); + uint8_t relays = 0; + if (port->fwd) { + relays = relaySystem->readValue_Forward(status); + } else { + relays = relaySystem->readValue_Reverse(status); + } + + if (*status != 0) return; // bad status read + + if (on) { + relays |= 1 << port->pin; + } else { + relays &= ~(1 << port->pin); + } + + if (port->fwd) { + relaySystem->writeValue_Forward(relays, status); + } else { + relaySystem->writeValue_Reverse(relays, status); + } +} + +/** + * Get the current state of the relay channel + */ +bool getRelay(HalRelayHandle relay_port_handle, int32_t* status) { + auto port = relayHandles.Get(relay_port_handle); if (port == nullptr) { - *status = NULL_PARAMETER; - return false; - } else if (!checkRelayChannel(port)) { *status = PARAMETER_OUT_OF_RANGE; return false; + } + + uint8_t relays = 0; + if (port->fwd) { + relays = relaySystem->readValue_Forward(status); } else { - return true; - } -} - -/** - * Set the state of a relay. - * Set the state of a relay output to be forward. Relays have two outputs and - * each is - * independently set to 0v or 12v. - */ -void setRelayForward(void* digital_port_pointer, bool on, int32_t* status) { - DigitalPort* port = (DigitalPort*)digital_port_pointer; - if (!verifyRelayChannel(port, status)) { - return; + relays = relaySystem->readValue_Reverse(status); } - { - std::lock_guard sync(digitalRelayMutex); - uint8_t forwardRelays = relaySystem->readValue_Forward(status); - if (on) - forwardRelays |= 1 << port->pin; - else - forwardRelays &= ~(1 << port->pin); - relaySystem->writeValue_Forward(forwardRelays, status); - } -} - -/** - * Set the state of a relay. - * Set the state of a relay output to be reverse. Relays have two outputs and - * each is - * independently set to 0v or 12v. - */ -void setRelayReverse(void* digital_port_pointer, bool on, int32_t* status) { - DigitalPort* port = (DigitalPort*)digital_port_pointer; - if (!verifyRelayChannel(port, status)) { - return; - } - - { - std::lock_guard sync(digitalRelayMutex); - uint8_t reverseRelays = relaySystem->readValue_Reverse(status); - if (on) - reverseRelays |= 1 << port->pin; - else - reverseRelays &= ~(1 << port->pin); - relaySystem->writeValue_Reverse(reverseRelays, status); - } -} - -/** - * Get the current state of the forward relay channel - */ -bool getRelayForward(void* digital_port_pointer, int32_t* status) { - DigitalPort* port = (DigitalPort*)digital_port_pointer; - if (!verifyRelayChannel(port, status)) { - return false; - } - - uint8_t forwardRelays = relaySystem->readValue_Forward(status); - return (forwardRelays & (1 << port->pin)) != 0; -} - -/** - * Get the current state of the reverse relay channel - */ -bool getRelayReverse(void* digital_port_pointer, int32_t* status) { - DigitalPort* port = (DigitalPort*)digital_port_pointer; - if (!verifyRelayChannel(port, status)) { - return false; - } - - uint8_t reverseRelays = relaySystem->readValue_Reverse(status); - return (reverseRelays & (1 << port->pin)) != 0; + return (relays & (1 << port->pin)) != 0; } } diff --git a/hal/lib/athena/handles/HandlesInternal.h b/hal/lib/athena/handles/HandlesInternal.h index 71bf3a738b..18d78bac17 100644 --- a/hal/lib/athena/handles/HandlesInternal.h +++ b/hal/lib/athena/handles/HandlesInternal.h @@ -33,7 +33,8 @@ enum class HalHandleEnum { Interrupt = 4, AnalogOutput = 5, AnalogInput = 6, - AnalogTrigger = 7 + AnalogTrigger = 7, + Relay = 8 }; static inline int16_t getHandleIndex(HalHandle handle) { diff --git a/wpilibc/athena/include/Relay.h b/wpilibc/athena/include/Relay.h index 91e0974724..8bb1d74f47 100644 --- a/wpilibc/athena/include/Relay.h +++ b/wpilibc/athena/include/Relay.h @@ -9,6 +9,7 @@ #include +#include "HAL/Handles.h" #include "LiveWindow/LiveWindowSendable.h" #include "MotorSafety.h" #include "SensorBase.h" @@ -66,5 +67,8 @@ class Relay : public MotorSafety, uint32_t m_channel; Direction m_direction; + HalRelayHandle m_forwardHandle = HAL_INVALID_HANDLE; + HalRelayHandle m_reverseHandle = HAL_INVALID_HANDLE; + std::unique_ptr m_safetyHelper; }; diff --git a/wpilibc/athena/src/Relay.cpp b/wpilibc/athena/src/Relay.cpp index a47f83a73a..9533f3a302 100644 --- a/wpilibc/athena/src/Relay.cpp +++ b/wpilibc/athena/src/Relay.cpp @@ -30,29 +30,32 @@ static std::unique_ptr relayChannels; Relay::Relay(uint32_t channel, Relay::Direction direction) : m_channel(channel), m_direction(direction) { std::stringstream buf; - Resource::CreateResourceObject(relayChannels, - dio_kNumSystems * kRelayChannels * 2); if (!SensorBase::CheckRelayChannel(m_channel)) { buf << "Relay Channel " << m_channel; wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str()); return; } + HalPortHandle portHandle = getPort(channel); + if (m_direction == kBothDirections || m_direction == kForwardOnly) { - buf << "Forward Relay " << m_channel; - if (relayChannels->Allocate(m_channel * 2, buf.str()) == - std::numeric_limits::max()) { - CloneError(*relayChannels); + int32_t status = 0; + m_forwardHandle = initializeRelayPort(portHandle, true, &status); + if (status != 0) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + m_forwardHandle = HAL_INVALID_HANDLE; + m_reverseHandle = HAL_INVALID_HANDLE; return; } - HALReport(HALUsageReporting::kResourceType_Relay, m_channel); } if (m_direction == kBothDirections || m_direction == kReverseOnly) { - buf << "Reverse Relay " << m_channel; - if (relayChannels->Allocate(m_channel * 2 + 1, buf.str()) == - std::numeric_limits::max()) { - CloneError(*relayChannels); + int32_t status = 0; + m_reverseHandle = initializeRelayPort(portHandle, false, &status); + if (status != 0) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + m_forwardHandle = HAL_INVALID_HANDLE; + m_reverseHandle = HAL_INVALID_HANDLE; return; } @@ -60,9 +63,24 @@ Relay::Relay(uint32_t channel, Relay::Direction direction) } int32_t status = 0; - setRelayForward(m_relay_ports[m_channel], false, &status); - setRelayReverse(m_relay_ports[m_channel], false, &status); - wpi_setErrorWithContext(status, getHALErrorMessage(status)); + if (m_forwardHandle != HAL_INVALID_HANDLE) { + setRelay(m_forwardHandle, false, &status); + if (status != 0) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + m_forwardHandle = HAL_INVALID_HANDLE; + m_reverseHandle = HAL_INVALID_HANDLE; + return; + } + } + if (m_reverseHandle != HAL_INVALID_HANDLE) { + setRelay(m_reverseHandle, false, &status); + if (status != 0) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + m_forwardHandle = HAL_INVALID_HANDLE; + m_reverseHandle = HAL_INVALID_HANDLE; + return; + } + } m_safetyHelper = std::make_unique(this); m_safetyHelper->SetSafetyEnabled(false); @@ -77,16 +95,12 @@ Relay::Relay(uint32_t channel, Relay::Direction direction) */ Relay::~Relay() { int32_t status = 0; - setRelayForward(m_relay_ports[m_channel], false, &status); - setRelayReverse(m_relay_ports[m_channel], false, &status); - wpi_setErrorWithContext(status, getHALErrorMessage(status)); + setRelay(m_forwardHandle, false, &status); + setRelay(m_reverseHandle, false, &status); + // ignore errors, as we want to make sure a free happens. + if (m_forwardHandle != HAL_INVALID_HANDLE) freeRelayPort(m_forwardHandle); + if (m_reverseHandle != HAL_INVALID_HANDLE) freeRelayPort(m_reverseHandle); - if (m_direction == kBothDirections || m_direction == kForwardOnly) { - relayChannels->Free(m_channel * 2); - } - if (m_direction == kBothDirections || m_direction == kReverseOnly) { - relayChannels->Free(m_channel * 2 + 1); - } if (m_table != nullptr) m_table->RemoveTableListener(this); } @@ -113,18 +127,18 @@ void Relay::Set(Relay::Value value) { switch (value) { case kOff: if (m_direction == kBothDirections || m_direction == kForwardOnly) { - setRelayForward(m_relay_ports[m_channel], false, &status); + setRelay(m_forwardHandle, false, &status); } if (m_direction == kBothDirections || m_direction == kReverseOnly) { - setRelayReverse(m_relay_ports[m_channel], false, &status); + setRelay(m_reverseHandle, false, &status); } break; case kOn: if (m_direction == kBothDirections || m_direction == kForwardOnly) { - setRelayForward(m_relay_ports[m_channel], true, &status); + setRelay(m_forwardHandle, true, &status); } if (m_direction == kBothDirections || m_direction == kReverseOnly) { - setRelayReverse(m_relay_ports[m_channel], true, &status); + setRelay(m_reverseHandle, true, &status); } break; case kForward: @@ -133,10 +147,10 @@ void Relay::Set(Relay::Value value) { break; } if (m_direction == kBothDirections || m_direction == kForwardOnly) { - setRelayForward(m_relay_ports[m_channel], true, &status); + setRelay(m_forwardHandle, true, &status); } if (m_direction == kBothDirections) { - setRelayReverse(m_relay_ports[m_channel], false, &status); + setRelay(m_reverseHandle, false, &status); } break; case kReverse: @@ -145,10 +159,10 @@ void Relay::Set(Relay::Value value) { break; } if (m_direction == kBothDirections) { - setRelayForward(m_relay_ports[m_channel], false, &status); + setRelay(m_forwardHandle, false, &status); } if (m_direction == kBothDirections || m_direction == kReverseOnly) { - setRelayReverse(m_relay_ports[m_channel], true, &status); + setRelay(m_reverseHandle, true, &status); } break; } @@ -169,8 +183,8 @@ void Relay::Set(Relay::Value value) { Relay::Value Relay::Get() const { int32_t status; - if (getRelayForward(m_relay_ports[m_channel], &status)) { - if (getRelayReverse(m_relay_ports[m_channel], &status)) { + if (getRelay(m_forwardHandle, &status)) { + if (getRelay(m_reverseHandle, &status)) { return kOn; } else { if (m_direction == kForwardOnly) { @@ -180,7 +194,7 @@ Relay::Value Relay::Get() const { } } } else { - if (getRelayReverse(m_relay_ports[m_channel], &status)) { + if (getRelay(m_reverseHandle, &status)) { if (m_direction == kReverseOnly) { return kOn; } else { diff --git a/wpilibc/athena/src/SensorBase.cpp b/wpilibc/athena/src/SensorBase.cpp index 64f9fafaf7..a1aee83cf7 100644 --- a/wpilibc/athena/src/SensorBase.cpp +++ b/wpilibc/athena/src/SensorBase.cpp @@ -22,7 +22,6 @@ const uint32_t SensorBase::kChassisSlots; static bool portsInitialized = false; void* SensorBase::m_digital_ports[kDigitalChannels]; -void* SensorBase::m_relay_ports[kRelayChannels]; void* SensorBase::m_pwm_ports[kPwmChannels]; /** @@ -37,13 +36,6 @@ SensorBase::SensorBase() { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } - for (uint32_t i = 0; i < kRelayChannels; i++) { - HalPortHandle port = getPort(i); - int32_t status = 0; - m_relay_ports[i] = initializeDigitalPort(port, &status); - wpi_setErrorWithContext(status, getHALErrorMessage(status)); - } - for (uint32_t i = 0; i < kPwmChannels; i++) { HalPortHandle port = getPort(i); int32_t status = 0; @@ -77,16 +69,15 @@ bool SensorBase::CheckDigitalChannel(uint32_t channel) { } /** - * Check that the digital channel number is valid. + * Check that the relay channel number is valid. * * Verify that the channel number is one of the legal channel numbers. Channel - * numbers are 1-based. + * numbers are 0-based. * * @return Relay channel is valid */ bool SensorBase::CheckRelayChannel(uint32_t channel) { - if (channel < kRelayChannels) return true; - return false; + return checkRelayChannel((uint8_t)channel); } /** diff --git a/wpilibj/src/athena/cpp/lib/RelayJNI.cpp b/wpilibj/src/athena/cpp/lib/RelayJNI.cpp index 7a8d343b6a..6c11701c00 100644 --- a/wpilibj/src/athena/cpp/lib/RelayJNI.cpp +++ b/wpilibj/src/athena/cpp/lib/RelayJNI.cpp @@ -27,68 +27,75 @@ extern "C" { /* * Class: edu_wpi_first_wpilibj_hal_RelayJNI - * Method: setRelayForward - * Signature: (JZ)V + * Method: initializeRelayPort + * Signature: (IZ)I; */ -JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_RelayJNI_setRelayForward( - JNIEnv* env, jclass, jlong id, jboolean value) { - RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI setRelayForward"; - RELAYJNI_LOG(logDEBUG) << "Port Ptr = " << (void*)id; +JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_RelayJNI_initializeRelayPort( + JNIEnv* env, jclass, jint id, jboolean fwd) { + RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI initializeRelayPort"; + RELAYJNI_LOG(logDEBUG) << "Port Handle = " << (HalPortHandle)id; + RELAYJNI_LOG(logDEBUG) << "Forward = " << (jint)fwd; + int32_t status = 0; + HalRelayHandle handle = initializeRelayPort((HalPortHandle)id, (uint8_t) fwd, &status); + RELAYJNI_LOG(logDEBUG) << "Status = " << status; + RELAYJNI_LOG(logDEBUG) << "Relay Handle = " << handle; + return (jint) handle; +} + +/* +* Class: edu_wpi_first_wpilibj_hal_RelayJNI +* Method: freeRelayPort +* Signature: (I)V; +*/ +JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_RelayJNI_freeRelayPort( + JNIEnv *env, jclass, jint id) { + RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI freeRelayPort"; + RELAYJNI_LOG(logDEBUG) << "Port Handle = " << (HalRelayHandle)id; + freeRelayPort((HalRelayHandle)id); +} + +/* +* Class: edu_wpi_first_wpilibj_hal_RelayJNI +* Method: checkRelayChannel +* Signature: (I)Z; +*/ +JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_hal_RelayJNI_checkRelayChannel( + JNIEnv *env, jclass, jint channel) { + RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI checkRelayChannel"; + RELAYJNI_LOG(logDEBUG) << "Channel = " << channel; + return (jboolean)checkRelayChannel((uint8_t) channel); +} + +/* + * Class: edu_wpi_first_wpilibj_hal_RelayJNI + * Method: setRelay + * Signature: (IZ)V + */ +JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_RelayJNI_setRelay( + JNIEnv* env, jclass, jint id, jboolean value) { + RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI setRelay"; + RELAYJNI_LOG(logDEBUG) << "Port Handle = " << (HalRelayHandle)id; RELAYJNI_LOG(logDEBUG) << "Flag = " << (jint)value; int32_t status = 0; - setRelayForward((void*)id, value, &status); + setRelay((HalRelayHandle)id, value, &status); RELAYJNI_LOG(logDEBUG) << "Status = " << status; CheckStatus(env, status); } /* * Class: edu_wpi_first_wpilibj_hal_RelayJNI - * Method: setRelayReverse - * Signature: (JZ)V - */ -JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_RelayJNI_setRelayReverse( - JNIEnv* env, jclass, jlong id, jboolean value) { - RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI setRelayReverse"; - RELAYJNI_LOG(logDEBUG) << "Port Ptr = " << (void*)id; - RELAYJNI_LOG(logDEBUG) << "Flag = " << (jint)value; - int32_t status = 0; - setRelayReverse((void*)id, value, &status); - RELAYJNI_LOG(logDEBUG) << "Status = " << status; - CheckStatus(env, status); -} - -/* - * Class: edu_wpi_first_wpilibj_hal_RelayJNI - * Method: getRelayForward - * Signature: (J)Z + * Method: getRelay + * Signature: (I)Z */ JNIEXPORT jboolean JNICALL -Java_edu_wpi_first_wpilibj_hal_RelayJNI_getRelayForward( - JNIEnv* env, jclass, jlong id) { - RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI getRelayForward"; - RELAYJNI_LOG(logDEBUG) << "Port Ptr = " << (void*)id; +Java_edu_wpi_first_wpilibj_hal_RelayJNI_getRelay( + JNIEnv* env, jclass, jint id) { + RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI getRelay"; + RELAYJNI_LOG(logDEBUG) << "Port Handle = " << (HalRelayHandle)id; int32_t status = 0; - jboolean returnValue = getRelayForward((void*)id, &status); + jboolean returnValue = getRelay((HalRelayHandle)id, &status); RELAYJNI_LOG(logDEBUG) << "Status = " << status; - RELAYJNI_LOG(logDEBUG) << "getRelayForwardResult = " << (jint)returnValue; - CheckStatus(env, status); - return returnValue; -} - -/* - * Class: edu_wpi_first_wpilibj_hal_RelayJNI - * Method: getRelayReverse - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL -Java_edu_wpi_first_wpilibj_hal_RelayJNI_getRelayReverse( - JNIEnv* env, jclass, jlong id) { - RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI getRelayReverse"; - RELAYJNI_LOG(logDEBUG) << "Port Ptr = " << (void*)id; - int32_t status = 0; - jboolean returnValue = getRelayReverse((void*)id, &status); - RELAYJNI_LOG(logDEBUG) << "Status = " << status; - RELAYJNI_LOG(logDEBUG) << "getRelayReverseResult = " << (jint)returnValue; + RELAYJNI_LOG(logDEBUG) << "getRelayResult = " << (jint)returnValue; CheckStatus(env, status); return returnValue; } diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/Relay.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/Relay.java index 7713e21907..6f329468fa 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/Relay.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/Relay.java @@ -16,7 +16,6 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable; import edu.wpi.first.wpilibj.tables.ITable; import edu.wpi.first.wpilibj.tables.ITableListener; import edu.wpi.first.wpilibj.util.AllocationException; -import edu.wpi.first.wpilibj.util.CheckedAllocationException; import static java.util.Objects.requireNonNull; @@ -111,10 +110,12 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable } private final int m_channel; + + private int m_forwardHandle = 0; + private int m_reverseHandle = 0; private long m_port; private Direction m_direction; - private static Resource relayChannels = new Resource(kRelayChannels * 2); /** * Common relay initialization method. This code is common to all Relay constructors and @@ -122,21 +123,18 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable * set to both lines at 0v. */ private void initRelay() { - SensorBase.checkRelayChannel(m_channel); - try { - if (m_direction == Direction.kBoth || m_direction == Direction.kForward) { - relayChannels.allocate(m_channel * 2); - UsageReporting.report(tResourceType.kResourceType_Relay, m_channel); - } - if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) { - relayChannels.allocate(m_channel * 2 + 1); - UsageReporting.report(tResourceType.kResourceType_Relay, m_channel + 128); - } - } catch (CheckedAllocationException ex) { - throw new AllocationException("Relay channel " + m_channel + " is already allocated"); + if (!RelayJNI.checkRelayChannel(m_channel)) { + throw new IndexOutOfBoundsException("Requested relay channel number is out of range."); + } + int portHandle = RelayJNI.getPort((byte)m_channel); + if (m_direction == Direction.kBoth || m_direction == Direction.kForward) { + m_forwardHandle = RelayJNI.initializeRelayPort(portHandle, true); + UsageReporting.report(tResourceType.kResourceType_Relay, m_channel); + } + if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) { + m_reverseHandle = RelayJNI.initializeRelayPort(portHandle, false); + UsageReporting.report(tResourceType.kResourceType_Relay, m_channel + 128); } - - m_port = DIOJNI.initializeDigitalPort(DIOJNI.getPort((byte) m_channel)); m_safetyHelper = new MotorSafetyHelper(this); m_safetyHelper.setSafetyEnabled(false); @@ -168,19 +166,22 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable @Override public void free() { - if (m_direction == Direction.kBoth || m_direction == Direction.kForward) { - relayChannels.free(m_channel * 2); + try { + RelayJNI.setRelay(m_forwardHandle, false); + } catch (RuntimeException ex) { + // do nothing. Ignore } - if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) { - relayChannels.free(m_channel * 2 + 1); + try { + RelayJNI.setRelay(m_reverseHandle, false); + } catch (RuntimeException ex) { + // do nothing. Ignore } - - RelayJNI.setRelayForward(m_port, false); - RelayJNI.setRelayReverse(m_port, false); - - DIOJNI.freeDIO(m_port); - DIOJNI.freeDigitalPort(m_port); - m_port = 0; + + RelayJNI.freeRelayPort(m_forwardHandle); + RelayJNI.freeRelayPort(m_reverseHandle); + + m_forwardHandle = 0; + m_reverseHandle = 0; } /** @@ -200,18 +201,18 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable switch (value) { case kOff: if (m_direction == Direction.kBoth || m_direction == Direction.kForward) { - RelayJNI.setRelayForward(m_port, false); + RelayJNI.setRelay(m_forwardHandle, false); } if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) { - RelayJNI.setRelayReverse(m_port, false); + RelayJNI.setRelay(m_reverseHandle, false); } break; case kOn: if (m_direction == Direction.kBoth || m_direction == Direction.kForward) { - RelayJNI.setRelayForward(m_port, true); + RelayJNI.setRelay(m_forwardHandle, true); } if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) { - RelayJNI.setRelayReverse(m_port, true); + RelayJNI.setRelay(m_reverseHandle, true); } break; case kForward: @@ -220,10 +221,10 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable + "forward"); } if (m_direction == Direction.kBoth || m_direction == Direction.kForward) { - RelayJNI.setRelayForward(m_port, true); + RelayJNI.setRelay(m_forwardHandle, true); } if (m_direction == Direction.kBoth) { - RelayJNI.setRelayReverse(m_port, false); + RelayJNI.setRelay(m_reverseHandle, false); } break; case kReverse: @@ -232,10 +233,10 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable + "reverse"); } if (m_direction == Direction.kBoth) { - RelayJNI.setRelayForward(m_port, false); + RelayJNI.setRelay(m_forwardHandle, false); } if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) { - RelayJNI.setRelayReverse(m_port, true); + RelayJNI.setRelay(m_reverseHandle, true); } break; default: @@ -254,8 +255,8 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable * @return The current state of the relay as a Relay::Value */ public Value get() { - if (RelayJNI.getRelayForward(m_port)) { - if (RelayJNI.getRelayReverse(m_port)) { + if (RelayJNI.getRelay(m_forwardHandle)) { + if (RelayJNI.getRelay(m_reverseHandle)) { return Value.kOn; } else { if (m_direction == Direction.kForward) { @@ -265,7 +266,7 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable } } } else { - if (RelayJNI.getRelayReverse(m_port)) { + if (RelayJNI.getRelay(m_reverseHandle)) { if (m_direction == Direction.kReverse) { return Value.kOn; } else { diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/hal/RelayJNI.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/hal/RelayJNI.java index 0162a96a04..bfe17d4139 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/hal/RelayJNI.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/hal/RelayJNI.java @@ -8,11 +8,13 @@ package edu.wpi.first.wpilibj.hal; public class RelayJNI extends DIOJNI { - public static native void setRelayForward(long digitalPortPointer, boolean on); + public static native int initializeRelayPort(int halPortHandle, boolean forward); + + public static native void freeRelayPort(int relayPortHandle); + + public static native boolean checkRelayChannel(int pin); + + public static native void setRelay(int relayPortHandle, boolean on); - public static native void setRelayReverse(long digitalPortPointer, boolean on); - - public static native boolean getRelayForward(long digitalPortPointer); - - public static native boolean getRelayReverse(long digitalPortPointer); + public static native boolean getRelay(int relayPortHandle); }