📄 digitalmodule.cpp
字号:
/*----------------------------------------------------------------------------*/
/* 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 "DigitalModule.h"
#include "I2C.h"
#include "PWM.h"
#include "Resource.h"
#include "Synchronized.h"
#include "Utility.h"
#include "WPIStatus.h"
static Resource *DIOChannels = NULL;
/**
* Get an instance of an Digital Module.
* Singleton digital module creation where a module is allocated on the first use
* and the same module is returned on subsequent uses.
*/
DigitalModule* DigitalModule::GetInstance(UINT32 slot)
{
CheckDigitalModule(slot);
if (m_modules[slot] == NULL)
{
m_modules[slot] = new DigitalModule(slot);
}
return (DigitalModule*)m_modules[slot];
}
UINT32 DigitalModule::SlotToIndex(UINT32 slot)
{
const UINT32 mapping[] = {0,0,0,0,0,1,0,0};
return mapping[slot - 1];
}
/**
* Create a new instance of an digital module.
* Create an instance of the digital module object. Initialize all the parameters
* to reasonable values on start.
* Setting a global value on an digital module can be done only once unless subsequent
* values are set the previously set value.
* Digital modules are a singleton, so the constructor is never called outside of this class.
*/
DigitalModule::DigitalModule(UINT32 slot)
: Module(slot)
, m_fpgaDIO (NULL)
{
Resource::CreateResourceObject(&DIOChannels, tDIO::kNumSystems * kDigitalChannels);
m_fpgaDIO = new tDIO(SlotToIndex(m_slot), &status);
// Make sure that the 9403 IONode has had a chance to initialize before continuing.
while(m_fpgaDIO->readLoopTiming(&status) == 0) taskDelay(1);
if (m_fpgaDIO->readLoopTiming(&status) != kExpectedLoopTiming)
{
wpi_fatal(LoopTimingError);
printf("DIO LoopTiming: %d, expecting: %d\n", m_fpgaDIO->readLoopTiming(&status), kExpectedLoopTiming);
}
m_fpgaDIO->writePWMConfig_Period(PWM::kDefaultPwmPeriod, &status);
m_fpgaDIO->writePWMConfig_MinHigh(PWM::kDefaultMinPwmHigh, &status);
// Ensure that PWM output values are set to OFF
for (UINT32 pwm_index = 1; pwm_index <= kPwmChannels; pwm_index++)
{
SetPWM(pwm_index, PWM::kPwmDisabled);
SetPWMPeriodScale(pwm_index, 3); // Set all to 4x by default.
}
// Turn off all relay outputs.
m_fpgaDIO->writeSlowValue_RelayFwd(0, &status);
m_fpgaDIO->writeSlowValue_RelayRev(0, &status);
// Create a semaphore to protect changes to the relay values
m_relaySemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
AddToSingletonList();
}
DigitalModule::~DigitalModule()
{
semDelete(m_relaySemaphore);
m_relaySemaphore = NULL;
delete m_fpgaDIO;
m_modules[m_slot] = NULL;
}
/**
* Set a PWM channel to the desired value. The values range from 0 to 255 and the period is controlled
* by the PWM Period and MinHigh registers.
*
* @param channel The PWM channel to set.
* @param value The PWM value to set.
*/
void DigitalModule::SetPWM(UINT32 channel, UINT8 value)
{
CheckPWMChannel(channel);
m_fpgaDIO->writePWMValue(channel - 1, value, &status);
}
/**
* Get a value from a PWM channel. The values range from 0 to 255.
*
* @param channel The PWM channel to read from.
* @return The raw PWM value.
*/
UINT8 DigitalModule::GetPWM(UINT32 channel)
{
CheckPWMChannel(channel);
return m_fpgaDIO->readPWMValue(channel - 1, &status);
}
/**
* Set how how often the PWM signal is squelched, thus scaling the period.
*
* @param channel The PWM channel to configure.
* @param squelchMask The 2-bit mask of outputs to squelch.
*/
void DigitalModule::SetPWMPeriodScale(UINT32 channel, UINT32 squelchMask)
{
CheckPWMChannel(channel);
m_fpgaDIO->writePWMPeriodScale(channel - 1, squelchMask, &status);
}
/**
* Set the state of a relay.
* Set the state of a relay output to be forward. Relays have two outputs and each is
* independently set to 0v or 12v.
*/
void DigitalModule::SetRelayForward(UINT32 channel, bool on)
{
status = 0;
CheckRelayChannel(channel);
{
Synchronized sync(m_relaySemaphore);
UINT8 forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&status);
if (on)
forwardRelays |= 1 << (channel - 1);
else
forwardRelays &= ~(1 << (channel - 1));
m_fpgaDIO->writeSlowValue_RelayFwd(forwardRelays, &status);
}
wpi_assertCleanStatus(status);
}
/**
* Set the state of a relay.
* Set the state of a relay output to be reverse. Relays have two outputs and each is
* independently set to 0v or 12v.
*/
void DigitalModule::SetRelayReverse(UINT32 channel, bool on)
{
status = 0;
CheckRelayChannel(channel);
{
Synchronized sync(m_relaySemaphore);
UINT8 reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&status);
if (on)
reverseRelays |= 1 << (channel - 1);
else
reverseRelays &= ~(1 << (channel - 1));
m_fpgaDIO->writeSlowValue_RelayRev(reverseRelays, &status);
}
wpi_assertCleanStatus(status);
}
/**
* Get the current state of the forward relay channel
*/
bool DigitalModule::GetRelayForward(UINT32 channel)
{
status = 0;
UINT8 forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&status);
return (forwardRelays & (1 << (channel - 1))) != 0;
}
/**
* Get the current state of all of the forward relay channels on this module.
*/
UINT8 DigitalModule::GetRelayForward(void)
{
status = 0;
return m_fpgaDIO->readSlowValue_RelayFwd(&status);
}
/**
* Get the current state of the reverse relay channel
*/
bool DigitalModule::GetRelayReverse(UINT32 channel)
{
status = 0;
UINT8 reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&status);
return (reverseRelays & (1 << (channel - 1))) != 0;
}
/**
* Get the current state of all of the reverse relay channels on this module.
*/
UINT8 DigitalModule::GetRelayReverse(void)
{
status = 0;
return m_fpgaDIO->readSlowValue_RelayRev(&status);
}
/**
* Allocate Digital I/O channels.
* Allocate channels so that they are not accidently reused. Also the direction is set at the
* time of the allocation.
*/
bool DigitalModule::AllocateDIO(UINT32 channel, bool input)
{
status = 0;
DIOChannels->Allocate(kDigitalChannels * SlotToIndex(m_slot) + channel - 1);
UINT32 outputEnable = m_fpgaDIO->readOutputEnable(&status);
UINT32 bitToSet = 1 << (RemapDigitalChannel(channel - 1));
UINT32 outputEnableValue;
if (input)
{
outputEnableValue = outputEnable & (~ bitToSet ); // clear the bit for read
}
else
{
outputEnableValue = outputEnable | bitToSet; // set the bit for write
}
m_fpgaDIO->writeOutputEnable(outputEnableValue, &status);
wpi_assertCleanStatus(status);
return true;
}
/**
* Free the resource associated with a digital I/O channel.
*/
void DigitalModule::FreeDIO(UINT32 channel)
{
DIOChannels->Free(kDigitalChannels * SlotToIndex(m_slot) + channel - 1);
}
/**
* Write a digital I/O bit to the FPGA.
* Set a single value on a digital I/O channel.
*/
void DigitalModule::SetDIO(UINT32 channel, short value)
{
status = 0;
if (value != 0 && value != 1)
{
wpi_fatal(NonBinaryDigitalValue);
if (value != 0)
value = 1;
}
UINT16 currentDIO = m_fpgaDIO->readDO(&status);
if(value == 0)
{
currentDIO = currentDIO & ~(1 << RemapDigitalChannel(channel - 1));
}
else if (value == 1)
{
currentDIO = currentDIO | (1 << RemapDigitalChannel(channel - 1));
}
m_fpgaDIO->writeDO(currentDIO, &status);
wpi_assertCleanStatus(status);
}
/**
* Read a digital I/O bit from the FPGA.
* Get a single value from a digital I/O channel.
*/
bool DigitalModule::GetDIO(UINT32 channel)
{
status = 0;
UINT32 currentDIO = m_fpgaDIO->readDI(&status);
//Shift 00000001 over channel-1 places.
//AND it against the currentDIO
//if it == 0, then return false
//else return true
wpi_assertCleanStatus(status);
return ((currentDIO >> RemapDigitalChannel(channel - 1)) & 1) != 0;
}
/**
* Read the state of all the Digital I/O lines from the FPGA
* These are not remapped to logical order. They are still in hardware order.
*/
UINT16 DigitalModule::GetDIO(void)
{
status = 0;
return m_fpgaDIO->readDI(&status);
}
/**
* Read the direction of a the Digital I/O lines
* A 1 bit means output and a 0 bit means input.
*/
bool DigitalModule::GetDIODirection(UINT32 channel)
{
status = 0;
UINT32 currentOutputEnable = m_fpgaDIO->readOutputEnable(&status);
//Shift 00000001 over channel-1 places.
//AND it against the currentOutputEnable
//if it == 0, then return false
//else return true
wpi_assertCleanStatus(status);
return ((currentOutputEnable >> RemapDigitalChannel(channel - 1)) & 1) != 0;
}
/**
* Read the direction of all the Digital I/O lines from the FPGA
* A 1 bit means output and a 0 bit means input.
* These are not remapped to logical order. They are still in hardware order.
*/
UINT16 DigitalModule::GetDIODirection(void)
{
status = 0;
return m_fpgaDIO->readOutputEnable(&status);
}
/**
* Generate a single pulse.
* Write a pulse to the specified digital output channel. There can only be a single pulse going at any time.
*/
void DigitalModule::Pulse(UINT32 channel, UINT8 pulseLength)
{
UINT32 mask = 1 << RemapDigitalChannel(channel - 1);
m_fpgaDIO->writePulseLength(pulseLength, &status);
m_fpgaDIO->writePulse(mask, &status);
wpi_assertCleanStatus(status);
}
/**
* Check a DIO line to see if it is currently generating a pulse.
*/
bool DigitalModule::IsPulsing(UINT32 channel)
{
UINT32 mask = 1 << RemapDigitalChannel(channel - 1);
UINT16 pulseRegister = m_fpgaDIO->readPulse(&status);
wpi_assertCleanStatus(status);
return pulseRegister & mask != 0;
}
/**
* Check if any DIO line is currently generating a pulse.
*/
bool DigitalModule::IsPulsing()
{
UINT16 pulseRegister = m_fpgaDIO->readPulse(&status);
wpi_assertCleanStatus(status);
return pulseRegister != 0;
}
/**
* Return a pointer to an I2C object for this digital module
* The caller is responsible for deleting the pointer.
*/
I2C* DigitalModule::GetI2C(UINT32 address)
{
return new I2C(this, address);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -