blob: ac3548720478d58a1c70d8ac8cb1069a20a029c4 [file] [log] [blame]
jerrymf1579332013-02-07 01:56:28 +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;
17SEM_ID AnalogModule::m_registerWindowSemaphore = NULL;
18
19/**
20 * Get an instance of an Analog Module.
21 *
22 * Singleton analog module creation where a module is allocated on the first use
23 * and the same module is returned on subsequent uses.
24 *
25 * @param moduleNumber The analog module to get (1 or 2).
26 * @return A pointer to the AnalogModule.
27 */
28AnalogModule* AnalogModule::GetInstance(UINT8 moduleNumber)
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
43/**
44 * Create a new instance of an analog module.
45 *
46 * Create an instance of the analog module object. Initialize all the parameters
47 * to reasonable values on start.
48 * Setting a global value on an analog module can be done only once unless subsequent
49 * values are set the previously set value.
50 * Analog modules are a singleton, so the constructor is never called outside of this class.
51 *
52 * @param moduleNumber The analog module to create (1 or 2).
53 */
54AnalogModule::AnalogModule(UINT8 moduleNumber)
55 : Module(nLoadOut::kModuleType_Analog, moduleNumber)
56 , m_module (NULL)
57 , m_sampleRateSet (false)
58 , m_numChannelsToActivate (0)
59{
60 AddToSingletonList();
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 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
82/**
83 * Destructor for AnalogModule.
84 */
85AnalogModule::~AnalogModule()
86{
87 delete m_module;
88}
89
90/**
91 * Set the sample rate on the module.
92 *
93 * This is a global setting for the module and effects all channels.
94 *
95 * @param samplesPerSecond The number of samples per channel per second.
96 */
97void 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 ticksPerSample = (UINT32)((float)kTimebase / samplesPerSecond);
106 UINT32 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
126/**
127 * Get the current sample rate on the module.
128 *
129 * This assumes one entry in the scan list.
130 * This is a global setting for the module and effects all channels.
131 *
132 * @return Sample rate.
133 */
134float AnalogModule::GetSampleRate()
135{
136 tRioStatusCode localStatus = NiFpga_Status_Success;
137 UINT32 ticksPerConversion = m_module->readLoopTiming(&localStatus);
138 wpi_setError(localStatus);
139 UINT32 ticksPerSample = ticksPerConversion * GetNumActiveChannels();
140 return (float)kTimebase / (float)ticksPerSample;
141}
142
143/**
144 * Return the number of channels on the module in use.
145 *
146 * @return Active channels.
147 */
148UINT32 AnalogModule::GetNumActiveChannels()
149{
150 tRioStatusCode localStatus = NiFpga_Status_Success;
151 UINT32 scanSize = m_module->readConfig_ScanSize(&localStatus);
152 wpi_setError(localStatus);
153 if (scanSize == 0)
154 return 8;
155 return scanSize;
156}
157
158/**
159 * Get the number of active channels.
160 *
161 * This is an internal function to allow the atomic update of both the
162 * number of active channels and the sample rate.
163 *
164 * When the number of channels changes, use the new value. Otherwise,
165 * return the curent value.
166 *
167 * @return Value to write to the active channels field.
168 */
169UINT32 AnalogModule::GetNumChannelsToActivate()
170{
171 if(m_numChannelsToActivate == 0) return GetNumActiveChannels();
172 return m_numChannelsToActivate;
173}
174
175/**
176 * Set the number of active channels.
177 *
178 * Store the number of active channels to set. Don't actually commit to hardware
179 * until SetSampleRate().
180 *
181 * @param channels Number of active channels.
182 */
183void AnalogModule::SetNumChannelsToActivate(UINT32 channels)
184{
185 m_numChannelsToActivate = channels;
186}
187
188/**
189 * Set the number of averaging bits.
190 *
191 * This sets the number of averaging bits. The actual number of averaged samples is 2**bits.
192 * Use averaging to improve the stability of your measurement at the expense of sampling rate.
193 * The averaging is done automatically in the FPGA.
194 *
195 * @param channel Analog channel to configure.
196 * @param bits Number of bits to average.
197 */
198void AnalogModule::SetAverageBits(UINT32 channel, UINT32 bits)
199{
200 tRioStatusCode localStatus = NiFpga_Status_Success;
201 m_module->writeAverageBits(channel - 1, bits, &localStatus);
202 wpi_setError(localStatus);
203}
204
205/**
206 * Get the number of averaging bits.
207 *
208 * This gets the number of averaging bits from the FPGA. The actual number of averaged samples is 2**bits.
209 * The averaging is done automatically in the FPGA.
210 *
211 * @param channel Channel to address.
212 * @return Bits to average.
213 */
214UINT32 AnalogModule::GetAverageBits(UINT32 channel)
215{
216 tRioStatusCode localStatus = NiFpga_Status_Success;
217 UINT32 result = m_module->readAverageBits(channel - 1, &localStatus);
218 wpi_setError(localStatus);
219 return result;
220}
221
222/**
223 * Set the number of oversample bits.
224 *
225 * This sets the number of oversample bits. The actual number of oversampled values is 2**bits.
226 * Use oversampling to improve the resolution of your measurements at the expense of sampling rate.
227 * The oversampling is done automatically in the FPGA.
228 *
229 * @param channel Analog channel to configure.
230 * @param bits Number of bits to oversample.
231 */
232void AnalogModule::SetOversampleBits(UINT32 channel, UINT32 bits)
233{
234 tRioStatusCode localStatus = NiFpga_Status_Success;
235 m_module->writeOversampleBits(channel - 1, bits, &localStatus);
236 wpi_setError(localStatus);
237}
238
239/**
240 * Get the number of oversample bits.
241 *
242 * This gets the number of oversample bits from the FPGA. The actual number of oversampled values is
243 * 2**bits. The oversampling is done automatically in the FPGA.
244 *
245 * @param channel Channel to address.
246 * @return Bits to oversample.
247 */
248UINT32 AnalogModule::GetOversampleBits(UINT32 channel)
249{
250 tRioStatusCode localStatus = NiFpga_Status_Success;
251 UINT32 result = m_module->readOversampleBits(channel - 1, &localStatus);
252 wpi_setError(localStatus);
253 return result;
254}
255
256/**
257 * Get a sample straight from the channel on this module.
258 *
259 * The sample is a 12-bit value representing the -10V to 10V range of the A/D converter in the module.
260 * The units are in A/D converter codes. Use GetVoltage() to get the analog value in calibrated units.
261 *
262 * @return A sample straight from the channel on this module.
263 */
264INT16 AnalogModule::GetValue(UINT32 channel)
265{
266 INT16 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) m_module->readOutput(&localStatus);
280 }
281
282 wpi_setError(localStatus);
283 return value;
284}
285
286/**
287 * Get a sample from the output of the oversample and average engine for the channel.
288 *
289 * The sample is 12-bit + the value configured in SetOversampleBits().
290 * The value configured in SetAverageBits() will cause this value to be averaged 2**bits number of samples.
291 * This is not a sliding window. The sample will not change until 2**(OversamplBits + AverageBits) samples
292 * have been acquired from the module on this channel.
293 * Use GetAverageVoltage() to get the analog value in calibrated units.
294 *
295 * @param channel Channel number to read.
296 * @return A sample from the oversample and average engine for the channel.
297 */
298INT32 AnalogModule::GetAverageValue(UINT32 channel)
299{
300 INT32 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
320/**
321 * Convert a voltage to a raw value for a specified channel.
322 *
323 * This process depends on the calibration of each channel, so the channel
324 * must be specified.
325 *
326 * @todo This assumes raw values. Oversampling not supported as is.
327 *
328 * @param channel The channel to convert for.
329 * @param voltage The voltage to convert.
330 * @return The raw value for the channel.
331 */
332INT32 AnalogModule::VoltsToValue(INT32 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 LSBWeight = GetLSBWeight(channel);
345 INT32 offset = GetOffset(channel);
346 INT32 value = (INT32) ((voltage + offset * 1.0e-9) / (LSBWeight * 1.0e-9));
347 return value;
348}
349
350/**
351 * Get a scaled sample straight from the channel on this module.
352 *
353 * The value is scaled to units of Volts using the calibrated scaling data from GetLSBWeight() and GetOffset().
354 *
355 * @param channel The channel to read.
356 * @return A scaled sample straight from the channel on this module.
357 */
358float AnalogModule::GetVoltage(UINT32 channel)
359{
360 INT16 value = GetValue(channel);
361 UINT32 LSBWeight = GetLSBWeight(channel);
362 INT32 offset = GetOffset(channel);
363 float voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
364 return voltage;
365}
366
367/**
368 * Get a scaled sample from the output of the oversample and average engine for the channel.
369 *
370 * The value is scaled to units of Volts using the calibrated scaling data from GetLSBWeight() and GetOffset().
371 * Using oversampling will cause this value to be higher resolution, but it will update more slowly.
372 * Using averaging will cause this value to be more stable, but it will update more slowly.
373 *
374 * @param channel The channel to read.
375 * @return A scaled sample from the output of the oversample and average engine for the channel.
376 */
377float AnalogModule::GetAverageVoltage(UINT32 channel)
378{
379 INT32 value = GetAverageValue(channel);
380 UINT32 LSBWeight = GetLSBWeight(channel);
381 INT32 offset = GetOffset(channel);
382 UINT32 oversampleBits = GetOversampleBits(channel);
383 float voltage = ((LSBWeight * 1.0e-9 * value) / (float)(1 << oversampleBits)) - offset * 1.0e-9;
384 return voltage;
385}
386
387/**
388 * Get the factory scaling least significant bit weight constant.
389 * The least significant bit weight constant for the channel that was calibrated in
390 * manufacturing and stored in an eeprom in the module.
391 *
392 * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
393 *
394 * @param channel The channel to get calibration data for.
395 * @return Least significant bit weight.
396 */
397UINT32 AnalogModule::GetLSBWeight(UINT32 channel)
398{
399 tRioStatusCode localStatus = NiFpga_Status_Success;
400 UINT32 lsbWeight = FRC_NetworkCommunication_nAICalibration_getLSBWeight(m_module->getSystemIndex(), channel - 1, (INT32*)&localStatus);
401 wpi_setError(localStatus);
402 return lsbWeight;
403}
404
405/**
406 * Get the factory scaling offset constant.
407 * The offset constant for the channel that was calibrated in manufacturing and stored
408 * in an eeprom in the module.
409 *
410 * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
411 *
412 * @param channel The channel to get calibration data for.
413 * @return Offset constant.
414 */
415INT32 AnalogModule::GetOffset(UINT32 channel)
416{
417 tRioStatusCode localStatus = NiFpga_Status_Success;
418 INT32 offset = FRC_NetworkCommunication_nAICalibration_getOffset(m_module->getSystemIndex(), channel - 1, (INT32*)&localStatus);
419 wpi_setError(localStatus);
420 return offset;
421}
422
423