blob: 68e794078ee97774e59292c058cb605b1c343bff [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001/*----------------------------------------------------------------------------*/
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
13const long AnalogModule::kTimebase; ///< 40 MHz clock
14const long AnalogModule::kDefaultOversampleBits;
15const long AnalogModule::kDefaultAverageBits;
16const float AnalogModule::kDefaultSampleRate;
Brian Silvermanf2375392013-04-14 21:12:33 -070017// Needs to be global since the protected resource spans both module singletons.
18ReentrantSemaphore AnalogModule::m_registerWindowSemaphore;
brians343bc112013-02-10 01:53:46 +000019
20/**
21 * Get an instance of an Analog Module.
22 *
23 * Singleton analog module creation where a module is allocated on the first use
24 * and the same module is returned on subsequent uses.
25 *
26 * @param moduleNumber The analog module to get (1 or 2).
27 * @return A pointer to the AnalogModule.
28 */
29AnalogModule* AnalogModule::GetInstance(UINT8 moduleNumber)
30{
31 if (CheckAnalogModule(moduleNumber))
32 {
33 return (AnalogModule*)GetModule(nLoadOut::kModuleType_Analog, moduleNumber);
34 }
35
36 // If this wasn't caught before now, make sure we say what's wrong before we crash
37 char buf[64];
38 snprintf(buf, 64, "Analog Module %d", moduleNumber);
39 wpi_setGlobalWPIErrorWithContext(ModuleIndexOutOfRange, buf);
40
41 return NULL;
42}
43
44/**
45 * Create a new instance of an analog module.
46 *
47 * Create an instance of the analog module object. Initialize all the parameters
48 * to reasonable values on start.
49 * Setting a global value on an analog module can be done only once unless subsequent
50 * values are set the previously set value.
51 * Analog modules are a singleton, so the constructor is never called outside of this class.
52 *
53 * @param moduleNumber The analog module to create (1 or 2).
54 */
55AnalogModule::AnalogModule(UINT8 moduleNumber)
56 : Module(nLoadOut::kModuleType_Analog, moduleNumber)
57 , m_module (NULL)
58 , m_sampleRateSet (false)
59 , m_numChannelsToActivate (0)
60{
61 AddToSingletonList();
62 tRioStatusCode localStatus = NiFpga_Status_Success;
63 m_module = tAI::create(m_moduleNumber - 1, &localStatus);
64 wpi_setError(localStatus);
65 SetNumChannelsToActivate(kAnalogChannels);
66 SetSampleRate(kDefaultSampleRate);
67
68 for (UINT32 i = 0; i < kAnalogChannels; i++)
69 {
70 m_module->writeScanList(i, i, &localStatus);
71 wpi_setError(localStatus);
72 SetAverageBits(i + 1, kDefaultAverageBits);
73 SetOversampleBits(i + 1, kDefaultOversampleBits);
74 }
brians343bc112013-02-10 01:53:46 +000075}
76
77/**
78 * Destructor for AnalogModule.
79 */
80AnalogModule::~AnalogModule()
81{
82 delete m_module;
83}
84
85/**
86 * Set the sample rate on the module.
87 *
88 * This is a global setting for the module and effects all channels.
89 *
90 * @param samplesPerSecond The number of samples per channel per second.
91 */
92void AnalogModule::SetSampleRate(float samplesPerSecond)
93{
94 // TODO: This will change when variable size scan lists are implemented.
95 // TODO: Need float comparison with epsilon.
96 //wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond);
97 m_sampleRateSet = true;
98
99 // Compute the convert rate
100 UINT32 ticksPerSample = (UINT32)((float)kTimebase / samplesPerSecond);
101 UINT32 ticksPerConversion = ticksPerSample / GetNumChannelsToActivate();
102 // ticksPerConversion must be at least 80
103 if (ticksPerConversion < 80)
104 {
105 wpi_setWPIError(SampleRateTooHigh);
106 ticksPerConversion = 80;
107 }
108
109 // Atomically set the scan size and the convert rate so that the sample rate is constant
110 tAI::tConfig config;
111 config.ScanSize = GetNumChannelsToActivate();
112 config.ConvertRate = ticksPerConversion;
113 tRioStatusCode localStatus = NiFpga_Status_Success;
114 m_module->writeConfig(config, &localStatus);
115 wpi_setError(localStatus);
116
117 // Indicate that the scan size has been commited to hardware.
118 SetNumChannelsToActivate(0);
119}
120
121/**
122 * Get the current sample rate on the module.
123 *
124 * This assumes one entry in the scan list.
125 * This is a global setting for the module and effects all channels.
126 *
127 * @return Sample rate.
128 */
129float AnalogModule::GetSampleRate()
130{
131 tRioStatusCode localStatus = NiFpga_Status_Success;
132 UINT32 ticksPerConversion = m_module->readLoopTiming(&localStatus);
133 wpi_setError(localStatus);
134 UINT32 ticksPerSample = ticksPerConversion * GetNumActiveChannels();
135 return (float)kTimebase / (float)ticksPerSample;
136}
137
138/**
139 * Return the number of channels on the module in use.
140 *
141 * @return Active channels.
142 */
143UINT32 AnalogModule::GetNumActiveChannels()
144{
145 tRioStatusCode localStatus = NiFpga_Status_Success;
146 UINT32 scanSize = m_module->readConfig_ScanSize(&localStatus);
147 wpi_setError(localStatus);
148 if (scanSize == 0)
149 return 8;
150 return scanSize;
151}
152
153/**
154 * Get the number of active channels.
155 *
156 * This is an internal function to allow the atomic update of both the
157 * number of active channels and the sample rate.
158 *
159 * When the number of channels changes, use the new value. Otherwise,
160 * return the curent value.
161 *
162 * @return Value to write to the active channels field.
163 */
164UINT32 AnalogModule::GetNumChannelsToActivate()
165{
166 if(m_numChannelsToActivate == 0) return GetNumActiveChannels();
167 return m_numChannelsToActivate;
168}
169
170/**
171 * Set the number of active channels.
172 *
173 * Store the number of active channels to set. Don't actually commit to hardware
174 * until SetSampleRate().
175 *
176 * @param channels Number of active channels.
177 */
178void AnalogModule::SetNumChannelsToActivate(UINT32 channels)
179{
180 m_numChannelsToActivate = channels;
181}
182
183/**
184 * Set the number of averaging bits.
185 *
186 * This sets the number of averaging bits. The actual number of averaged samples is 2**bits.
187 * Use averaging to improve the stability of your measurement at the expense of sampling rate.
188 * The averaging is done automatically in the FPGA.
189 *
190 * @param channel Analog channel to configure.
191 * @param bits Number of bits to average.
192 */
193void AnalogModule::SetAverageBits(UINT32 channel, UINT32 bits)
194{
195 tRioStatusCode localStatus = NiFpga_Status_Success;
196 m_module->writeAverageBits(channel - 1, bits, &localStatus);
197 wpi_setError(localStatus);
198}
199
200/**
201 * Get the number of averaging bits.
202 *
203 * This gets the number of averaging bits from the FPGA. The actual number of averaged samples is 2**bits.
204 * The averaging is done automatically in the FPGA.
205 *
206 * @param channel Channel to address.
207 * @return Bits to average.
208 */
209UINT32 AnalogModule::GetAverageBits(UINT32 channel)
210{
211 tRioStatusCode localStatus = NiFpga_Status_Success;
212 UINT32 result = m_module->readAverageBits(channel - 1, &localStatus);
213 wpi_setError(localStatus);
214 return result;
215}
216
217/**
218 * Set the number of oversample bits.
219 *
220 * This sets the number of oversample bits. The actual number of oversampled values is 2**bits.
221 * Use oversampling to improve the resolution of your measurements at the expense of sampling rate.
222 * The oversampling is done automatically in the FPGA.
223 *
224 * @param channel Analog channel to configure.
225 * @param bits Number of bits to oversample.
226 */
227void AnalogModule::SetOversampleBits(UINT32 channel, UINT32 bits)
228{
229 tRioStatusCode localStatus = NiFpga_Status_Success;
230 m_module->writeOversampleBits(channel - 1, bits, &localStatus);
231 wpi_setError(localStatus);
232}
233
234/**
235 * Get the number of oversample bits.
236 *
237 * This gets the number of oversample bits from the FPGA. The actual number of oversampled values is
238 * 2**bits. The oversampling is done automatically in the FPGA.
239 *
240 * @param channel Channel to address.
241 * @return Bits to oversample.
242 */
243UINT32 AnalogModule::GetOversampleBits(UINT32 channel)
244{
245 tRioStatusCode localStatus = NiFpga_Status_Success;
246 UINT32 result = m_module->readOversampleBits(channel - 1, &localStatus);
247 wpi_setError(localStatus);
248 return result;
249}
250
251/**
252 * Get a sample straight from the channel on this module.
253 *
254 * The sample is a 12-bit value representing the -10V to 10V range of the A/D converter in the module.
255 * The units are in A/D converter codes. Use GetVoltage() to get the analog value in calibrated units.
256 *
257 * @return A sample straight from the channel on this module.
258 */
259INT16 AnalogModule::GetValue(UINT32 channel)
260{
261 INT16 value;
262 CheckAnalogChannel(channel);
263
264 tAI::tReadSelect readSelect;
265 readSelect.Channel = channel - 1;
266 readSelect.Module = m_moduleNumber - 1;
267 readSelect.Averaged = false;
268 tRioStatusCode localStatus = NiFpga_Status_Success;
269
270 {
271 Synchronized sync(m_registerWindowSemaphore);
272 m_module->writeReadSelect(readSelect, &localStatus);
273 m_module->strobeLatchOutput(&localStatus);
274 value = (INT16) m_module->readOutput(&localStatus);
275 }
276
277 wpi_setError(localStatus);
278 return value;
279}
280
281/**
282 * Get a sample from the output of the oversample and average engine for the channel.
283 *
284 * The sample is 12-bit + the value configured in SetOversampleBits().
285 * The value configured in SetAverageBits() will cause this value to be averaged 2**bits number of samples.
286 * This is not a sliding window. The sample will not change until 2**(OversamplBits + AverageBits) samples
287 * have been acquired from the module on this channel.
288 * Use GetAverageVoltage() to get the analog value in calibrated units.
289 *
290 * @param channel Channel number to read.
291 * @return A sample from the oversample and average engine for the channel.
292 */
293INT32 AnalogModule::GetAverageValue(UINT32 channel)
294{
295 INT32 value;
296 CheckAnalogChannel(channel);
297
298 tAI::tReadSelect readSelect;
299 readSelect.Channel = channel - 1;
300 readSelect.Module = m_moduleNumber - 1;
301 readSelect.Averaged = true;
302 tRioStatusCode localStatus = NiFpga_Status_Success;
303
304 {
305 Synchronized sync(m_registerWindowSemaphore);
306 m_module->writeReadSelect(readSelect, &localStatus);
307 m_module->strobeLatchOutput(&localStatus);
308 value = m_module->readOutput(&localStatus);
309 }
310
311 wpi_setError(localStatus);
312 return value;
313}
314
315/**
316 * Convert a voltage to a raw value for a specified channel.
317 *
318 * This process depends on the calibration of each channel, so the channel
319 * must be specified.
320 *
321 * @todo This assumes raw values. Oversampling not supported as is.
322 *
323 * @param channel The channel to convert for.
324 * @param voltage The voltage to convert.
325 * @return The raw value for the channel.
326 */
327INT32 AnalogModule::VoltsToValue(INT32 channel, float voltage)
328{
329 if (voltage > 10.0)
330 {
331 voltage = 10.0;
332 wpi_setWPIError(VoltageOutOfRange);
333 }
334 if (voltage < -10.0)
335 {
336 voltage = -10.0;
337 wpi_setWPIError(VoltageOutOfRange);
338 }
339 UINT32 LSBWeight = GetLSBWeight(channel);
340 INT32 offset = GetOffset(channel);
341 INT32 value = (INT32) ((voltage + offset * 1.0e-9) / (LSBWeight * 1.0e-9));
342 return value;
343}
344
345/**
346 * Get a scaled sample straight from the channel on this module.
347 *
348 * The value is scaled to units of Volts using the calibrated scaling data from GetLSBWeight() and GetOffset().
349 *
350 * @param channel The channel to read.
351 * @return A scaled sample straight from the channel on this module.
352 */
353float AnalogModule::GetVoltage(UINT32 channel)
354{
355 INT16 value = GetValue(channel);
356 UINT32 LSBWeight = GetLSBWeight(channel);
357 INT32 offset = GetOffset(channel);
358 float voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
359 return voltage;
360}
361
362/**
363 * Get a scaled sample from the output of the oversample and average engine for the channel.
364 *
365 * The value is scaled to units of Volts using the calibrated scaling data from GetLSBWeight() and GetOffset().
366 * Using oversampling will cause this value to be higher resolution, but it will update more slowly.
367 * Using averaging will cause this value to be more stable, but it will update more slowly.
368 *
369 * @param channel The channel to read.
370 * @return A scaled sample from the output of the oversample and average engine for the channel.
371 */
372float AnalogModule::GetAverageVoltage(UINT32 channel)
373{
374 INT32 value = GetAverageValue(channel);
375 UINT32 LSBWeight = GetLSBWeight(channel);
376 INT32 offset = GetOffset(channel);
377 UINT32 oversampleBits = GetOversampleBits(channel);
378 float voltage = ((LSBWeight * 1.0e-9 * value) / (float)(1 << oversampleBits)) - offset * 1.0e-9;
379 return voltage;
380}
381
382/**
383 * Get the factory scaling least significant bit weight constant.
384 * The least significant bit weight constant for the channel that was calibrated in
385 * manufacturing and stored in an eeprom in the module.
386 *
387 * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
388 *
389 * @param channel The channel to get calibration data for.
390 * @return Least significant bit weight.
391 */
392UINT32 AnalogModule::GetLSBWeight(UINT32 channel)
393{
394 tRioStatusCode localStatus = NiFpga_Status_Success;
395 UINT32 lsbWeight = FRC_NetworkCommunication_nAICalibration_getLSBWeight(m_module->getSystemIndex(), channel - 1, (INT32*)&localStatus);
396 wpi_setError(localStatus);
397 return lsbWeight;
398}
399
400/**
401 * Get the factory scaling offset constant.
402 * The offset constant for the channel that was calibrated in manufacturing and stored
403 * in an eeprom in the module.
404 *
405 * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
406 *
407 * @param channel The channel to get calibration data for.
408 * @return Offset constant.
409 */
410INT32 AnalogModule::GetOffset(UINT32 channel)
411{
412 tRioStatusCode localStatus = NiFpga_Status_Success;
413 INT32 offset = FRC_NetworkCommunication_nAICalibration_getOffset(m_module->getSystemIndex(), channel - 1, (INT32*)&localStatus);
414 wpi_setError(localStatus);
415 return offset;
416}
417
418