mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
HAL Port is using a special handle, where the module and pin are bit shifted straight into the handle. This is one of the few special cases we have, but for the way port is used it is much cleaner and uses much less memory. Plus it is generic and not specific to one type.
163 lines
6.0 KiB
C++
163 lines
6.0 KiB
C++
/*----------------------------------------------------------------------------*/
|
|
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
/* the project. */
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
#include "HAL/AnalogTrigger.h"
|
|
|
|
#include "AnalogInternal.h"
|
|
#include "HAL/AnalogInput.h"
|
|
#include "HAL/Errors.h"
|
|
#include "HAL/cpp/Resource.h"
|
|
#include "handles/HandlesInternal.h"
|
|
|
|
using namespace hal;
|
|
|
|
extern "C" {
|
|
struct trigger_t {
|
|
tAnalogTrigger* trigger;
|
|
AnalogPort* port;
|
|
uint32_t index;
|
|
};
|
|
typedef struct trigger_t AnalogTrigger;
|
|
|
|
static hal::Resource* triggers = nullptr;
|
|
|
|
void* initializeAnalogTrigger(HalPortHandle port_handle, uint32_t* index,
|
|
int32_t* status) {
|
|
hal::Resource::CreateResourceObject(&triggers, tAnalogTrigger::kNumSystems);
|
|
|
|
AnalogTrigger* trigger = new AnalogTrigger();
|
|
trigger->port = (AnalogPort*)initializeAnalogInputPort(port_handle, status);
|
|
if (*status != 0) {
|
|
return nullptr;
|
|
}
|
|
trigger->index = triggers->Allocate("Analog Trigger");
|
|
*index = trigger->index;
|
|
// TODO: if (index == ~0ul) { CloneError(triggers); return; }
|
|
|
|
trigger->trigger = tAnalogTrigger::create(trigger->index, status);
|
|
trigger->trigger->writeSourceSelect_Channel(trigger->port->pin, status);
|
|
return trigger;
|
|
}
|
|
|
|
void cleanAnalogTrigger(void* analog_trigger_pointer, int32_t* status) {
|
|
AnalogTrigger* trigger = (AnalogTrigger*)analog_trigger_pointer;
|
|
if (!trigger) return;
|
|
triggers->Free(trigger->index);
|
|
delete trigger->trigger;
|
|
freeAnalogInputPort(trigger->port);
|
|
delete trigger;
|
|
}
|
|
|
|
void setAnalogTriggerLimitsRaw(void* analog_trigger_pointer, int32_t lower,
|
|
int32_t upper, int32_t* status) {
|
|
AnalogTrigger* trigger = (AnalogTrigger*)analog_trigger_pointer;
|
|
if (lower > upper) {
|
|
*status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
|
|
}
|
|
trigger->trigger->writeLowerLimit(lower, status);
|
|
trigger->trigger->writeUpperLimit(upper, status);
|
|
}
|
|
|
|
/**
|
|
* Set the upper and lower limits of the analog trigger.
|
|
* The limits are given as floating point voltage values.
|
|
*/
|
|
void setAnalogTriggerLimitsVoltage(void* analog_trigger_pointer, double lower,
|
|
double upper, int32_t* status) {
|
|
AnalogTrigger* trigger = (AnalogTrigger*)analog_trigger_pointer;
|
|
if (lower > upper) {
|
|
*status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
|
|
}
|
|
// TODO: This depends on the averaged setting. Only raw values will work as
|
|
// is.
|
|
trigger->trigger->writeLowerLimit(
|
|
getAnalogVoltsToValue(trigger->port, lower, status), status);
|
|
trigger->trigger->writeUpperLimit(
|
|
getAnalogVoltsToValue(trigger->port, upper, status), status);
|
|
}
|
|
|
|
/**
|
|
* Configure the analog trigger to use the averaged vs. raw values.
|
|
* If the value is true, then the averaged value is selected for the analog
|
|
* trigger, otherwise the immediate value is used.
|
|
*/
|
|
void setAnalogTriggerAveraged(void* analog_trigger_pointer,
|
|
bool useAveragedValue, int32_t* status) {
|
|
AnalogTrigger* trigger = (AnalogTrigger*)analog_trigger_pointer;
|
|
if (trigger->trigger->readSourceSelect_Filter(status) != 0) {
|
|
*status = INCOMPATIBLE_STATE;
|
|
// TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not
|
|
// support average and filtering at the same time.");
|
|
}
|
|
trigger->trigger->writeSourceSelect_Averaged(useAveragedValue, status);
|
|
}
|
|
|
|
/**
|
|
* Configure the analog trigger to use a filtered value.
|
|
* The analog trigger will operate with a 3 point average rejection filter. This
|
|
* is designed to help with 360 degree pot applications for the period where the
|
|
* pot crosses through zero.
|
|
*/
|
|
void setAnalogTriggerFiltered(void* analog_trigger_pointer,
|
|
bool useFilteredValue, int32_t* status) {
|
|
AnalogTrigger* trigger = (AnalogTrigger*)analog_trigger_pointer;
|
|
if (trigger->trigger->readSourceSelect_Averaged(status) != 0) {
|
|
*status = INCOMPATIBLE_STATE;
|
|
// TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not "
|
|
// "support average and filtering at the same time.");
|
|
}
|
|
trigger->trigger->writeSourceSelect_Filter(useFilteredValue, status);
|
|
}
|
|
|
|
/**
|
|
* Return the InWindow output of the analog trigger.
|
|
* True if the analog input is between the upper and lower limits.
|
|
* @return The InWindow output of the analog trigger.
|
|
*/
|
|
bool getAnalogTriggerInWindow(void* analog_trigger_pointer, int32_t* status) {
|
|
AnalogTrigger* trigger = (AnalogTrigger*)analog_trigger_pointer;
|
|
return trigger->trigger->readOutput_InHysteresis(trigger->index, status) != 0;
|
|
}
|
|
|
|
/**
|
|
* Return the TriggerState output of the analog trigger.
|
|
* True if above upper limit.
|
|
* False if below lower limit.
|
|
* If in Hysteresis, maintain previous state.
|
|
* @return The TriggerState output of the analog trigger.
|
|
*/
|
|
bool getAnalogTriggerTriggerState(void* analog_trigger_pointer,
|
|
int32_t* status) {
|
|
AnalogTrigger* trigger = (AnalogTrigger*)analog_trigger_pointer;
|
|
return trigger->trigger->readOutput_OverLimit(trigger->index, status) != 0;
|
|
}
|
|
|
|
/**
|
|
* Get the state of the analog trigger output.
|
|
* @return The state of the analog trigger output.
|
|
*/
|
|
bool getAnalogTriggerOutput(void* analog_trigger_pointer,
|
|
AnalogTriggerType type, int32_t* status) {
|
|
AnalogTrigger* trigger = (AnalogTrigger*)analog_trigger_pointer;
|
|
bool result = false;
|
|
switch (type) {
|
|
case kInWindow:
|
|
result =
|
|
trigger->trigger->readOutput_InHysteresis(trigger->index, status);
|
|
break; // XXX: Backport
|
|
case kState:
|
|
result = trigger->trigger->readOutput_OverLimit(trigger->index, status);
|
|
break; // XXX: Backport
|
|
case kRisingPulse:
|
|
case kFallingPulse:
|
|
*status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
|
|
return false;
|
|
}
|
|
return result;
|
|
}
|
|
}
|