Scope
FPGAResonanceScanner.cpp
1 #include "StdAfx.h"
2 #include "FPGAResonanceScanner.h"
3 #include "parameters/IO.h"
4 #include "helpers/DaqChunk.h"
5 #include "helpers/DaqChunkResonance.h"
6 
7 namespace scope {
8 
10  : FPGAIO5751(NiFpga_ResonanceScanner_IndicatorBool_Configured) {
11  assert(SCOPE_NAREAS == 1);
12 
13  status = NiFpga_Initialize();
14 
15  char* const Bitfile = "devices\\fpga\\" NiFpga_ResonanceScanner_Bitfile;
16 
17  // Load but do not run yet
18  status = NiFpga_Open(Bitfile, NiFpga_ResonanceScanner_Signature, "RIO0", 0, &session);
19  DBOUT(L"FPGAResonanceScanner: FPGA Session opened");
20 
21  // Reset the non-running FPGA to clear any bad stuff (e.g. after a program crash with open FPGA before)
22  status = NiFpga_Reset(session);
23 
24  // YOU HAVE TO WAIT THAT LONG!!!
25  // Otherwise you will occasionally (!!!) into strange problems (communication with fpga error -61046)
26  // This took me very very long to figure out...
27  std::this_thread::sleep_for(std::chrono::milliseconds(500));
28  // Run after reset
29  status = NiFpga_Run(session, 0);
30 
32 
33  // Set the fifo constants
34  fifos[0] = NiFpga_ResonanceScanner_TargetToHostFifoU32_ToHostCh1FIFO;
35  fifos[1] = NiFpga_ResonanceScanner_TargetToHostFifoU32_ToHostCh2FIFO;
36 }
37 
39  status = NiFpga_Close(session, 0);
40  status = NiFpga_Finalize();
41  DBOUT(L"FPGAResonanceScanner::~FPGAResonanceScanner session closed");
42 }
43 
45  if ( !initialized ) {
46  parameters = dynamic_cast<parameters::InputsFPGAResonanceScanner*>(_parameters);
47 
49 
50  uint32_t chunksize = 1000000;
51 
52  status = NiFpga_ConfigureFifo(session, fifos[0], 5*chunksize);
53  status = NiFpga_ConfigureFifo(session, fifos[1], 5*chunksize);
54 
55  FPGAInterface::Initialize(_parameters);
56  }
57 }
58 
59 double FPGAResonanceScanner::SetPixeltime(const uint32_t& _area, const double& _pixeltime) {
60  uint16_t samplesperpixel = round2ui16(_pixeltime * 1E-6 * parameters->AcquisitionClockRate());
61  status = NiFpga_WriteU16(session, NiFpga_ResonanceScanner_ControlU32_Samplesperpixel, samplesperpixel);
62 
63  DBOUT(L"FPGAResonanceScanner::SetPixeltime samples per pixel: " << samplesperpixel);
64 
65  return static_cast<double>(samplesperpixel)*1E6/parameters->AcquisitionClockRate();
66 }
67 
68 double FPGAResonanceScanner::SetLinetime(const uint32_t& _area, const double& _linetime) {
69  uint16_t samplesperline = round2ui32(_linetime * 1E-6 * parameters->AcquisitionClockRate());
70  status = NiFpga_WriteU16(session, NiFpga_ResonanceScanner_ControlU32_Samplesperline, samplesperline);
71 
72  DBOUT(L"FPGAResonanceScanner::SetPixeltime samples per line" << samplesperline);
73 
74  return static_cast<double>(samplesperline)*1E6/parameters->AcquisitionClockRate();
75 }
76 
77 void FPGAResonanceScanner::SetTriggering(const bool& _waitfortrigger) {
78  status = NiFpga_WriteBool(session, NiFpga_ResonanceScanner_ControlBool_Waitfortrigger, _waitfortrigger);
79 }
80 
82  status = NiFpga_WriteBool(session, NiFpga_ResonanceScanner_ControlBool_Acquirecontinuously, _cont);
83 }
84 
85 void FPGAResonanceScanner::SetRequestedPixels(const uint32_t& _area, const uint32_t& _reqpixels) {
86  status = NiFpga_WriteU32(session, NiFpga_ResonanceScanner_ControlU32_Requestedpixels, _reqpixels);
87 }
88 
90  ClearFIFOs();
92  status = NiFpga_WriteBool(session, NiFpga_ResonanceScanner_ControlBool_Acquire, true);
93 }
94 
95 int32_t FPGAResonanceScanner::ReadPixels(DaqChunk& _chunk, const double& _timeout, bool& _timedout) {
96  size_t remaining = 0;
97 
98  // only two channels and one area supported in FPGA vi
99  assert( (_chunk.NChannels() == 2) && (_chunk.Area() == 0) );
100 
101  // we need enough space
102  assert(_chunk.data.size() >= _chunk.PerChannel() * _chunk.NChannels());
103 
104  NiFpga_Status stat = NiFpga_Status_Success;
105 
106  std::vector<uint32_t> u32data(_chunk.PerChannel());
107  std::vector<int32_t> bitshift(_chunk.NChannels());
108  bitshift[0] = parameters->BitshiftCh1();
109  bitshift[1] = parameters->BitshiftCh2();
110 
111  // Read each channels fifo
112  for ( uint32_t c = 0 ; c < _chunk.NChannels() ; c++ ) {
113  stat = NiFpga_ReadFifoU32(session
114  , fifos[c]
115  , u32data.data()
116  , _chunk.PerChannel()
117  , static_cast<uint32_t>(_timeout * 1000) // FPGA C API takes timeout in milliseconds, to be consistent with DAQmx we have _timeout in seconds
118  , &remaining);
119 
120  _timedout = (stat == NiFpga_Status_FifoTimeout);
121 
122  // avoid throwing exception on time out (since FpgaStatus status could throw on all errors)
123  // return immediately, makes no sense to also wait for the other channels, since anyway something went seriously wrong
124  if ( _timedout )
125  return -1;
126 
127  // this could throw on error (if we would use FPGAStatus instead of FPGAStatusSafe)
128  status = stat;
129 
130  // Isolate pixel uint16 from uint32
131  std::transform(std::begin(u32data), std::end(u32data), std::begin(_chunk.data) + c*_chunk.PerChannel(), [](const uint32_t& _u32) {
132  return static_cast<uint16_t>(_u32 & 0x0000ffff);
133  });
134  }
135 
136  // We have to upcast here to get access to the resonance sync vector
137  auto chunkres = dynamic_cast<DaqChunkResonance&>(_chunk);
138  // Isolate sync uint16/bool from uint32
139  std::transform(std::begin(u32data), std::end(u32data), std::begin(chunkres.resSync), [](const uint32_t& _u32) {
140  return (_u32 >> 31) != 0;
141  });
142 
143  if ( status.Success() )
144  return _chunk.PerChannel();
145 
146  return -1;
147 }
148 
150  status = NiFpga_WriteBool(session, NiFpga_ResonanceScanner_ControlBool_Acquire, false);
151 }
152 
153 void FPGAResonanceScanner::SetScannerdelay(const uint32_t& _scannerdelay) {
154  status = NiFpga_WriteU32(session, NiFpga_ResonanceScanner_ControlI16_Scannerdelay, _scannerdelay);
155 }
156 
158  // We want to right-shift bits thus *-1
159  //status = NiFpga_WriteI8(session, NiFpga_ResonanceScanner_ControlI8_BitshiftCh1, -1 * parameters->BitshiftCh1());
160  //status = NiFpga_WriteI8(session, NiFpga_ResonanceScanner_ControlI8_BitshiftCh2, -1 * parameters->BitshiftCh2());
161 
162  status = NiFpga_WriteU16(session, NiFpga_ResonanceScanner_ControlU16_Baselinex8Ch1, static_cast<uint16_t>(parameters->BaselineCh1()));
163  status = NiFpga_WriteU16(session, NiFpga_ResonanceScanner_ControlU16_Baselinex8Ch2, static_cast<uint16_t>(parameters->BaselineCh2()));
164 
165  DBOUT(L"FPGAResonanceScanner::SetChannelProps " << parameters->BitshiftCh1() << L" " << parameters->BaselineCh1());
166 }
167 
169  NiFpga_Bool b;
170  status = NiFpga_ReadBool(session, NiFpga_ResonanceScanner_IndicatorBool_ToHostCh1FIFOOverflow, &b);
171  parameters->diagnosis.ToHostOverflowCh1 = (b!=0);
172  status = NiFpga_ReadBool(session, NiFpga_ResonanceScanner_IndicatorBool_ToHostCh2FIFOOverflow, &b);
173  parameters->diagnosis.ToHostOverflowCh2 = (b!=0);
174  status = NiFpga_ReadBool(session, NiFpga_ResonanceScanner_IndicatorBool_InterloopFIFOOverflow, &b);
175  parameters->diagnosis.InterloopOverflow = (b!=0);
176  status = NiFpga_ReadBool(session, NiFpga_ResonanceScanner_IndicatorBool_InterloopFIFOTimeout, &b);
177  parameters->diagnosis.InterloopTimeout = (b!=0);
178  status = NiFpga_ReadBool(session, NiFpga_ResonanceScanner_IndicatorBool_Acquiring, &b);
179  parameters->diagnosis.Acquiring = (b!=0);
180  status = NiFpga_ReadBool(session, NiFpga_ResonanceScanner_IndicatorBool_IOModuleAIOverRange, &b);
181  parameters->diagnosis.AIOverRange = (b!=0);
182 }
183 
185  // Clear interloop fifo
186  status = NiFpga_WriteBool(session, NiFpga_ResonanceScanner_ControlBool_ClearInterloopFIFO, true);
187  std::this_thread::sleep_for(std::chrono::milliseconds(50));
188  status = NiFpga_WriteBool(session, NiFpga_ResonanceScanner_ControlBool_ClearInterloopFIFO, false);
189 
190  // Stop to host FIFOs (clears them)
191  for ( auto f : fifos )
192  status = NiFpga_StopFifo(session, f);
193  std::this_thread::sleep_for(std::chrono::milliseconds(50));
194 
195  // Restart to host FIFOs
196  for ( auto f : fifos )
197  status = NiFpga_StartFifo(session, f);
198  std::this_thread::sleep_for(std::chrono::milliseconds(50));
199 }
200 
201 }
parameters::InputsFPGAResonanceScanner * parameters
the parameter set
void StartAcquisition() override
Starts the acquisition on the FPGA.
ScopeNumber< uint32_t > BaselineCh1
Baseline U16 value to set zero in channel 1.
Definition: IO.h:336
A DaqChunk contains data from all channels sequentially and additionally a bool vector for the resona...
ScopeNumber< uint8_t > BitshiftCh2
Number of bits to shift U32 right before casting to U16 (channel 2)
Definition: IO.h:475
void SetContinuousAcquisition(const bool &_cont) override
Sets if the FPGA should acquire data continuously or acquire the number of pixels per channel set wit...
ScopeNumber< uint32_t > BaselineCh2
Baseline U16 value to set zero in channel 2.
Definition: IO.h:339
void SetClockSource(NiFpga_Session _session, const uint8_t &_clock_source=0)
Possible clock sources (see adapter modules help and Configure Clock.vi from NI 5751 Clock Select exa...
Definition: FPGAIO5751.cpp:11
void StopAcquisition() override
Stops the acquisition on the FPGA.
void CheckFPGADiagnosis()
Checks the status of the FIFOs on the FPGA.
bool CheckIOModule(NiFpga_Session _session)
Necessary calls at the moment not supported by NI FPGA API 12.0, see CheckIOModule.vi for what to do.
Definition: FPGAIO5751.cpp:42
std::vector< uint16_t > data
The data vector.
Definition: DaqChunk.h:26
void SetRequestedPixels(const uint32_t &_area, const uint32_t &_reqpixels) override
Sets the number of pixels per channel the FPGA should acquire, set to -1 for live scanning...
Handels the NI FlexRIO adapter module IO-5751.
Definition: FPGAIO5751.h:11
A DaqChunk contains data from all channels sequentially.
Definition: DaqChunk.h:9
This is the include file for standard system include files, or project specific include files that ar...
~FPGAResonanceScanner()
Close FPGA session.
bool initialized
true if already initialized
Definition: FPGAInterface.h:29
FPGAStatusSafe status
current FPGA status.
Definition: FPGAInterface.h:23
#define DBOUT(s)
A debug output to the debug console.
Definition: helpers.h:153
int32_t ReadPixels(DaqChunk &_chunk, const double &_timeout, bool &_timedout) override
Read only pixels from the FPGA FIFO.
FPGAResonanceScanner()
Load the FPGA bitfile, set the IO module's onboard clock and initialize the acquisition.
bool Success() const
void Initialize(parameters::InputsFPGA *_parameters) override
Set initial parameters.
void SetScannerdelay(const uint32_t &_scannerdelay) override
Sets the scanner delay on the FPGA (used currently for resonance scanners only)
void SetChannelProps()
Set channel properties as baseline and bitshift.
ScopeNumber< bool > Acquiring
and the Acquiring indicator
Definition: IO.h:487
void SetTriggering(const bool &_waitfortrigger) override
Sets if the FPGA should wait for a trigger before starting acquisition.
virtual void Initialize(parameters::InputsFPGA *_parameters)
Set initial parameters.
Definition: FPGAInterface.h:38
double SetLinetime(const uint32_t &_area, const double &_linetime) override
Sets the time per line (in seconds) for the generation of the line clock (if implemented) ...
ScopeNumber< uint8_t > BitshiftCh1
Number of bits to shift U32 right before casting to U16 (channel 1)
Definition: IO.h:472
Parameters for pixel acquisition FPGAResonanceScanner.
Definition: IO.h:461
void ClearFIFOs()
Clears the interloop and ToHost FIFOs.
ScopeNumber< double > AcquisitionClockRate
Frequency in Hz of the clock used in the FPGA VI for the acquisition.
Definition: IO.h:342
Parameters for pixel acquisition with NI-FPGA.
Definition: IO.h:117
std::array< NiFpga_ResonanceScanner_TargetToHostFifoU32, 2 > fifos
both fifos for both channels
Diagnosis diagnosis
Keeps the LEDs/ScopeNumber for FPGA diagnosis together.
Definition: IO.h:503
NiFpga_Session session
NI FPGA session handle.
Definition: FPGAInterface.h:26
double SetPixeltime(const uint32_t &_area, const double &_pixeltime) override
Sets the time per pixel/dwell time (in seconds)
ScopeNumber< bool > AIOverRange
indicator if input is over the ADC range
Definition: IO.h:490