diff --git a/wpilibc/wpilibC++/include/SensorBase.h b/wpilibc/wpilibC++/include/SensorBase.h index a629e1864b..08ba1d25b3 100644 --- a/wpilibc/wpilibC++/include/SensorBase.h +++ b/wpilibc/wpilibC++/include/SensorBase.h @@ -8,6 +8,7 @@ #include "ErrorBase.h" #include #include "Base.h" +#include "Resource.h" /** * Base class for all sensors. @@ -51,6 +52,7 @@ protected: static void* m_digital_ports[kDigitalChannels]; static void* m_relay_ports[kRelayChannels]; static void* m_pwm_ports[kPwmChannels]; + static Resource *m_interrupts; private: DISALLOW_COPY_AND_ASSIGN(SensorBase); diff --git a/wpilibc/wpilibC++/lib/AnalogTriggerOutput.cpp b/wpilibc/wpilibC++/lib/AnalogTriggerOutput.cpp index 70ad5a5bd7..805cfd88fd 100644 --- a/wpilibc/wpilibC++/lib/AnalogTriggerOutput.cpp +++ b/wpilibc/wpilibC++/lib/AnalogTriggerOutput.cpp @@ -27,6 +27,14 @@ AnalogTriggerOutput::AnalogTriggerOutput(AnalogTrigger *trigger, AnalogTriggerTy AnalogTriggerOutput::~AnalogTriggerOutput() { + if (m_interrupt != NULL) + { + int32_t status = 0; + cleanInterrupts(m_interrupt, &status); + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + m_interrupt = NULL; + m_interrupts->Free(m_interruptIndex); + } } /** @@ -54,7 +62,7 @@ uint32_t AnalogTriggerOutput::GetChannelForRouting() */ uint32_t AnalogTriggerOutput::GetModuleForRouting() { - return m_trigger->m_index >> 2; + return 0; } /** @@ -67,16 +75,51 @@ bool AnalogTriggerOutput::GetAnalogTriggerForRouting() /** * Request interrupts asynchronously on this analog trigger output. - * TODO: Hardware supports interrupts on Analog Trigger outputs... WPILib should too + * @param handler The address of the interrupt handler function of type tInterruptHandler that + * will be called whenever there is an interrupt on the digitial input port. + * Request interrupts in synchronus mode where the user program interrupt handler will be + * called when an interrupt occurs. */ void AnalogTriggerOutput::RequestInterrupts(InterruptHandlerFunction handler, void *param) { + if (StatusIsFatal()) return; + uint32_t index = m_interrupts->Allocate("Async Interrupt"); + if (index == ~0ul) + { + CloneError(m_interrupts); + return; + } + m_interruptIndex = index; + + AllocateInterrupts(false); + + int32_t status = 0; + requestInterrupts(m_interrupt, GetModuleForRouting(), GetChannelForRouting(), + GetAnalogTriggerForRouting(), &status); + attachInterruptHandler(m_interrupt, handler, param, &status); + wpi_setErrorWithContext(status, getHALErrorMessage(status)); } /** * Request interrupts synchronously on this analog trigger output. - * TODO: Hardware supports interrupts on Analog Trigger outputs... WPILib should too + * Request interrupts in asynchronus mode where the user program will have to + * explicitly wait for the interrupt to occur. */ void AnalogTriggerOutput::RequestInterrupts() { + if (StatusIsFatal()) return; + uint32_t index = m_interrupts->Allocate("Sync Interrupt"); + if (index == ~0ul) + { + CloneError(m_interrupts); + return; + } + m_interruptIndex = index; + + AllocateInterrupts(true); + + int32_t status = 0; + requestInterrupts(m_interrupt, GetModuleForRouting(), GetChannelForRouting(), + GetAnalogTriggerForRouting(), &status); + wpi_setErrorWithContext(status, getHALErrorMessage(status)); } diff --git a/wpilibc/wpilibC++/lib/DigitalInput.cpp b/wpilibc/wpilibC++/lib/DigitalInput.cpp index 941fbd2a45..2081816d79 100644 --- a/wpilibc/wpilibC++/lib/DigitalInput.cpp +++ b/wpilibc/wpilibC++/lib/DigitalInput.cpp @@ -9,9 +9,6 @@ #include "Resource.h" #include "WPIErrors.h" -// TODO: This is not a good place for this... -Resource *interruptsResource = NULL; - /** * Create an instance of a DigitalInput. * Creates a digital input given a channel. Common creation routine for all @@ -21,7 +18,6 @@ void DigitalInput::InitDigitalInput(uint32_t channel) { m_table = NULL; char buf[64]; - Resource::CreateResourceObject(&interruptsResource, interrupt_kNumSystems); if (!CheckDigitalChannel(channel)) { @@ -61,7 +57,7 @@ DigitalInput::~DigitalInput() cleanInterrupts(m_interrupt, &status); wpi_setErrorWithContext(status, getHALErrorMessage(status)); m_interrupt = NULL; - interruptsResource->Free(m_interruptIndex); + m_interrupts->Free(m_interruptIndex); } int32_t status = 0; @@ -117,17 +113,17 @@ bool DigitalInput::GetAnalogTriggerForRouting() * Request interrupts asynchronously on this digital input. * @param handler The address of the interrupt handler function of type tInterruptHandler that * will be called whenever there is an interrupt on the digitial input port. - * Request interrupts in synchronus mode where the user program interrupt handler will be + * Request interrupts in asynchronus mode where the user program interrupt handler will be * called when an interrupt occurs. * The default is interrupt on rising edges only. */ void DigitalInput::RequestInterrupts(InterruptHandlerFunction handler, void *param) { if (StatusIsFatal()) return; - uint32_t index = interruptsResource->Allocate("Async Interrupt"); + uint32_t index = m_interrupts->Allocate("Async Interrupt"); if (index == ~0ul) { - CloneError(interruptsResource); + CloneError(m_interrupts); return; } m_interruptIndex = index; @@ -152,10 +148,10 @@ void DigitalInput::RequestInterrupts(InterruptHandlerFunction handler, void *par void DigitalInput::RequestInterrupts() { if (StatusIsFatal()) return; - uint32_t index = interruptsResource->Allocate("Sync Interrupt"); + uint32_t index = m_interrupts->Allocate("Sync Interrupt"); if (index == ~0ul) { - CloneError(interruptsResource); + CloneError(m_interrupts); return; } m_interruptIndex = index; diff --git a/wpilibc/wpilibC++/lib/DigitalOutput.cpp b/wpilibc/wpilibC++/lib/DigitalOutput.cpp index f4ecf6da18..ed54b7e4e8 100644 --- a/wpilibc/wpilibC++/lib/DigitalOutput.cpp +++ b/wpilibc/wpilibC++/lib/DigitalOutput.cpp @@ -9,8 +9,6 @@ #include "Resource.h" #include "WPIErrors.h" -extern Resource *interruptsResource; - /** * Create an instance of a DigitalOutput. * Creates a digital output given a channel. Common creation routine for all @@ -235,10 +233,10 @@ bool DigitalOutput::GetAnalogTriggerForRouting() void DigitalOutput::RequestInterrupts(InterruptHandlerFunction handler, void *param) { if (StatusIsFatal()) return; - uint32_t index = interruptsResource->Allocate("Sync Interrupt"); + uint32_t index = m_interrupts->Allocate("Sync Interrupt"); if (index == ~0ul) { - CloneError(interruptsResource); + CloneError(m_interrupts); return; } m_interruptIndex = index; @@ -263,10 +261,10 @@ void DigitalOutput::RequestInterrupts(InterruptHandlerFunction handler, void *pa void DigitalOutput::RequestInterrupts() { if (StatusIsFatal()) return; - uint32_t index = interruptsResource->Allocate("Sync Interrupt"); + uint32_t index = m_interrupts->Allocate("Sync Interrupt"); if (index == ~0ul) { - CloneError(interruptsResource); + CloneError(m_interrupts); return; } m_interruptIndex = index; diff --git a/wpilibc/wpilibC++/lib/SensorBase.cpp b/wpilibc/wpilibC++/lib/SensorBase.cpp index a7942b8013..1a5fbbbbd3 100644 --- a/wpilibc/wpilibC++/lib/SensorBase.cpp +++ b/wpilibc/wpilibC++/lib/SensorBase.cpp @@ -17,6 +17,7 @@ const uint32_t SensorBase::kPwmChannels; const uint32_t SensorBase::kRelayChannels; const uint32_t SensorBase::kPDPChannels; const uint32_t SensorBase::kChassisSlots; +Resource *SensorBase::m_interrupts = NULL; SensorBase *SensorBase::m_singletonList = NULL; static bool portsInitialized = false; @@ -54,6 +55,8 @@ SensorBase::SensorBase() wpi_setErrorWithContext(status, getHALErrorMessage(status)); } } + + Resource::CreateResourceObject(&m_interrupts, interrupt_kNumSystems); } /** diff --git a/wpilibc/wpilibC++IntegrationTests/src/AnalogLoopTest.cpp b/wpilibc/wpilibC++IntegrationTests/src/AnalogLoopTest.cpp index 71cc1bfbc0..e692632199 100644 --- a/wpilibc/wpilibC++IntegrationTests/src/AnalogLoopTest.cpp +++ b/wpilibc/wpilibC++IntegrationTests/src/AnalogLoopTest.cpp @@ -93,3 +93,30 @@ TEST_F(AnalogLoopTest, AnalogTriggerCounterWorks) { // The counter should be 50 EXPECT_EQ(50, counter.Get()) << "Analog trigger counter did not count 50 ticks"; } + +static void InterruptHandler(uint32_t interruptAssertedMask, void *param) { + *(int *)param = 12345; +} + +TEST_F(AnalogLoopTest, AsynchronusInterruptWorks) { + int param = 0; + AnalogTrigger trigger(m_input); + trigger.SetLimitsVoltage(2.0f, 3.0f); + + // Given an interrupt handler that sets an int to 12345 + AnalogTriggerOutput *triggerOutput = trigger.CreateOutput(kState); + triggerOutput->RequestInterrupts(InterruptHandler, ¶m); + triggerOutput->EnableInterrupts(); + + // If the analog output moves from below to above the window + m_output->SetVoltage(0.0); + Wait(kDelayTime); + m_output->SetVoltage(5.0); + triggerOutput->CancelInterrupts(); + + // Then the int should be 12345 + Wait(kDelayTime); + EXPECT_EQ(12345, param) << "The interrupt did not run."; + + delete triggerOutput; +} diff --git a/wpilibc/wpilibC++IntegrationTests/src/DIOLoopTest.cpp b/wpilibc/wpilibC++IntegrationTests/src/DIOLoopTest.cpp index 8294a5a38a..507023a0b7 100644 --- a/wpilibc/wpilibC++IntegrationTests/src/DIOLoopTest.cpp +++ b/wpilibc/wpilibC++IntegrationTests/src/DIOLoopTest.cpp @@ -75,7 +75,7 @@ TEST_F(DIOLoopTest, FakeCounter) { EXPECT_EQ(100, counter.Get()) << "Counter did not count up to 100."; } -void InterruptHandler(uint32_t interruptAssertedMask, void *param) { +static void InterruptHandler(uint32_t interruptAssertedMask, void *param) { *(int *)param = 12345; }