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 a cable delay
97static const double MAX_DELAY_PS = 500000.;
98
99class Ndigo6GAppSingle : public Ndigo6GApp {
100 private:
101 // last falling edge to compute the difference to
102 double lastFallingEdgeTs = 0;
103
104 public:
105 Ndigo6GAppSingle(int tdcChannelMask) : Ndigo6GApp(tdcChannelMask) {
106 }
107 virtual void ConfigureADC(ndigo6g12_configuration *config,
108 int adc_threshold);
109 virtual double ProcessADCPacket(crono_packet *pkt);
110 virtual void ProcessTDCTimestamp(int tdcChannel, double timestamp) {}
111};
112
113
114
115// Implementation of the different sample applications
116class Ndigo6GAppDual : public Ndigo6GApp {
117 private:
118 DelayMeasurement delayMeasure;
119
120 public:
121 Ndigo6GAppDual(int tdcChannelMask) : Ndigo6GApp(tdcChannelMask) {
122 std::map<int, std::string> channelMap = {{0, "A"}, {3, "D"}};
123 AddTDCChannels(channelMap);
124 delayMeasure.Init(0, MAX_DELAY_PS, channelMap);
125 }
126 virtual void ConfigureADC(ndigo6g12_configuration *config,
127 int adc_threshold);
128
129 virtual double ProcessADCPacket(crono_packet *pkt);
130
131 virtual void ProcessTDCTimestamp(int tdcChannel, double timestamp);
132 virtual void SetParamInfo(ndigo6g12_param_info *pi) {
133 Ndigo6GApp::SetParamInfo(pi);
134 // we have to wait for 3 TDC periods to make sure that the TDC data has
135 // arrived
136 delayMeasure.SetMaxWaitTime(pi->tdc_rollover_period * 3.5 *
137 pi->tdc_period);
138 }
139};
140
141class Ndigo6GAppQuad : public Ndigo6GApp {
142 private:
143 DelayMeasurement delayMeasure;
144
145 public:
146 Ndigo6GAppQuad(int tdcChannelMask) : Ndigo6GApp(tdcChannelMask) {
147
148 std::map<int, std::string> channelMap = {
149 {0, "A"}, {1, "B"}, {2, "C"}, {3, "D"}};
150 AddTDCChannels(channelMap);
151 delayMeasure.Init(0, MAX_DELAY_PS, channelMap);
152 }
153
154 virtual void ConfigureADC(ndigo6g12_configuration *config,
155 int adc_threshold);
156
157 virtual void SetParamInfo(ndigo6g12_param_info *pi) {
158 Ndigo6GApp::SetParamInfo( pi);
159 // we have to wait for 3 TDC periods to make sure that the TDC data has
160 // arrived
161 delayMeasure.SetMaxWaitTime(pi->tdc_rollover_period * 3.5 *
162 pi->packet_ts_period);
163 }
164
165 virtual double ProcessADCPacket(crono_packet *pkt);
166
167 virtual void ProcessTDCTimestamp(int tdcChannel, double timestamp);
168};
169
170class Ndigo6GAppAverager : public Ndigo6GApp {
171 private:
172 // last falling edge to compute the difference to
173 double lastFallingEdgeTs = 0;
174
175 public:
176 Ndigo6GAppAverager(int tdcChannelMask) : Ndigo6GApp(tdcChannelMask) {}
177 virtual void ConfigureADC(ndigo6g12_configuration *config,
178 int adc_threshold);
179 virtual double ProcessADCPacket(crono_packet *pkt);
180};