ndigo6g12_example.cpp

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