/** * 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(); }
/** * Create a new instance of an analog module. * * Create an instance of the analog module object. Initialize all the parameters * to reasonable values on start. * Setting a global value on an analog module can be done only once unless subsequent * values are set the previously set value. * Analog modules are a singleton, so the constructor is never called outside of this class. * * @param slot The slot in the chassis that the module is plugged into. */ AnalogModule::AnalogModule(UINT32 slot) : Module(slot) , m_module (NULL) , m_sampleRateSet (false) , m_numChannelsToActivate (0) { status = 0; AddToSingletonList(); m_module = new tAI(SlotToIndex(slot), &status); SetNumChannelsToActivate(kAnalogChannels); SetSampleRate(kDefaultSampleRate); for (UINT32 i = 0; i < kAnalogChannels; i++) { m_module->writeScanList(i, i, &status); SetAverageBits(i + 1, kDefaultAverageBits); SetOversampleBits(i + 1, kDefaultOversampleBits); } if (m_registerWindowSemaphore == NULL) { // Needs to be global since the protected resource spans both module singletons. m_registerWindowSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); } wpi_assertCleanStatus(status); }
/** * Destructor. */ Solenoid::~Solenoid() { allocated->Free(SlotToIndex(m_chassisSlot) * kSolenoidChannels + m_channel - 1); if (m_refCount == 1) { delete m_fpgaSolenoidModule; m_fpgaSolenoidModule = NULL; semDelete(m_semaphore); m_semaphore = NULL; } m_refCount--; }
/** * Common function to implement constructor behavior. */ void Solenoid::InitSolenoid() { Resource::CreateResourceObject(&allocated, tSolenoid::kNumSystems * kSolenoidChannels); CheckSolenoidModule(m_chassisSlot); CheckSolenoidChannel(m_channel); m_refCount++; if (m_refCount == 1) { // Needs to be global since the protected resource spans all Solenoid objects. m_semaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); m_fpgaSolenoidModule = new tSolenoid(&status); } allocated->Allocate(SlotToIndex(m_chassisSlot) * kSolenoidChannels + m_channel - 1); wpi_assertCleanStatus(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; }
/** * Get a sample from the output of the oversample and average engine for the channel. * * The sample is 12-bit + the value configured in SetOversampleBits(). * The value configured in SetAverageBits() will cause this value to be averaged 2**bits number of samples. * This is not a sliding window. The sample will not change until 2**(OversamplBits + AverageBits) samples * have been acquired from the module on this channel. * Use GetAverageVoltage() to get the analog value in calibrated units. * * @param channel Channel number to read. * @return A sample from the oversample and average engine for the channel. */ INT32 AnalogModule::GetAverageValue(UINT32 channel) { INT32 value; CheckAnalogChannel(channel); tAI::tReadSelect readSelect; readSelect.Channel = channel - 1; readSelect.Module = SlotToIndex(m_slot); readSelect.Averaged = true; { Synchronized sync(m_registerWindowSemaphore); m_module->writeReadSelect(readSelect, &status); m_module->strobeLatchOutput(&status); value = m_module->readOutput(&status); } wpi_assertCleanStatus(status); return value; }
/** * Free the resource associated with a digital I/O channel. */ void DigitalModule::FreeDIO(UINT32 channel) { DIOChannels->Free(kDigitalChannels * SlotToIndex(m_slot) + channel - 1); }