/** * Common initialization code for Encoders. * This code allocates resources for Encoders and is common to all constructors. * @param reverseDirection If true, counts down instead of up (this is all relative) * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then * a counter object will be used and the returned value will either exactly match the spec'd count * or be double (2x) the spec'd count. */ void Encoder::InitEncoder(bool reverseDirection, EncodingType encodingType) { m_table = NULL; m_encodingType = encodingType; tRioStatusCode localStatus = NiFpga_Status_Success; switch (encodingType) { case k4X: { Resource::CreateResourceObject(&quadEncoders, tEncoder::kNumSystems); uint32_t index = quadEncoders->Allocate("4X Encoder"); if (index == ~0ul) { CloneError(quadEncoders); return; } if (m_aSource->StatusIsFatal()) { CloneError(m_aSource); return; } if (m_bSource->StatusIsFatal()) { CloneError(m_bSource); return; } m_index = index; m_encoder = tEncoder::create(m_index, &localStatus); m_encoder->writeConfig_ASource_Module(m_aSource->GetModuleForRouting(), &localStatus); m_encoder->writeConfig_ASource_Channel(m_aSource->GetChannelForRouting(), &localStatus); m_encoder->writeConfig_ASource_AnalogTrigger(m_aSource->GetAnalogTriggerForRouting(), &localStatus); m_encoder->writeConfig_BSource_Module(m_bSource->GetModuleForRouting(), &localStatus); m_encoder->writeConfig_BSource_Channel(m_bSource->GetChannelForRouting(), &localStatus); m_encoder->writeConfig_BSource_AnalogTrigger(m_bSource->GetAnalogTriggerForRouting(), &localStatus); m_encoder->strobeReset(&localStatus); m_encoder->writeConfig_Reverse(reverseDirection, &localStatus); m_encoder->writeTimerConfig_AverageSize(4, &localStatus); m_counter = NULL; break; } case k1X: case k2X: { m_counter = new Counter(m_encodingType, m_aSource, m_bSource, reverseDirection); m_index = m_counter->GetIndex(); break; } } m_distancePerPulse = 1.0; m_pidSource = kDistance; wpi_setError(localStatus); nUsageReporting::report(nUsageReporting::kResourceType_Encoder, m_index, encodingType); LiveWindow::GetInstance()->AddSensor("Encoder", m_aSource->GetModuleForRouting(), m_aSource->GetChannelForRouting(), this); }
/** * Common initialization code for Encoders. * This code allocates resources for Encoders and is common to all constructors. * * The counter will start counting immediately. * * @param reverseDirection If true, counts down instead of up (this is all relative) * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then * a counter object will be used and the returned value will either exactly match the spec'd count * or be double (2x) the spec'd count. */ void Encoder::InitEncoder(bool reverseDirection, EncodingType encodingType) { m_table = NULL; m_encodingType = encodingType; m_index = 0; switch (encodingType) { case k4X: { m_encodingScale = 4; if (m_aSource->StatusIsFatal()) { CloneError(m_aSource); return; } if (m_bSource->StatusIsFatal()) { CloneError(m_bSource); return; } int32_t status = 0; m_encoder = initializeEncoder(m_aSource->GetModuleForRouting(), m_aSource->GetChannelForRouting(), m_aSource->GetAnalogTriggerForRouting(), m_bSource->GetModuleForRouting(), m_bSource->GetChannelForRouting(), m_bSource->GetAnalogTriggerForRouting(), reverseDirection, &m_index, &status); wpi_setErrorWithContext(status, getHALErrorMessage(status)); m_counter = NULL; SetMaxPeriod(.5); break; } case k1X: case k2X: { m_encodingScale = encodingType == k1X ? 1 : 2; m_counter = new Counter(m_encodingType, m_aSource, m_bSource, reverseDirection); m_index = m_counter->GetFPGAIndex(); break; } default: wpi_setErrorWithContext(-1, "Invalid encodingType argument"); break; } m_distancePerPulse = 1.0; m_pidSource = kDistance; HALReport(HALUsageReporting::kResourceType_Encoder, m_index, encodingType); LiveWindow::GetInstance()->AddSensor("Encoder", m_aSource->GetChannelForRouting(), this); }
/** * Set the source object that causes the counter to count up. * Set the up counting DigitalSource. */ void xCounter::SetUpSource(DigitalSource *source) { if (StatusIsFatal()) return; if (m_allocatedUpSource) { delete m_upSource; m_upSource = NULL; m_allocatedUpSource = false; } m_upSource = source; if (m_upSource->StatusIsFatal()) { CloneError(m_upSource); } else { tRioStatusCode localStatus = NiFpga_Status_Success; m_counter->writeConfig_UpSource_Module(source->GetModuleForRouting(), &localStatus); m_counter->writeConfig_UpSource_Channel(source->GetChannelForRouting(), &localStatus); m_counter->writeConfig_UpSource_AnalogTrigger(source->GetAnalogTriggerForRouting(), &localStatus); if(m_counter->readConfig_Mode(&localStatus) == kTwoPulse || m_counter->readConfig_Mode(&localStatus) == kExternalDirection) { SetUpSourceEdge(true, false); } m_counter->strobeReset(&localStatus); wpi_setError(localStatus); } }
/** * Set the source object that causes the counter to count down. * Set the down counting DigitalSource. */ void xCounter::SetDownSource(DigitalSource *source) { if (StatusIsFatal()) return; if (m_allocatedDownSource) { delete m_downSource; m_downSource = NULL; m_allocatedDownSource = false; } m_downSource = source; if (m_downSource->StatusIsFatal()) { CloneError(m_downSource); } else { tRioStatusCode localStatus = NiFpga_Status_Success; unsigned char mode = m_counter->readConfig_Mode(&localStatus); if (mode != kTwoPulse && mode != kExternalDirection) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "Counter only supports DownSource in TwoPulse and ExternalDirection modes."); return; } m_counter->writeConfig_DownSource_Module(source->GetModuleForRouting(), &localStatus); m_counter->writeConfig_DownSource_Channel(source->GetChannelForRouting(), &localStatus); m_counter->writeConfig_DownSource_AnalogTrigger(source->GetAnalogTriggerForRouting(), &localStatus); SetDownSourceEdge(true, false); m_counter->strobeReset(&localStatus); wpi_setError(localStatus); } }
/** * Constructor. * * @param moduleNumber The CAN ID of the PCM the solenoid is attached to * @param channel The channel on the PCM to control (0..7). */ Solenoid::Solenoid(uint8_t moduleNumber, uint32_t channel) : SolenoidBase(moduleNumber), m_channel(channel) { std::stringstream buf; if (!CheckSolenoidModule(m_moduleNumber)) { buf << "Solenoid Module " << m_moduleNumber; wpi_setWPIErrorWithContext(ModuleIndexOutOfRange, buf.str()); return; } if (!CheckSolenoidChannel(m_channel)) { buf << "Solenoid Module " << m_channel; wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str()); return; } Resource::CreateResourceObject(m_allocated, m_maxModules * m_maxPorts); buf << "Solenoid " << m_channel << " (Module: " << m_moduleNumber << ")"; if (m_allocated->Allocate(m_moduleNumber * kSolenoidChannels + m_channel, buf.str()) == std::numeric_limits<uint32_t>::max()) { CloneError(*m_allocated); return; } #if FULL_WPILIB LiveWindow::GetInstance()->AddActuator("Solenoid", m_moduleNumber, m_channel, this); #endif HALReport(HALUsageReporting::kResourceType_Solenoid, m_channel, m_moduleNumber); }
/** * Construct an analog input. * * @param channel The channel number on the roboRIO to represent. 0-3 are * on-board 4-7 are on the MXP port. */ AnalogInput::AnalogInput(uint32_t channel) { std::stringstream buf; buf << "Analog Input " << channel; Resource::CreateResourceObject(inputs, kAnalogInputs); if (!checkAnalogInputChannel(channel)) { wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str()); return; } if (inputs->Allocate(channel, buf.str()) == std::numeric_limits<uint32_t>::max()) { CloneError(*inputs); return; } m_channel = channel; void *port = getPort(channel); int32_t status = 0; m_port = initializeAnalogInputPort(port, &status); wpi_setErrorWithContext(status, getHALErrorMessage(status)); LiveWindow::GetInstance()->AddSensor("AnalogInput", channel, this); HALReport(HALUsageReporting::kResourceType_AnalogChannel, channel); }
/** * Common function to implement constructor behavior. */ void Solenoid::InitSolenoid() { m_table = NULL; char buf[64]; if (!CheckSolenoidModule(m_moduleNumber)) { snprintf(buf, 64, "Solenoid Module %d", m_moduleNumber); wpi_setWPIErrorWithContext(ModuleIndexOutOfRange, buf); return; } if (!CheckSolenoidChannel(m_channel)) { snprintf(buf, 64, "Solenoid Channel %d", m_channel); wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf); return; } Resource::CreateResourceObject(&m_allocated, tSolenoid::kNumDO7_0Elements * kSolenoidChannels); snprintf(buf, 64, "Solenoid %d (Module: %d)", m_channel, m_moduleNumber); if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels + m_channel - 1, buf) == ~0ul) { CloneError(m_allocated); return; } LiveWindow::GetInstance()->AddActuator("Solenoid", m_moduleNumber, m_channel, this); nUsageReporting::report(nUsageReporting::kResourceType_Solenoid, m_channel, m_moduleNumber - 1); }
/** * Initialize PWMs given an module and channel. * * This method is private and is the common path for all the constructors for creating PWM * instances. Checks module and channel value ranges and allocates the appropriate channel. * The allocation is only done to help users ensure that they don't double assign channels. */ void PWM::InitPWM(UINT8 moduleNumber, UINT32 channel) { char buf[64]; Resource::CreateResourceObject(&allocated, tDIO::kNumSystems * kPwmChannels); if (!CheckPWMModule(moduleNumber)) { snprintf(buf, 64, "Digital Module %d", moduleNumber); wpi_setWPIErrorWithContext(ModuleIndexOutOfRange, buf); return; } if (!CheckPWMChannel(channel)) { snprintf(buf, 64, "PWM Channel %d", channel); wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf); return; } snprintf(buf, 64, "PWM %d (Module: %d)", channel, moduleNumber); if (allocated->Allocate((moduleNumber - 1) * kPwmChannels + channel - 1, buf) == ~0ul) { CloneError(allocated); return; } m_channel = channel; m_module = DigitalModule::GetInstance(moduleNumber); m_module->SetPWM(m_channel, kPwmDisabled); m_eliminateDeadband = false; nUsageReporting::report(nUsageReporting::kResourceType_PWM, channel, moduleNumber - 1); }
/** * Common initialization code for Encoders. * This code allocates resources for Encoders and is common to all constructors. * @param reverseDirection If true, counts down instead of up (this is all relative) * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then * a counter object will be used and the returned value will either exactly match the spec'd count * or be double (2x) the spec'd count. */ void Encoder::InitEncoder(bool reverseDirection, EncodingType encodingType) { m_encodingType = encodingType; tRioStatusCode localStatus = NiFpga_Status_Success; UINT32 index; // declared out here because gcc doesn't like it declared in there switch (encodingType) { case k4X: Resource::CreateResourceObject(&quadEncoders, tEncoder::kNumSystems); index = quadEncoders->Allocate("4X Encoder"); if (index == ~0ul) { CloneError(quadEncoders); return; } if (m_aSource->StatusIsFatal()) { CloneError(m_aSource); return; } if (m_bSource->StatusIsFatal()) { CloneError(m_bSource); return; } m_index = index; m_encoder = tEncoder::create(m_index, &localStatus); m_encoder->writeConfig_ASource_Module(m_aSource->GetModuleForRouting(), &localStatus); m_encoder->writeConfig_ASource_Channel(m_aSource->GetChannelForRouting(), &localStatus); m_encoder->writeConfig_ASource_AnalogTrigger(m_aSource->GetAnalogTriggerForRouting(), &localStatus); m_encoder->writeConfig_BSource_Module(m_bSource->GetModuleForRouting(), &localStatus); m_encoder->writeConfig_BSource_Channel(m_bSource->GetChannelForRouting(), &localStatus); m_encoder->writeConfig_BSource_AnalogTrigger(m_bSource->GetAnalogTriggerForRouting(), &localStatus); m_encoder->strobeReset(&localStatus); m_encoder->writeConfig_Reverse(reverseDirection, &localStatus); m_encoder->writeTimerConfig_AverageSize(4, &localStatus); m_counter = NULL; break; case k1X: case k2X: m_counter = new Counter(m_encodingType, m_aSource, m_bSource, reverseDirection); break; } m_distancePerPulse = 1.0; m_pidSource = kDistance; wpi_setError(localStatus); }
/** * Common function to implement constructor behavior. */ void DoubleSolenoid::InitSolenoid() { char buf[64]; if (!CheckSolenoidModule(m_moduleNumber)) { snprintf(buf, 64, "Solenoid Module %lu", m_moduleNumber); wpi_setWPIErrorWithContext(ModuleIndexOutOfRange, buf); return; } if (!CheckSolenoidChannel(m_forwardChannel)) { snprintf(buf, 64, "Solenoid Channel %lu", m_forwardChannel); wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf); return; } if (!CheckSolenoidChannel(m_reverseChannel)) { snprintf(buf, 64, "Solenoid Channel %lu", m_reverseChannel); wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf); return; } Resource::CreateResourceObject(&m_allocated, tSolenoid::kNumDO7_0Elements * kSolenoidChannels); snprintf(buf, 64, "Solenoid %lu (Module %lu)", m_forwardChannel, m_moduleNumber); if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels + m_forwardChannel - 1, buf) == ~0ul) { CloneError(m_allocated); return; } snprintf(buf, 64, "Solenoid %lu (Module %lu)", m_reverseChannel, m_moduleNumber); if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels + m_reverseChannel - 1, buf) == ~0ul) { CloneError(m_allocated); return; } m_forwardMask = 1 << (m_forwardChannel - 1); m_reverseMask = 1 << (m_reverseChannel - 1); nUsageReporting::report(nUsageReporting::kResourceType_Solenoid, m_forwardChannel, m_moduleNumber - 1); nUsageReporting::report(nUsageReporting::kResourceType_Solenoid, m_reverseChannel, m_moduleNumber - 1); LiveWindow::GetInstance()->AddActuator("Double Solenoid", m_moduleNumber, m_forwardChannel, this); }
/** * Relay constructor given a channel. * * This code initializes the relay and reserves all resources that need to be * locked. Initially the relay is set to both lines at 0v. * @param channel The channel number (0-3). * @param direction The direction that the Relay object will control. */ Relay::Relay(uint32_t channel, Relay::Direction direction) : m_channel(channel), m_direction(direction) { std::stringstream buf; Resource::CreateResourceObject(relayChannels, dio_kNumSystems * kRelayChannels * 2); if (!SensorBase::CheckRelayChannel(m_channel)) { buf << "Relay Channel " << m_channel; wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str()); return; } if (m_direction == kBothDirections || m_direction == kForwardOnly) { buf << "Forward Relay " << m_channel; if (relayChannels->Allocate(m_channel * 2, buf.str()) == ~0ul) { CloneError(*relayChannels); return; } HALReport(HALUsageReporting::kResourceType_Relay, m_channel); } if (m_direction == kBothDirections || m_direction == kReverseOnly) { buf << "Reverse Relay " << m_channel; if (relayChannels->Allocate(m_channel * 2 + 1, buf.str()) == ~0ul) { CloneError(*relayChannels); return; } HALReport(HALUsageReporting::kResourceType_Relay, m_channel + 128); } int32_t status = 0; setRelayForward(m_relay_ports[m_channel], false, &status); setRelayReverse(m_relay_ports[m_channel], false, &status); wpi_setErrorWithContext(status, getHALErrorMessage(status)); LiveWindow::GetInstance().AddActuator("Relay", 1, m_channel, this); }
/** * @brief Constructor. */ PCVideoServer::PCVideoServer() : m_serverTask("PCVideoServer", (FUNCPTR)s_ServerTask) , m_newImageSem (NULL) , m_stopServer (false) { AxisCamera &cam = AxisCamera::GetInstance(); m_newImageSem = cam.GetNewImageSem(); if (!cam.StatusIsFatal()) { StartServerTask(); } else { CloneError(&cam); } }
/** * Request one of the 8 interrupts synchronously on this digital input. * Request interrupts in synchronous mode where the user program will have to * explicitly * wait for the interrupt to occur using WaitForInterrupt. * The default is interrupt on rising edges only. */ void InterruptableSensorBase::RequestInterrupts() { if (StatusIsFatal()) return; uint32_t index = m_interrupts->Allocate("Sync Interrupt"); if (index == std::numeric_limits<uint32_t>::max()) { CloneError(*m_interrupts); return; } m_interruptIndex = index; AllocateInterrupts(true); int32_t status = 0; requestInterrupts(m_interrupt, GetModuleForRouting(), GetChannelForRouting(), GetAnalogTriggerForRouting(), &status); wpi_setErrorWithContext(status, getHALErrorMessage(status)); SetUpSourceEdge(true, false); }
/** * 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); }
/** * Create an instance of a counter object. * This creates a ChipObject counter and initializes status variables appropriately */ void Counter::InitCounter(Mode mode) { Resource::CreateResourceObject(&counters, tCounter::kNumSystems); UINT32 index = counters->Allocate("Counter"); if (index == ~0ul) { CloneError(counters); return; } m_index = index; tRioStatusCode localStatus = NiFpga_Status_Success; m_counter = tCounter::create(m_index, &localStatus); m_counter->writeConfig_Mode(mode, &localStatus); m_upSource = NULL; m_downSource = NULL; m_allocatedUpSource = false; m_allocatedDownSource = false; m_counter->writeTimerConfig_AverageSize(1, &localStatus); wpi_setError(localStatus); }
/** * Request one of the 8 interrupts asynchronously on this digital input. * Request interrupts in asynchronous mode where the user's interrupt handler * will be * called when the interrupt fires. Users that want control over the thread * priority * should use the synchronous method with their own spawned thread. * The default is interrupt on rising edges only. */ void InterruptableSensorBase::RequestInterrupts( InterruptHandlerFunction handler, void *param) { if (StatusIsFatal()) return; uint32_t index = m_interrupts->Allocate("Async Interrupt"); if (index == std::numeric_limits<uint32_t>::max()) { CloneError(*m_interrupts); return; } m_interruptIndex = index; // Creates a manager too AllocateInterrupts(false); int32_t status = 0; requestInterrupts(m_interrupt, GetModuleForRouting(), GetChannelForRouting(), GetAnalogTriggerForRouting(), &status); SetUpSourceEdge(true, false); attachInterruptHandler(m_interrupt, handler, param, &status); wpi_setErrorWithContext(status, getHALErrorMessage(status)); }
/** * Request interrupts synchronously on this digital input. * Request interrupts in synchronus mode where the user program will have to explicitly * wait for the interrupt to occur. * The default is interrupt on rising edges only. */ void DigitalInput::RequestInterrupts() { if (StatusIsFatal()) return; uint32_t index = interruptsResource->Allocate("Sync Interrupt"); if (index == ~0ul) { CloneError(interruptsResource); return; } m_interruptIndex = index; AllocateInterrupts(true); tRioStatusCode localStatus = NiFpga_Status_Success; m_interrupt->writeConfig_Source_AnalogTrigger(GetAnalogTriggerForRouting(), &localStatus); m_interrupt->writeConfig_Source_Channel(GetChannelForRouting(), &localStatus); m_interrupt->writeConfig_Source_Module(GetModuleForRouting(), &localStatus); SetUpSourceEdge(true, false); wpi_setError(localStatus); }
/** * Common initialization. */ void AnalogChannel::InitChannel(UINT8 moduleNumber, UINT32 channel) { char buf[64]; Resource::CreateResourceObject(&channels, kAnalogModules * kAnalogChannels); if (!CheckAnalogModule(moduleNumber)) { snprintf(buf, 64, "Analog Module %d", moduleNumber); wpi_setWPIErrorWithContext(ModuleIndexOutOfRange, buf); return; } if (!CheckAnalogChannel(channel)) { snprintf(buf, 64, "Analog Channel %d", channel); wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf); return; } snprintf(buf, 64, "Analog Input %d (Module: %d)", channel, moduleNumber); if (channels->Allocate((moduleNumber - 1) * kAnalogChannels + channel - 1, buf) == ~0ul) { CloneError(channels); return; } m_channel = channel; m_module = AnalogModule::GetInstance(moduleNumber); if (IsAccumulatorChannel()) { tRioStatusCode localStatus = NiFpga_Status_Success; m_accumulator = tAccumulator::create(channel - 1, &localStatus); wpi_setError(localStatus); m_accumulatorOffset=0; } else { m_accumulator = NULL; } LiveWindow::GetInstance()->AddActuator("AnalogChannel",channel, GetModuleNumber(), this); nUsageReporting::report(nUsageReporting::kResourceType_AnalogChannel, channel, GetModuleNumber() - 1); }
/** * Request interrupts asynchronously on this digital input. * @param handler The address of the interrupt handler function of type tInterruptHandler that * will be called whenever there is an interrupt on the digitial input port. * Request interrupts in synchronus mode where the user program interrupt handler will be * called when an interrupt occurs. * The default is interrupt on rising edges only. */ void DigitalInput::RequestInterrupts(tInterruptHandler handler, void *param) { if (StatusIsFatal()) return; uint32_t index = interruptsResource->Allocate("Async Interrupt"); if (index == ~0ul) { CloneError(interruptsResource); return; } m_interruptIndex = index; // Creates a manager too AllocateInterrupts(false); tRioStatusCode localStatus = NiFpga_Status_Success; m_interrupt->writeConfig_WaitForAck(false, &localStatus); m_interrupt->writeConfig_Source_AnalogTrigger(GetAnalogTriggerForRouting(), &localStatus); m_interrupt->writeConfig_Source_Channel(GetChannelForRouting(), &localStatus); m_interrupt->writeConfig_Source_Module(GetModuleForRouting(), &localStatus); SetUpSourceEdge(true, false); m_manager->registerHandler(handler, param, &localStatus); wpi_setError(localStatus); }