1// Example application for the Ndigo6G-12
2//
3#include "ndigo6g12_app.h"
4#include "ndigo6g12_interface.h"
5#include <map>
6#include <stdio.h>
7#include <stdlib.h>
8
9std::map<int, std::string> appTypeMap = {{1, "One ADC channels @6.4 Gsps"},
10 {2, "Two ADC channels @3.2 Gsps"},
11 {4, "Four ADC channels @1.6 Gsp"},
12 {5, "Averaging mode @6.4 Gsps"}};
13
14std::map<int, std::string> requirementsMap = {
15 {0,
16 "Starts the test of the currently configured app type"},
17 {1,
18 "Measure time distance between passing of "
19 "threshold, calculates the frequency, requires NIM signal on channel A"},
20 {2, "Dual-channel application that measures delay between start "
21 "pulse on channel A and stop pulse on channel D (NIM)"},
22 {4, "Quad-channel application that measures delay between start "
23 "pulse on channel A and stop pulses on channels B-D (NIM)"},
24 {5, "Measure time distance between averaged start on TRG (NIM) and stop on "
25 "channel A (falling) by summing data of 16 runs "
26 "to increase precision of measurement for signal with low amplitude"}};
27
28Ndigo6GApp *adcApp;
29ndigo6g12_param_info paramInfo;
30
31// initialize Ndigo6G-12 device
32ndigo6g12_device initialize_ndigo6g12(int bufferSize, int boardId,
33 int cardIndex, int appType, int tdcChannels) {
34 // prepare initialization
35 ndigo6g12_init_parameters params;
36 // fill initialization data structure with default values
37 // so that the data is valid and only parameters
38 // of interest have to be set explicitly
39 ndigo6g12_get_default_init_parameters(¶ms);
40 params.application_type = appType;
41
42 params.buffer_size[0] = bufferSize; // size of the packet buffer
43 params.board_id = boardId; // value copied to "card" field of every packet,
44 // allowed range 0..255
45 params.card_index = cardIndex; // which of the Ndigo6G-12 board found in
46 // the system to be used
47 // this specifies the directories or the specific .cronorom if dynamic
48 // switching of appType is required. If not specified, the example will
49 // return an error if the appType does not match the current appType in the
50 // firmware
51 params.firmware_locations = ".";
52
53 // initialize card
54 int errorCode;
55 const char *errorMessage;
56 ndigo6g12_device device;
57 errorCode = ndigo6g12_init(&device, ¶ms, &errorMessage);
58
59 if (errorCode != CRONO_OK) {
60 printf("Could not init Ndigo6G-12: %s\n", errorMessage);
61 printf("Please change path to the .cronorom in ndigo6g12_example.cpp\n");
62 exit(1);
63 }
64
65 // check if firmware now supports the chosen application type
66 ndigo6g12_static_info si;
67 ndigo6g12_get_static_info(&device, &si);
68 if (si.application_type != appType) {
69 printf("The switch to appType did not work, please make sure that "
70 "the firmware file is provided");
71 ndigo6g12_close(&device);
72 exit(1);
73 }
74 if (appType == 0) {
75 appType = si.application_type;
76 }
77 switch (appType) {
78 case 1:
79 adcApp = new Ndigo6GAppSingle(tdcChannels);
80 break;
81 case 2:
82 adcApp = new Ndigo6GAppDual(tdcChannels);
83 break;
84 case 4:
85 adcApp = new Ndigo6GAppQuad(tdcChannels);
86 break;
87 case 5:
88 adcApp = new Ndigo6GAppAverager(tdcChannels);
89 break;
90 default:
91 printf("Not supported appType %d'\n", appType);
92 ndigo6g12_close(&device);
93 exit(1);
94 }
95 printf("Running in %s\n%s\n", appTypeMap[appType].c_str(),
96 requirementsMap[appType].c_str());
97 return device;
98}
99
100int configure_ndigo6g12(ndigo6g12_device *device, int adcThreshold) {
101 // prepare configuration
102 ndigo6g12_configuration config;
103
104 // fill configuration data structure with default values
105 // so that the configuration is valid and only parameters
106 // of interest have to be set explicitly
107 if (CRONO_OK != ndigo6g12_get_default_configuration(device, &config)) {
108 printf("Could not get default configuration: %s\n",
109 ndigo6g12_get_last_error_message(device));
110 ndigo6g12_close(device);
111 return 1;
112 }
113
114 //**************************************************************************
115 // configuration for the TDC channels
116 adcApp->ConfigureTDC(&config);
117
118 //**************************************************************************
119 // configuration for the ADC channels
120 adcApp->ConfigureADC(&config, adcThreshold);
121
122 // write configuration to board
123 int error_code = ndigo6g12_configure(device, &config);
124 if (error_code != CRONO_OK) {
125 printf("Could not configure Ndigo6G-12: %s\n",
126 ndigo6g12_get_last_error_message(device));
127 return 1;
128 }
129 ndigo6g12_get_param_info(device, ¶mInfo);
130 adcApp->SetParamInfo(¶mInfo);
131 return 0;
132}
133
134// print some basic information about the Ndigo6G-12 device
135void print_device_information(ndigo6g12_device *device) {
136 ndigo6g12_static_info si;
137 ndigo6g12_get_static_info(device, &si);
138 printf("Firmware revision %d.%d - Type %d\n", si.fw_revision,
139 si.svn_revision, si.application_type);
140 printf("Firmware Bitstream Timestamp : %s\n", si.bitstream_date);
141 printf("Calibration date : %s\n", si.calibration_date);
142 printf("Board serial : %d.%d\n", si.board_serial >> 24,
143 si.board_serial & 0xffffff);
144 printf("Board revision : %d\n", si.board_revision);
145 printf("Board configuration : %d\n", si.board_configuration);
146 printf("Driver Revision : %d.%d.%d\n",
147 ((si.driver_revision >> 16) & 255),
148 ((si.driver_revision >> 8) & 255), (si.driver_revision & 255));
149 printf("Driver Build Revision : %d\n", si.driver_build_revision);
150
151 ndigo6g12_fast_info fi;
152 ndigo6g12_get_fast_info(device, &fi);
153 printf("TDC temperature : %.2f C\n", fi.tdc1_temp);
154 printf("ADC temperature : %.2f C\n", fi.ev12_temp);
155 printf("FPGA temperature : %.2f C\n", fi.fpga_temperature);
156 printf("PCIe link speed : Gen. %d\n", fi.pcie_link_speed);
157 printf("PCIe link width : %d lanes\n", fi.pcie_link_width);
158 printf("PCIe payload : %d bytes\n", fi.pcie_max_payload);
159
160 ndigo6g12_param_info pi;
161 ndigo6g12_get_param_info(device, &pi);
162 printf("Sample rate : %.0f Msps\n",
163 pi.sample_rate / 1000000.0);
164 printf("Resolution : %d Bit\n", pi.resolution);
165 printf("Sample period : %.2f ps\n", pi.sample_period);
166 printf("TDC bin size : %.2f ps\n", pi.tdc_period);
167 printf("Packet Timestamp period : %.2f ps\n", pi.packet_ts_period);
168 printf("ADC Sample delay : %.2f ps\n", pi.adc_sample_delay);
169}
170
171int main(int argc, char *argv[]) {
172 if (argc < 2) {
173 printf("Usage: ndigo6g12_example <appType> [<tdcMask>]\n");
174 for (auto atPair : appTypeMap) {
175 int at = atPair.first;
176 printf("AppType %d: %s\n %s\n", at, appTypeMap[at].c_str(),
177 requirementsMap[at].c_str());
178 }
179 printf("tdcMask: Bit flag for TDC channels E-H\n");
180 exit(1);
181 }
182
183 int appType = atoi(argv[1]);
184 int tdcChannelMask = 0;
185 if (argc > 2) {
186 tdcChannelMask = atoi(argv[2]);
187 }
188 // use 128 MiByte to buffer incoming data
189 // largest ADC data packet has about 500 KiByte
190 const int64_t BUFFER_SIZE = 128 * 1024 * 1024;
191
192 // use the first Ndigo6G-12 device found in the system
193 const int CARD_INDEX = 0;
194
195 // set board ID in all packets to 0
196 // can be used to distinguish packets of multiple devices
197 const int BOARD_ID = 0;
198
199 printf("cronologic ndigo6g12_example using driver: %s\n",
200 ndigo6g12_get_driver_revision_str());
201
202 // create and initialize the device
203 // may fail if the device is already in use by another process
204 // or the device driver is not installed
205 ndigo6g12_device device =
206 initialize_ndigo6g12(BUFFER_SIZE, BOARD_ID, CARD_INDEX, appType,
207 tdcChannelMask);
208
209 print_device_information(&device);
210
211 // set the configuration required for capturing data
212 // the base line is shifted by +350mV, as the target is to trigger at the
213 // middle of the NIM pulse edge
214 int adcThreshold = 0;
215 int status = configure_ndigo6g12(&device, adcThreshold);
216 if (status != 0) {
217 exit(1);
218 }
219
220 // configure readout behaviour
221 // automatically acknowledge all data as processed
222 // on the next call to ndigo6g12_read()
223 // old packet pointers are invalid after calling ndigo6g12_read()
224 ndigo6g12_read_in readConfig;
225 readConfig.acknowledge_last_read = 1;
226
227 // structure with packet pointers for read data
228 ndigo6g12_read_out readData;
229
230 // start data capture
231 status = ndigo6g12_start_capture(&device);
232 if (status != CRONO_OK) {
233 printf("Could not start capturing: %s",
234 ndigo6g12_get_last_error_message(&device));
235 ndigo6g12_close(&device);
236 exit(1);
237 }
238
239 // get current sample rate to calculate event timestamps
240 ndigo6g12_param_info paramInfo;
241 ndigo6g12_get_param_info(&device, ¶mInfo);
242
243 // ADC data is provided in packets, one packet per ADC channel and trigger
244 // TDC data is provided in a single packet for all TDC inputs in a certain
245 // timespan
246 printf("\nReading packets:\n");
247
248 const int MAX_PACKET_COUNT = 70;
249 int packetCount = 0;
250 bool noDataLastTime = false;
251 while ((packetCount < MAX_PACKET_COUNT)) {
252 // get pointers to acquired packets
253 status = ndigo6g12_read(&device, &readConfig, &readData);
254 if (status != CRONO_OK) {
255 if (!noDataLastTime) {
256 printf(" - No data! -\n");
257 }
258 noDataLastTime = true;
259
260 } else {
261 noDataLastTime = false;
262 // iterate over all packets received by the last read
263 volatile crono_packet *p = readData.first_packet;
264 while (p <= readData.last_packet) {
265
266 if (p->channel < 4) {
267 // packets with channel number < 4 are ADC data
268 double packet_ts =
269 adcApp->ProcessADCPacket(const_cast<crono_packet *>(p));
270 } else {
271 // packets with channel number >= 4 are TDC data
272 adcApp->ProcessTDCPacket(const_cast<crono_packet *>(p));
273 }
274
275 // go to next packet
276 p = crono_next_packet(p);
277
278 packetCount++;
279 } // end: iterate over received packets
280 } // end: Got any packets?
281 } // end: while
282
283 // shut down packet generation and DMA transfers
284 ndigo6g12_stop_capture(&device);
285
286 // deactivate Ndigo6G-12
287 ndigo6g12_close(&device);
288
289 return 0;
290}