Now you can download a copy of these docs so you can use them offline! Download now
DigitalModule.cpp
00001 /*----------------------------------------------------------------------------*/ 00002 /* Copyright (c) FIRST 2008. All Rights Reserved. */ 00003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 00004 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ 00005 /*----------------------------------------------------------------------------*/ 00006 00007 #include "DigitalModule.h" 00008 #include "I2C.h" 00009 #include "PWM.h" 00010 #include "Resource.h" 00011 #include "Synchronized.h" 00012 #include "WPIErrors.h" 00013 #include <math.h> 00014 #include <taskLib.h> 00015 00016 static Resource *DIOChannels = NULL; 00017 static Resource *DO_PWMGenerators[tDIO::kNumSystems] = {NULL}; 00018 00026 DigitalModule* DigitalModule::GetInstance(UINT8 moduleNumber) 00027 { 00028 if (CheckDigitalModule(moduleNumber)) 00029 { 00030 return (DigitalModule *)GetModule(nLoadOut::kModuleType_Digital, moduleNumber); 00031 } 00032 00033 // If this wasn't caught before now, make sure we say what's wrong before we crash 00034 char buf[64]; 00035 snprintf(buf, 64, "Digital Module %d", moduleNumber); 00036 wpi_setGlobalWPIErrorWithContext(ModuleIndexOutOfRange, buf); 00037 00038 return NULL; 00039 } 00040 00051 DigitalModule::DigitalModule(UINT8 moduleNumber) 00052 : Module(nLoadOut::kModuleType_Digital, moduleNumber) 00053 , m_fpgaDIO (NULL) 00054 { 00055 Resource::CreateResourceObject(&DIOChannels, tDIO::kNumSystems * kDigitalChannels); 00056 Resource::CreateResourceObject(&DO_PWMGenerators[m_moduleNumber - 1], tDIO::kNumDO_PWMDutyCycleElements); 00057 tRioStatusCode localStatus = NiFpga_Status_Success; 00058 m_fpgaDIO = tDIO::create(m_moduleNumber - 1, &localStatus); 00059 wpi_setError(localStatus); 00060 00061 // Make sure that the 9403 IONode has had a chance to initialize before continuing. 00062 while(m_fpgaDIO->readLoopTiming(&localStatus) == 0) taskDelay(1); 00063 if (m_fpgaDIO->readLoopTiming(&localStatus) != kExpectedLoopTiming) 00064 { 00065 char err[128]; 00066 sprintf(err, "DIO LoopTiming: %d, expecting: %d\n", m_fpgaDIO->readLoopTiming(&localStatus), kExpectedLoopTiming); 00067 wpi_setWPIErrorWithContext(LoopTimingError, err); 00068 } 00069 m_fpgaDIO->writePWMConfig_Period(PWM::kDefaultPwmPeriod, &localStatus); 00070 m_fpgaDIO->writePWMConfig_MinHigh(PWM::kDefaultMinPwmHigh, &localStatus); 00071 00072 // Ensure that PWM output values are set to OFF 00073 for (UINT32 pwm_index = 1; pwm_index <= kPwmChannels; pwm_index++) 00074 { 00075 SetPWM(pwm_index, PWM::kPwmDisabled); 00076 SetPWMPeriodScale(pwm_index, 3); // Set all to 4x by default. 00077 } 00078 00079 // Turn off all relay outputs. 00080 m_fpgaDIO->writeSlowValue_RelayFwd(0, &localStatus); 00081 m_fpgaDIO->writeSlowValue_RelayRev(0, &localStatus); 00082 wpi_setError(localStatus); 00083 00084 // Create a semaphore to protect changes to the digital output values 00085 m_digitalSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); 00086 00087 // Create a semaphore to protect changes to the relay values 00088 m_relaySemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); 00089 00090 // Create a semaphore to protect changes to the DO PWM config 00091 m_doPwmSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); 00092 00093 AddToSingletonList(); 00094 } 00095 00096 DigitalModule::~DigitalModule() 00097 { 00098 semDelete(m_doPwmSemaphore); 00099 m_doPwmSemaphore = NULL; 00100 semDelete(m_relaySemaphore); 00101 m_relaySemaphore = NULL; 00102 semDelete(m_digitalSemaphore); 00103 m_digitalSemaphore = NULL; 00104 delete m_fpgaDIO; 00105 } 00106 00114 void DigitalModule::SetPWM(UINT32 channel, UINT8 value) 00115 { 00116 CheckPWMChannel(channel); 00117 tRioStatusCode localStatus = NiFpga_Status_Success; 00118 m_fpgaDIO->writePWMValue(channel - 1, value, &localStatus); 00119 wpi_setError(localStatus); 00120 } 00121 00128 UINT8 DigitalModule::GetPWM(UINT32 channel) 00129 { 00130 CheckPWMChannel(channel); 00131 tRioStatusCode localStatus = NiFpga_Status_Success; 00132 return m_fpgaDIO->readPWMValue(channel - 1, &localStatus); 00133 wpi_setError(localStatus); 00134 } 00135 00142 void DigitalModule::SetPWMPeriodScale(UINT32 channel, UINT32 squelchMask) 00143 { 00144 CheckPWMChannel(channel); 00145 tRioStatusCode localStatus = NiFpga_Status_Success; 00146 m_fpgaDIO->writePWMPeriodScale(channel - 1, squelchMask, &localStatus); 00147 wpi_setError(localStatus); 00148 } 00149 00155 void DigitalModule::SetRelayForward(UINT32 channel, bool on) 00156 { 00157 tRioStatusCode localStatus = NiFpga_Status_Success; 00158 CheckRelayChannel(channel); 00159 { 00160 Synchronized sync(m_relaySemaphore); 00161 UINT8 forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&localStatus); 00162 if (on) 00163 forwardRelays |= 1 << (channel - 1); 00164 else 00165 forwardRelays &= ~(1 << (channel - 1)); 00166 m_fpgaDIO->writeSlowValue_RelayFwd(forwardRelays, &localStatus); 00167 } 00168 wpi_setError(localStatus); 00169 } 00170 00176 void DigitalModule::SetRelayReverse(UINT32 channel, bool on) 00177 { 00178 tRioStatusCode localStatus = NiFpga_Status_Success; 00179 CheckRelayChannel(channel); 00180 { 00181 Synchronized sync(m_relaySemaphore); 00182 UINT8 reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&localStatus); 00183 if (on) 00184 reverseRelays |= 1 << (channel - 1); 00185 else 00186 reverseRelays &= ~(1 << (channel - 1)); 00187 m_fpgaDIO->writeSlowValue_RelayRev(reverseRelays, &localStatus); 00188 } 00189 wpi_setError(localStatus); 00190 } 00191 00195 bool DigitalModule::GetRelayForward(UINT32 channel) 00196 { 00197 tRioStatusCode localStatus = NiFpga_Status_Success; 00198 UINT8 forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&localStatus); 00199 wpi_setError(localStatus); 00200 return (forwardRelays & (1 << (channel - 1))) != 0; 00201 } 00202 00206 UINT8 DigitalModule::GetRelayForward() 00207 { 00208 tRioStatusCode localStatus = NiFpga_Status_Success; 00209 UINT8 forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&localStatus); 00210 wpi_setError(localStatus); 00211 return forwardRelays; 00212 } 00213 00217 bool DigitalModule::GetRelayReverse(UINT32 channel) 00218 { 00219 tRioStatusCode localStatus = NiFpga_Status_Success; 00220 UINT8 reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&localStatus); 00221 wpi_setError(localStatus); 00222 return (reverseRelays & (1 << (channel - 1))) != 0; 00223 00224 } 00225 00229 UINT8 DigitalModule::GetRelayReverse() 00230 { 00231 tRioStatusCode localStatus = NiFpga_Status_Success; 00232 UINT8 reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&localStatus); 00233 wpi_setError(localStatus); 00234 return reverseRelays; 00235 } 00236 00237 00247 bool DigitalModule::AllocateDIO(UINT32 channel, bool input) 00248 { 00249 char buf[64]; 00250 snprintf(buf, 64, "DIO %d (Module %d)", channel, m_moduleNumber); 00251 if (DIOChannels->Allocate(kDigitalChannels * (m_moduleNumber - 1) + channel - 1, buf) == ~0ul) return false; 00252 tRioStatusCode localStatus = NiFpga_Status_Success; 00253 { 00254 Synchronized sync(m_digitalSemaphore); 00255 UINT32 bitToSet = 1 << (RemapDigitalChannel(channel - 1)); 00256 UINT32 outputEnable = m_fpgaDIO->readOutputEnable(&localStatus); 00257 UINT32 outputEnableValue; 00258 if (input) 00259 { 00260 outputEnableValue = outputEnable & (~bitToSet); // clear the bit for read 00261 } 00262 else 00263 { 00264 outputEnableValue = outputEnable | bitToSet; // set the bit for write 00265 } 00266 m_fpgaDIO->writeOutputEnable(outputEnableValue, &localStatus); 00267 } 00268 wpi_setError(localStatus); 00269 return true; 00270 } 00271 00277 void DigitalModule::FreeDIO(UINT32 channel) 00278 { 00279 DIOChannels->Free(kDigitalChannels * (m_moduleNumber - 1) + channel - 1); 00280 } 00281 00289 void DigitalModule::SetDIO(UINT32 channel, short value) 00290 { 00291 if (value != 0 && value != 1) 00292 { 00293 wpi_setWPIError(NonBinaryDigitalValue); 00294 if (value != 0) 00295 value = 1; 00296 } 00297 tRioStatusCode localStatus = NiFpga_Status_Success; 00298 { 00299 Synchronized sync(m_digitalSemaphore); 00300 UINT16 currentDIO = m_fpgaDIO->readDO(&localStatus); 00301 if(value == 0) 00302 { 00303 currentDIO = currentDIO & ~(1 << RemapDigitalChannel(channel - 1)); 00304 } 00305 else if (value == 1) 00306 { 00307 currentDIO = currentDIO | (1 << RemapDigitalChannel(channel - 1)); 00308 } 00309 m_fpgaDIO->writeDO(currentDIO, &localStatus); 00310 } 00311 wpi_setError(localStatus); 00312 } 00313 00321 bool DigitalModule::GetDIO(UINT32 channel) 00322 { 00323 tRioStatusCode localStatus = NiFpga_Status_Success; 00324 UINT32 currentDIO = m_fpgaDIO->readDI(&localStatus); 00325 wpi_setError(localStatus); 00326 00327 //Shift 00000001 over channel-1 places. 00328 //AND it against the currentDIO 00329 //if it == 0, then return false 00330 //else return true 00331 return ((currentDIO >> RemapDigitalChannel(channel - 1)) & 1) != 0; 00332 } 00333 00338 UINT16 DigitalModule::GetDIO() 00339 { 00340 tRioStatusCode localStatus = NiFpga_Status_Success; 00341 UINT32 currentDIO = m_fpgaDIO->readDI(&localStatus); 00342 wpi_setError(localStatus); 00343 return currentDIO; 00344 } 00345 00353 bool DigitalModule::GetDIODirection(UINT32 channel) 00354 { 00355 tRioStatusCode localStatus = NiFpga_Status_Success; 00356 UINT32 currentOutputEnable = m_fpgaDIO->readOutputEnable(&localStatus); 00357 wpi_setError(localStatus); 00358 00359 //Shift 00000001 over channel-1 places. 00360 //AND it against the currentOutputEnable 00361 //if it == 0, then return false 00362 //else return true 00363 return ((currentOutputEnable >> RemapDigitalChannel(channel - 1)) & 1) != 0; 00364 } 00365 00371 UINT16 DigitalModule::GetDIODirection() 00372 { 00373 tRioStatusCode localStatus = NiFpga_Status_Success; 00374 UINT32 currentOutputEnable = m_fpgaDIO->readOutputEnable(&localStatus); 00375 wpi_setError(localStatus); 00376 return currentOutputEnable; 00377 } 00378 00386 void DigitalModule::Pulse(UINT32 channel, float pulseLength) 00387 { 00388 UINT16 mask = 1 << RemapDigitalChannel(channel - 1); 00389 tRioStatusCode localStatus = NiFpga_Status_Success; 00390 m_fpgaDIO->writePulseLength((UINT8)(1.0e9 * pulseLength / (m_fpgaDIO->readLoopTiming(&localStatus) * 25)), &localStatus); 00391 m_fpgaDIO->writePulse(mask, &localStatus); 00392 wpi_setError(localStatus); 00393 } 00394 00400 bool DigitalModule::IsPulsing(UINT32 channel) 00401 { 00402 UINT16 mask = 1 << RemapDigitalChannel(channel - 1); 00403 tRioStatusCode localStatus = NiFpga_Status_Success; 00404 UINT16 pulseRegister = m_fpgaDIO->readPulse(&localStatus); 00405 wpi_setError(localStatus); 00406 return (pulseRegister & mask) != 0; 00407 } 00408 00414 bool DigitalModule::IsPulsing() 00415 { 00416 tRioStatusCode localStatus = NiFpga_Status_Success; 00417 UINT16 pulseRegister = m_fpgaDIO->readPulse(&localStatus); 00418 wpi_setError(localStatus); 00419 return pulseRegister != 0; 00420 } 00421 00428 UINT32 DigitalModule::AllocateDO_PWM() 00429 { 00430 char buf[64]; 00431 snprintf(buf, 64, "DO_PWM (Module: %d)", m_moduleNumber); 00432 return DO_PWMGenerators[(m_moduleNumber - 1)]->Allocate(buf); 00433 } 00434 00440 void DigitalModule::FreeDO_PWM(UINT32 pwmGenerator) 00441 { 00442 if (pwmGenerator == ~0ul) return; 00443 DO_PWMGenerators[(m_moduleNumber - 1)]->Free(pwmGenerator); 00444 } 00445 00453 void DigitalModule::SetDO_PWMRate(float rate) 00454 { 00455 // Currently rounding in the log rate domain... heavy weight toward picking a higher freq. 00456 // TODO: Round in the linear rate domain. 00457 tRioStatusCode localStatus = NiFpga_Status_Success; 00458 UINT8 pwmPeriodPower = (UINT8)(log(1.0 / (m_fpgaDIO->readLoopTiming(&localStatus) * 0.25E-6 * rate))/log(2.0) + 0.5); 00459 m_fpgaDIO->writeDO_PWMConfig_PeriodPower(pwmPeriodPower, &localStatus); 00460 wpi_setError(localStatus); 00461 } 00462 00469 void DigitalModule::SetDO_PWMOutputChannel(UINT32 pwmGenerator, UINT32 channel) 00470 { 00471 if (pwmGenerator == ~0ul) return; 00472 tRioStatusCode localStatus = NiFpga_Status_Success; 00473 switch(pwmGenerator) 00474 { 00475 case 0: 00476 m_fpgaDIO->writeDO_PWMConfig_OutputSelect_0(RemapDigitalChannel(channel - 1), &localStatus); 00477 break; 00478 case 1: 00479 m_fpgaDIO->writeDO_PWMConfig_OutputSelect_1(RemapDigitalChannel(channel - 1), &localStatus); 00480 break; 00481 case 2: 00482 m_fpgaDIO->writeDO_PWMConfig_OutputSelect_2(RemapDigitalChannel(channel - 1), &localStatus); 00483 break; 00484 case 3: 00485 m_fpgaDIO->writeDO_PWMConfig_OutputSelect_3(RemapDigitalChannel(channel - 1), &localStatus); 00486 break; 00487 } 00488 wpi_setError(localStatus); 00489 } 00490 00497 void DigitalModule::SetDO_PWMDutyCycle(UINT32 pwmGenerator, float dutyCycle) 00498 { 00499 if (pwmGenerator == ~0ul) return; 00500 if (dutyCycle > 1.0) dutyCycle = 1.0; 00501 if (dutyCycle < 0.0) dutyCycle = 0.0; 00502 float rawDutyCycle = 256.0 * dutyCycle; 00503 if (rawDutyCycle > 255.5) rawDutyCycle = 255.5; 00504 tRioStatusCode localStatus = NiFpga_Status_Success; 00505 { 00506 Synchronized sync(m_doPwmSemaphore); 00507 UINT8 pwmPeriodPower = m_fpgaDIO->readDO_PWMConfig_PeriodPower(&localStatus); 00508 if (pwmPeriodPower < 4) 00509 { 00510 // The resolution of the duty cycle drops close to the highest frequencies. 00511 rawDutyCycle = rawDutyCycle / pow(2.0, 4 - pwmPeriodPower); 00512 } 00513 m_fpgaDIO->writeDO_PWMDutyCycle(pwmGenerator, (UINT8)rawDutyCycle, &localStatus); 00514 } 00515 wpi_setError(localStatus); 00516 } 00517 00525 I2C* DigitalModule::GetI2C(UINT32 address) 00526 { 00527 return new I2C(this, address); 00528 } 00529 00530
Generated on Thu Jan 12 2012 22:35:19 for WPILibC++ by
1.7.1