mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-04 03:11:43 +00:00
Implement PCM One Shot feature. Fixes artf4731 (#539)
This commit is contained in:
committed by
Peter Johnson
parent
a338ee8be0
commit
7a250a1b93
@@ -154,4 +154,25 @@ void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status) {
|
||||
*status = PCM_modules[module]->ClearStickyFaults();
|
||||
}
|
||||
|
||||
void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
|
||||
int32_t durMS, int32_t* status) {
|
||||
auto port = solenoidHandles.Get(solenoidPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
*status =
|
||||
PCM_modules[port->module]->SetOneShotDurationMs(port->channel, durMS);
|
||||
}
|
||||
|
||||
void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status) {
|
||||
auto port = solenoidHandles.Get(solenoidPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
*status = PCM_modules[port->module]->FireOneShotSolenoid(port->channel);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -213,7 +213,9 @@ CTR_Code PCM::FireOneShotSolenoid(UINT8 idx)
|
||||
return CTR_OKAY;
|
||||
}
|
||||
/* Configure the pulse width of a solenoid channel for one-shot pulse.
|
||||
* Preprogrammed pulsewidth is 10ms resolute and can be between 20ms and 5.1s.
|
||||
* Preprogrammed pulsewidth is 10ms resolution and can be between 10ms and
|
||||
* 2.55s.
|
||||
*
|
||||
* @Return - CTR_Code - Error code (if any)
|
||||
* @Param - idx - ID of solenoid [0,7] to configure.
|
||||
* @Param - durMs - pulse width in ms.
|
||||
|
||||
@@ -30,6 +30,9 @@ int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status);
|
||||
HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status);
|
||||
HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status);
|
||||
void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status);
|
||||
void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
|
||||
int32_t durMS, int32_t* status);
|
||||
void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
@@ -117,4 +117,7 @@ HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status) {
|
||||
return 0;
|
||||
}
|
||||
void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status) {}
|
||||
void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
|
||||
int32_t durMS, int32_t* status) {}
|
||||
void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status) {}
|
||||
} // extern "C"
|
||||
|
||||
@@ -111,6 +111,36 @@ bool Solenoid::IsBlackListed() const {
|
||||
return (value != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pulse duration in the PCM. This is used in conjunction with
|
||||
* the startPulse method to allow the PCM to control the timing of a pulse.
|
||||
* The timing can be controlled in 0.01 second increments.
|
||||
*
|
||||
* @param durationSeconds The duration of the pulse, from 0.01 to 2.55 seconds.
|
||||
*
|
||||
* @see startPulse()
|
||||
*/
|
||||
void Solenoid::SetPulseDuration(double durationSeconds) {
|
||||
int32_t durationMS = durationSeconds * 1000;
|
||||
if (StatusIsFatal()) return;
|
||||
int32_t status = 0;
|
||||
HAL_SetOneShotDuration(m_solenoidHandle, durationMS, &status);
|
||||
wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the PCM to generate a pulse of the duration set in
|
||||
* setPulseDuration.
|
||||
*
|
||||
* @see setPulseDuration()
|
||||
*/
|
||||
void Solenoid::StartPulse() {
|
||||
if (StatusIsFatal()) return;
|
||||
int32_t status = 0;
|
||||
HAL_FireOneShot(m_solenoidHandle, &status);
|
||||
wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
|
||||
}
|
||||
|
||||
void Solenoid::UpdateTable() {
|
||||
if (m_valueEntry) m_valueEntry.SetBoolean(Get());
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ class Solenoid : public SolenoidBase, public LiveWindowSendable {
|
||||
virtual void Set(bool on);
|
||||
virtual bool Get() const;
|
||||
bool IsBlackListed() const;
|
||||
void SetPulseDuration(double durationSeconds);
|
||||
void StartPulse();
|
||||
|
||||
void UpdateTable();
|
||||
void StartLiveWindowMode();
|
||||
|
||||
@@ -157,3 +157,85 @@ TEST_F(PCMTest, DoubleSolenoid) {
|
||||
EXPECT_TRUE(solenoid.Get() == DoubleSolenoid::kReverse)
|
||||
<< "Solenoid does not read reverse";
|
||||
}
|
||||
|
||||
TEST_F(PCMTest, OneShot) {
|
||||
Reset();
|
||||
Solenoid solenoid1(TestBench::kSolenoidChannel1);
|
||||
Solenoid solenoid2(TestBench::kSolenoidChannel2);
|
||||
|
||||
// Turn both solenoids off
|
||||
solenoid1.Set(false);
|
||||
solenoid2.Set(false);
|
||||
Wait(kSolenoidDelayTime);
|
||||
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
|
||||
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
|
||||
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
|
||||
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
|
||||
|
||||
// Pulse Solenoid #1 on, and turn Solenoid #2 off
|
||||
solenoid1.SetPulseDuration(2 * kSolenoidDelayTime);
|
||||
solenoid2.Set(false);
|
||||
solenoid1.StartPulse();
|
||||
Wait(kSolenoidDelayTime);
|
||||
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
|
||||
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
|
||||
EXPECT_TRUE(solenoid1.Get()) << "Solenoid #1 did not read on";
|
||||
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
|
||||
Wait(2 * kSolenoidDelayTime);
|
||||
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
|
||||
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
|
||||
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
|
||||
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
|
||||
|
||||
// Turn Solenoid #1 off, and pulse Solenoid #2 on
|
||||
solenoid1.Set(false);
|
||||
solenoid2.SetPulseDuration(2 * kSolenoidDelayTime);
|
||||
solenoid2.StartPulse();
|
||||
Wait(kSolenoidDelayTime);
|
||||
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
|
||||
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
|
||||
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
|
||||
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
|
||||
Wait(2 * kSolenoidDelayTime);
|
||||
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
|
||||
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
|
||||
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
|
||||
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
|
||||
|
||||
// Pulse both Solenoids on
|
||||
solenoid1.SetPulseDuration(2 * kSolenoidDelayTime);
|
||||
solenoid2.SetPulseDuration(2 * kSolenoidDelayTime);
|
||||
solenoid1.StartPulse();
|
||||
solenoid2.StartPulse();
|
||||
Wait(kSolenoidDelayTime);
|
||||
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
|
||||
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
|
||||
EXPECT_TRUE(solenoid1.Get()) << "Solenoid #1 did not read on";
|
||||
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
|
||||
Wait(2 * kSolenoidDelayTime);
|
||||
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
|
||||
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
|
||||
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
|
||||
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
|
||||
|
||||
// Pulse both Solenoids on with different durations
|
||||
solenoid1.SetPulseDuration(1.5 * kSolenoidDelayTime);
|
||||
solenoid2.SetPulseDuration(2.5 * kSolenoidDelayTime);
|
||||
solenoid1.StartPulse();
|
||||
solenoid2.StartPulse();
|
||||
Wait(kSolenoidDelayTime);
|
||||
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
|
||||
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
|
||||
EXPECT_TRUE(solenoid1.Get()) << "Solenoid #1 did not read on";
|
||||
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
|
||||
Wait(kSolenoidDelayTime);
|
||||
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
|
||||
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
|
||||
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
|
||||
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
|
||||
Wait(2 * kSolenoidDelayTime);
|
||||
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
|
||||
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
|
||||
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
|
||||
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
|
||||
}
|
||||
|
||||
@@ -98,6 +98,30 @@ public class Solenoid extends SolenoidBase implements LiveWindowSendable {
|
||||
return value != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pulse duration in the PCM. This is used in conjunction with
|
||||
* the startPulse method to allow the PCM to control the timing of a pulse.
|
||||
* The timing can be controlled in 0.01 second increments.
|
||||
*
|
||||
* @param durationSeconds The duration of the pulse, from 0.01 to 2.55 seconds.
|
||||
*
|
||||
* @see #startPulse()
|
||||
*/
|
||||
public void setPulseDuration(double durationSeconds) {
|
||||
long durationMS = (long) (durationSeconds * 1000);
|
||||
SolenoidJNI.setOneShotDuration(m_solenoidHandle, durationMS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the PCM to generate a pulse of the duration set in
|
||||
* setPulseDuration.
|
||||
*
|
||||
* @see #setPulseDuration()
|
||||
*/
|
||||
public void startPulse() {
|
||||
SolenoidJNI.fireOneShot(m_solenoidHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
|
||||
@@ -29,4 +29,8 @@ public class SolenoidJNI extends JNIWrapper {
|
||||
public static native boolean getPCMSolenoidVoltageFault(int module);
|
||||
|
||||
public static native void clearAllPCMStickyFaults(int module);
|
||||
|
||||
public static native void setOneShotDuration(int portHandle, long durationMS);
|
||||
|
||||
public static native void fireOneShot(int portHandle);
|
||||
}
|
||||
|
||||
@@ -187,4 +187,40 @@ Java_edu_wpi_first_wpilibj_hal_SolenoidJNI_clearAllPCMStickyFaults(
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_SolenoidJNI
|
||||
* Method: setOneShotDuration
|
||||
* Signature: (IJ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_SolenoidJNI_setOneShotDuration
|
||||
(JNIEnv *env, jclass, jint solenoid_port, jlong durationMS)
|
||||
{
|
||||
SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI SetOneShotDuration";
|
||||
|
||||
SOLENOIDJNI_LOG(logDEBUG) << "Solenoid Port Handle = "
|
||||
<< (HAL_SolenoidHandle)solenoid_port;
|
||||
SOLENOIDJNI_LOG(logDEBUG) << "Duration (MS) = " << durationMS;
|
||||
|
||||
int32_t status = 0;
|
||||
HAL_SetOneShotDuration((HAL_SolenoidHandle)solenoid_port, durationMS, &status);
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_SolenoidJNI
|
||||
* Method: fireOneShot
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_SolenoidJNI_fireOneShot
|
||||
(JNIEnv *env, jclass, jint solenoid_port)
|
||||
{
|
||||
SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI fireOneShot";
|
||||
|
||||
SOLENOIDJNI_LOG(logDEBUG) << "Solenoid Port Handle = "
|
||||
<< (HAL_SolenoidHandle)solenoid_port;
|
||||
|
||||
int32_t status = 0;
|
||||
HAL_FireOneShot((HAL_SolenoidHandle)solenoid_port, &status);
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -180,6 +180,95 @@ public class PCMTest extends AbstractComsSetup {
|
||||
solenoid.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the correct solenoids turn on and off when they should.
|
||||
*/
|
||||
@Test
|
||||
public void testOneShot() throws Exception {
|
||||
reset();
|
||||
|
||||
Solenoid solenoid1 = new Solenoid(0);
|
||||
Solenoid solenoid2 = new Solenoid(1);
|
||||
|
||||
solenoid1.set(false);
|
||||
solenoid2.set(false);
|
||||
Timer.delay(kSolenoidDelayTime);
|
||||
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
|
||||
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
|
||||
assertFalse("Solenoid #1 did not report off", solenoid1.get());
|
||||
assertFalse("Solenoid #2 did not report off", solenoid2.get());
|
||||
|
||||
// Pulse Solenoid #1 on, and turn Solenoid #2 off
|
||||
solenoid1.setPulseDuration(2 * kSolenoidDelayTime);
|
||||
solenoid1.startPulse();
|
||||
solenoid2.set(false);
|
||||
Timer.delay(kSolenoidDelayTime);
|
||||
assertFalse("Solenoid #1 did not turn on", fakeSolenoid1.get());
|
||||
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
|
||||
assertTrue("Solenoid #1 did not report on", solenoid1.get());
|
||||
assertFalse("Solenoid #2 did not report off", solenoid2.get());
|
||||
Timer.delay(2 * kSolenoidDelayTime);
|
||||
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
|
||||
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
|
||||
assertFalse("Solenoid #1 did not report off", solenoid1.get());
|
||||
assertFalse("Solenoid #2 did not report off", solenoid2.get());
|
||||
|
||||
// Turn Solenoid #1 off, and pulse Solenoid #2 on
|
||||
solenoid1.set(false);
|
||||
solenoid2.setPulseDuration(2 * kSolenoidDelayTime);
|
||||
solenoid2.startPulse();
|
||||
Timer.delay(kSolenoidDelayTime);
|
||||
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
|
||||
assertFalse("Solenoid #2 did not turn on", fakeSolenoid2.get());
|
||||
assertFalse("Solenoid #1 did not report off", solenoid1.get());
|
||||
assertTrue("Solenoid #2 did not report on", solenoid2.get());
|
||||
Timer.delay(2 * kSolenoidDelayTime);
|
||||
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
|
||||
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
|
||||
assertFalse("Solenoid #1 did not report off", solenoid1.get());
|
||||
assertFalse("Solenoid #2 did not report off", solenoid2.get());
|
||||
|
||||
// Pulse both Solenoids on
|
||||
solenoid1.setPulseDuration(2 * kSolenoidDelayTime);
|
||||
solenoid2.setPulseDuration(2 * kSolenoidDelayTime);
|
||||
solenoid1.startPulse();
|
||||
solenoid2.startPulse();
|
||||
Timer.delay(kSolenoidDelayTime);
|
||||
assertFalse("Solenoid #1 did not turn on", fakeSolenoid1.get());
|
||||
assertFalse("Solenoid #2 did not turn on", fakeSolenoid2.get());
|
||||
assertTrue("Solenoid #1 did not report on", solenoid1.get());
|
||||
assertTrue("Solenoid #2 did not report on", solenoid2.get());
|
||||
Timer.delay(2 * kSolenoidDelayTime);
|
||||
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
|
||||
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
|
||||
assertFalse("Solenoid #1 did not report off", solenoid1.get());
|
||||
assertFalse("Solenoid #2 did not report off", solenoid2.get());
|
||||
|
||||
// Pulse both Solenoids on with different durations
|
||||
solenoid1.setPulseDuration(1.5 * kSolenoidDelayTime);
|
||||
solenoid2.setPulseDuration(2.5 * kSolenoidDelayTime);
|
||||
solenoid1.startPulse();
|
||||
solenoid2.startPulse();
|
||||
Timer.delay(kSolenoidDelayTime);
|
||||
assertFalse("Solenoid #1 did not turn on", fakeSolenoid1.get());
|
||||
assertFalse("Solenoid #2 did not turn on", fakeSolenoid2.get());
|
||||
assertTrue("Solenoid #1 did not report on", solenoid1.get());
|
||||
assertTrue("Solenoid #2 did not report on", solenoid2.get());
|
||||
Timer.delay(kSolenoidDelayTime);
|
||||
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
|
||||
assertFalse("Solenoid #2 did not turn on", fakeSolenoid2.get());
|
||||
assertFalse("Solenoid #1 did not report off", solenoid1.get());
|
||||
assertTrue("Solenoid #2 did not report on", solenoid2.get());
|
||||
Timer.delay(kSolenoidDelayTime);
|
||||
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
|
||||
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
|
||||
assertFalse("Solenoid #1 did not report off", solenoid1.get());
|
||||
assertFalse("Solenoid #2 did not report off", solenoid2.get());
|
||||
|
||||
solenoid1.free();
|
||||
solenoid2.free();
|
||||
}
|
||||
|
||||
protected Logger getClassLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user