Now you can download a copy of these docs so you can use them offline! Download now
DigitalModule.cpp
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2008. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
5 /*----------------------------------------------------------------------------*/
6 
7 #include "DigitalModule.h"
8 #include "I2C.h"
9 #include "PWM.h"
10 #include "Resource.h"
11 #include "Synchronized.h"
12 #include "WPIErrors.h"
13 #include <math.h>
14 #include <taskLib.h>
15 
16 static Resource *DIOChannels = NULL;
17 static Resource *DO_PWMGenerators[tDIO::kNumSystems] = {NULL};
18 
27 {
28  if (CheckDigitalModule(moduleNumber))
29  {
30  return (DigitalModule *)GetModule(nLoadOut::kModuleType_Digital, moduleNumber);
31  }
32 
33  // If this wasn't caught before now, make sure we say what's wrong before we crash
34  char buf[64];
35  snprintf(buf, 64, "Digital Module %d", moduleNumber);
36  wpi_setGlobalWPIErrorWithContext(ModuleIndexOutOfRange, buf);
37 
38  return NULL;
39 }
40 
51 DigitalModule::DigitalModule(uint8_t moduleNumber)
52  : Module(nLoadOut::kModuleType_Digital, moduleNumber)
53  , m_fpgaDIO (NULL)
54 {
55  Resource::CreateResourceObject(&DIOChannels, tDIO::kNumSystems * kDigitalChannels);
56  Resource::CreateResourceObject(&DO_PWMGenerators[m_moduleNumber - 1], tDIO::kNumDO_PWMDutyCycleElements);
57  tRioStatusCode localStatus = NiFpga_Status_Success;
58  m_fpgaDIO = tDIO::create(m_moduleNumber - 1, &localStatus);
59  wpi_setError(localStatus);
60 
61  // Make sure that the 9403 IONode has had a chance to initialize before continuing.
62  while(m_fpgaDIO->readLoopTiming(&localStatus) == 0) taskDelay(1);
63 
64  if (m_fpgaDIO->readLoopTiming(&localStatus) != kExpectedLoopTiming)
65  {
66  char err[128];
67  sprintf(err, "DIO LoopTiming: %d, expecting: %lu\n", m_fpgaDIO->readLoopTiming(&localStatus), kExpectedLoopTiming);
68  wpi_setWPIErrorWithContext(LoopTimingError, err);
69  }
70 
71  //Calculate the length, in ms, of one DIO loop
72  double loopTime = m_fpgaDIO->readLoopTiming(&localStatus)/(kSystemClockTicksPerMicrosecond*1e3);
73 
74  m_fpgaDIO->writePWMConfig_Period((uint16_t) (PWM::kDefaultPwmPeriod/loopTime + .5), &localStatus);
75  m_fpgaDIO->writePWMConfig_MinHigh((uint16_t) ((PWM::kDefaultPwmCenter-PWM::kDefaultPwmStepsDown*loopTime)/loopTime + .5), &localStatus);
76 
77  // Ensure that PWM output values are set to OFF
78  for (uint32_t pwm_index = 1; pwm_index <= kPwmChannels; pwm_index++)
79  {
80  SetPWM(pwm_index, PWM::kPwmDisabled);
81  SetPWMPeriodScale(pwm_index, 3); // Set all to 4x by default.
82  }
83 
84  // Turn off all relay outputs.
85  m_fpgaDIO->writeSlowValue_RelayFwd(0, &localStatus);
86  m_fpgaDIO->writeSlowValue_RelayRev(0, &localStatus);
87  wpi_setError(localStatus);
88 
89  // Create a semaphore to protect changes to the digital output values
90  m_digitalSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
91 
92  // Create a semaphore to protect changes to the relay values
93  m_relaySemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
94 
95  // Create a semaphore to protect changes to the DO PWM config
96  m_doPwmSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
97 
99 }
100 
101 DigitalModule::~DigitalModule()
102 {
103  semDelete(m_doPwmSemaphore);
104  m_doPwmSemaphore = NULL;
105  semDelete(m_relaySemaphore);
106  m_relaySemaphore = NULL;
107  semDelete(m_digitalSemaphore);
108  m_digitalSemaphore = NULL;
109  delete m_fpgaDIO;
110 }
111 
119 void DigitalModule::SetPWM(uint32_t channel, uint8_t value)
120 {
121  CheckPWMChannel(channel);
122  tRioStatusCode localStatus = NiFpga_Status_Success;
123  m_fpgaDIO->writePWMValue(channel - 1, value, &localStatus);
124  wpi_setError(localStatus);
125 }
126 
133 uint8_t DigitalModule::GetPWM(uint32_t channel)
134 {
135  CheckPWMChannel(channel);
136  tRioStatusCode localStatus = NiFpga_Status_Success;
137  return m_fpgaDIO->readPWMValue(channel - 1, &localStatus);
138  wpi_setError(localStatus);
139 }
140 
147 void DigitalModule::SetPWMPeriodScale(uint32_t channel, uint32_t squelchMask)
148 {
149  CheckPWMChannel(channel);
150  tRioStatusCode localStatus = NiFpga_Status_Success;
151  m_fpgaDIO->writePWMPeriodScale(channel - 1, squelchMask, &localStatus);
152  wpi_setError(localStatus);
153 }
154 
160 void DigitalModule::SetRelayForward(uint32_t channel, bool on)
161 {
162  tRioStatusCode localStatus = NiFpga_Status_Success;
163  CheckRelayChannel(channel);
164  {
165  Synchronized sync(m_relaySemaphore);
166  uint8_t forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&localStatus);
167  if (on)
168  forwardRelays |= 1 << (channel - 1);
169  else
170  forwardRelays &= ~(1 << (channel - 1));
171  m_fpgaDIO->writeSlowValue_RelayFwd(forwardRelays, &localStatus);
172  }
173  wpi_setError(localStatus);
174 }
175 
181 void DigitalModule::SetRelayReverse(uint32_t channel, bool on)
182 {
183  tRioStatusCode localStatus = NiFpga_Status_Success;
184  CheckRelayChannel(channel);
185  {
186  Synchronized sync(m_relaySemaphore);
187  uint8_t reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&localStatus);
188  if (on)
189  reverseRelays |= 1 << (channel - 1);
190  else
191  reverseRelays &= ~(1 << (channel - 1));
192  m_fpgaDIO->writeSlowValue_RelayRev(reverseRelays, &localStatus);
193  }
194  wpi_setError(localStatus);
195 }
196 
200 bool DigitalModule::GetRelayForward(uint32_t channel)
201 {
202  tRioStatusCode localStatus = NiFpga_Status_Success;
203  uint8_t forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&localStatus);
204  wpi_setError(localStatus);
205  return (forwardRelays & (1 << (channel - 1))) != 0;
206 }
207 
212 {
213  tRioStatusCode localStatus = NiFpga_Status_Success;
214  uint8_t forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&localStatus);
215  wpi_setError(localStatus);
216  return forwardRelays;
217 }
218 
222 bool DigitalModule::GetRelayReverse(uint32_t channel)
223 {
224  tRioStatusCode localStatus = NiFpga_Status_Success;
225  uint8_t reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&localStatus);
226  wpi_setError(localStatus);
227  return (reverseRelays & (1 << (channel - 1))) != 0;
228 
229 }
230 
235 {
236  tRioStatusCode localStatus = NiFpga_Status_Success;
237  uint8_t reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&localStatus);
238  wpi_setError(localStatus);
239  return reverseRelays;
240 }
241 
242 
252 bool DigitalModule::AllocateDIO(uint32_t channel, bool input)
253 {
254  char buf[64];
255  snprintf(buf, 64, "DIO %d (Module %d)", channel, m_moduleNumber);
256  if (DIOChannels->Allocate(kDigitalChannels * (m_moduleNumber - 1) + channel - 1, buf) == ~0ul) return false;
257  tRioStatusCode localStatus = NiFpga_Status_Success;
258  {
259  Synchronized sync(m_digitalSemaphore);
260  uint32_t bitToSet = 1 << (RemapDigitalChannel(channel - 1));
261  uint32_t outputEnable = m_fpgaDIO->readOutputEnable(&localStatus);
262  uint32_t outputEnableValue;
263  if (input)
264  {
265  outputEnableValue = outputEnable & (~bitToSet); // clear the bit for read
266  }
267  else
268  {
269  outputEnableValue = outputEnable | bitToSet; // set the bit for write
270  }
271  m_fpgaDIO->writeOutputEnable(outputEnableValue, &localStatus);
272  }
273  wpi_setError(localStatus);
274  return true;
275 }
276 
282 void DigitalModule::FreeDIO(uint32_t channel)
283 {
284  DIOChannels->Free(kDigitalChannels * (m_moduleNumber - 1) + channel - 1);
285 }
286 
294 void DigitalModule::SetDIO(uint32_t channel, short value)
295 {
296  if (value != 0 && value != 1)
297  {
298  wpi_setWPIError(NonBinaryDigitalValue);
299  if (value != 0)
300  value = 1;
301  }
302  tRioStatusCode localStatus = NiFpga_Status_Success;
303  {
304  Synchronized sync(m_digitalSemaphore);
305  uint16_t currentDIO = m_fpgaDIO->readDO(&localStatus);
306  if(value == 0)
307  {
308  currentDIO = currentDIO & ~(1 << RemapDigitalChannel(channel - 1));
309  }
310  else if (value == 1)
311  {
312  currentDIO = currentDIO | (1 << RemapDigitalChannel(channel - 1));
313  }
314  m_fpgaDIO->writeDO(currentDIO, &localStatus);
315  }
316  wpi_setError(localStatus);
317 }
318 
326 bool DigitalModule::GetDIO(uint32_t channel)
327 {
328  tRioStatusCode localStatus = NiFpga_Status_Success;
329  uint32_t currentDIO = m_fpgaDIO->readDI(&localStatus);
330  wpi_setError(localStatus);
331 
332  //Shift 00000001 over channel-1 places.
333  //AND it against the currentDIO
334  //if it == 0, then return false
335  //else return true
336  return ((currentDIO >> RemapDigitalChannel(channel - 1)) & 1) != 0;
337 }
338 
344 {
345  tRioStatusCode localStatus = NiFpga_Status_Success;
346  uint32_t currentDIO = m_fpgaDIO->readDI(&localStatus);
347  wpi_setError(localStatus);
348  return currentDIO;
349 }
350 
358 bool DigitalModule::GetDIODirection(uint32_t channel)
359 {
360  tRioStatusCode localStatus = NiFpga_Status_Success;
361  uint32_t currentOutputEnable = m_fpgaDIO->readOutputEnable(&localStatus);
362  wpi_setError(localStatus);
363 
364  //Shift 00000001 over channel-1 places.
365  //AND it against the currentOutputEnable
366  //if it == 0, then return false
367  //else return true
368  return ((currentOutputEnable >> RemapDigitalChannel(channel - 1)) & 1) != 0;
369 }
370 
377 {
378  tRioStatusCode localStatus = NiFpga_Status_Success;
379  uint32_t currentOutputEnable = m_fpgaDIO->readOutputEnable(&localStatus);
380  wpi_setError(localStatus);
381  return currentOutputEnable;
382 }
383 
391 void DigitalModule::Pulse(uint32_t channel, float pulseLength)
392 {
393  uint16_t mask = 1 << RemapDigitalChannel(channel - 1);
394  tRioStatusCode localStatus = NiFpga_Status_Success;
395  m_fpgaDIO->writePulseLength((uint8_t)(1.0e9 * pulseLength / (m_fpgaDIO->readLoopTiming(&localStatus) * 25)), &localStatus);
396  m_fpgaDIO->writePulse(mask, &localStatus);
397  wpi_setError(localStatus);
398 }
399 
405 bool DigitalModule::IsPulsing(uint32_t channel)
406 {
407  uint16_t mask = 1 << RemapDigitalChannel(channel - 1);
408  tRioStatusCode localStatus = NiFpga_Status_Success;
409  uint16_t pulseRegister = m_fpgaDIO->readPulse(&localStatus);
410  wpi_setError(localStatus);
411  return (pulseRegister & mask) != 0;
412 }
413 
420 {
421  tRioStatusCode localStatus = NiFpga_Status_Success;
422  uint16_t pulseRegister = m_fpgaDIO->readPulse(&localStatus);
423  wpi_setError(localStatus);
424  return pulseRegister != 0;
425 }
426 
434 {
435  char buf[64];
436  snprintf(buf, 64, "DO_PWM (Module: %d)", m_moduleNumber);
437  return DO_PWMGenerators[(m_moduleNumber - 1)]->Allocate(buf);
438 }
439 
445 void DigitalModule::FreeDO_PWM(uint32_t pwmGenerator)
446 {
447  if (pwmGenerator == ~0ul) return;
448  DO_PWMGenerators[(m_moduleNumber - 1)]->Free(pwmGenerator);
449 }
450 
459 {
460  // Currently rounding in the log rate domain... heavy weight toward picking a higher freq.
461  // TODO: Round in the linear rate domain.
462  tRioStatusCode localStatus = NiFpga_Status_Success;
463  uint8_t pwmPeriodPower = (uint8_t)(log(1.0 / (m_fpgaDIO->readLoopTiming(&localStatus) * 0.25E-6 * rate))/log(2.0) + 0.5);
464  m_fpgaDIO->writeDO_PWMConfig_PeriodPower(pwmPeriodPower, &localStatus);
465  wpi_setError(localStatus);
466 }
467 
474 void DigitalModule::SetDO_PWMOutputChannel(uint32_t pwmGenerator, uint32_t channel)
475 {
476  if (pwmGenerator == ~0ul) return;
477  tRioStatusCode localStatus = NiFpga_Status_Success;
478  switch(pwmGenerator)
479  {
480  case 0:
481  m_fpgaDIO->writeDO_PWMConfig_OutputSelect_0(RemapDigitalChannel(channel - 1), &localStatus);
482  break;
483  case 1:
484  m_fpgaDIO->writeDO_PWMConfig_OutputSelect_1(RemapDigitalChannel(channel - 1), &localStatus);
485  break;
486  case 2:
487  m_fpgaDIO->writeDO_PWMConfig_OutputSelect_2(RemapDigitalChannel(channel - 1), &localStatus);
488  break;
489  case 3:
490  m_fpgaDIO->writeDO_PWMConfig_OutputSelect_3(RemapDigitalChannel(channel - 1), &localStatus);
491  break;
492  }
493  wpi_setError(localStatus);
494 }
495 
502 void DigitalModule::SetDO_PWMDutyCycle(uint32_t pwmGenerator, float dutyCycle)
503 {
504  if (pwmGenerator == ~0ul) return;
505  if (dutyCycle > 1.0) dutyCycle = 1.0;
506  if (dutyCycle < 0.0) dutyCycle = 0.0;
507  float rawDutyCycle = 256.0 * dutyCycle;
508  if (rawDutyCycle > 255.5) rawDutyCycle = 255.5;
509  tRioStatusCode localStatus = NiFpga_Status_Success;
510  {
511  Synchronized sync(m_doPwmSemaphore);
512  uint8_t pwmPeriodPower = m_fpgaDIO->readDO_PWMConfig_PeriodPower(&localStatus);
513  if (pwmPeriodPower < 4)
514  {
515  // The resolution of the duty cycle drops close to the highest frequencies.
516  rawDutyCycle = rawDutyCycle / pow(2.0, 4 - pwmPeriodPower);
517  }
518  m_fpgaDIO->writeDO_PWMDutyCycle(pwmGenerator, (uint8_t)rawDutyCycle, &localStatus);
519  }
520  wpi_setError(localStatus);
521 }
522 
529 {
530  tRioStatusCode localStatus = NiFpga_Status_Success;
531  uint16_t timing = m_fpgaDIO->readLoopTiming(&localStatus);
532  wpi_setError(localStatus);
533 
534  return timing;
535 }
536 
544 I2C* DigitalModule::GetI2C(uint32_t address)
545 {
546  return new I2C(this, address);
547 }
548 
549 
void SetRelayReverse(uint32_t channel, bool on)
uint16_t GetLoopTiming()
uint8_t GetPWM(uint32_t channel)
uint8_t GetRelayForward()
void SetDIO(uint32_t channel, short value)
static bool CheckPWMChannel(uint32_t channel)
Definition: SensorBase.cpp:160
void SetRelayForward(uint32_t channel, bool on)
void Pulse(uint32_t channel, float pulseLength)
uint16_t GetDIO()
void SetDO_PWMOutputChannel(uint32_t pwmGenerator, uint32_t channel)
Definition: I2C.h:22
DigitalModule(uint8_t moduleNumber)
void FreeDIO(uint32_t channel)
void SetDO_PWMDutyCycle(uint32_t pwmGenerator, float dutyCycle)
bool AllocateDIO(uint32_t channel, bool input)
static const int32_t kDefaultPwmStepsDown
Definition: PWM.h:75
void Free(uint32_t index)
Definition: Resource.cpp:105
void SetDO_PWMRate(float rate)
uint32_t Allocate(const char *resourceDesc)
Definition: Resource.cpp:62
uint8_t m_moduleNumber
The module index within the module type.
Definition: Module.h:27
uint32_t AllocateDO_PWM()
static constexpr float kDefaultPwmCenter
Definition: PWM.h:71
Definition: Module.h:15
static bool CheckDigitalModule(uint8_t moduleNumber)
Definition: SensorBase.cpp:86
void SetPWM(uint32_t channel, uint8_t value)
static DigitalModule * GetInstance(uint8_t moduleNumber)
static void CreateResourceObject(Resource **r, uint32_t elements)
Definition: Resource.cpp:39
static constexpr float kDefaultPwmPeriod
Definition: PWM.h:67
static Module * GetModule(nLoadOut::tModuleType type, uint8_t number)
Definition: Module.cpp:40
static bool CheckRelayChannel(uint32_t channel)
Definition: SensorBase.cpp:146
I2C * GetI2C(uint32_t address)
void AddToSingletonList()
Definition: SensorBase.cpp:47
uint16_t GetDIODirection()
void SetPWMPeriodScale(uint32_t channel, uint32_t squelchMask)
uint8_t GetRelayReverse()
void FreeDO_PWM(uint32_t pwmGenerator)

Generated on Sat Apr 26 2014 12:26:45 for WPILibC++ by doxygen 1.8.6