WPILibC++  trunk
AnalogModule.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 "AnalogModule.h"
8 #include "Synchronized.h"
9 #include "Timer.h"
10 #include "WPIErrors.h"
11 #include "NetworkCommunication/AICalibration.h"
12 
13 const long AnalogModule::kTimebase;
14 const long AnalogModule::kDefaultOversampleBits;
15 const long AnalogModule::kDefaultAverageBits;
16 constexpr float AnalogModule::kDefaultSampleRate;
17 SEM_ID AnalogModule::m_registerWindowSemaphore = NULL;
18 
29 {
30  if (CheckAnalogModule(moduleNumber))
31  {
32  return (AnalogModule*)GetModule(nLoadOut::kModuleType_Analog, moduleNumber);
33  }
34 
35  // If this wasn't caught before now, make sure we say what's wrong before we crash
36  char buf[64];
37  snprintf(buf, 64, "Analog Module %d", moduleNumber);
38  wpi_setGlobalWPIErrorWithContext(ModuleIndexOutOfRange, buf);
39 
40  return NULL;
41 }
42 
54 AnalogModule::AnalogModule(uint8_t moduleNumber)
55  : Module(nLoadOut::kModuleType_Analog, moduleNumber)
56  , m_module (NULL)
57  , m_sampleRateSet (false)
58  , m_numChannelsToActivate (0)
59 {
61  tRioStatusCode localStatus = NiFpga_Status_Success;
62  m_module = tAI::create(m_moduleNumber - 1, &localStatus);
63  wpi_setError(localStatus);
64  SetNumChannelsToActivate(kAnalogChannels);
65  SetSampleRate(kDefaultSampleRate);
66 
67  for (uint32_t i = 0; i < kAnalogChannels; i++)
68  {
69  m_module->writeScanList(i, i, &localStatus);
70  wpi_setError(localStatus);
71  SetAverageBits(i + 1, kDefaultAverageBits);
72  SetOversampleBits(i + 1, kDefaultOversampleBits);
73  }
74 
75  if (m_registerWindowSemaphore == NULL)
76  {
77  // Needs to be global since the protected resource spans both module singletons.
78  m_registerWindowSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
79  }
80 }
81 
86 {
87  delete m_module;
88 }
89 
97 void AnalogModule::SetSampleRate(float samplesPerSecond)
98 {
99  // TODO: This will change when variable size scan lists are implemented.
100  // TODO: Need float comparison with epsilon.
101  //wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond);
102  m_sampleRateSet = true;
103 
104  // Compute the convert rate
105  uint32_t ticksPerSample = (uint32_t)((float)kTimebase / samplesPerSecond);
106  uint32_t ticksPerConversion = ticksPerSample / GetNumChannelsToActivate();
107  // ticksPerConversion must be at least 80
108  if (ticksPerConversion < 80)
109  {
110  wpi_setWPIError(SampleRateTooHigh);
111  ticksPerConversion = 80;
112  }
113 
114  // Atomically set the scan size and the convert rate so that the sample rate is constant
115  tAI::tConfig config;
116  config.ScanSize = GetNumChannelsToActivate();
117  config.ConvertRate = ticksPerConversion;
118  tRioStatusCode localStatus = NiFpga_Status_Success;
119  m_module->writeConfig(config, &localStatus);
120  wpi_setError(localStatus);
121 
122  // Indicate that the scan size has been commited to hardware.
123  SetNumChannelsToActivate(0);
124 }
125 
135 {
136  tRioStatusCode localStatus = NiFpga_Status_Success;
137  uint32_t ticksPerConversion = m_module->readLoopTiming(&localStatus);
138  wpi_setError(localStatus);
139  uint32_t ticksPerSample = ticksPerConversion * GetNumActiveChannels();
140  return (float)kTimebase / (float)ticksPerSample;
141 }
142 
148 uint32_t AnalogModule::GetNumActiveChannels()
149 {
150  tRioStatusCode localStatus = NiFpga_Status_Success;
151  uint32_t scanSize = m_module->readConfig_ScanSize(&localStatus);
152  wpi_setError(localStatus);
153  if (scanSize == 0)
154  return 8;
155  return scanSize;
156 }
157 
169 uint32_t AnalogModule::GetNumChannelsToActivate()
170 {
171  if(m_numChannelsToActivate == 0) return GetNumActiveChannels();
172  return m_numChannelsToActivate;
173 }
174 
183 void AnalogModule::SetNumChannelsToActivate(uint32_t channels)
184 {
185  m_numChannelsToActivate = channels;
186 }
187 
198 void AnalogModule::SetAverageBits(uint32_t channel, uint32_t bits)
199 {
200  tRioStatusCode localStatus = NiFpga_Status_Success;
201  m_module->writeAverageBits(channel - 1, bits, &localStatus);
202  wpi_setError(localStatus);
203 }
204 
214 uint32_t AnalogModule::GetAverageBits(uint32_t channel)
215 {
216  tRioStatusCode localStatus = NiFpga_Status_Success;
217  uint32_t result = m_module->readAverageBits(channel - 1, &localStatus);
218  wpi_setError(localStatus);
219  return result;
220 }
221 
232 void AnalogModule::SetOversampleBits(uint32_t channel, uint32_t bits)
233 {
234  tRioStatusCode localStatus = NiFpga_Status_Success;
235  m_module->writeOversampleBits(channel - 1, bits, &localStatus);
236  wpi_setError(localStatus);
237 }
238 
248 uint32_t AnalogModule::GetOversampleBits(uint32_t channel)
249 {
250  tRioStatusCode localStatus = NiFpga_Status_Success;
251  uint32_t result = m_module->readOversampleBits(channel - 1, &localStatus);
252  wpi_setError(localStatus);
253  return result;
254 }
255 
264 int16_t AnalogModule::GetValue(uint32_t channel)
265 {
266  int16_t value;
267  CheckAnalogChannel(channel);
268 
269  tAI::tReadSelect readSelect;
270  readSelect.Channel = channel - 1;
271  readSelect.Module = m_moduleNumber - 1;
272  readSelect.Averaged = false;
273  tRioStatusCode localStatus = NiFpga_Status_Success;
274 
275  {
276  Synchronized sync(m_registerWindowSemaphore);
277  m_module->writeReadSelect(readSelect, &localStatus);
278  m_module->strobeLatchOutput(&localStatus);
279  value = (int16_t) m_module->readOutput(&localStatus);
280  }
281 
282  wpi_setError(localStatus);
283  return value;
284 }
285 
298 int32_t AnalogModule::GetAverageValue(uint32_t channel)
299 {
300  int32_t value;
301  CheckAnalogChannel(channel);
302 
303  tAI::tReadSelect readSelect;
304  readSelect.Channel = channel - 1;
305  readSelect.Module = m_moduleNumber - 1;
306  readSelect.Averaged = true;
307  tRioStatusCode localStatus = NiFpga_Status_Success;
308 
309  {
310  Synchronized sync(m_registerWindowSemaphore);
311  m_module->writeReadSelect(readSelect, &localStatus);
312  m_module->strobeLatchOutput(&localStatus);
313  value = m_module->readOutput(&localStatus);
314  }
315 
316  wpi_setError(localStatus);
317  return value;
318 }
319 
332 int32_t AnalogModule::VoltsToValue(int32_t channel, float voltage)
333 {
334  if (voltage > 10.0)
335  {
336  voltage = 10.0;
337  wpi_setWPIError(VoltageOutOfRange);
338  }
339  if (voltage < -10.0)
340  {
341  voltage = -10.0;
342  wpi_setWPIError(VoltageOutOfRange);
343  }
344  uint32_t LSBWeight = GetLSBWeight(channel);
345  int32_t offset = GetOffset(channel);
346  int32_t value = (int32_t) ((voltage + offset * 1.0e-9) / (LSBWeight * 1.0e-9));
347  return value;
348 }
349 
358 float AnalogModule::GetVoltage(uint32_t channel)
359 {
360  int16_t value = GetValue(channel);
361  uint32_t LSBWeight = GetLSBWeight(channel);
362  int32_t offset = GetOffset(channel);
363  float voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
364  return voltage;
365 }
366 
377 float AnalogModule::GetAverageVoltage(uint32_t channel)
378 {
379  int32_t value = GetAverageValue(channel);
380  uint32_t LSBWeight = GetLSBWeight(channel);
381  int32_t offset = GetOffset(channel);
382  uint32_t oversampleBits = GetOversampleBits(channel);
383  float voltage = ((LSBWeight * 1.0e-9 * value) / (float)(1 << oversampleBits)) - offset * 1.0e-9;
384  return voltage;
385 }
386 
397 uint32_t AnalogModule::GetLSBWeight(uint32_t channel)
398 {
399  tRioStatusCode localStatus = NiFpga_Status_Success;
400  uint32_t lsbWeight = FRC_NetworkCommunication_nAICalibration_getLSBWeight(m_module->getSystemIndex(), channel - 1, (int32_t*)&localStatus);
401  wpi_setError(localStatus);
402  return lsbWeight;
403 }
404 
415 int32_t AnalogModule::GetOffset(uint32_t channel)
416 {
417  tRioStatusCode localStatus = NiFpga_Status_Success;
418  int32_t offset = FRC_NetworkCommunication_nAICalibration_getOffset(m_module->getSystemIndex(), channel - 1, (int32_t*)&localStatus);
419  wpi_setError(localStatus);
420  return offset;
421 }
422 
423 
static bool CheckAnalogModule(uint8_t moduleNumber)
Definition: SensorBase.cpp:74
int32_t GetOffset(uint32_t channel)
static const long kTimebase
40 MHz clock
Definition: AnalogModule.h:25
AnalogModule(uint8_t moduleNumber)
void SetSampleRate(float samplesPerSecond)
static AnalogModule * GetInstance(uint8_t moduleNumber)
void SetOversampleBits(uint32_t channel, uint32_t bits)
int16_t GetValue(uint32_t channel)
float GetAverageVoltage(uint32_t channel)
uint8_t m_moduleNumber
The module index within the module type.
Definition: Module.h:27
uint32_t GetLSBWeight(uint32_t channel)
uint32_t GetOversampleBits(uint32_t channel)
void SetAverageBits(uint32_t channel, uint32_t bits)
Definition: Module.h:15
virtual ~AnalogModule()
static Module * GetModule(nLoadOut::tModuleType type, uint8_t number)
Definition: Module.cpp:40
int32_t VoltsToValue(int32_t channel, float voltage)
float GetSampleRate()
void AddToSingletonList()
Definition: SensorBase.cpp:47
int32_t GetAverageValue(uint32_t channel)
uint32_t GetAverageBits(uint32_t channel)
float GetVoltage(uint32_t channel)
static bool CheckAnalogChannel(uint32_t channel)
Definition: SensorBase.cpp:174