/*----------------------------------------------------------------------------*/ | |
/* Copyright (c) FIRST 2008. 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 $(WIND_BASE)/WPILib. */ | |
/*----------------------------------------------------------------------------*/ | |
#include "AnalogTrigger.h" | |
#include "AnalogChannel.h" | |
#include "AnalogModule.h" | |
#include "NetworkCommunication/UsageReporting.h" | |
#include "Resource.h" | |
#include "WPIErrors.h" | |
static Resource *triggers = NULL; | |
/** | |
* Initialize an analog trigger from a slot and channel. | |
* This is the common code for the two constructors that use a slot and channel. | |
*/ | |
void AnalogTrigger::InitTrigger(UINT8 moduleNumber, UINT32 channel) | |
{ | |
Resource::CreateResourceObject(&triggers, tAnalogTrigger::kNumSystems); | |
UINT32 index = triggers->Allocate("Analog Trigger"); | |
if (index == ~0ul) | |
{ | |
CloneError(triggers); | |
return; | |
} | |
m_index = (UINT8)index; | |
m_channel = channel; | |
m_analogModule = AnalogModule::GetInstance(moduleNumber); | |
tRioStatusCode localStatus = NiFpga_Status_Success; | |
m_trigger = tAnalogTrigger::create(m_index, &localStatus); | |
m_trigger->writeSourceSelect_Channel(m_channel - 1, &localStatus); | |
m_trigger->writeSourceSelect_Module(moduleNumber - 1, &localStatus); | |
wpi_setError(localStatus); | |
nUsageReporting::report(nUsageReporting::kResourceType_AnalogTrigger, m_channel, moduleNumber - 1); | |
} | |
/** | |
* Constructor for an analog trigger given a channel number. | |
* The default module is used in this case. | |
* | |
* @param channel The analog channel (1..8). | |
*/ | |
AnalogTrigger::AnalogTrigger(UINT32 channel) | |
{ | |
InitTrigger(GetDefaultAnalogModule(), channel); | |
} | |
/** | |
* Constructor for an analog trigger given both the slot and channel. | |
* | |
* @param moduleNumber The analog module (1 or 2). | |
* @param channel The analog channel (1..8). | |
*/ | |
AnalogTrigger::AnalogTrigger(UINT8 moduleNumber, UINT32 channel) | |
{ | |
InitTrigger(moduleNumber, channel); | |
} | |
/** | |
* Construct an analog trigger given an analog channel. | |
* This should be used in the case of sharing an analog channel between the trigger | |
* and an analog input object. | |
*/ | |
AnalogTrigger::AnalogTrigger(AnalogChannel *channel) | |
{ | |
InitTrigger(channel->GetModuleNumber(), channel->GetChannel()); | |
} | |
AnalogTrigger::~AnalogTrigger() | |
{ | |
triggers->Free(m_index); | |
delete m_trigger; | |
} | |
/** | |
* Set the upper and lower limits of the analog trigger. | |
* The limits are given in ADC codes. If oversampling is used, the units must be scaled | |
* appropriately. | |
*/ | |
void AnalogTrigger::SetLimitsRaw(INT32 lower, INT32 upper) | |
{ | |
if (StatusIsFatal()) return; | |
if (lower > upper) | |
{ | |
wpi_setWPIError(AnalogTriggerLimitOrderError); | |
} | |
tRioStatusCode localStatus = NiFpga_Status_Success; | |
m_trigger->writeLowerLimit(lower, &localStatus); | |
m_trigger->writeUpperLimit(upper, &localStatus); | |
wpi_setError(localStatus); | |
} | |
/** | |
* Set the upper and lower limits of the analog trigger. | |
* The limits are given as floating point voltage values. | |
*/ | |
void AnalogTrigger::SetLimitsVoltage(float lower, float upper) | |
{ | |
if (StatusIsFatal()) return; | |
if (lower > upper) | |
{ | |
wpi_setWPIError(AnalogTriggerLimitOrderError); | |
} | |
// TODO: This depends on the averaged setting. Only raw values will work as is. | |
tRioStatusCode localStatus = NiFpga_Status_Success; | |
m_trigger->writeLowerLimit(m_analogModule->VoltsToValue(m_channel, lower), &localStatus); | |
m_trigger->writeUpperLimit(m_analogModule->VoltsToValue(m_channel, upper), &localStatus); | |
wpi_setError(localStatus); | |
} | |
/** | |
* 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 AnalogTrigger::SetAveraged(bool useAveragedValue) | |
{ | |
if (StatusIsFatal()) return; | |
tRioStatusCode localStatus = NiFpga_Status_Success; | |
if (m_trigger->readSourceSelect_Filter(&localStatus) != 0) | |
wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not support average and filtering at the same time."); | |
m_trigger->writeSourceSelect_Averaged(useAveragedValue, &localStatus); | |
wpi_setError(localStatus); | |
} | |
/** | |
* 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 AnalogTrigger::SetFiltered(bool useFilteredValue) | |
{ | |
if (StatusIsFatal()) return; | |
tRioStatusCode localStatus = NiFpga_Status_Success; | |
if (m_trigger->readSourceSelect_Averaged(&localStatus) != 0) | |
wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not support average and filtering at the same time."); | |
m_trigger->writeSourceSelect_Filter(useFilteredValue, &localStatus); | |
wpi_setError(localStatus); | |
} | |
/** | |
* Return the index of the analog trigger. | |
* This is the FPGA index of this analog trigger instance. | |
* @return The index of the analog trigger. | |
*/ | |
UINT32 AnalogTrigger::GetIndex() | |
{ | |
if (StatusIsFatal()) return ~0ul; | |
return m_index; | |
} | |
/** | |
* 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 AnalogTrigger::GetInWindow() | |
{ | |
if (StatusIsFatal()) return false; | |
tRioStatusCode localStatus = NiFpga_Status_Success; | |
bool result = m_trigger->readOutput_InHysteresis(m_index, &localStatus) != 0; | |
wpi_setError(localStatus); | |
return result; | |
} | |
/** | |
* 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 AnalogTrigger::GetTriggerState() | |
{ | |
if (StatusIsFatal()) return false; | |
tRioStatusCode localStatus = NiFpga_Status_Success; | |
bool result = m_trigger->readOutput_OverLimit(m_index, &localStatus) != 0; | |
wpi_setError(localStatus); | |
return result; | |
} | |
/** | |
* Creates an AnalogTriggerOutput object. | |
* Gets an output object that can be used for routing. | |
* Caller is responsible for deleting the AnalogTriggerOutput object. | |
* @param type An enum of the type of output object to create. | |
* @return A pointer to a new AnalogTriggerOutput object. | |
*/ | |
AnalogTriggerOutput *AnalogTrigger::CreateOutput(AnalogTriggerOutput::Type type) | |
{ | |
if (StatusIsFatal()) return NULL; | |
return new AnalogTriggerOutput(this, type); | |
} | |