blob: a3420d5057f3a7f895935f3dcc026aebf49b3c0a [file] [log] [blame]
/*----------------------------------------------------------------------------*/
/* 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);
}