5.1 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, 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(&params);
 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, &params, &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, &paramInfo);
130    adcApp->SetParamInfo(&paramInfo);
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, &paramInfo);
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}