Compare commits

...

8 Commits

Author SHA1 Message Date
Starlight220
791d8354da [build] Suppress deprecation/removal warnings for old commands (#3618) 2021-10-10 20:07:12 -07:00
Thad House
10f19e6fc3 [hal, wpilib] Add REV PneumaticsHub (#3600) 2021-10-10 20:04:50 -07:00
Peter Johnson
4c61a13057 [ntcore] Revert to per-element copy for toNative() (#3621)
arraycopy() does not unbox values, so throws an exception.

This was broken in #3419 due to a false positive in PMD
(see https://sourceforge.net/p/pmd/bugs/804/).
2021-10-10 15:53:35 -07:00
Peter Johnson
7b3f62244f [wpiutil] SendableRegistry: Print exception stacktrace (#3620) 2021-10-10 15:53:11 -07:00
Thad House
d347928e4d [hal] Use better error for when console out is enabled while attempting to use onboard serial port (#3622) 2021-10-10 15:52:50 -07:00
Tyler Veness
cc31079a11 [hal] Use setcap instead of setuid for setting thread priorities (#3613)
We originally moved to setuid admin so user programs could do other
things requiring admin if they wanted. However, these things, like
setting RT priorities of other processes, can usually be done instead as
admin during the GradleRIO 2022 deploy process, or adding commands to
the robotCommand script. By going back to setcap, we can simplify the
HAL code.
2021-10-04 09:49:34 -07:00
Tyler Veness
4676648b78 [wpimath] Upgrade to Drake v0.34.0 (#3607) 2021-09-29 15:39:47 -07:00
Thad House
c7594c9111 [build] Allow building wpilibc in cmake without cscore and opencv (#3605)
The hard dependency on cscore was removed a while ago in gradle, so make it not a hard requirement in cmake.
2021-09-27 21:37:04 -07:00
61 changed files with 8506 additions and 99 deletions

View File

@@ -270,19 +270,20 @@ if (WITH_CSCORE)
set(CAMERASERVER_DEP_REPLACE ${CAMERASERVER_DEP_REPLACE_IMPL})
add_subdirectory(cscore)
add_subdirectory(cameraserver)
if (WITH_WPILIB)
set(WPILIBC_DEP_REPLACE ${WPILIBC_DEP_REPLACE_IMPL})
add_subdirectory(wpilibj)
add_subdirectory(wpilibc)
add_subdirectory(wpilibNewCommands)
if (WITH_OLD_COMMANDS)
add_subdirectory(wpilibOldCommands)
endif()
if (WITH_EXAMPLES)
add_subdirectory(wpilibcExamples)
endif()
add_subdirectory(myRobot)
endif()
if (WITH_WPILIB)
set(WPILIBC_DEP_REPLACE ${WPILIBC_DEP_REPLACE_IMPL})
add_subdirectory(wpilibj)
add_subdirectory(wpilibc)
add_subdirectory(wpilibNewCommands)
if (WITH_OLD_COMMANDS)
add_subdirectory(wpilibOldCommands)
endif()
if (WITH_EXAMPLES)
add_subdirectory(wpilibcExamples)
endif()
add_subdirectory(myRobot)
endif()
if (WITH_SIMULATION_MODULES AND NOT WITH_EXTERNAL_HAL)

View File

@@ -45,4 +45,8 @@ public class PortsJNI extends JNIWrapper {
public static native int getNumREVPDHModules();
public static native int getNumREVPDHChannels();
public static native int getNumREVPHModules();
public static native int getNumREVPHChannels();
}

View File

@@ -0,0 +1,32 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal;
@SuppressWarnings("AbbreviationAsWordInName")
public class REVPHJNI extends JNIWrapper {
public static native int initialize(int module);
public static native void free(int handle);
public static native boolean checkSolenoidChannel(int channel);
public static native boolean getCompressor(int handle);
public static native void setClosedLoopControl(int handle, boolean enabled);
public static native boolean getClosedLoopControl(int handle);
public static native boolean getPressureSwitch(int handle);
public static native double getAnalogPressure(int handle, int channel);
public static native double getCompressorCurrent(int handle);
public static native int getSolenoids(int handle);
public static native void setSolenoids(int handle, int mask, int values);
public static native void fireOneShot(int handle, int index, int durMs);
}

View File

@@ -0,0 +1,72 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal.simulation;
import edu.wpi.first.hal.JNIWrapper;
@SuppressWarnings("AbbreviationAsWordInName")
public class REVPHDataJNI extends JNIWrapper {
public static native int registerInitializedCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelInitializedCallback(int index, int uid);
public static native boolean getInitialized(int index);
public static native void setInitialized(int index, boolean initialized);
public static native int registerSolenoidOutputCallback(
int index, int channel, NotifyCallback callback, boolean initialNotify);
public static native void cancelSolenoidOutputCallback(int index, int channel, int uid);
public static native boolean getSolenoidOutput(int index, int channel);
public static native void setSolenoidOutput(int index, int channel, boolean solenoidOutput);
public static native int registerCompressorOnCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelCompressorOnCallback(int index, int uid);
public static native boolean getCompressorOn(int index);
public static native void setCompressorOn(int index, boolean compressorOn);
public static native int registerClosedLoopEnabledCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelClosedLoopEnabledCallback(int index, int uid);
public static native boolean getClosedLoopEnabled(int index);
public static native void setClosedLoopEnabled(int index, boolean closeLoopEnabled);
public static native int registerPressureSwitchCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelPressureSwitchCallback(int index, int uid);
public static native boolean getPressureSwitch(int index);
public static native void setPressureSwitch(int index, boolean pressureSwitch);
public static native int registerCompressorCurrentCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelCompressorCurrentCallback(int index, int uid);
public static native double getCompressorCurrent(int index);
public static native void setCompressorCurrent(int index, double compressorCurrent);
public static native void registerAllNonSolenoidCallbacks(
int index, NotifyCallback callback, boolean initialNotify);
public static native void registerAllSolenoidCallbacks(
int index, int channel, NotifyCallback callback, boolean initialNotify);
public static native void resetData(int index);
}

View File

@@ -41,6 +41,7 @@ namespace hal {
namespace init {
void InitializeHAL() {
InitializeCTREPCM();
InitializeREVPH();
InitializeAddressableLED();
InitializeAccelerometer();
InitializeAnalogAccumulator();
@@ -226,6 +227,8 @@ const char* HAL_GetErrorMessage(int32_t code) {
return HAL_INVALID_DMA_ADDITION_MESSAGE;
case HAL_USE_LAST_ERROR:
return HAL_USE_LAST_ERROR_MESSAGE;
case HAL_CONSOLE_OUT_ENABLED_ERROR:
return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
default:
return "Unknown error status";
}

View File

@@ -17,6 +17,7 @@ inline void CheckInit() {
}
extern void InitializeCTREPCM();
extern void InitializeREVPH();
extern void InitializeAccelerometer();
extern void InitializeAddressableLED();
extern void InitializeAnalogAccumulator();

View File

@@ -74,6 +74,12 @@ int32_t HAL_GetNumREVPDHModules(void) {
int32_t HAL_GetNumREVPDHChannels(void) {
return kNumREVPDHChannels;
}
int32_t HAL_GetNumREVPHModules(void) {
return kNumREVPHModules;
}
int32_t HAL_GetNumREVPHChannels(void) {
return kNumREVPHChannels;
}
int32_t HAL_GetNumDutyCycles(void) {
return kNumDutyCycles;
}

View File

@@ -36,5 +36,7 @@ constexpr int32_t kNumREVPDHModules = 63;
constexpr int32_t kNumREVPDHChannels = 24;
constexpr int32_t kNumDutyCycles = tDutyCycle::kNumSystems;
constexpr int32_t kNumAddressableLEDs = tLED::kNumSystems;
constexpr int32_t kNumREVPHModules = 63;
constexpr int32_t kNumREVPHChannels = 16;
} // namespace hal

View File

@@ -0,0 +1,479 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "hal/REVPH.h"
#include <fmt/format.h>
#include "HALInitializer.h"
#include "HALInternal.h"
#include "PortsInternal.h"
#include "hal/CANAPI.h"
#include "hal/Errors.h"
#include "hal/handles/IndexedHandleResource.h"
#include "rev/PHFrames.h"
using namespace hal;
static constexpr HAL_CANManufacturer manufacturer =
HAL_CANManufacturer::HAL_CAN_Man_kREV;
static constexpr HAL_CANDeviceType deviceType =
HAL_CANDeviceType::HAL_CAN_Dev_kPneumatics;
static constexpr int32_t kDefaultControlPeriod = 20;
// static constexpr uint8_t kDefaultSensorMask = (1 <<
// HAL_REV_PHSENSOR_DIGITAL);
static constexpr uint8_t kDefaultCompressorDuty = 255;
static constexpr uint8_t kDefaultPressureTarget = 120;
static constexpr uint8_t kDefaultPressureHysteresis = 60;
#define HAL_REV_MAX_PULSE_TIME 65534
#define HAL_REV_MAX_PRESSURE_TARGET 120
#define HAL_REV_MAX_PRESSURE_HYSTERESIS HAL_REV_MAX_PRESSURE_TARGET
static constexpr uint32_t APIFromExtId(uint32_t extId) {
return (extId >> 6) & 0x3FF;
}
static constexpr uint32_t PH_SET_ALL_FRAME_API =
APIFromExtId(PH_SET_ALL_FRAME_ID);
static constexpr uint32_t PH_PULSE_ONCE_FRAME_API =
APIFromExtId(PH_PULSE_ONCE_FRAME_ID);
static constexpr uint32_t PH_STATUS0_FRAME_API =
APIFromExtId(PH_STATUS0_FRAME_ID);
static constexpr uint32_t PH_STATUS1_FRAME_API =
APIFromExtId(PH_STATUS1_FRAME_ID);
static constexpr int32_t kPHFrameStatus0Timeout = 50;
static constexpr int32_t kPHFrameStatus1Timeout = 50;
namespace {
struct REV_PHObj {
int32_t controlPeriod;
PH_set_all_t desiredSolenoidsState;
wpi::mutex solenoidLock;
HAL_CANHandle hcan;
std::string previousAllocation;
};
} // namespace
static IndexedHandleResource<HAL_REVPHHandle, REV_PHObj, 63,
HAL_HandleEnum::REVPH>* REVPHHandles;
namespace hal::init {
void InitializeREVPH() {
static IndexedHandleResource<HAL_REVPHHandle, REV_PHObj, kNumREVPHModules,
HAL_HandleEnum::REVPH>
rH;
REVPHHandles = &rH;
}
} // namespace hal::init
static PH_status0_t HAL_REV_ReadPHStatus0(HAL_CANHandle hcan, int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PH_status0_t result = {};
HAL_ReadCANPacketTimeout(hcan, PH_STATUS0_FRAME_API, packedData, &length,
&timestamp, kPHFrameStatus0Timeout * 2, status);
if (*status != 0) {
return result;
}
PH_status0_unpack(&result, packedData, PH_STATUS0_LENGTH);
return result;
}
static PH_status1_t HAL_REV_ReadPHStatus1(HAL_CANHandle hcan, int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PH_status1_t result = {};
HAL_ReadCANPacketTimeout(hcan, PH_STATUS1_FRAME_API, packedData, &length,
&timestamp, kPHFrameStatus1Timeout * 2, status);
if (*status != 0) {
return result;
}
PH_status1_unpack(&result, packedData, PH_STATUS1_LENGTH);
return result;
}
enum REV_SolenoidState {
kSolenoidDisabled = 0,
kSolenoidEnabled,
kSolenoidControlledViaPulse
};
static void HAL_REV_UpdateDesiredPHSolenoidState(REV_PHObj* hph,
int32_t solenoid,
REV_SolenoidState state) {
switch (solenoid) {
case 0:
hph->desiredSolenoidsState.channel_0 = state;
break;
case 1:
hph->desiredSolenoidsState.channel_1 = state;
break;
case 2:
hph->desiredSolenoidsState.channel_2 = state;
break;
case 3:
hph->desiredSolenoidsState.channel_3 = state;
break;
case 4:
hph->desiredSolenoidsState.channel_4 = state;
break;
case 5:
hph->desiredSolenoidsState.channel_5 = state;
break;
case 6:
hph->desiredSolenoidsState.channel_6 = state;
break;
case 7:
hph->desiredSolenoidsState.channel_7 = state;
break;
case 8:
hph->desiredSolenoidsState.channel_8 = state;
break;
case 9:
hph->desiredSolenoidsState.channel_9 = state;
break;
case 10:
hph->desiredSolenoidsState.channel_10 = state;
break;
case 11:
hph->desiredSolenoidsState.channel_11 = state;
break;
case 12:
hph->desiredSolenoidsState.channel_12 = state;
break;
case 13:
hph->desiredSolenoidsState.channel_13 = state;
break;
case 14:
hph->desiredSolenoidsState.channel_14 = state;
break;
case 15:
hph->desiredSolenoidsState.channel_15 = state;
break;
}
}
static void HAL_REV_SendSolenoidsState(REV_PHObj* hph, int32_t* status) {
uint8_t packedData[PH_SET_ALL_LENGTH] = {0};
PH_set_all_pack(packedData, &(hph->desiredSolenoidsState), PH_SET_ALL_LENGTH);
HAL_WriteCANPacketRepeating(hph->hcan, packedData, PH_SET_ALL_LENGTH,
PH_SET_ALL_FRAME_API, hph->controlPeriod, status);
}
static HAL_Bool HAL_REV_CheckPHPulseTime(int32_t time) {
return ((time > 0) && (time <= HAL_REV_MAX_PULSE_TIME)) ? 1 : 0;
}
HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();
if (!HAL_CheckREVPHModuleNumber(module)) {
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
kNumREVPHModules, module);
return HAL_kInvalidHandle;
}
HAL_REVPHHandle handle;
auto hph = REVPHHandles->Allocate(module, &handle, status);
if (*status != 0) {
if (hph) {
hal::SetLastErrorPreviouslyAllocated(status, "REV PH", module,
hph->previousAllocation);
} else {
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
kNumREVPHModules, module);
}
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
}
HAL_CANHandle hcan =
HAL_InitializeCAN(manufacturer, module, deviceType, status);
if (*status != 0) {
REVPHHandles->Free(handle);
return HAL_kInvalidHandle;
}
hph->previousAllocation = allocationLocation ? allocationLocation : "";
hph->hcan = hcan;
hph->controlPeriod = kDefaultControlPeriod;
// TODO any other things
return handle;
}
void HAL_FreeREVPH(HAL_REVPHHandle handle) {
auto hph = REVPHHandles->Get(handle);
if (hph == nullptr)
return;
HAL_CleanCAN(hph->hcan);
REVPHHandles->Free(handle);
}
HAL_Bool HAL_CheckREVPHModuleNumber(int32_t module) {
return module >= 1 && module < kNumREVPDHModules;
}
HAL_Bool HAL_CheckREVPHSolenoidChannel(int32_t channel) {
return channel >= 0 && channel < kNumREVPHChannels;
}
HAL_Bool HAL_GetREVPHCompressor(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
if (*status != 0) {
return false;
}
return status0.compressor_on;
}
void HAL_SetREVPHClosedLoopControl(HAL_REVPHHandle handle, HAL_Bool enabled,
int32_t* status) {
// TODO
}
HAL_Bool HAL_GetREVPHClosedLoopControl(HAL_REVPHHandle handle,
int32_t* status) {
return false; // TODO
}
HAL_Bool HAL_GetREVPHPressureSwitch(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
if (*status != 0) {
return false;
}
return status0.digital_sensor;
}
double HAL_GetREVPHCompressorCurrent(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
PH_status1_t status1 = HAL_REV_ReadPHStatus1(ph->hcan, status);
if (*status != 0) {
return 0;
}
return PH_status1_compressor_current_decode(status1.compressor_current);
}
double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
if (channel < 0 || channel > 1) {
*status = PARAMETER_OUT_OF_RANGE;
hal::SetLastErrorIndexOutOfRange(status, "Invalid REV Analog Index", 0, 2,
channel);
return 0;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
if (*status != 0) {
return 0;
}
if (channel == 1) {
return PH_status0_analog_0_decode(status0.analog_0);
}
return PH_status0_analog_1_decode(status0.analog_1);
}
int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
if (*status != 0) {
return 0;
}
uint32_t result = status0.channel_0;
result |= status0.channel_1 << 1;
result |= status0.channel_2 << 2;
result |= status0.channel_3 << 3;
result |= status0.channel_4 << 4;
result |= status0.channel_5 << 5;
result |= status0.channel_6 << 6;
result |= status0.channel_7 << 7;
result |= status0.channel_8 << 8;
result |= status0.channel_9 << 9;
result |= status0.channel_10 << 10;
result |= status0.channel_11 << 11;
result |= status0.channel_12 << 12;
result |= status0.channel_13 << 13;
result |= status0.channel_14 << 14;
result |= status0.channel_15 << 15;
return result;
}
void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
std::scoped_lock lock{ph->solenoidLock};
for (int solenoid = 0; solenoid < kNumREVPHChannels; solenoid++) {
if (mask & (1 << solenoid)) {
// The mask bit for the solenoid is set, so we update the solenoid state
REV_SolenoidState desiredSolenoidState =
values & (1 << solenoid) ? kSolenoidEnabled : kSolenoidDisabled;
HAL_REV_UpdateDesiredPHSolenoidState(ph.get(), solenoid,
desiredSolenoidState);
}
}
HAL_REV_SendSolenoidsState(ph.get(), status);
}
void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
if (index >= kNumREVPHChannels || index < 0) {
*status = PARAMETER_OUT_OF_RANGE;
hal::SetLastError(
status,
fmt::format("Only [0-15] are valid index values. Requested {}", index));
return;
}
if (!HAL_REV_CheckPHPulseTime(durMs)) {
*status = PARAMETER_OUT_OF_RANGE;
hal::SetLastError(
status,
fmt::format("Time not within expected range [0-65534]. Requested {}",
durMs));
return;
}
{
std::scoped_lock lock{ph->solenoidLock};
HAL_REV_UpdateDesiredPHSolenoidState(ph.get(), index,
kSolenoidControlledViaPulse);
HAL_REV_SendSolenoidsState(ph.get(), status);
}
if (*status != 0) {
return;
}
PH_pulse_once_t pulse = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
pulse.pulse_length_ms = durMs;
// Specify which solenoid should be pulsed
// The protocol supports specifying any number of solenoids to be pulsed at
// the same time, should that functionality be exposed to users in the future.
switch (index) {
case 0:
pulse.channel_0 = true;
break;
case 1:
pulse.channel_1 = true;
break;
case 2:
pulse.channel_2 = true;
break;
case 3:
pulse.channel_3 = true;
break;
case 4:
pulse.channel_4 = true;
break;
case 5:
pulse.channel_5 = true;
break;
case 6:
pulse.channel_6 = true;
break;
case 7:
pulse.channel_7 = true;
break;
case 8:
pulse.channel_8 = true;
break;
case 9:
pulse.channel_9 = true;
break;
case 10:
pulse.channel_10 = true;
break;
case 11:
pulse.channel_11 = true;
break;
case 12:
pulse.channel_12 = true;
break;
case 13:
pulse.channel_13 = true;
break;
case 14:
pulse.channel_14 = true;
break;
case 15:
pulse.channel_15 = true;
break;
}
// Send pulse command
uint8_t packedData[PH_PULSE_ONCE_LENGTH] = {0};
PH_pulse_once_pack(packedData, &pulse, PH_PULSE_ONCE_LENGTH);
HAL_WriteCANPacket(ph->hcan, packedData, PH_PULSE_ONCE_LENGTH,
PH_PULSE_ONCE_FRAME_API, status);
}

View File

@@ -84,6 +84,9 @@ HAL_SerialPortHandle HAL_InitializeSerialPortDirect(HAL_SerialPort port,
serialPort->portId = open(portName, O_RDWR | O_NOCTTY);
if (serialPort->portId < 0) {
*status = errno;
if (*status == EACCES) {
*status = HAL_CONSOLE_OUT_ENABLED_ERROR;
}
serialPortHandles->Free(handle);
return HAL_kInvalidHandle;
}

View File

@@ -6,42 +6,9 @@
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#include <cerrno>
#include <cstdlib>
#include <system_error>
#include <fmt/format.h>
#include "hal/Errors.h"
namespace {
class UidSetter {
public:
explicit UidSetter(uid_t uid) {
m_uid = geteuid();
if (uid == 0 && setuid(uid) == -1) {
throw std::system_error(errno, std::generic_category(),
fmt::format("setuid({}) failed", uid));
} else if (uid != 0 && seteuid(uid) == -1) {
throw std::system_error(errno, std::generic_category(),
fmt::format("seteuid({}) failed", uid));
}
}
~UidSetter() noexcept(false) {
if (geteuid() != m_uid && seteuid(m_uid) == -1) {
throw std::system_error(errno, std::generic_category(),
fmt::format("seteuid({}) failed", m_uid));
}
}
private:
uid_t m_uid;
};
} // namespace
namespace hal::init {
void InitializeThreads() {}
} // namespace hal::init
@@ -104,20 +71,13 @@ HAL_Bool HAL_SetThreadPriority(NativeThreadHandle handle, HAL_Bool realTime,
sch.sched_priority = 0;
}
try {
UidSetter uidSetter{0};
if (pthread_setschedparam(*reinterpret_cast<const pthread_t*>(handle),
scheduler, &sch)) {
*status = HAL_THREAD_PRIORITY_ERROR;
return false;
} else {
*status = 0;
return true;
}
} catch (const std::system_error& e) {
*status = HAL_SETUID_ERROR;
if (pthread_setschedparam(*reinterpret_cast<const pthread_t*>(handle),
scheduler, &sch)) {
*status = HAL_THREAD_PRIORITY_ERROR;
return false;
} else {
*status = 0;
return true;
}
}

View File

@@ -0,0 +1,37 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "hal/simulation/REVPHData.h"
#include "hal/simulation/SimDataValue.h"
extern "C" {
void HALSIM_ResetREVPHData(int32_t index) {}
#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, REVPH##CAPINAME, RETURN)
HAL_SIMDATAVALUE_STUB_CAPI_CHANNEL(HAL_Bool, HALSIM, REVPHSolenoidOutput, false)
DEFINE_CAPI(HAL_Bool, Initialized, false)
DEFINE_CAPI(HAL_Bool, CompressorOn, false)
DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, false)
DEFINE_CAPI(HAL_Bool, PressureSwitch, false)
DEFINE_CAPI(double, CompressorCurrent, 0)
void HALSIM_GetREVPHAllSolenoids(int32_t index, uint8_t* values) {
*values = 0;
}
void HALSIM_SetREVPHAllSolenoids(int32_t index, uint8_t values) {}
void HALSIM_RegisterREVPHAllNonSolenoidCallbacks(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify) {}
void HALSIM_RegisterREVPHAllSolenoidCallbacks(int32_t index, int32_t channel,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify) {}
} // extern "C"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -272,4 +272,30 @@ Java_edu_wpi_first_hal_PortsJNI_getNumREVPDHChannels
jint value = HAL_GetNumREVPDHChannels();
return value;
}
/*
* Class: edu_wpi_first_hal_PortsJNI
* Method: getNumREVPHModules
* Signature: ()I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_PortsJNI_getNumREVPHModules
(JNIEnv* env, jclass)
{
jint value = HAL_GetNumREVPHModules();
return value;
}
/*
* Class: edu_wpi_first_hal_PortsJNI
* Method: getNumREVPHChannels
* Signature: ()I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_PortsJNI_getNumREVPHChannels
(JNIEnv* env, jclass)
{
jint value = HAL_GetNumREVPHChannels();
return value;
}
} // extern "C"

View File

@@ -0,0 +1,191 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <jni.h>
#include <wpi/jni_util.h>
#include "HALUtil.h"
#include "edu_wpi_first_hal_REVPHJNI.h"
#include "hal/Ports.h"
#include "hal/REVPH.h"
#include "hal/handles/HandlesInternal.h"
using namespace hal;
extern "C" {
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: initialize
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_REVPHJNI_initialize
(JNIEnv* env, jclass, jint module)
{
int32_t status = 0;
auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
auto handle = HAL_InitializeREVPH(module, stack.c_str(), &status);
CheckStatusForceThrow(env, status);
return handle;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: free
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_REVPHJNI_free
(JNIEnv* env, jclass, jint handle)
{
HAL_FreeREVPH(handle);
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: checkSolenoidChannel
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_REVPHJNI_checkSolenoidChannel
(JNIEnv*, jclass, jint channel)
{
return HAL_CheckREVPHSolenoidChannel(channel);
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getCompressor
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getCompressor
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto result = HAL_GetREVPHCompressor(handle, &status);
CheckStatus(env, status, false);
return result;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: setClosedLoopControl
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_REVPHJNI_setClosedLoopControl
(JNIEnv* env, jclass, jint handle, jboolean enabled)
{
int32_t status = 0;
HAL_SetREVPHClosedLoopControl(handle, enabled, &status);
CheckStatus(env, status, false);
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getClosedLoopControl
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getClosedLoopControl
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto result = HAL_GetREVPHClosedLoopControl(handle, &status);
CheckStatus(env, status, false);
return result;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getPressureSwitch
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getPressureSwitch
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto result = HAL_GetREVPHPressureSwitch(handle, &status);
CheckStatus(env, status, false);
return result;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getAnalogPressure
* Signature: (II)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getAnalogPressure
(JNIEnv* env, jclass, jint handle, jint channel)
{
int32_t status = 0;
auto result = HAL_GetREVPHAnalogPressure(handle, channel, &status);
CheckStatus(env, status, false);
return result;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getCompressorCurrent
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getCompressorCurrent
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto result = HAL_GetREVPHCompressorCurrent(handle, &status);
CheckStatus(env, status, false);
return result;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getSolenoids
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getSolenoids
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto result = HAL_GetREVPHSolenoids(handle, &status);
CheckStatus(env, status, false);
return result;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: setSolenoids
* Signature: (III)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_REVPHJNI_setSolenoids
(JNIEnv* env, jclass, jint handle, jint mask, jint value)
{
int32_t status = 0;
HAL_SetREVPHSolenoids(handle, mask, value, &status);
CheckStatus(env, status, false);
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: fireOneShot
* Signature: (III)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_REVPHJNI_fireOneShot
(JNIEnv* env, jclass, jint handle, jint index, jint durMs)
{
int32_t status = 0;
HAL_FireREVPHOneShot(handle, index, durMs, &status);
CheckStatus(env, status, false);
}
} // extern "C"

View File

@@ -0,0 +1,365 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <jni.h>
#include "CallbackStore.h"
#include "edu_wpi_first_hal_simulation_REVPHDataJNI.h"
#include "hal/simulation/REVPHData.h"
using namespace hal;
extern "C" {
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: registerInitializedCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerInitializedCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterREVPHInitializedCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: cancelInitializedCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelInitializedCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelREVPHInitializedCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: getInitialized
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getInitialized
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetREVPHInitialized(index);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: setInitialized
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setInitialized
(JNIEnv*, jclass, jint index, jboolean value)
{
HALSIM_SetREVPHInitialized(index, value);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: registerSolenoidOutputCallback
* Signature: (IILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerSolenoidOutputCallback
(JNIEnv* env, jclass, jint index, jint channel, jobject callback,
jboolean initialNotify)
{
return sim::AllocateChannelCallback(
env, index, channel, callback, initialNotify,
&HALSIM_RegisterREVPHSolenoidOutputCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: cancelSolenoidOutputCallback
* Signature: (III)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelSolenoidOutputCallback
(JNIEnv* env, jclass, jint index, jint channel, jint handle)
{
return sim::FreeChannelCallback(env, handle, index, channel,
&HALSIM_CancelREVPHSolenoidOutputCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: getSolenoidOutput
* Signature: (II)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getSolenoidOutput
(JNIEnv*, jclass, jint index, jint channel)
{
return HALSIM_GetREVPHSolenoidOutput(index, channel);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: setSolenoidOutput
* Signature: (IIZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setSolenoidOutput
(JNIEnv*, jclass, jint index, jint channel, jboolean value)
{
HALSIM_SetREVPHSolenoidOutput(index, channel, value);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: registerCompressorOnCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerCompressorOnCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterREVPHCompressorOnCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: cancelCompressorOnCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelCompressorOnCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelREVPHCompressorOnCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: getCompressorOn
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getCompressorOn
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetREVPHCompressorOn(index);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: setCompressorOn
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setCompressorOn
(JNIEnv*, jclass, jint index, jboolean value)
{
HALSIM_SetREVPHCompressorOn(index, value);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: registerClosedLoopEnabledCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerClosedLoopEnabledCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterREVPHClosedLoopEnabledCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: cancelClosedLoopEnabledCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelClosedLoopEnabledCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelREVPHClosedLoopEnabledCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: getClosedLoopEnabled
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getClosedLoopEnabled
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetREVPHClosedLoopEnabled(index);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: setClosedLoopEnabled
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setClosedLoopEnabled
(JNIEnv*, jclass, jint index, jboolean value)
{
HALSIM_SetREVPHClosedLoopEnabled(index, value);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: registerPressureSwitchCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerPressureSwitchCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterREVPHPressureSwitchCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: cancelPressureSwitchCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelPressureSwitchCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelREVPHPressureSwitchCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: getPressureSwitch
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getPressureSwitch
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetREVPHPressureSwitch(index);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: setPressureSwitch
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setPressureSwitch
(JNIEnv*, jclass, jint index, jboolean value)
{
HALSIM_SetREVPHPressureSwitch(index, value);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: registerCompressorCurrentCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerCompressorCurrentCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterREVPHCompressorCurrentCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: cancelCompressorCurrentCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelCompressorCurrentCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelREVPHCompressorCurrentCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: getCompressorCurrent
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getCompressorCurrent
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetREVPHCompressorCurrent(index);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: setCompressorCurrent
* Signature: (ID)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setCompressorCurrent
(JNIEnv*, jclass, jint index, jdouble value)
{
HALSIM_SetREVPHCompressorCurrent(index, value);
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: registerAllNonSolenoidCallbacks
* Signature: (ILjava/lang/Object;Z)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerAllNonSolenoidCallbacks
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
sim::AllocateCallback(
env, index, callback, initialNotify,
[](int32_t index, HAL_NotifyCallback cb, void* param, HAL_Bool in) {
HALSIM_RegisterREVPHAllNonSolenoidCallbacks(index, cb, param, in);
return 0;
});
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: registerAllSolenoidCallbacks
* Signature: (IILjava/lang/Object;Z)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerAllSolenoidCallbacks
(JNIEnv* env, jclass, jint index, jint channel, jobject callback,
jboolean initialNotify)
{
sim::AllocateChannelCallback(
env, index, channel, callback, initialNotify,
[](int32_t index, int32_t channel, HAL_NotifyCallback cb, void* param,
HAL_Bool in) {
HALSIM_RegisterREVPHAllSolenoidCallbacks(index, channel, cb, param, in);
return 0;
});
}
/*
* Class: edu_wpi_first_hal_simulation_REVPHDataJNI
* Method: resetData
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_REVPHDataJNI_resetData
(JNIEnv*, jclass, jint index)
{
HALSIM_ResetREVPHData(index);
}
} // extern "C"

View File

@@ -135,8 +135,10 @@
#define HAL_USE_LAST_ERROR_MESSAGE \
"HAL: Use HAL_GetLastError(status) to get last error"
#define HAL_SETUID_ERROR -1157
#define HAL_SETUID_ERROR_MESSAGE "HAL: Setting the effective user ID has failed"
#define HAL_CONSOLE_OUT_ENABLED_ERROR -1157
#define HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE \
"HAL: Onboard serial port is requested, but Console Out is enabled. " \
"Disable Console Out using imaging tool"
#define HAL_CAN_BUFFER_OVERRUN -35007
#define HAL_CAN_BUFFER_OVERRUN_MESSAGE \

View File

@@ -156,6 +156,20 @@ int32_t HAL_GetNumREVPDHModules(void);
*/
int32_t HAL_GetNumREVPDHChannels(void);
/**
* Gets the number of PH modules in the current system.
*
* @return the number of PH modules
*/
int32_t HAL_GetNumREVPHModules(void);
/**
* Gets the number of PH channels in the current system.
*
* @return the number of PH channels
*/
int32_t HAL_GetNumREVPHChannels(void);
/**
* Gets the number of duty cycle inputs in the current system.
*

View File

@@ -0,0 +1,49 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <stdint.h>
#include "hal/Types.h"
/**
* @defgroup hal_rev_ph REV PH Functions
* @ingroup hal_capi
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
const char* allocationLocation,
int32_t* status);
void HAL_FreeREVPH(HAL_REVPHHandle handle);
HAL_Bool HAL_CheckREVPHSolenoidChannel(int32_t channel);
HAL_Bool HAL_CheckREVPHModuleNumber(int32_t module);
HAL_Bool HAL_GetREVPHCompressor(HAL_REVPHHandle handle, int32_t* status);
void HAL_SetREVPHClosedLoopControl(HAL_REVPHHandle handle, HAL_Bool enabled,
int32_t* status);
HAL_Bool HAL_GetREVPHClosedLoopControl(HAL_REVPHHandle handle, int32_t* status);
HAL_Bool HAL_GetREVPHPressureSwitch(HAL_REVPHHandle handle, int32_t* status);
double HAL_GetREVPHCompressorCurrent(HAL_REVPHHandle handle, int32_t* status);
double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
int32_t* status);
int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status);
void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
int32_t* status);
void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
int32_t* status);
#ifdef __cplusplus
} // extern "C"
#endif
/** @} */

View File

@@ -68,6 +68,8 @@ typedef HAL_Handle HAL_CTREPCMHandle;
typedef HAL_Handle HAL_REVPDHHandle;
typedef HAL_Handle HAL_REVPHHandle;
typedef int32_t HAL_Bool;
#ifdef __cplusplus

View File

@@ -68,7 +68,8 @@ enum class HAL_HandleEnum {
AddressableLED = 23,
CTREPCM = 24,
CTREPDP = 25,
REVPDH = 26
REVPDH = 26,
REVPH = 27,
};
/**

View File

@@ -0,0 +1,80 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include "hal/Types.h"
#include "hal/simulation/NotifyListener.h"
#ifdef __cplusplus
extern "C" {
#endif
void HALSIM_ResetREVPHData(int32_t index);
int32_t HALSIM_RegisterREVPHInitializedCallback(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
void HALSIM_CancelREVPHInitializedCallback(int32_t index, int32_t uid);
HAL_Bool HALSIM_GetREVPHInitialized(int32_t index);
void HALSIM_SetREVPHInitialized(int32_t index, HAL_Bool solenoidInitialized);
int32_t HALSIM_RegisterREVPHSolenoidOutputCallback(int32_t index,
int32_t channel,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
void HALSIM_CancelREVPHSolenoidOutputCallback(int32_t index, int32_t channel,
int32_t uid);
HAL_Bool HALSIM_GetREVPHSolenoidOutput(int32_t index, int32_t channel);
void HALSIM_SetREVPHSolenoidOutput(int32_t index, int32_t channel,
HAL_Bool solenoidOutput);
int32_t HALSIM_RegisterREVPHCompressorOnCallback(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
void HALSIM_CancelREVPHCompressorOnCallback(int32_t index, int32_t uid);
HAL_Bool HALSIM_GetREVPHCompressorOn(int32_t index);
void HALSIM_SetREVPHCompressorOn(int32_t index, HAL_Bool compressorOn);
int32_t HALSIM_RegisterREVPHClosedLoopEnabledCallback(
int32_t index, HAL_NotifyCallback callback, void* param,
HAL_Bool initialNotify);
void HALSIM_CancelREVPHClosedLoopEnabledCallback(int32_t index, int32_t uid);
HAL_Bool HALSIM_GetREVPHClosedLoopEnabled(int32_t index);
void HALSIM_SetREVPHClosedLoopEnabled(int32_t index,
HAL_Bool closedLoopEnabled);
int32_t HALSIM_RegisterREVPHPressureSwitchCallback(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
void HALSIM_CancelREVPHPressureSwitchCallback(int32_t index, int32_t uid);
HAL_Bool HALSIM_GetREVPHPressureSwitch(int32_t index);
void HALSIM_SetREVPHPressureSwitch(int32_t index, HAL_Bool pressureSwitch);
int32_t HALSIM_RegisterREVPHCompressorCurrentCallback(
int32_t index, HAL_NotifyCallback callback, void* param,
HAL_Bool initialNotify);
void HALSIM_CancelREVPHCompressorCurrentCallback(int32_t index, int32_t uid);
double HALSIM_GetREVPHCompressorCurrent(int32_t index);
void HALSIM_SetREVPHCompressorCurrent(int32_t index, double compressorCurrent);
void HALSIM_GetREVPHAllSolenoids(int32_t index, uint8_t* values);
void HALSIM_SetREVPHAllSolenoids(int32_t index, uint8_t values);
void HALSIM_RegisterREVPHAllNonSolenoidCallbacks(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
void HALSIM_RegisterREVPHAllSolenoidCallbacks(int32_t index, int32_t channel,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -48,7 +48,7 @@ HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t module,
pcm->previousAllocation);
} else {
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for CTRE PCM", 0,
kNumAccumulators, module);
kNumCTREPCMModules, module);
}
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
}

View File

@@ -74,6 +74,7 @@ void InitializeHAL() {
InitializeEncoderData();
InitializeI2CData();
InitializeCTREPCMData();
InitializeREVPHData();
InitializePowerDistributionData();
InitializePWMData();
InitializeRelayData();
@@ -107,6 +108,7 @@ void InitializeHAL() {
InitializePorts();
InitializePower();
InitializeCTREPCM();
InitializeREVPH();
InitializePWM();
InitializeRelay();
InitializeSerialPort();
@@ -251,6 +253,8 @@ const char* HAL_GetErrorMessage(int32_t code) {
return HAL_LED_CHANNEL_ERROR_MESSAGE;
case HAL_USE_LAST_ERROR:
return HAL_USE_LAST_ERROR_MESSAGE;
case HAL_CONSOLE_OUT_ENABLED_ERROR:
return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
default:
return "Unknown error status";
}

View File

@@ -32,6 +32,7 @@ extern void InitializeDriverStationData();
extern void InitializeEncoderData();
extern void InitializeI2CData();
extern void InitializeCTREPCMData();
extern void InitializeREVPHData();
extern void InitializePowerDistributionData();
extern void InitializePWMData();
extern void InitializeRelayData();
@@ -65,6 +66,7 @@ extern void InitializePowerDistribution();
extern void InitializePorts();
extern void InitializePower();
extern void InitializeCTREPCM();
extern void InitializeREVPH();
extern void InitializePWM();
extern void InitializeRelay();
extern void InitializeSerialPort();

View File

@@ -73,6 +73,12 @@ int32_t HAL_GetNumREVPDHModules(void) {
int32_t HAL_GetNumREVPDHChannels(void) {
return kNumREVPDHChannels;
}
int32_t HAL_GetNumREVPHModules(void) {
return kNumREVPHModules;
}
int32_t HAL_GetNumREVPHChannels(void) {
return kNumREVPHChannels;
}
int32_t HAL_GetNumDutyCycles(void) {
return kNumDutyCycles;
}

View File

@@ -29,4 +29,6 @@ constexpr int32_t kNumREVPDHModules = 63;
constexpr int32_t kNumREVPDHChannels = 24;
constexpr int32_t kNumDutyCycles = 8;
constexpr int32_t kNumAddressableLEDs = 1;
constexpr int32_t kNumREVPHModules = 63;
constexpr int32_t kNumREVPHChannels = 16;
} // namespace hal

View File

@@ -0,0 +1,181 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "hal/REVPH.h"
#include "HALInitializer.h"
#include "HALInternal.h"
#include "PortsInternal.h"
#include "hal/CANAPI.h"
#include "hal/Errors.h"
#include "hal/handles/IndexedHandleResource.h"
#include "mockdata/REVPHDataInternal.h"
using namespace hal;
namespace {
struct PCM {
int32_t module;
wpi::mutex lock;
std::string previousAllocation;
};
} // namespace
static IndexedHandleResource<HAL_REVPHHandle, PCM, kNumREVPHModules,
HAL_HandleEnum::REVPH>* pcmHandles;
namespace hal::init {
void InitializeREVPH() {
static IndexedHandleResource<HAL_REVPHHandle, PCM, kNumREVPHModules,
HAL_HandleEnum::REVPH>
pH;
pcmHandles = &pH;
}
} // namespace hal::init
HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();
if (module == 0) {
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
kNumREVPHModules, module);
return HAL_kInvalidHandle;
}
HAL_REVPHHandle handle;
auto pcm = pcmHandles->Allocate(module, &handle, status);
if (*status != 0) {
if (pcm) {
hal::SetLastErrorPreviouslyAllocated(status, "REV PH", module,
pcm->previousAllocation);
} else {
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
kNumREVPHModules, module);
}
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
}
pcm->previousAllocation = allocationLocation ? allocationLocation : "";
pcm->module = module;
SimREVPHData[module].initialized = true;
// Enable closed loop
SimREVPHData[module].closedLoopEnabled = true;
return handle;
}
void HAL_FreeREVPH(HAL_REVPHHandle handle) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
pcmHandles->Free(handle);
return;
}
SimREVPHData[pcm->module].initialized = false;
pcmHandles->Free(handle);
}
HAL_Bool HAL_CheckREVPHModuleNumber(int32_t module) {
return module >= 1 && module < kNumREVPDHModules;
}
HAL_Bool HAL_CheckREVPHSolenoidChannel(int32_t channel) {
return channel < kNumREVPHChannels && channel >= 0;
}
HAL_Bool HAL_GetREVPHCompressor(HAL_REVPHHandle handle, int32_t* status) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}
return SimREVPHData[pcm->module].compressorOn;
}
void HAL_SetREVPHClosedLoopControl(HAL_REVPHHandle handle, HAL_Bool enabled,
int32_t* status) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
SimREVPHData[pcm->module].closedLoopEnabled = enabled;
}
HAL_Bool HAL_GetREVPHClosedLoopControl(HAL_REVPHHandle handle,
int32_t* status) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}
return SimREVPHData[pcm->module].closedLoopEnabled;
}
HAL_Bool HAL_GetREVPHPressureSwitch(HAL_REVPHHandle handle, int32_t* status) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}
return SimREVPHData[pcm->module].pressureSwitch;
}
double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
int32_t* status) {
return 0;
}
double HAL_GetREVPHCompressorCurrent(HAL_REVPHHandle handle, int32_t* status) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
return SimREVPHData[pcm->module].compressorCurrent;
}
int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
std::scoped_lock lock{pcm->lock};
auto& data = SimREVPHData[pcm->module].solenoidOutput;
uint8_t ret = 0;
for (int i = 0; i < kNumREVPHChannels; i++) {
ret |= (data[i] << i);
}
return ret;
}
void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
int32_t* status) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
auto& data = SimREVPHData[pcm->module].solenoidOutput;
std::scoped_lock lock{pcm->lock};
for (int i = 0; i < kNumREVPHChannels; i++) {
auto indexMask = (1 << i);
if ((mask & indexMask) != 0) {
data[i] = (values & indexMask) != 0;
}
}
}
void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
int32_t* status) {}

View File

@@ -0,0 +1,83 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "../PortsInternal.h"
#include "REVPHDataInternal.h"
using namespace hal;
namespace hal::init {
void InitializeREVPHData() {
static REVPHData spd[kNumREVPHModules];
::hal::SimREVPHData = spd;
}
} // namespace hal::init
REVPHData* hal::SimREVPHData;
void REVPHData::ResetData() {
for (int i = 0; i < kNumREVPHChannels; i++) {
solenoidOutput[i].Reset(false);
}
initialized.Reset(false);
compressorOn.Reset(false);
closedLoopEnabled.Reset(true);
pressureSwitch.Reset(false);
compressorCurrent.Reset(0.0);
}
extern "C" {
void HALSIM_ResetREVPHData(int32_t index) {
SimREVPHData[index].ResetData();
}
#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME) \
HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, REVPH##CAPINAME, SimREVPHData, \
LOWERNAME)
HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(HAL_Bool, HALSIM, REVPHSolenoidOutput,
SimREVPHData, solenoidOutput)
DEFINE_CAPI(HAL_Bool, Initialized, initialized)
DEFINE_CAPI(HAL_Bool, CompressorOn, compressorOn)
DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, closedLoopEnabled)
DEFINE_CAPI(HAL_Bool, PressureSwitch, pressureSwitch)
DEFINE_CAPI(double, CompressorCurrent, compressorCurrent)
void HALSIM_GetREVPHAllSolenoids(int32_t index, uint8_t* values) {
auto& data = SimREVPHData[index].solenoidOutput;
uint8_t ret = 0;
for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
ret |= (data[i] << i);
}
*values = ret;
}
void HALSIM_SetREVPHAllSolenoids(int32_t index, uint8_t values) {
auto& data = SimREVPHData[index].solenoidOutput;
for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
data[i] = (values & 0x1) != 0;
values >>= 1;
}
}
#define REGISTER(NAME) \
SimREVPHData[index].NAME.RegisterCallback(callback, param, initialNotify)
void HALSIM_RegisterREVPHAllNonSolenoidCallbacks(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify) {
REGISTER(initialized);
REGISTER(compressorOn);
REGISTER(closedLoopEnabled);
REGISTER(pressureSwitch);
REGISTER(compressorCurrent);
}
void HALSIM_RegisterREVPHAllSolenoidCallbacks(int32_t index, int32_t channel,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify) {
REGISTER(solenoidOutput[channel]);
}
} // extern "C"

View File

@@ -0,0 +1,43 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include "../PortsInternal.h"
#include "hal/simulation/REVPHData.h"
#include "hal/simulation/SimDataValue.h"
namespace hal {
class REVPHData {
HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
HAL_SIMDATAVALUE_DEFINE_NAME(SolenoidOutput)
HAL_SIMDATAVALUE_DEFINE_NAME(CompressorOn)
HAL_SIMDATAVALUE_DEFINE_NAME(ClosedLoopEnabled)
HAL_SIMDATAVALUE_DEFINE_NAME(PressureSwitch)
HAL_SIMDATAVALUE_DEFINE_NAME(CompressorCurrent)
static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr HAL_Bool
GetSolenoidOutputDefault() {
return false;
}
public:
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
false};
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetSolenoidOutputName,
GetSolenoidOutputDefault>
solenoidOutput[kNumREVPHChannels];
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetCompressorOnName> compressorOn{
false};
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetClosedLoopEnabledName>
closedLoopEnabled{true};
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetPressureSwitchName> pressureSwitch{
false};
SimDataValue<double, HAL_MakeDouble, GetCompressorCurrentName>
compressorCurrent{0.0};
virtual void ResetData();
};
extern REVPHData* SimREVPHData;
} // namespace hal

View File

@@ -478,27 +478,41 @@ public final class NetworkTableValue {
return Objects.hash(m_type, m_value);
}
// arraycopy() doesn't know how to unwrap boxed values; this is a false positive in PMD
// (see https://sourceforge.net/p/pmd/bugs/804/)
@SuppressWarnings("PMD.AvoidArrayLoops")
static boolean[] toNative(Boolean[] arr) {
boolean[] out = new boolean[arr.length];
System.arraycopy(arr, 0, out, 0, arr.length);
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i];
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static double[] toNative(Number[] arr) {
double[] out = new double[arr.length];
System.arraycopy(arr, 0, out, 0, arr.length);
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i].doubleValue();
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static Boolean[] fromNative(boolean[] arr) {
Boolean[] out = new Boolean[arr.length];
System.arraycopy(arr, 0, out, 0, arr.length);
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i];
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static Double[] fromNative(double[] arr) {
Double[] out = new Double[arr.length];
System.arraycopy(arr, 0, out, 0, arr.length);
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i];
}
return out;
}

View File

@@ -0,0 +1,28 @@
diff --git b/wpimath/src/main/native/include/drake/math/discrete_algebraic_riccati_equation.h a/wpimath/src/main/native/include/drake/math/discrete_algebraic_riccati_equation.h
index cb0a4ee13..5d7a316f3 100644
--- b/wpimath/src/main/native/include/drake/math/discrete_algebraic_riccati_equation.h
+++ a/wpimath/src/main/native/include/drake/math/discrete_algebraic_riccati_equation.h
@@ -4,6 +4,7 @@
#include <cstdlib>
#include <Eigen/Core>
+#include <wpi/SymbolExports.h>
namespace drake {
namespace math {
@@ -20,6 +21,7 @@ namespace math {
/// "On the Numerical Solution of the Discrete-Time Algebraic Riccati Equation"
/// by Thrasyvoulos Pappas, Alan J. Laub, and Nils R. Sandell
///
+WPILIB_DLLEXPORT
Eigen::MatrixXd DiscreteAlgebraicRiccatiEquation(
const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::MatrixXd>& B,
@@ -69,6 +71,7 @@ Eigen::MatrixXd DiscreteAlgebraicRiccatiEquation(
/// @throws std::runtime_error if Q NR⁻¹Nᵀ is not positive semi-definite.
/// @throws std::runtime_error if R is not positive definite.
///
+WPILIB_DLLEXPORT
Eigen::MatrixXd DiscreteAlgebraicRiccatiEquation(
const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::MatrixXd>& B,

View File

@@ -8,7 +8,7 @@ from upstream_utils import setup_upstream_repo, comment_out_invalid_includes, wa
def main():
root, repo = setup_upstream_repo("https://github.com/RobotLocomotion/drake",
"v0.33.0")
"v0.34.0")
wpimath = os.path.join(root, "wpimath")
# Delete old install
@@ -61,7 +61,10 @@ def main():
os.path.join(wpimath, "src/test/native/include")
])
apply_patches(root, ["upstream_utils/drake-replace-dense-with-core.patch"])
apply_patches(root, [
"upstream_utils/drake-dllexport-dare.patch",
"upstream_utils/drake-replace-dense-with-core.patch"
])
if __name__ == "__main__":

View File

@@ -113,3 +113,7 @@ test {
showStandardStreams = true
}
}
tasks.withType(JavaCompile) {
options.compilerArgs += "-Xlint:-removal"
}

View File

@@ -3,8 +3,6 @@ project(wpilibc)
include(CompileWarnings)
include(AddTest)
find_package( OpenCV REQUIRED )
configure_file(src/generate/WPILibVersion.cpp.in WPILibVersion.cpp)
file(GLOB_RECURSE
@@ -17,7 +15,18 @@ target_include_directories(wpilibc PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
$<INSTALL_INTERFACE:${include_dest}/wpilibc>)
wpilib_target_warnings(wpilibc)
target_link_libraries(wpilibc PUBLIC cameraserver hal ntcore cscore wpimath wpiutil ${OpenCV_LIBS})
if (WITH_CSCORE)
find_package( OpenCV )
target_link_libraries(wpilibc PUBLIC cameraserver cscore ${OpenCV_LIBS})
else()
target_compile_definitions(wpilibc PRIVATE DYNAMIC_CAMERA_SERVER)
# Add just the camera server include directory
target_include_directories(wpilibc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../cameraserver/src/main/native/include)
endif()
target_link_libraries(wpilibc PUBLIC hal ntcore wpimath wpiutil)
set_property(TARGET wpilibc PROPERTY FOLDER "libraries")
@@ -43,4 +52,9 @@ if (WITH_TESTS)
else()
target_compile_options(wpilibc_test PRIVATE /WX-)
endif()
if (NOT WITH_CSCORE)
target_compile_definitions(wpilibc_test PRIVATE DYNAMIC_CAMERA_SERVER)
# Add just the camera server include directory
target_include_directories(wpilibc_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../cameraserver/src/main/native/include)
endif()
endif()

View File

@@ -6,6 +6,7 @@
#include "frc/Errors.h"
#include "frc/PneumaticsControlModule.h"
#include "frc/PneumaticsHub.h"
#include "frc/SensorUtil.h"
using namespace frc;
@@ -14,6 +15,8 @@ std::shared_ptr<PneumaticsBase> PneumaticsBase::GetForType(
int module, PneumaticsModuleType moduleType) {
if (moduleType == PneumaticsModuleType::CTREPCM) {
return PneumaticsControlModule::GetForModule(module);
} else if (moduleType == PneumaticsModuleType::REVPH) {
return PneumaticsHub::GetForModule(module);
}
throw FRC_MakeError(err::InvalidParameter, "{}", moduleType);
}
@@ -21,6 +24,8 @@ std::shared_ptr<PneumaticsBase> PneumaticsBase::GetForType(
int PneumaticsBase::GetDefaultForType(PneumaticsModuleType moduleType) {
if (moduleType == PneumaticsModuleType::CTREPCM) {
return SensorUtil::GetDefaultCTREPCMModule();
} else if (moduleType == PneumaticsModuleType::REVPH) {
return SensorUtil::GetDefaultREVPHModule();
}
throw FRC_MakeError(err::InvalidParameter, "{}", moduleType);
}

View File

@@ -0,0 +1,210 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/PneumaticsHub.h"
#include <hal/REVPH.h>
#include <wpi/NullDeleter.h>
#include <wpi/StackTrace.h>
#include "frc/Compressor.h"
#include "frc/DoubleSolenoid.h"
#include "frc/Errors.h"
#include "frc/SensorUtil.h"
#include "frc/Solenoid.h"
using namespace frc;
wpi::mutex PneumaticsHub::m_handleLock;
std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<PneumaticsHub::DataStore>>>
PneumaticsHub::m_handleMap = nullptr;
// Always called under lock, so we can avoid the double lock from the magic
// static
std::weak_ptr<PneumaticsHub::DataStore>& PneumaticsHub::GetDataStore(
int module) {
if (!m_handleMap) {
m_handleMap = std::make_unique<
wpi::DenseMap<int, std::weak_ptr<PneumaticsHub::DataStore>>>();
}
return (*m_handleMap)[module];
}
class PneumaticsHub::DataStore {
public:
explicit DataStore(int module, const char* stackTrace) {
int32_t status = 0;
HAL_REVPHHandle handle = HAL_InitializeREVPH(module, stackTrace, &status);
FRC_CheckErrorStatus(status, "Module {}", module);
m_moduleObject = PneumaticsHub{handle, module};
m_moduleObject.m_dataStore =
std::shared_ptr<DataStore>{this, wpi::NullDeleter<DataStore>()};
}
~DataStore() noexcept { HAL_FreeREVPH(m_moduleObject.m_handle); }
DataStore(DataStore&&) = delete;
DataStore& operator=(DataStore&&) = delete;
private:
friend class PneumaticsHub;
uint32_t m_reservedMask{0};
bool m_compressorReserved{false};
wpi::mutex m_reservedLock;
PneumaticsHub m_moduleObject{HAL_kInvalidHandle, 0};
};
PneumaticsHub::PneumaticsHub()
: PneumaticsHub{SensorUtil::GetDefaultREVPHModule()} {}
PneumaticsHub::PneumaticsHub(int module) {
std::string stackTrace = wpi::GetStackTrace(1);
std::scoped_lock lock(m_handleLock);
auto& res = GetDataStore(module);
m_dataStore = res.lock();
if (!m_dataStore) {
m_dataStore = std::make_shared<DataStore>(module, stackTrace.c_str());
res = m_dataStore;
}
m_handle = m_dataStore->m_moduleObject.m_handle;
m_module = module;
}
PneumaticsHub::PneumaticsHub(HAL_REVPHHandle handle, int module)
: m_handle{handle}, m_module{module} {}
bool PneumaticsHub::GetCompressor() const {
int32_t status = 0;
auto result = HAL_GetREVPHCompressor(m_handle, &status);
FRC_CheckErrorStatus(status, "Module {}", m_module);
return result;
}
void PneumaticsHub::SetClosedLoopControl(bool enabled) {
int32_t status = 0;
HAL_SetREVPHClosedLoopControl(m_handle, enabled, &status);
FRC_CheckErrorStatus(status, "Module {}", m_module);
}
bool PneumaticsHub::GetClosedLoopControl() const {
int32_t status = 0;
auto result = HAL_GetREVPHClosedLoopControl(m_handle, &status);
FRC_CheckErrorStatus(status, "Module {}", m_module);
return result;
}
bool PneumaticsHub::GetPressureSwitch() const {
int32_t status = 0;
auto result = HAL_GetREVPHPressureSwitch(m_handle, &status);
FRC_CheckErrorStatus(status, "Module {}", m_module);
return result;
}
double PneumaticsHub::GetCompressorCurrent() const {
int32_t status = 0;
auto result = HAL_GetREVPHCompressorCurrent(m_handle, &status);
FRC_CheckErrorStatus(status, "Module {}", m_module);
return result;
}
void PneumaticsHub::SetSolenoids(int mask, int values) {
int32_t status = 0;
HAL_SetREVPHSolenoids(m_handle, mask, values, &status);
FRC_CheckErrorStatus(status, "Module {}", m_module);
}
int PneumaticsHub::GetSolenoids() const {
int32_t status = 0;
auto result = HAL_GetREVPHSolenoids(m_handle, &status);
FRC_CheckErrorStatus(status, "Module {}", m_module);
return result;
}
int PneumaticsHub::GetModuleNumber() const {
return m_module;
}
int PneumaticsHub::GetSolenoidDisabledList() const {
return 0;
// TODO Fix me
// int32_t status = 0;
// auto result = HAL_GetREVPHSolenoidDisabledList(m_handle, &status);
// FRC_CheckErrorStatus(status, "Module {}", m_module);
// return result;
}
void PneumaticsHub::FireOneShot(int index) {
// TODO Fix me
// int32_t status = 0;
// HAL_FireREVPHOneShot(m_handle, index, &status);
// FRC_CheckErrorStatus(status, "Module {}", m_module);
}
void PneumaticsHub::SetOneShotDuration(int index, units::second_t duration) {
// TODO Fix me
// int32_t status = 0;
// units::millisecond_t millis = duration;
// HAL_SetREVPHOneShotDuration(m_handle, index, millis.to<int32_t>(),
// &status); FRC_CheckErrorStatus(status, "Module {}", m_module);
}
bool PneumaticsHub::CheckSolenoidChannel(int channel) const {
return HAL_CheckREVPHSolenoidChannel(channel);
}
int PneumaticsHub::CheckAndReserveSolenoids(int mask) {
std::scoped_lock lock{m_dataStore->m_reservedLock};
uint32_t uMask = static_cast<uint32_t>(mask);
if ((m_dataStore->m_reservedMask & uMask) != 0) {
return m_dataStore->m_reservedMask & uMask;
}
m_dataStore->m_reservedMask |= uMask;
return 0;
}
void PneumaticsHub::UnreserveSolenoids(int mask) {
std::scoped_lock lock{m_dataStore->m_reservedLock};
m_dataStore->m_reservedMask &= ~(static_cast<uint32_t>(mask));
}
bool PneumaticsHub::ReserveCompressor() {
std::scoped_lock lock{m_dataStore->m_reservedLock};
if (m_dataStore->m_compressorReserved) {
return false;
}
m_dataStore->m_compressorReserved = true;
return true;
}
void PneumaticsHub::UnreserveCompressor() {
std::scoped_lock lock{m_dataStore->m_reservedLock};
m_dataStore->m_compressorReserved = false;
}
Solenoid PneumaticsHub::MakeSolenoid(int channel) {
return Solenoid{m_module, PneumaticsModuleType::REVPH, channel};
}
DoubleSolenoid PneumaticsHub::MakeDoubleSolenoid(int forwardChannel,
int reverseChannel) {
return DoubleSolenoid{m_module, PneumaticsModuleType::REVPH, forwardChannel,
reverseChannel};
}
Compressor PneumaticsHub::MakeCompressor() {
return Compressor{m_module, PneumaticsModuleType::REVPH};
}
std::shared_ptr<PneumaticsBase> PneumaticsHub::GetForModule(int module) {
std::string stackTrace = wpi::GetStackTrace(1);
std::scoped_lock lock(m_handleLock);
auto& res = GetDataStore(module);
std::shared_ptr<DataStore> dataStore = res.lock();
if (!dataStore) {
dataStore = std::make_shared<DataStore>(module, stackTrace.c_str());
res = dataStore;
}
return std::shared_ptr<PneumaticsBase>{dataStore, &dataStore->m_moduleObject};
}

View File

@@ -23,6 +23,10 @@ int SensorUtil::GetDefaultCTREPCMModule() {
return 0;
}
int SensorUtil::GetDefaultREVPHModule() {
return 1;
}
bool SensorUtil::CheckDigitalChannel(int channel) {
return HAL_CheckDIOChannel(channel);
}

View File

@@ -0,0 +1,139 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/simulation/REVPHSim.h"
#include <memory>
#include <utility>
#include <hal/simulation/REVPHData.h>
#include "frc/SensorUtil.h"
using namespace frc;
using namespace frc::sim;
REVPHSim::REVPHSim() : m_index{SensorUtil::GetDefaultREVPHModule()} {}
REVPHSim::REVPHSim(int module) : m_index{module} {}
REVPHSim::REVPHSim(const PneumaticsBase& pneumatics)
: m_index{pneumatics.GetModuleNumber()} {}
std::unique_ptr<CallbackStore> REVPHSim::RegisterInitializedCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, -1, callback, &HALSIM_CancelREVPHInitializedCallback);
store->SetUid(HALSIM_RegisterREVPHInitializedCallback(
m_index, &CallbackStoreThunk, store.get(), initialNotify));
return store;
}
bool REVPHSim::GetInitialized() const {
return HALSIM_GetREVPHInitialized(m_index);
}
void REVPHSim::SetInitialized(bool solenoidInitialized) {
HALSIM_SetREVPHInitialized(m_index, solenoidInitialized);
}
std::unique_ptr<CallbackStore> REVPHSim::RegisterSolenoidOutputCallback(
int channel, NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, channel, -1, callback,
&HALSIM_CancelREVPHSolenoidOutputCallback);
store->SetUid(HALSIM_RegisterREVPHSolenoidOutputCallback(
m_index, channel, &CallbackStoreThunk, store.get(), initialNotify));
return store;
}
bool REVPHSim::GetSolenoidOutput(int channel) const {
return HALSIM_GetREVPHSolenoidOutput(m_index, channel);
}
void REVPHSim::SetSolenoidOutput(int channel, bool solenoidOutput) {
HALSIM_SetREVPHSolenoidOutput(m_index, channel, solenoidOutput);
}
std::unique_ptr<CallbackStore> REVPHSim::RegisterCompressorOnCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, -1, callback, &HALSIM_CancelREVPHCompressorOnCallback);
store->SetUid(HALSIM_RegisterREVPHCompressorOnCallback(
m_index, &CallbackStoreThunk, store.get(), initialNotify));
return store;
}
bool REVPHSim::GetCompressorOn() const {
return HALSIM_GetREVPHCompressorOn(m_index);
}
void REVPHSim::SetCompressorOn(bool compressorOn) {
HALSIM_SetREVPHCompressorOn(m_index, compressorOn);
}
std::unique_ptr<CallbackStore> REVPHSim::RegisterClosedLoopEnabledCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, -1, callback, &HALSIM_CancelREVPHClosedLoopEnabledCallback);
store->SetUid(HALSIM_RegisterREVPHClosedLoopEnabledCallback(
m_index, &CallbackStoreThunk, store.get(), initialNotify));
return store;
}
bool REVPHSim::GetClosedLoopEnabled() const {
return HALSIM_GetREVPHClosedLoopEnabled(m_index);
}
void REVPHSim::SetClosedLoopEnabled(bool closedLoopEnabled) {
HALSIM_SetREVPHClosedLoopEnabled(m_index, closedLoopEnabled);
}
std::unique_ptr<CallbackStore> REVPHSim::RegisterPressureSwitchCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, -1, callback, &HALSIM_CancelREVPHPressureSwitchCallback);
store->SetUid(HALSIM_RegisterREVPHPressureSwitchCallback(
m_index, &CallbackStoreThunk, store.get(), initialNotify));
return store;
}
bool REVPHSim::GetPressureSwitch() const {
return HALSIM_GetREVPHPressureSwitch(m_index);
}
void REVPHSim::SetPressureSwitch(bool pressureSwitch) {
HALSIM_SetREVPHPressureSwitch(m_index, pressureSwitch);
}
std::unique_ptr<CallbackStore> REVPHSim::RegisterCompressorCurrentCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, -1, callback, &HALSIM_CancelREVPHCompressorCurrentCallback);
store->SetUid(HALSIM_RegisterREVPHCompressorCurrentCallback(
m_index, &CallbackStoreThunk, store.get(), initialNotify));
return store;
}
double REVPHSim::GetCompressorCurrent() const {
return HALSIM_GetREVPHCompressorCurrent(m_index);
}
void REVPHSim::SetCompressorCurrent(double compressorCurrent) {
HALSIM_SetREVPHCompressorCurrent(m_index, compressorCurrent);
}
uint8_t REVPHSim::GetAllSolenoidOutputs() const {
uint8_t ret = 0;
HALSIM_GetREVPHAllSolenoids(m_index, &ret);
return ret;
}
void REVPHSim::SetAllSolenoidOutputs(uint8_t outputs) {
HALSIM_SetREVPHAllSolenoids(m_index, outputs);
}
void REVPHSim::ResetData() {
HALSIM_ResetREVPHData(m_index);
}

View File

@@ -0,0 +1,77 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <memory>
#include <hal/Types.h>
#include <wpi/DenseMap.h>
#include <wpi/mutex.h>
#include "PneumaticsBase.h"
namespace frc {
class PneumaticsHub : public PneumaticsBase {
public:
PneumaticsHub();
explicit PneumaticsHub(int module);
~PneumaticsHub() override = default;
bool GetCompressor() const override;
void SetClosedLoopControl(bool enabled) override;
bool GetClosedLoopControl() const override;
bool GetPressureSwitch() const override;
double GetCompressorCurrent() const override;
void SetSolenoids(int mask, int values) override;
int GetSolenoids() const override;
int GetModuleNumber() const override;
int GetSolenoidDisabledList() const override;
void FireOneShot(int index) override;
void SetOneShotDuration(int index, units::second_t duration) override;
bool CheckSolenoidChannel(int channel) const override;
int CheckAndReserveSolenoids(int mask) override;
void UnreserveSolenoids(int mask) override;
bool ReserveCompressor() override;
void UnreserveCompressor() override;
Solenoid MakeSolenoid(int channel) override;
DoubleSolenoid MakeDoubleSolenoid(int forwardChannel,
int reverseChannel) override;
Compressor MakeCompressor() override;
private:
class DataStore;
friend class DataStore;
friend class PneumaticsBase;
PneumaticsHub(HAL_REVPHHandle handle, int module);
static std::shared_ptr<PneumaticsBase> GetForModule(int module);
std::shared_ptr<DataStore> m_dataStore;
HAL_REVPHHandle m_handle;
int m_module;
static wpi::mutex m_handleLock;
static std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<DataStore>>>
m_handleMap;
static std::weak_ptr<DataStore>& GetDataStore(int module);
};
} // namespace frc

View File

@@ -21,6 +21,13 @@ class SensorUtil final {
*/
static int GetDefaultCTREPCMModule();
/**
* Get the number of the default solenoid module.
*
* @return The number of the default solenoid module.
*/
static int GetDefaultREVPHModule();
/**
* Check that the digital channel number is valid.
*

View File

@@ -0,0 +1,214 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <memory>
#include "frc/PneumaticsBase.h"
#include "frc/simulation/CallbackStore.h"
namespace frc {
class Compressor;
namespace sim {
/**
* Class to control a simulated Pneumatic Control Module (PCM).
*/
class REVPHSim {
public:
/**
* Constructs with the default PCM module number (CAN ID).
*/
REVPHSim();
/**
* Constructs from a PCM module number (CAN ID).
*
* @param module module number
*/
explicit REVPHSim(int module);
explicit REVPHSim(const PneumaticsBase& pneumatics);
/**
* Register a callback to be run when a solenoid is initialized on a channel.
*
* @param channel the channel to monitor
* @param callback the callback
* @param initialNotify should the callback be run with the initial state
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
NotifyCallback callback, bool initialNotify);
/**
* Check if a solenoid has been initialized on a specific channel.
*
* @return true if initialized
*/
bool GetInitialized() const;
/**
* Define whether a solenoid has been initialized on a specific channel.
*
* @param channel the channel
* @param solenoidInitialized is there a solenoid initialized on that channel
*/
void SetInitialized(bool solenoidInitialized);
/**
* Register a callback to be run when the solenoid output on a channel
* changes.
*
* @param channel the channel to monitor
* @param callback the callback
* @param initialNotify should the callback be run with the initial value
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]] std::unique_ptr<CallbackStore> RegisterSolenoidOutputCallback(
int channel, NotifyCallback callback, bool initialNotify);
/**
* Check the solenoid output on a specific channel.
*
* @param channel the channel to check
* @return the solenoid output
*/
bool GetSolenoidOutput(int channel) const;
/**
* Change the solenoid output on a specific channel.
*
* @param channel the channel to check
* @param solenoidOutput the new solenoid output
*/
void SetSolenoidOutput(int channel, bool solenoidOutput);
/**
* Register a callback to be run when the compressor activates.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial state
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]] std::unique_ptr<CallbackStore> RegisterCompressorOnCallback(
NotifyCallback callback, bool initialNotify);
/**
* Check if the compressor is on.
*
* @return true if the compressor is active
*/
bool GetCompressorOn() const;
/**
* Set whether the compressor is active.
*
* @param compressorOn the new value
*/
void SetCompressorOn(bool compressorOn);
/**
* Register a callback to be run whenever the closed loop state changes.
*
* @param callback the callback
* @param initialNotify whether the callback should be called with the
* initial value
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]] std::unique_ptr<CallbackStore>
RegisterClosedLoopEnabledCallback(NotifyCallback callback,
bool initialNotify);
/**
* Check whether the closed loop compressor control is active.
*
* @return true if active
*/
bool GetClosedLoopEnabled() const;
/**
* Turn on/off the closed loop control of the compressor.
*
* @param closedLoopEnabled whether the control loop is active
*/
void SetClosedLoopEnabled(bool closedLoopEnabled);
/**
* Register a callback to be run whenever the pressure switch value changes.
*
* @param callback the callback
* @param initialNotify whether the callback should be called with the
* initial value
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]] std::unique_ptr<CallbackStore> RegisterPressureSwitchCallback(
NotifyCallback callback, bool initialNotify);
/**
* Check the value of the pressure switch.
*
* @return the pressure switch value
*/
bool GetPressureSwitch() const;
/**
* Set the value of the pressure switch.
*
* @param pressureSwitch the new value
*/
void SetPressureSwitch(bool pressureSwitch);
/**
* Register a callback to be run whenever the compressor current changes.
*
* @param callback the callback
* @param initialNotify whether to call the callback with the initial state
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]] std::unique_ptr<CallbackStore>
RegisterCompressorCurrentCallback(NotifyCallback callback,
bool initialNotify);
/**
* Read the compressor current.
*
* @return the current of the compressor connected to this module
*/
double GetCompressorCurrent() const;
/**
* Set the compressor current.
*
* @param compressorCurrent the new compressor current
*/
void SetCompressorCurrent(double compressorCurrent);
/**
* Get the current value of all solenoid outputs.
*
* @return the solenoid outputs (1 bit per output)
*/
uint8_t GetAllSolenoidOutputs() const;
/**
* Change all of the solenoid outputs.
*
* @param outputs the new solenoid outputs (1 bit per output)
*/
void SetAllSolenoidOutputs(uint8_t outputs);
/**
* Reset all simulation data for this object.
*/
void ResetData();
private:
int m_index;
};
} // namespace sim
} // namespace frc

View File

@@ -0,0 +1,75 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <hal/HAL.h>
#include "frc/DoubleSolenoid.h"
#include "frc/PneumaticsControlModule.h"
#include "frc/Solenoid.h"
#include "gtest/gtest.h"
namespace frc {
TEST(DoubleSolenoidCTRETest, ValidInitialization) {
DoubleSolenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
solenoid.Set(DoubleSolenoid::kReverse);
EXPECT_EQ(DoubleSolenoid::kReverse, solenoid.Get());
solenoid.Set(DoubleSolenoid::kForward);
EXPECT_EQ(DoubleSolenoid::kForward, solenoid.Get());
solenoid.Set(DoubleSolenoid::kOff);
EXPECT_EQ(DoubleSolenoid::kOff, solenoid.Get());
}
TEST(DoubleSolenoidCTRETest, ThrowForwardPortAlreadyInitialized) {
// Single solenoid that is reused for forward port
Solenoid solenoid{5, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_THROW(DoubleSolenoid(5, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidCTRETest, ThrowReversePortAlreadyInitialized) {
// Single solenoid that is reused for forward port
Solenoid solenoid{6, frc::PneumaticsModuleType::CTREPCM, 3};
EXPECT_THROW(DoubleSolenoid(6, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidCTRETest, ThrowBothPortsAlreadyInitialized) {
PneumaticsControlModule pcm{6};
// Single solenoid that is reused for forward port
Solenoid solenoid0(6, frc::PneumaticsModuleType::CTREPCM, 2);
Solenoid solenoid1(6, frc::PneumaticsModuleType::CTREPCM, 3);
EXPECT_THROW(DoubleSolenoid(6, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidCTRETest, Toggle) {
DoubleSolenoid solenoid{4, frc::PneumaticsModuleType::CTREPCM, 2, 3};
// Bootstrap it into reverse
solenoid.Set(DoubleSolenoid::kReverse);
solenoid.Toggle();
EXPECT_EQ(DoubleSolenoid::kForward, solenoid.Get());
solenoid.Toggle();
EXPECT_EQ(DoubleSolenoid::kReverse, solenoid.Get());
// Of shouldn't do anything on toggle
solenoid.Set(DoubleSolenoid::kOff);
solenoid.Toggle();
EXPECT_EQ(DoubleSolenoid::kOff, solenoid.Get());
}
TEST(DoubleSolenoidCTRETest, InvalidForwardPort) {
EXPECT_THROW(DoubleSolenoid(0, frc::PneumaticsModuleType::CTREPCM, 100, 1),
std::runtime_error);
}
TEST(DoubleSolenoidCTRETest, InvalidReversePort) {
EXPECT_THROW(DoubleSolenoid(0, frc::PneumaticsModuleType::CTREPCM, 0, 100),
std::runtime_error);
}
} // namespace frc

View File

@@ -11,7 +11,7 @@
namespace frc {
TEST(DoubleSolenoidTest, ValidInitialization) {
TEST(DoubleSolenoidREVTest, ValidInitialization) {
DoubleSolenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
solenoid.Set(DoubleSolenoid::kReverse);
EXPECT_EQ(DoubleSolenoid::kReverse, solenoid.Get());
@@ -23,21 +23,21 @@ TEST(DoubleSolenoidTest, ValidInitialization) {
EXPECT_EQ(DoubleSolenoid::kOff, solenoid.Get());
}
TEST(DoubleSolenoidTest, ThrowForwardPortAlreadyInitialized) {
TEST(DoubleSolenoidREVTest, ThrowForwardPortAlreadyInitialized) {
// Single solenoid that is reused for forward port
Solenoid solenoid{5, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_THROW(DoubleSolenoid(5, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidTest, ThrowReversePortAlreadyInitialized) {
TEST(DoubleSolenoidREVTest, ThrowReversePortAlreadyInitialized) {
// Single solenoid that is reused for forward port
Solenoid solenoid{6, frc::PneumaticsModuleType::CTREPCM, 3};
EXPECT_THROW(DoubleSolenoid(6, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidTest, ThrowBothPortsAlreadyInitialized) {
TEST(DoubleSolenoidREVTest, ThrowBothPortsAlreadyInitialized) {
PneumaticsControlModule pcm{6};
// Single solenoid that is reused for forward port
Solenoid solenoid0(6, frc::PneumaticsModuleType::CTREPCM, 2);
@@ -46,7 +46,7 @@ TEST(DoubleSolenoidTest, ThrowBothPortsAlreadyInitialized) {
std::runtime_error);
}
TEST(DoubleSolenoidTest, Toggle) {
TEST(DoubleSolenoidREVTest, Toggle) {
DoubleSolenoid solenoid{4, frc::PneumaticsModuleType::CTREPCM, 2, 3};
// Bootstrap it into reverse
solenoid.Set(DoubleSolenoid::kReverse);
@@ -63,12 +63,12 @@ TEST(DoubleSolenoidTest, Toggle) {
EXPECT_EQ(DoubleSolenoid::kOff, solenoid.Get());
}
TEST(DoubleSolenoidTest, InvalidForwardPort) {
TEST(DoubleSolenoidREVTest, InvalidForwardPort) {
EXPECT_THROW(DoubleSolenoid(0, frc::PneumaticsModuleType::CTREPCM, 100, 1),
std::runtime_error);
}
TEST(DoubleSolenoidTest, InvalidReversePort) {
TEST(DoubleSolenoidREVTest, InvalidReversePort) {
EXPECT_THROW(DoubleSolenoid(0, frc::PneumaticsModuleType::CTREPCM, 0, 100),
std::runtime_error);
}

View File

@@ -10,7 +10,7 @@
#include "gtest/gtest.h"
namespace frc {
TEST(SolenoidTest, ValidInitialization) {
TEST(SolenoidCTRETest, ValidInitialization) {
Solenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_EQ(2, solenoid.GetChannel());
@@ -21,24 +21,24 @@ TEST(SolenoidTest, ValidInitialization) {
EXPECT_FALSE(solenoid.Get());
}
TEST(SolenoidTest, DoubleInitialization) {
TEST(SolenoidCTRETest, DoubleInitialization) {
Solenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::CTREPCM, 2),
std::runtime_error);
}
TEST(SolenoidTest, DoubleInitializationFromDoubleSolenoid) {
TEST(SolenoidCTRETest, DoubleInitializationFromDoubleSolenoid) {
DoubleSolenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::CTREPCM, 2),
std::runtime_error);
}
TEST(SolenoidTest, InvalidChannel) {
TEST(SolenoidCTRETest, InvalidChannel) {
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::CTREPCM, 100),
std::runtime_error);
}
TEST(SolenoidTest, Toggle) {
TEST(SolenoidCTRETest, Toggle) {
Solenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2};
solenoid.Set(true);
EXPECT_TRUE(solenoid.Get());

View File

@@ -0,0 +1,52 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <hal/HAL.h>
#include "frc/DoubleSolenoid.h"
#include "frc/PneumaticsControlModule.h"
#include "frc/Solenoid.h"
#include "gtest/gtest.h"
namespace frc {
TEST(SolenoidREVTest, ValidInitialization) {
Solenoid solenoid{3, frc::PneumaticsModuleType::REVPH, 2};
EXPECT_EQ(2, solenoid.GetChannel());
solenoid.Set(true);
EXPECT_TRUE(solenoid.Get());
solenoid.Set(false);
EXPECT_FALSE(solenoid.Get());
}
TEST(SolenoidREVTest, DoubleInitialization) {
Solenoid solenoid{3, frc::PneumaticsModuleType::REVPH, 2};
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::REVPH, 2),
std::runtime_error);
}
TEST(SolenoidREVTest, DoubleInitializationFromDoubleSolenoid) {
DoubleSolenoid solenoid{3, frc::PneumaticsModuleType::REVPH, 2, 3};
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::REVPH, 2),
std::runtime_error);
}
TEST(SolenoidREVTest, InvalidChannel) {
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::REVPH, 100),
std::runtime_error);
}
TEST(SolenoidREVTest, Toggle) {
Solenoid solenoid{3, frc::PneumaticsModuleType::REVPH, 2};
solenoid.Set(true);
EXPECT_TRUE(solenoid.Get());
solenoid.Toggle();
EXPECT_FALSE(solenoid.Get());
solenoid.Toggle();
EXPECT_TRUE(solenoid.Get());
}
} // namespace frc

View File

@@ -0,0 +1,150 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/simulation/REVPHSim.h" // NOLINT(build/include_order)
#include <hal/HAL.h>
#include "callback_helpers/TestCallbackHelpers.h"
#include "frc/DoubleSolenoid.h"
#include "frc/PneumaticsHub.h"
#include "gtest/gtest.h"
namespace frc::sim {
TEST(REVPHSimTest, InitializedCallback) {
REVPHSim sim;
sim.ResetData();
EXPECT_FALSE(sim.GetInitialized());
BooleanCallback callback;
auto cb = sim.RegisterInitializedCallback(callback.GetCallback(), false);
PneumaticsHub ph;
EXPECT_TRUE(sim.GetInitialized());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_TRUE(callback.GetLastValue());
}
TEST(REVPHSimTest, SolenoidOutput) {
PneumaticsHub ph;
REVPHSim sim(ph);
sim.ResetData();
DoubleSolenoid doubleSolenoid{1, frc::PneumaticsModuleType::REVPH, 3, 4};
BooleanCallback callback3;
BooleanCallback callback4;
auto cb3 =
sim.RegisterSolenoidOutputCallback(3, callback3.GetCallback(), false);
auto cb4 =
sim.RegisterSolenoidOutputCallback(4, callback4.GetCallback(), false);
callback3.Reset();
callback4.Reset();
doubleSolenoid.Set(DoubleSolenoid::kReverse);
EXPECT_FALSE(callback3.WasTriggered());
EXPECT_FALSE(callback3.GetLastValue());
EXPECT_TRUE(callback4.WasTriggered());
EXPECT_TRUE(callback4.GetLastValue());
EXPECT_FALSE(sim.GetSolenoidOutput(3));
EXPECT_TRUE(sim.GetSolenoidOutput(4));
EXPECT_EQ(0b00010000, ph.GetSolenoids());
EXPECT_EQ(0b00010000, sim.GetAllSolenoidOutputs());
callback3.Reset();
callback4.Reset();
doubleSolenoid.Set(DoubleSolenoid::kForward);
EXPECT_TRUE(callback3.WasTriggered());
EXPECT_TRUE(callback3.GetLastValue());
EXPECT_TRUE(callback4.WasTriggered());
EXPECT_FALSE(callback4.GetLastValue());
EXPECT_TRUE(sim.GetSolenoidOutput(3));
EXPECT_FALSE(sim.GetSolenoidOutput(4));
EXPECT_EQ(0b00001000, ph.GetSolenoids());
EXPECT_EQ(0b00001000, sim.GetAllSolenoidOutputs());
callback3.Reset();
callback4.Reset();
doubleSolenoid.Set(DoubleSolenoid::kOff);
EXPECT_TRUE(callback3.WasTriggered());
EXPECT_FALSE(callback3.GetLastValue());
EXPECT_FALSE(callback4.WasTriggered());
EXPECT_FALSE(callback4.GetLastValue());
EXPECT_FALSE(sim.GetSolenoidOutput(3));
EXPECT_FALSE(sim.GetSolenoidOutput(4));
EXPECT_EQ(0b00000000, ph.GetSolenoids());
EXPECT_EQ(0b00000000, sim.GetAllSolenoidOutputs());
}
TEST(REVPHSimTest, SetCompressorOn) {
PneumaticsHub ph;
REVPHSim sim(ph);
sim.ResetData();
BooleanCallback callback;
auto cb = sim.RegisterCompressorOnCallback(callback.GetCallback(), false);
EXPECT_FALSE(ph.GetCompressor());
EXPECT_FALSE(ph.GetCompressor());
sim.SetCompressorOn(true);
EXPECT_TRUE(sim.GetCompressorOn());
EXPECT_TRUE(ph.GetCompressor());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_TRUE(callback.GetLastValue());
}
TEST(REVPHSimTest, SetClosedLoopEnabled) {
PneumaticsHub ph;
REVPHSim sim(ph);
sim.ResetData();
BooleanCallback callback;
auto cb =
sim.RegisterClosedLoopEnabledCallback(callback.GetCallback(), false);
ph.SetClosedLoopControl(false);
EXPECT_FALSE(ph.GetClosedLoopControl());
ph.SetClosedLoopControl(true);
EXPECT_TRUE(sim.GetClosedLoopEnabled());
EXPECT_TRUE(ph.GetClosedLoopControl());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_TRUE(callback.GetLastValue());
}
TEST(REVPHSimTest, SetPressureSwitchEnabled) {
PneumaticsHub ph;
REVPHSim sim(ph);
sim.ResetData();
BooleanCallback callback;
auto cb = sim.RegisterPressureSwitchCallback(callback.GetCallback(), false);
EXPECT_FALSE(ph.GetPressureSwitch());
sim.SetPressureSwitch(true);
EXPECT_TRUE(sim.GetPressureSwitch());
EXPECT_TRUE(ph.GetPressureSwitch());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_TRUE(callback.GetLastValue());
}
TEST(REVPHSimTest, SetCompressorCurrent) {
PneumaticsHub ph;
REVPHSim sim(ph);
sim.ResetData();
DoubleCallback callback;
auto cb =
sim.RegisterCompressorCurrentCallback(callback.GetCallback(), false);
sim.SetCompressorCurrent(35.04);
EXPECT_EQ(35.04, sim.GetCompressorCurrent());
EXPECT_EQ(35.04, ph.GetCompressorCurrent());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_EQ(35.04, callback.GetLastValue());
}
} // namespace frc::sim

View File

@@ -1,9 +1,8 @@
project (wpilibj)
find_package( OpenCV REQUIRED )
# Java bindings
if (WITH_JAVA)
find_package( OpenCV REQUIRED )
find_package(Java REQUIRED)
include(UseJava)
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")

View File

@@ -12,9 +12,11 @@ public interface PneumaticsBase extends AutoCloseable {
* @param type module type
* @return module
*/
static PneumaticsControlModule getForType(int module, PneumaticsModuleType type) {
static PneumaticsBase getForType(int module, PneumaticsModuleType type) {
if (type == PneumaticsModuleType.CTREPCM) {
return new PneumaticsControlModule();
return new PneumaticsControlModule(module);
} else if (type == PneumaticsModuleType.REVPH) {
return new PneumaticsHub(module);
}
throw new IllegalArgumentException("Unknown module type");
}
@@ -28,6 +30,8 @@ public interface PneumaticsBase extends AutoCloseable {
static int getDefaultForType(PneumaticsModuleType type) {
if (type == PneumaticsModuleType.CTREPCM) {
return SensorUtil.getDefaultCTREPCMModule();
} else if (type == PneumaticsModuleType.REVPH) {
return SensorUtil.getDefaultREVPHModule();
}
throw new IllegalArgumentException("Unknown module type");
}

View File

@@ -147,7 +147,7 @@ public class PneumaticsControlModule implements PneumaticsBase {
@Override
public int getModuleNumber() {
return m_dataStore.m_handle;
return m_dataStore.m_module;
}
@Override

View File

@@ -0,0 +1,203 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.REVPHJNI;
import java.util.HashMap;
import java.util.Map;
/** Module class for controlling a REV Robotics Pneumatics Hub. */
public class PneumaticsHub implements PneumaticsBase {
private static class DataStore implements AutoCloseable {
public final int m_module;
public final int m_handle;
private int m_refCount;
private int m_reservedMask;
private boolean m_compressorReserved;
private final Object m_reserveLock = new Object();
DataStore(int module) {
m_handle = REVPHJNI.initialize(module);
m_module = module;
m_handleMap.put(module, this);
}
@Override
public void close() {
REVPHJNI.free(m_handle);
m_handleMap.remove(m_module);
}
public void addRef() {
m_refCount++;
}
public void removeRef() {
m_refCount--;
if (m_refCount == 0) {
this.close();
}
}
}
private static final Map<Integer, DataStore> m_handleMap = new HashMap<>();
private static final Object m_handleLock = new Object();
private static DataStore getForModule(int module) {
synchronized (m_handleLock) {
Integer moduleBoxed = module;
DataStore pcm = m_handleMap.get(moduleBoxed);
if (pcm == null) {
pcm = new DataStore(module);
}
pcm.addRef();
return pcm;
}
}
private static void freeModule(DataStore store) {
synchronized (m_handleLock) {
store.removeRef();
}
}
private final DataStore m_dataStore;
private final int m_handle;
/** Constructs a PneumaticsHub with the default id (1). */
public PneumaticsHub() {
this(SensorUtil.getDefaultREVPHModule());
}
/**
* Constructs a PneumaticsHub.
*
* @param module module number to construct
*/
public PneumaticsHub(int module) {
m_dataStore = getForModule(module);
m_handle = m_dataStore.m_handle;
}
@Override
public void close() {
freeModule(m_dataStore);
}
@Override
public boolean getCompressor() {
return REVPHJNI.getCompressor(m_handle);
}
@Override
public void setClosedLoopControl(boolean enabled) {
REVPHJNI.setClosedLoopControl(m_handle, enabled);
}
@Override
public boolean getClosedLoopControl() {
return REVPHJNI.getClosedLoopControl(m_handle);
}
@Override
public boolean getPressureSwitch() {
return REVPHJNI.getPressureSwitch(m_handle);
}
@Override
public double getCompressorCurrent() {
return REVPHJNI.getCompressorCurrent(m_handle);
}
@Override
public void setSolenoids(int mask, int values) {
REVPHJNI.setSolenoids(m_handle, mask, values);
}
@Override
public int getSolenoids() {
return REVPHJNI.getSolenoids(m_handle);
}
@Override
public int getModuleNumber() {
return m_dataStore.m_module;
}
@Override
public void fireOneShot(int index) {
// TODO Combine APIs
// REVPHJNI.fireOneShot(m_handle, index, durMs);
}
@Override
public void setOneShotDuration(int index, int durMs) {
// TODO Combine APIs
// REVPHJNI.setOneShotDuration(m_handle, index, durMs);
}
@Override
public boolean checkSolenoidChannel(int channel) {
return REVPHJNI.checkSolenoidChannel(channel);
}
@Override
public int checkAndReserveSolenoids(int mask) {
synchronized (m_dataStore.m_reserveLock) {
if ((m_dataStore.m_reservedMask & mask) != 0) {
return m_dataStore.m_reservedMask & mask;
}
m_dataStore.m_reservedMask |= mask;
return 0;
}
}
@Override
public void unreserveSolenoids(int mask) {
synchronized (m_dataStore.m_reserveLock) {
m_dataStore.m_reservedMask &= ~mask;
}
}
@Override
public Solenoid makeSolenoid(int channel) {
return new Solenoid(m_dataStore.m_module, PneumaticsModuleType.REVPH, channel);
}
@Override
public DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel) {
return new DoubleSolenoid(
m_dataStore.m_module, PneumaticsModuleType.REVPH, forwardChannel, reverseChannel);
}
@Override
public Compressor makeCompressor() {
return new Compressor(m_dataStore.m_module, PneumaticsModuleType.REVPH);
}
@Override
public boolean reserveCompressor() {
synchronized (m_dataStore.m_reserveLock) {
if (m_dataStore.m_compressorReserved) {
return false;
}
m_dataStore.m_compressorReserved = true;
return true;
}
}
@Override
public void unreserveCompressor() {
synchronized (m_dataStore.m_reserveLock) {
m_dataStore.m_compressorReserved = false;
}
}
@Override
public int getSolenoidDisabledList() {
// TODO Get this working
return 0;
}
}

View File

@@ -47,6 +47,10 @@ public final class SensorUtil {
/** Number of PCM Modules. */
public static final int kCTREPCMModules = PortsJNI.getNumCTREPCMModules();
public static final int kREVPHChannels = PortsJNI.getNumREVPHChannels();
public static final int kREVPHModules = PortsJNI.getNumREVPHModules();
/**
* Check that the digital channel number is valid. Verify that the channel number is one of the
* legal channel numbers. Channel numbers are 0-based.
@@ -142,5 +146,15 @@ public final class SensorUtil {
return 0;
}
/**
* Get the number of the default solenoid module.
*
* @return The number of the default solenoid module.
*/
@SuppressWarnings("AbbreviationAsWordInName")
public static int getDefaultREVPHModule() {
return 1;
}
private SensorUtil() {}
}

View File

@@ -0,0 +1,239 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.hal.simulation.REVPHDataJNI;
import edu.wpi.first.wpilibj.PneumaticsBase;
import edu.wpi.first.wpilibj.SensorUtil;
/** Class to control a simulated PneumaticsHub (PH). */
@SuppressWarnings("AbbreviationAsWordInName")
public class REVPHSim {
private final int m_index;
/** Constructs for the default PH. */
public REVPHSim() {
m_index = SensorUtil.getDefaultREVPHModule();
}
/**
* Constructs from a PH module number (CAN ID).
*
* @param module module number
*/
public REVPHSim(int module) {
m_index = module;
}
/**
* Constructs from a Compressor object.
*
* @param module PCM module to simulate
*/
public REVPHSim(PneumaticsBase module) {
m_index = module.getModuleNumber();
}
/**
* Register a callback to be run when the solenoid output on a channel changes.
*
* @param channel the channel to monitor
* @param callback the callback
* @param initialNotify should the callback be run with the initial value
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerSolenoidOutputCallback(
int channel, NotifyCallback callback, boolean initialNotify) {
int uid =
REVPHDataJNI.registerSolenoidOutputCallback(m_index, channel, callback, initialNotify);
return new CallbackStore(m_index, channel, uid, REVPHDataJNI::cancelSolenoidOutputCallback);
}
/**
* Check the solenoid output on a specific channel.
*
* @param channel the channel to check
* @return the solenoid output
*/
public boolean getSolenoidOutput(int channel) {
return REVPHDataJNI.getSolenoidOutput(m_index, channel);
}
/**
* Change the solenoid output on a specific channel.
*
* @param channel the channel to check
* @param solenoidOutput the new solenoid output
*/
public void setSolenoidOutput(int channel, boolean solenoidOutput) {
REVPHDataJNI.setSolenoidOutput(m_index, channel, solenoidOutput);
}
/**
* Register a callback to be run when the compressor is initialized.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial state
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelInitializedCallback);
}
/**
* Check whether the compressor has been initialized.
*
* @return true if initialized
*/
public boolean getInitialized() {
return REVPHDataJNI.getInitialized(m_index);
}
/**
* Define whether the compressor has been initialized.
*
* @param initialized whether the compressor is initialized
*/
public void setInitialized(boolean initialized) {
REVPHDataJNI.setInitialized(m_index, initialized);
}
/**
* Register a callback to be run when the compressor activates.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial state
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerCompressorOnCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerCompressorOnCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelCompressorOnCallback);
}
/**
* Check if the compressor is on.
*
* @return true if the compressor is active
*/
public boolean getCompressorOn() {
return REVPHDataJNI.getCompressorOn(m_index);
}
/**
* Set whether the compressor is active.
*
* @param compressorOn the new value
*/
public void setCompressorOn(boolean compressorOn) {
REVPHDataJNI.setCompressorOn(m_index, compressorOn);
}
/**
* Register a callback to be run whenever the closed loop state changes.
*
* @param callback the callback
* @param initialNotify whether the callback should be called with the initial value
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerClosedLoopEnabledCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerClosedLoopEnabledCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelClosedLoopEnabledCallback);
}
/**
* Check whether the closed loop compressor control is active.
*
* @return true if active
*/
public boolean getClosedLoopEnabled() {
return REVPHDataJNI.getClosedLoopEnabled(m_index);
}
/**
* Turn on/off the closed loop control of the compressor.
*
* @param closedLoopEnabled whether the control loop is active
*/
public void setClosedLoopEnabled(boolean closedLoopEnabled) {
REVPHDataJNI.setClosedLoopEnabled(m_index, closedLoopEnabled);
}
/**
* Register a callback to be run whenever the pressure switch value changes.
*
* @param callback the callback
* @param initialNotify whether the callback should be called with the initial value
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerPressureSwitchCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerPressureSwitchCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelPressureSwitchCallback);
}
/**
* Check the value of the pressure switch.
*
* @return the pressure switch value
*/
public boolean getPressureSwitch() {
return REVPHDataJNI.getPressureSwitch(m_index);
}
/**
* Set the value of the pressure switch.
*
* @param pressureSwitch the new value
*/
public void setPressureSwitch(boolean pressureSwitch) {
REVPHDataJNI.setPressureSwitch(m_index, pressureSwitch);
}
/**
* Register a callback to be run whenever the compressor current changes.
*
* @param callback the callback
* @param initialNotify whether to call the callback with the initial state
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerCompressorCurrentCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerCompressorCurrentCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelCompressorCurrentCallback);
}
/**
* Read the compressor current.
*
* @return the current of the compressor connected to this module
*/
public double getCompressorCurrent() {
return REVPHDataJNI.getCompressorCurrent(m_index);
}
/**
* Set the compressor current.
*
* @param compressorCurrent the new compressor current
*/
public void setCompressorCurrent(double compressorCurrent) {
REVPHDataJNI.setCompressorCurrent(m_index, compressorCurrent);
}
/** Reset all simulation data for this object. */
public void resetData() {
REVPHDataJNI.resetData(m_index);
}
}

View File

@@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import edu.wpi.first.hal.util.AllocationException;
import org.junit.jupiter.api.Test;
public class DoubleSolenoidTest {
public class DoubleSolenoidTestCTRE {
@Test
void testValidInitialization() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.CTREPCM, 2, 3)) {

View File

@@ -0,0 +1,91 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import edu.wpi.first.hal.util.AllocationException;
import org.junit.jupiter.api.Test;
public class DoubleSolenoidTestREV {
@Test
void testValidInitialization() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.REVPH, 2, 3)) {
solenoid.set(DoubleSolenoid.Value.kReverse);
assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
solenoid.set(DoubleSolenoid.Value.kForward);
assertEquals(DoubleSolenoid.Value.kForward, solenoid.get());
solenoid.set(DoubleSolenoid.Value.kOff);
assertEquals(DoubleSolenoid.Value.kOff, solenoid.get());
}
}
@Test
void testThrowForwardPortAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(5, PneumaticsModuleType.REVPH, 2)) {
assertThrows(
AllocationException.class, () -> new DoubleSolenoid(5, PneumaticsModuleType.REVPH, 2, 3));
}
}
@Test
void testThrowReversePortAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(6, PneumaticsModuleType.REVPH, 3)) {
assertThrows(
AllocationException.class, () -> new DoubleSolenoid(6, PneumaticsModuleType.REVPH, 2, 3));
}
}
@Test
void testThrowBothPortsAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid0 = new Solenoid(6, PneumaticsModuleType.REVPH, 2);
Solenoid solenoid1 = new Solenoid(6, PneumaticsModuleType.REVPH, 3)) {
assertThrows(
AllocationException.class, () -> new DoubleSolenoid(6, PneumaticsModuleType.REVPH, 2, 3));
}
}
@Test
void testToggle() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(4, PneumaticsModuleType.REVPH, 2, 3)) {
// Bootstrap it into reverse
solenoid.set(DoubleSolenoid.Value.kReverse);
solenoid.toggle();
assertEquals(DoubleSolenoid.Value.kForward, solenoid.get());
solenoid.toggle();
assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
// Of shouldn't do anything on toggle
solenoid.set(DoubleSolenoid.Value.kOff);
solenoid.toggle();
assertEquals(DoubleSolenoid.Value.kOff, solenoid.get());
}
}
@Test
void testInvalidForwardPort() {
assertThrows(
IllegalArgumentException.class,
() -> new DoubleSolenoid(1, PneumaticsModuleType.REVPH, 100, 1));
}
@Test
void testInvalidReversePort() {
assertThrows(
IllegalArgumentException.class,
() -> new DoubleSolenoid(1, PneumaticsModuleType.REVPH, 0, 100));
}
}

View File

@@ -12,7 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.hal.util.AllocationException;
import org.junit.jupiter.api.Test;
public class SolenoidTest {
public class SolenoidTestCTRE {
@Test
void testValidInitialization() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {

View File

@@ -0,0 +1,62 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.hal.util.AllocationException;
import org.junit.jupiter.api.Test;
public class SolenoidTestREV {
@Test
void testValidInitialization() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
assertEquals(2, solenoid.getChannel());
solenoid.set(true);
assertTrue(solenoid.get());
solenoid.set(false);
assertFalse(solenoid.get());
}
}
@Test
void testDoubleInitialization() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
assertThrows(AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 2));
}
}
@Test
void testDoubleInitializationFromDoubleSolenoid() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.REVPH, 2, 3)) {
assertThrows(AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 2));
}
}
@Test
void testInvalidChannel() {
assertThrows(
IllegalArgumentException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 100));
}
@Test
void testToggle() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
solenoid.set(true);
assertTrue(solenoid.get());
solenoid.toggle();
assertFalse(solenoid.get());
solenoid.toggle();
assertTrue(solenoid.get());
}
}
}

View File

@@ -0,0 +1,168 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.wpilibj.DoubleSolenoid;
import edu.wpi.first.wpilibj.PneumaticsHub;
import edu.wpi.first.wpilibj.PneumaticsModuleType;
import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
import org.junit.jupiter.api.Test;
@SuppressWarnings("AbbreviationAsWordInName")
class REVPHSimTest {
@Test
void testInitialization() {
HAL.initialize(500, 0);
REVPHSim sim = new REVPHSim(1);
sim.resetData();
assertFalse(sim.getInitialized());
BooleanCallback callback = new BooleanCallback();
try (CallbackStore cb = sim.registerInitializedCallback(callback, false);
PneumaticsHub ph = new PneumaticsHub(1)) {
assertTrue(sim.getInitialized());
}
assertFalse(sim.getInitialized());
}
@Test
void solenoidOutputTest() {
HAL.initialize(500, 0);
try (PneumaticsHub ph = new PneumaticsHub(1);
DoubleSolenoid doubleSolenoid = new DoubleSolenoid(1, PneumaticsModuleType.REVPH, 3, 4)) {
REVPHSim sim = new REVPHSim(ph);
sim.resetData();
BooleanCallback callback3 = new BooleanCallback();
BooleanCallback callback4 = new BooleanCallback();
try (CallbackStore cb3 = sim.registerSolenoidOutputCallback(3, callback3, false);
CallbackStore cb4 = sim.registerSolenoidOutputCallback(4, callback4, false)) {
// Reverse
callback3.reset();
callback4.reset();
doubleSolenoid.set(DoubleSolenoid.Value.kReverse);
assertFalse(callback3.wasTriggered());
assertNull(callback3.getSetValue());
assertTrue(callback4.wasTriggered());
assertTrue(callback4.getSetValue());
assertFalse(sim.getSolenoidOutput(3));
assertTrue(sim.getSolenoidOutput(4));
assertEquals(0x10, ph.getSolenoids());
// Forward
callback3.reset();
callback4.reset();
doubleSolenoid.set(DoubleSolenoid.Value.kForward);
assertTrue(callback3.wasTriggered());
assertTrue(callback3.getSetValue());
assertTrue(callback4.wasTriggered());
assertFalse(callback4.getSetValue());
assertTrue(sim.getSolenoidOutput(3));
assertFalse(sim.getSolenoidOutput(4));
assertEquals(0x8, ph.getSolenoids());
// Off
callback3.reset();
callback4.reset();
doubleSolenoid.set(DoubleSolenoid.Value.kOff);
assertTrue(callback3.wasTriggered());
assertFalse(callback3.getSetValue());
assertFalse(callback4.wasTriggered());
assertNull(callback4.getSetValue());
assertFalse(sim.getSolenoidOutput(3));
assertFalse(sim.getSolenoidOutput(4));
assertEquals(0x0, ph.getSolenoids());
}
}
}
@Test
void setCompressorOnTest() {
HAL.initialize(500, 0);
REVPHSim sim = new REVPHSim(1);
BooleanCallback callback = new BooleanCallback();
try (PneumaticsHub ph = new PneumaticsHub(1);
CallbackStore cb = sim.registerCompressorOnCallback(callback, false)) {
assertFalse(ph.getCompressor());
assertFalse(sim.getCompressorOn());
sim.setCompressorOn(true);
assertTrue(ph.getCompressor());
assertTrue(sim.getCompressorOn());
assertTrue(callback.wasTriggered());
assertTrue(callback.getSetValue());
}
}
@Test
void setClosedLoopEnabled() {
HAL.initialize(500, 0);
REVPHSim sim = new REVPHSim(1);
BooleanCallback callback = new BooleanCallback();
try (PneumaticsHub ph = new PneumaticsHub(1);
CallbackStore cb = sim.registerClosedLoopEnabledCallback(callback, false)) {
ph.setClosedLoopControl(false);
assertFalse(ph.getClosedLoopControl());
ph.setClosedLoopControl(true);
assertTrue(sim.getClosedLoopEnabled());
assertTrue(ph.getClosedLoopControl());
assertTrue(callback.wasTriggered());
assertTrue(callback.getSetValue());
}
}
@Test
void setPressureSwitchEnabledTest() {
HAL.initialize(500, 0);
REVPHSim sim = new REVPHSim(1);
BooleanCallback callback = new BooleanCallback();
try (PneumaticsHub ph = new PneumaticsHub(1);
CallbackStore cb = sim.registerPressureSwitchCallback(callback, false)) {
assertFalse(ph.getPressureSwitch());
sim.setPressureSwitch(true);
assertTrue(sim.getPressureSwitch());
assertTrue(ph.getPressureSwitch());
assertTrue(callback.wasTriggered());
assertTrue(callback.getSetValue());
}
}
@Test
void setCompressorCurrentTest() {
HAL.initialize(500, 0);
REVPHSim sim = new REVPHSim(1);
DoubleCallback callback = new DoubleCallback();
try (PneumaticsHub ph = new PneumaticsHub(1);
CallbackStore cb = sim.registerCompressorCurrentCallback(callback, false)) {
assertFalse(ph.getPressureSwitch());
sim.setCompressorCurrent(35.04);
assertEquals(35.04, sim.getCompressorCurrent());
assertEquals(35.04, ph.getCompressorCurrent());
assertTrue(callback.wasTriggered());
assertEquals(35.04, callback.getSetValue());
}
}
}

View File

@@ -88,6 +88,14 @@ namespace internal {
// Report an assertion failure; will either Abort(...) or throw.
[[noreturn]] void AssertionFailed(const char* condition, const char* func,
const char* file, int line);
template <bool>
constexpr void DrakeAssertWasUsedWithRawPointer() {}
template<>
[[deprecated("\nDRAKE DEPRECATED: When using DRAKE_ASSERT or DRAKE_DEMAND on"
" a raw pointer, always write out DRAKE_ASSERT(foo != nullptr), do not write"
" DRAKE_ASSERT(foo) and rely on implicit pointer-to-bool conversion."
"\nThe deprecated code will be removed from Drake on or after 2021-12-01.")]]
constexpr void DrakeAssertWasUsedWithRawPointer<true>() {}
} // namespace internal
namespace assert {
// Allows for specialization of how to bool-convert Conditions used in
@@ -114,6 +122,8 @@ struct ConditionTraits {
typedef ::drake::assert::ConditionTraits< \
typename std::remove_cv_t<decltype(condition)>> Trait; \
static_assert(Trait::is_valid, "Condition should be bool-convertible."); \
::drake::internal::DrakeAssertWasUsedWithRawPointer< \
std::is_pointer_v<decltype(condition)>>(); \
if (!Trait::Evaluate(condition)) { \
::drake::internal::AssertionFailed( \
#condition, __func__, __FILE__, __LINE__); \
@@ -139,10 +149,14 @@ namespace drake {
constexpr bool kDrakeAssertIsArmed = false;
constexpr bool kDrakeAssertIsDisarmed = true;
} // namespace drake
# define DRAKE_ASSERT(condition) static_assert( \
::drake::assert::ConditionTraits< \
typename std::remove_cv_t<decltype(condition)>>::is_valid, \
"Condition should be bool-convertible.");
# define DRAKE_ASSERT(condition) do { \
static_assert( \
::drake::assert::ConditionTraits< \
typename std::remove_cv_t<decltype(condition)>>::is_valid, \
"Condition should be bool-convertible."); \
::drake::internal::DrakeAssertWasUsedWithRawPointer< \
std::is_pointer_v<decltype(condition)>>(); \
} while (0)
# define DRAKE_ASSERT_VOID(expression) static_assert( \
std::is_convertible_v<decltype(expression), void>, \
"Expression should be void.")

View File

@@ -494,11 +494,8 @@ public class SendableRegistry {
if (cause != null) {
throwable = cause;
}
System.out.println(
"Unhandled exception calling LiveWindow for "
+ comp.m_name
+ ": "
+ throwable.toString());
System.err.println("Unhandled exception calling LiveWindow for " + comp.m_name + ": ");
throwable.printStackTrace();
comp.m_liveWindow = false;
}
if (cbdata.data != null) {