1#pragma once
2#include "delay.h"
3#include "ndigo6g12_interface.h"
4#include <map>
5#include <string>
6#include <vector>
7
8// Base class for Ndigo6G applications
9// contains common code for packet processing
10class Ndigo6GApp {
11 protected:
12 const int PRECURSOR = 1;
13 // contains the timing parameters of the current mode like sample period
14 ndigo6g12_param_info *pi;
15 int adcThreshold;
16 int tdcChannelMask;
17 // convenience method for adding the TDC channels to the channel map
18 void AddTDCChannels(std::map<int, std::string> &channelMap) {
19 for (int i = 0; i < 4; i++) {
20 if (tdcChannelMask & (1 << i)) {
21 channelMap[4 + i] = (char)'E' + (char)i;
22 }
23 }
24 }
25
26 public:
27 Ndigo6GApp(int tdcChannelMask) { this->tdcChannelMask = tdcChannelMask; }
28
29 // configure the Ndigo6G with the appropiate mode and triggers
30 virtual void ConfigureADC(ndigo6g12_configuration *config,
31 int adcThreshold) = 0;
32
33 virtual void ConfigureTDC(ndigo6g12_configuration *config);
34
35 // react to an ADC incoming packet
36 virtual double ProcessADCPacket(crono_packet *pkt) = 0;
37
38 // set the parameters after configuration was successful
39 virtual void SetParamInfo(ndigo6g12_param_info *pi) { this->pi = pi; }
40
41 // called by the main loop on a TDC packet arrival
42 virtual void ProcessTDCPacket(crono_packet *pkt);
43
44 // react to an incoming TDC packet, called by default implementation of
45 // ProcessTDCPacket
46 virtual void ProcessTDCTimestamp(int tdcChannel, double timestamp) {
47 printf("TDC event on channel %d timestamp: %.3f ns\n", tdcChannel,
48 timestamp / 1000.0);
49 };
50
51 // helper method to find the timestamp of the current packet
52 double ComputePacketTimestamp(volatile crono_packet *pkt) {
53 // calculate packet timestamp in picoseconds
54 // the precursor time is constant in the modes, but the amount of
55 // samples is different (32/16/8 for 1/2/4)
56 double packet_ts =
57 pkt->timestamp * pi->packet_ts_period - PRECURSOR * 5e3 ;
58 return packet_ts;
59 }
60
61 // Computes the falling edge in the given data, returns the absolute ps
62 // value, and -1 if threshold was not passed in the packet.
63 double ComputeFallingEdge(crono_packet *pkt) {
64 // packet length is number of 64-bit words of data
65 double packetTs = ComputePacketTimestamp(pkt);
66 // 4 ADC samples are stored in each 64-bit chunk of packet data
67 uint32_t sampleCount = (pkt->length * 4);
68
69 // ADC data is a signed 16-bit integer
70 int16_t *adc_data = (int16_t *)(pkt->data);
71
72 // find first falling edge in ADC data
73 for (uint32_t i = 0; i < (sampleCount - 1); i++) {
74 if (adc_data[i] >= adcThreshold && adc_data[i + 1] < adcThreshold) {
75 // calculate threshold crossing relative to start of packet
76 double feOffset = i;
77 // linear interpolation of trigger threshold crossing
78 feOffset += (double)(adc_data[i] - adcThreshold) /
79 (adc_data[i] - adc_data[i + 1]);
80 // convert to picoseconds
81 feOffset *= pi->sample_period;
82
83 // calculate timestamp of threshold crossing in picoseconds
84 double fallingEdgeTs = packetTs + feOffset;
85 // adjust for ADC pipeline delay
86 fallingEdgeTs -= pi->adc_sample_delay;
87
88 return fallingEdgeTs;
89 }
90 }
91 return -1;
92 }
93
94
95};
96// maximum distance of two pulses, so that they are considered to be
97// a cable delay
98static const double MAX_DELAY_PS = 500000.;
99
100class Ndigo6GAppSingle : public Ndigo6GApp {
101 private:
102 // last falling edge to compute the difference to
103 double lastFallingEdgeTs = 0;
104
105 public:
106 Ndigo6GAppSingle(int tdcChannelMask) : Ndigo6GApp(tdcChannelMask) {
107 }
108 virtual void ConfigureADC(ndigo6g12_configuration *config,
109 int adc_threshold);
110 virtual double ProcessADCPacket(crono_packet *pkt);
111 virtual void ProcessTDCTimestamp(int tdcChannel, double timestamp) {}
112};
113
114
115
116// Implementation of the different sample applications
117class Ndigo6GAppDual : public Ndigo6GApp {
118 private:
119 DelayMeasurement delayMeasure;
120
121 public:
122 Ndigo6GAppDual(int tdcChannelMask) : Ndigo6GApp(tdcChannelMask) {
123 std::map<int, std::string> channelMap = {{0, "A"}, {3, "D"}};
124 AddTDCChannels(channelMap);
125 delayMeasure.Init(0, MAX_DELAY_PS, channelMap);
126 }
127 virtual void ConfigureADC(ndigo6g12_configuration *config,
128 int adc_threshold);
129
130 virtual double ProcessADCPacket(crono_packet *pkt);
131
132 virtual void ProcessTDCTimestamp(int tdcChannel, double timestamp);
133 virtual void SetParamInfo(ndigo6g12_param_info *pi) {
134 Ndigo6GApp::SetParamInfo(pi);
135 // we have to wait for 3 TDC periods to make sure that the TDC data has
136 // arrived
137 delayMeasure.SetMaxWaitTime(pi->tdc_rollover_period * 3.5 *
138 pi->tdc_period);
139 }
140};
141
142class Ndigo6GAppQuad : public Ndigo6GApp {
143 private:
144 DelayMeasurement delayMeasure;
145
146 public:
147 Ndigo6GAppQuad(int tdcChannelMask) : Ndigo6GApp(tdcChannelMask) {
148
149 std::map<int, std::string> channelMap = {
150 {0, "A"}, {1, "B"}, {2, "C"}, {3, "D"}};
151 AddTDCChannels(channelMap);
152 delayMeasure.Init(0, MAX_DELAY_PS, channelMap);
153 }
154
155 virtual void ConfigureADC(ndigo6g12_configuration *config,
156 int adc_threshold);
157
158 virtual void SetParamInfo(ndigo6g12_param_info *pi) {
159 Ndigo6GApp::SetParamInfo( pi);
160 // we have to wait for 3 TDC periods to make sure that the TDC data has
161 // arrived
162 delayMeasure.SetMaxWaitTime(pi->tdc_rollover_period * 3.5 *
163 pi->packet_ts_period);
164 }
165
166 virtual double ProcessADCPacket(crono_packet *pkt);
167
168 virtual void ProcessTDCTimestamp(int tdcChannel, double timestamp);
169};
170
171class Ndigo6GAppAverager : public Ndigo6GApp {
172 private:
173 // last falling edge to compute the difference to
174 double lastFallingEdgeTs = 0;
175
176 public:
177 Ndigo6GAppAverager(int tdcChannelMask) : Ndigo6GApp(tdcChannelMask) {}
178 virtual void ConfigureADC(ndigo6g12_configuration *config,
179 int adc_threshold);
180 virtual double ProcessADCPacket(crono_packet *pkt);
181};