jerrym | f157933 | 2013-02-07 01:56:28 +0000 | [diff] [blame^] | 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 "AnalogChannel.h"
|
| 8 | #include "AnalogModule.h"
|
| 9 | #include "NetworkCommunication/UsageReporting.h"
|
| 10 | #include "Resource.h"
|
| 11 | #include "WPIErrors.h"
|
| 12 | #include "LiveWindow/LiveWindow.h"
|
| 13 |
|
| 14 | static Resource *channels = NULL;
|
| 15 |
|
| 16 | const UINT8 AnalogChannel::kAccumulatorModuleNumber;
|
| 17 | const UINT32 AnalogChannel::kAccumulatorNumChannels;
|
| 18 | const UINT32 AnalogChannel::kAccumulatorChannels[] = {1, 2};
|
| 19 |
|
| 20 | /**
|
| 21 | * Common initialization.
|
| 22 | */
|
| 23 | void AnalogChannel::InitChannel(UINT8 moduleNumber, UINT32 channel)
|
| 24 | {
|
| 25 | char buf[64];
|
| 26 | Resource::CreateResourceObject(&channels, kAnalogModules * kAnalogChannels);
|
| 27 | if (!CheckAnalogModule(moduleNumber))
|
| 28 | {
|
| 29 | snprintf(buf, 64, "Analog Module %d", moduleNumber);
|
| 30 | wpi_setWPIErrorWithContext(ModuleIndexOutOfRange, buf);
|
| 31 | return;
|
| 32 | }
|
| 33 | if (!CheckAnalogChannel(channel))
|
| 34 | {
|
| 35 | snprintf(buf, 64, "Analog Channel %d", channel);
|
| 36 | wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf);
|
| 37 | return;
|
| 38 | }
|
| 39 |
|
| 40 | snprintf(buf, 64, "Analog Input %d (Module: %d)", channel, moduleNumber);
|
| 41 | if (channels->Allocate((moduleNumber - 1) * kAnalogChannels + channel - 1, buf) == ~0ul)
|
| 42 | {
|
| 43 | CloneError(channels);
|
| 44 | return;
|
| 45 | }
|
| 46 | m_channel = channel;
|
| 47 | m_module = AnalogModule::GetInstance(moduleNumber);
|
| 48 | if (IsAccumulatorChannel())
|
| 49 | {
|
| 50 | tRioStatusCode localStatus = NiFpga_Status_Success;
|
| 51 | m_accumulator = tAccumulator::create(channel - 1, &localStatus);
|
| 52 | wpi_setError(localStatus);
|
| 53 | m_accumulatorOffset=0;
|
| 54 | }
|
| 55 | else
|
| 56 | {
|
| 57 | m_accumulator = NULL;
|
| 58 | }
|
| 59 | LiveWindow::GetInstance()->AddActuator("AnalogChannel",channel, GetModuleNumber(), this);
|
| 60 | nUsageReporting::report(nUsageReporting::kResourceType_AnalogChannel, channel, GetModuleNumber() - 1);
|
| 61 | }
|
| 62 |
|
| 63 | /**
|
| 64 | * Construct an analog channel on a specified module.
|
| 65 | *
|
| 66 | * @param moduleNumber The analog module (1 or 2).
|
| 67 | * @param channel The channel number to represent.
|
| 68 | */
|
| 69 | AnalogChannel::AnalogChannel(UINT8 moduleNumber, UINT32 channel)
|
| 70 | {
|
| 71 | InitChannel(moduleNumber, channel);
|
| 72 | }
|
| 73 |
|
| 74 | /**
|
| 75 | * Construct an analog channel on the default module.
|
| 76 | *
|
| 77 | * @param channel The channel number to represent.
|
| 78 | */
|
| 79 | AnalogChannel::AnalogChannel(UINT32 channel)
|
| 80 | {
|
| 81 | InitChannel(GetDefaultAnalogModule(), channel);
|
| 82 | }
|
| 83 |
|
| 84 | /**
|
| 85 | * Channel destructor.
|
| 86 | */
|
| 87 | AnalogChannel::~AnalogChannel()
|
| 88 | {
|
| 89 | channels->Free((m_module->GetNumber() - 1) * kAnalogChannels + m_channel - 1);
|
| 90 | }
|
| 91 |
|
| 92 | /**
|
| 93 | * Get the analog module that this channel is on.
|
| 94 | * @return A pointer to the AnalogModule that this channel is on.
|
| 95 | */
|
| 96 | AnalogModule *AnalogChannel::GetModule()
|
| 97 | {
|
| 98 | if (StatusIsFatal()) return NULL;
|
| 99 | return m_module;
|
| 100 | }
|
| 101 |
|
| 102 | /**
|
| 103 | * Get a sample straight from this channel on the module.
|
| 104 | * The sample is a 12-bit value representing the -10V to 10V range of the A/D converter in the module.
|
| 105 | * The units are in A/D converter codes. Use GetVoltage() to get the analog value in calibrated units.
|
| 106 | * @return A sample straight from this channel on the module.
|
| 107 | */
|
| 108 | INT16 AnalogChannel::GetValue()
|
| 109 | {
|
| 110 | if (StatusIsFatal()) return 0;
|
| 111 | return m_module->GetValue(m_channel);
|
| 112 | }
|
| 113 |
|
| 114 | /**
|
| 115 | * Get a sample from the output of the oversample and average engine for this channel.
|
| 116 | * The sample is 12-bit + the value configured in SetOversampleBits().
|
| 117 | * The value configured in SetAverageBits() will cause this value to be averaged 2**bits number of samples.
|
| 118 | * This is not a sliding window. The sample will not change until 2**(OversamplBits + AverageBits) samples
|
| 119 | * have been acquired from the module on this channel.
|
| 120 | * Use GetAverageVoltage() to get the analog value in calibrated units.
|
| 121 | * @return A sample from the oversample and average engine for this channel.
|
| 122 | */
|
| 123 | INT32 AnalogChannel::GetAverageValue()
|
| 124 | {
|
| 125 | if (StatusIsFatal()) return 0;
|
| 126 | return m_module->GetAverageValue(m_channel);
|
| 127 | }
|
| 128 |
|
| 129 | /**
|
| 130 | * Get a scaled sample straight from this channel on the module.
|
| 131 | * The value is scaled to units of Volts using the calibrated scaling data from GetLSBWeight() and GetOffset().
|
| 132 | * @return A scaled sample straight from this channel on the module.
|
| 133 | */
|
| 134 | float AnalogChannel::GetVoltage()
|
| 135 | {
|
| 136 | if (StatusIsFatal()) return 0.0f;
|
| 137 | return m_module->GetVoltage(m_channel);
|
| 138 | }
|
| 139 |
|
| 140 | /**
|
| 141 | * Get a scaled sample from the output of the oversample and average engine for this channel.
|
| 142 | * The value is scaled to units of Volts using the calibrated scaling data from GetLSBWeight() and GetOffset().
|
| 143 | * Using oversampling will cause this value to be higher resolution, but it will update more slowly.
|
| 144 | * Using averaging will cause this value to be more stable, but it will update more slowly.
|
| 145 | * @return A scaled sample from the output of the oversample and average engine for this channel.
|
| 146 | */
|
| 147 | float AnalogChannel::GetAverageVoltage()
|
| 148 | {
|
| 149 | if (StatusIsFatal()) return 0.0f;
|
| 150 | return m_module->GetAverageVoltage(m_channel);
|
| 151 | }
|
| 152 |
|
| 153 | /**
|
| 154 | * Get the factory scaling least significant bit weight constant.
|
| 155 | * The least significant bit weight constant for the channel that was calibrated in
|
| 156 | * manufacturing and stored in an eeprom in the module.
|
| 157 | *
|
| 158 | * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
|
| 159 | *
|
| 160 | * @return Least significant bit weight.
|
| 161 | */
|
| 162 | UINT32 AnalogChannel::GetLSBWeight()
|
| 163 | {
|
| 164 | if (StatusIsFatal()) return 0;
|
| 165 | return m_module->GetLSBWeight(m_channel);
|
| 166 | }
|
| 167 |
|
| 168 | /**
|
| 169 | * Get the factory scaling offset constant.
|
| 170 | * The offset constant for the channel that was calibrated in manufacturing and stored
|
| 171 | * in an eeprom in the module.
|
| 172 | *
|
| 173 | * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
|
| 174 | *
|
| 175 | * @return Offset constant.
|
| 176 | */
|
| 177 | INT32 AnalogChannel::GetOffset()
|
| 178 | {
|
| 179 | if (StatusIsFatal()) return 0;
|
| 180 | return m_module->GetOffset(m_channel);
|
| 181 | }
|
| 182 |
|
| 183 | /**
|
| 184 | * Get the channel number.
|
| 185 | * @return The channel number.
|
| 186 | */
|
| 187 | UINT32 AnalogChannel::GetChannel()
|
| 188 | {
|
| 189 | if (StatusIsFatal()) return 0;
|
| 190 | return m_channel;
|
| 191 | }
|
| 192 |
|
| 193 | /**
|
| 194 | * Get the module number.
|
| 195 | * @return The module number.
|
| 196 | */
|
| 197 | UINT8 AnalogChannel::GetModuleNumber()
|
| 198 | {
|
| 199 | if (StatusIsFatal()) return 0;
|
| 200 | return m_module->GetNumber();
|
| 201 | }
|
| 202 |
|
| 203 | /**
|
| 204 | * Set the number of averaging bits.
|
| 205 | * This sets the number of averaging bits. The actual number of averaged samples is 2**bits.
|
| 206 | * Use averaging to improve the stability of your measurement at the expense of sampling rate.
|
| 207 | * The averaging is done automatically in the FPGA.
|
| 208 | *
|
| 209 | * @param bits Number of bits of averaging.
|
| 210 | */
|
| 211 | void AnalogChannel::SetAverageBits(UINT32 bits)
|
| 212 | {
|
| 213 | if (StatusIsFatal()) return;
|
| 214 | m_module->SetAverageBits(m_channel, bits);
|
| 215 | }
|
| 216 |
|
| 217 | /**
|
| 218 | * Get the number of averaging bits previously configured.
|
| 219 | * This gets the number of averaging bits from the FPGA. The actual number of averaged samples is 2**bits.
|
| 220 | * The averaging is done automatically in the FPGA.
|
| 221 | *
|
| 222 | * @return Number of bits of averaging previously configured.
|
| 223 | */
|
| 224 | UINT32 AnalogChannel::GetAverageBits()
|
| 225 | {
|
| 226 | if (StatusIsFatal()) return 0;
|
| 227 | return m_module->GetAverageBits(m_channel);
|
| 228 | }
|
| 229 |
|
| 230 | /**
|
| 231 | * Set the number of oversample bits.
|
| 232 | * This sets the number of oversample bits. The actual number of oversampled values is 2**bits.
|
| 233 | * Use oversampling to improve the resolution of your measurements at the expense of sampling rate.
|
| 234 | * The oversampling is done automatically in the FPGA.
|
| 235 | *
|
| 236 | * @param bits Number of bits of oversampling.
|
| 237 | */
|
| 238 | void AnalogChannel::SetOversampleBits(UINT32 bits)
|
| 239 | {
|
| 240 | if (StatusIsFatal()) return;
|
| 241 | m_module->SetOversampleBits(m_channel, bits);
|
| 242 | }
|
| 243 |
|
| 244 | /**
|
| 245 | * Get the number of oversample bits previously configured.
|
| 246 | * This gets the number of oversample bits from the FPGA. The actual number of oversampled values is
|
| 247 | * 2**bits. The oversampling is done automatically in the FPGA.
|
| 248 | *
|
| 249 | * @return Number of bits of oversampling previously configured.
|
| 250 | */
|
| 251 | UINT32 AnalogChannel::GetOversampleBits()
|
| 252 | {
|
| 253 | if (StatusIsFatal()) return 0;
|
| 254 | return m_module->GetOversampleBits(m_channel);
|
| 255 | }
|
| 256 |
|
| 257 | /**
|
| 258 | * Is the channel attached to an accumulator.
|
| 259 | *
|
| 260 | * @return The analog channel is attached to an accumulator.
|
| 261 | */
|
| 262 | bool AnalogChannel::IsAccumulatorChannel()
|
| 263 | {
|
| 264 | if (StatusIsFatal()) return false;
|
| 265 | if(m_module->GetNumber() != kAccumulatorModuleNumber) return false;
|
| 266 | for (UINT32 i=0; i<kAccumulatorNumChannels; i++)
|
| 267 | {
|
| 268 | if (m_channel == kAccumulatorChannels[i]) return true;
|
| 269 | }
|
| 270 | return false;
|
| 271 | }
|
| 272 |
|
| 273 | /**
|
| 274 | * Initialize the accumulator.
|
| 275 | */
|
| 276 | void AnalogChannel::InitAccumulator()
|
| 277 | {
|
| 278 | if (StatusIsFatal()) return;
|
| 279 | m_accumulatorOffset = 0;
|
| 280 | SetAccumulatorCenter(0);
|
| 281 | ResetAccumulator();
|
| 282 | }
|
| 283 |
|
| 284 |
|
| 285 | /**
|
| 286 | * Set an inital value for the accumulator.
|
| 287 | *
|
| 288 | * This will be added to all values returned to the user.
|
| 289 | * @param initialValue The value that the accumulator should start from when reset.
|
| 290 | */
|
| 291 | void AnalogChannel::SetAccumulatorInitialValue(INT64 initialValue)
|
| 292 | {
|
| 293 | if (StatusIsFatal()) return;
|
| 294 | m_accumulatorOffset = initialValue;
|
| 295 | }
|
| 296 |
|
| 297 | /**
|
| 298 | * Resets the accumulator to the initial value.
|
| 299 | */
|
| 300 | void AnalogChannel::ResetAccumulator()
|
| 301 | {
|
| 302 | if (StatusIsFatal()) return;
|
| 303 | if (m_accumulator == NULL)
|
| 304 | {
|
| 305 | wpi_setWPIError(NullParameter);
|
| 306 | return;
|
| 307 | }
|
| 308 | tRioStatusCode localStatus = NiFpga_Status_Success;
|
| 309 | m_accumulator->strobeReset(&localStatus);
|
| 310 | wpi_setError(localStatus);
|
| 311 | }
|
| 312 |
|
| 313 | /**
|
| 314 | * Set the center value of the accumulator.
|
| 315 | *
|
| 316 | * The center value is subtracted from each A/D value before it is added to the accumulator. This
|
| 317 | * is used for the center value of devices like gyros and accelerometers to make integration work
|
| 318 | * and to take the device offset into account when integrating.
|
| 319 | *
|
| 320 | * This center value is based on the output of the oversampled and averaged source from channel 1.
|
| 321 | * Because of this, any non-zero oversample bits will affect the size of the value for this field.
|
| 322 | */
|
| 323 | void AnalogChannel::SetAccumulatorCenter(INT32 center)
|
| 324 | {
|
| 325 | if (StatusIsFatal()) return;
|
| 326 | if (m_accumulator == NULL)
|
| 327 | {
|
| 328 | wpi_setWPIError(NullParameter);
|
| 329 | return;
|
| 330 | }
|
| 331 | tRioStatusCode localStatus = NiFpga_Status_Success;
|
| 332 | m_accumulator->writeCenter(center, &localStatus);
|
| 333 | wpi_setError(localStatus);
|
| 334 | }
|
| 335 |
|
| 336 | /**
|
| 337 | * Set the accumulator's deadband.
|
| 338 | */
|
| 339 | void AnalogChannel::SetAccumulatorDeadband(INT32 deadband)
|
| 340 | {
|
| 341 | if (StatusIsFatal()) return;
|
| 342 | if (m_accumulator == NULL)
|
| 343 | {
|
| 344 | wpi_setWPIError(NullParameter);
|
| 345 | return;
|
| 346 | }
|
| 347 | tRioStatusCode localStatus = NiFpga_Status_Success;
|
| 348 | m_accumulator->writeDeadband(deadband, &localStatus);
|
| 349 | wpi_setError(localStatus);
|
| 350 | }
|
| 351 |
|
| 352 | /**
|
| 353 | * Read the accumulated value.
|
| 354 | *
|
| 355 | * Read the value that has been accumulating on channel 1.
|
| 356 | * The accumulator is attached after the oversample and average engine.
|
| 357 | *
|
| 358 | * @return The 64-bit value accumulated since the last Reset().
|
| 359 | */
|
| 360 | INT64 AnalogChannel::GetAccumulatorValue()
|
| 361 | {
|
| 362 | if (StatusIsFatal()) return 0;
|
| 363 | if (m_accumulator == NULL)
|
| 364 | {
|
| 365 | wpi_setWPIError(NullParameter);
|
| 366 | return 0;
|
| 367 | }
|
| 368 | tRioStatusCode localStatus = NiFpga_Status_Success;
|
| 369 | INT64 value = m_accumulator->readOutput_Value(&localStatus) + m_accumulatorOffset;
|
| 370 | wpi_setError(localStatus);
|
| 371 | return value;
|
| 372 | }
|
| 373 |
|
| 374 | /**
|
| 375 | * Read the number of accumulated values.
|
| 376 | *
|
| 377 | * Read the count of the accumulated values since the accumulator was last Reset().
|
| 378 | *
|
| 379 | * @return The number of times samples from the channel were accumulated.
|
| 380 | */
|
| 381 | UINT32 AnalogChannel::GetAccumulatorCount()
|
| 382 | {
|
| 383 | if (StatusIsFatal()) return 0;
|
| 384 | if (m_accumulator == NULL)
|
| 385 | {
|
| 386 | wpi_setWPIError(NullParameter);
|
| 387 | return 0;
|
| 388 | }
|
| 389 | tRioStatusCode localStatus = NiFpga_Status_Success;
|
| 390 | UINT32 count = m_accumulator->readOutput_Count(&localStatus);
|
| 391 | wpi_setError(localStatus);
|
| 392 | return count;
|
| 393 | }
|
| 394 |
|
| 395 |
|
| 396 | /**
|
| 397 | * Read the accumulated value and the number of accumulated values atomically.
|
| 398 | *
|
| 399 | * This function reads the value and count from the FPGA atomically.
|
| 400 | * This can be used for averaging.
|
| 401 | *
|
| 402 | * @param value Pointer to the 64-bit accumulated output.
|
| 403 | * @param count Pointer to the number of accumulation cycles.
|
| 404 | */
|
| 405 | void AnalogChannel::GetAccumulatorOutput(INT64 *value, UINT32 *count)
|
| 406 | {
|
| 407 | if (StatusIsFatal()) return;
|
| 408 | if (m_accumulator == NULL)
|
| 409 | {
|
| 410 | wpi_setWPIError(NullParameter);
|
| 411 | return;
|
| 412 | }
|
| 413 | if (value == NULL || count == NULL)
|
| 414 | {
|
| 415 | wpi_setWPIError(NullParameter);
|
| 416 | return;
|
| 417 | }
|
| 418 |
|
| 419 | tRioStatusCode localStatus = NiFpga_Status_Success;
|
| 420 | tAccumulator::tOutput output = m_accumulator->readOutput(&localStatus);
|
| 421 | *value = output.Value + m_accumulatorOffset;
|
| 422 | *count = output.Count;
|
| 423 | wpi_setError(localStatus);
|
| 424 | }
|
| 425 |
|
| 426 | /**
|
| 427 | * Get the Average voltage for the PID Source base object.
|
| 428 | *
|
| 429 | * @return The average voltage.
|
| 430 | */
|
| 431 | double AnalogChannel::PIDGet()
|
| 432 | {
|
| 433 | if (StatusIsFatal()) return 0.0;
|
| 434 | return GetAverageValue();
|
| 435 | }
|
| 436 |
|
| 437 | void AnalogChannel::UpdateTable() {
|
| 438 | if (m_table != NULL) {
|
| 439 | m_table->PutNumber("Value", GetAverageVoltage());
|
| 440 | }
|
| 441 | }
|
| 442 |
|
| 443 | void AnalogChannel::StartLiveWindowMode() {
|
| 444 |
|
| 445 | }
|
| 446 |
|
| 447 | void AnalogChannel::StopLiveWindowMode() {
|
| 448 |
|
| 449 | }
|
| 450 |
|
| 451 | std::string AnalogChannel::GetSmartDashboardType() {
|
| 452 | return "Analog Input";
|
| 453 | }
|
| 454 |
|
| 455 | void AnalogChannel::InitTable(ITable *subTable) {
|
| 456 | m_table = subTable;
|
| 457 | UpdateTable();
|
| 458 | }
|
| 459 |
|
| 460 | ITable * AnalogChannel::GetTable() {
|
| 461 | return m_table;
|
| 462 | }
|
| 463 |
|
| 464 |
|