LDMX Software
QIEEncoder.cxx
1#include "TrigScint/QIEEncoder.h"
2
3#include <bitset>
4#include <iomanip>
5#include <iostream>
6
7#include "TrigScint/Event/QIEStream.h"
8#include "TrigScint/Event/TrigScintQIEDigis.h"
9
10namespace trigscint {
11
13 // Configure this instance of the encoder
14 output_collection_ = ps.get<std::string>("output_collection");
15 input_collection_ = ps.get<std::string>("input_collection");
16 input_pass_name_ = ps.get<std::string>("input_pass_name");
17 channel_map_file_name_ = ps.get<std::string>("channel_map_file");
18 n_channels_ = ps.get<int>("number_channels");
19 verbose_ = ps.get<bool>("verbose");
20
21 ldmx_log(debug) << "In configure, got parameters:" << "\noutput_collection = "
22 << output_collection_
23 << "\ninput_collection = " << input_collection_
24 << "\ninput_pass_name = " << input_pass_name_
25 << "\nchannel_map_file = " << channel_map_file_name_
26 << "\nnumber_channels = " << n_channels_
27 << "\nverbose = " << verbose_;
28
29 // set up channel mapping
30 channel_map_file_.open(channel_map_file_name_, std::ios::in);
31 if (!channel_map_file_.is_open()) {
32 EXCEPTION_RAISE(
33 "BadMapFile",
34 "The channel mapping file cannot be opened."); // <-- appears this
35 // needs implementing
36 // first
37 ldmx_log(fatal) << "The channel mapping file cannot be opened.";
38 return;
39 }
40 int ch_id, el_id;
41 while (!channel_map_file_.eof()) {
42 channel_map_file_ >> el_id >> ch_id;
43 // for test beam, we will only know the elecID from
44 // the position of the word in the stream.
45 // so these need to be strictly ordered in the map.
46 // barID can always be set, or looked up, as a property of the digi.
47
48 // make this based on channel ID. this is like looking up the position in a
49 // vector of a certain value. but it's fine
50 channel_map_.insert(std::pair<int, int>(ch_id, el_id));
51 ldmx_log(debug) << "elID " << el_id << " chID " << ch_id;
52 }
53 if (el_id != n_channels_ - 1)
54 ldmx_log(fatal) << "The set number of channels " << n_channels_
55 << " seems not to match the number from the map (+1) :"
56 << el_id;
57 channel_map_file_.close();
58
59 return;
60}
61
63 ldmx_log(debug) << "QIEEncoder: produce() starts! Event number: "
64 << event.getEventHeader().getEventNumber();
65
66 std::vector<trigscint::QIEStream> qie_outs;
67 int n_samp = QIEStream::NUM_SAMPLES;
68 std::vector<int> init_vec(n_samp, 0);
69 ldmx_log(debug) << "num samples = " << n_samp;
70
71 // we're keeping a list ordered in elec ID since this is the order we'll use
72 // to write them to stream
73 for (int i_q = 0; i_q < n_channels_; i_q++) {
74 QIEStream qie_out;
75 qie_out.setADC(init_vec);
76 qie_out.setTDC(init_vec);
77 qie_out.setCID(init_vec);
78 qie_out.setElectronicsID(i_q); // assume id is index
79
80 qie_outs.push_back(qie_out);
81 }
82
83 ldmx_log(debug) << "Looking up input collection " << input_collection_ << "_"
84 << input_pass_name_;
85 const auto digis{event.getCollection<trigscint::TrigScintQIEDigis>(
86 input_collection_, input_pass_name_)};
87 ldmx_log(debug) << "Got input collection" << input_collection_ << "_"
88 << input_pass_name_;
89
90 bool is_ci_dunsync = false; // mismatch between CID reported by channels
91 // within the same time sample
92 bool is_ci_dskipped = false; // a gap in the CID increment
93 bool is_cr_c0malformed = false; // an issue with CRC from fiber0
94 bool is_cr_c1malformed = false; // an issue with CRC from fiber1
95
96 int first_cid = -1;
97 ldmx_log(debug) << "entering loop over digis ";
98 for (auto& digi : digis) {
99 int bar = digi.getChanID();
100 auto itr = channel_map_.find(bar);
101 if (itr == channel_map_.end()) { // yikes! didn't find the bar in the map
102 ldmx_log(fatal) << "Couldn't find an entry for bar " << bar
103 << "; check the (choice of) channel map!. Exiting event "
104 << event.getEventHeader().getEventNumber();
105 return;
106 }
107 int idx = itr->second; // here we're just using the order. no actual elID
108 // is assumed.
109 qie_outs.at(idx).setChannelID(bar);
110 qie_outs.at(idx).setElectronicsID(idx);
111 ldmx_log(debug) << "Channel " << bar << " elec ID "
112 << qie_outs.at(idx).getElectronicsID();
113 std::vector<int> l_etdcs; // make the LE (Leading Edge) truncation explicit
114 std::vector<uint8_t> cids;
115 for (int i_s = 0; i_s < n_samp; i_s++) {
116 int tdc = digi.getTDC().at(i_s);
117 int cid = digi.getCID().at(i_s);
118 if (cids.size() > 0 && (cid % 4) != ((cids.back() + 1) % 4)) {
119 // by construction shouldn't happen in simulation. still, explicitly
120 // checking here, considering any future changes to our CID simulation.
121 is_ci_dskipped = true;
122 }
123 if (verbose_) { // all this is only useful for debugging
124 std::vector<uint8_t> adcs;
125 int adc = digi.getADC().at(i_s);
126 uint8_t mant = adc % 64;
127 uint8_t exp = adc / 64;
128 ldmx_log(debug) << "\tSample " << i_s << std::left << std::setw(6)
129 << " ADC " << adc << ",\texp " << unsigned(exp)
130 << " mant " << unsigned(mant) << ",\tTDC = " << tdc
131 << ", LE TDC = " << std::bitset<8>(tdc / 16)
132 << " and capID= " << cid;
133 adcs.push_back(64 * exp + mant);
134 ldmx_log(debug) << "Combined ADC: " << std::showbase
135 << std::bitset<8>(adcs.back()) << " and original adc "
136 << std::bitset<8>(adc) << std::dec;
137 } // if verbose
138
139 tdc /= 16; // do LE (leading edge) TDC
140 l_etdcs.push_back(tdc);
141 cids.push_back((uint8_t)cid);
142 } // over samples
143 if (first_cid == -1) {
144 // just store the 5th one, doesn't matter; if all channels
145 // are aligned then cids should match at any given time sample
146 first_cid = cids.back();
147 }
148 if (first_cid != cids.back()) {
149 is_ci_dunsync =
150 true; // any one channel not aligned is enough to set this bool
151 }
152 qie_outs.at(idx).setADC(digi.getADC());
153 qie_outs.at(idx).setTDC(l_etdcs);
154 } // over digis
155 if (is_ci_dunsync) ldmx_log(debug) << "Found unsynced CIDs!";
156 if (is_ci_dskipped) ldmx_log(info) << "Found skipped CIDs!";
157
158 // data format:
159 // RM ID: we don't set it for testbeam so skip for now.
160 // 16 bit trigger ID.
161 // 4 bits of flags, then 4 reserved 0 for now
162 // some 8-bit error word/checksum.
163 // all channel 8-bit ADCs.
164 // all channel TDCS.
165 // done.
166
167 uint16_t trigger_id = event.getEventHeader().getEventNumber();
168 uint8_t random_checksum =
169 30; // just some number for now. TODO implement a checksum
170 uint8_t flags = 0; // we use this to contain the four reserved 0's too
171 // put it all in, at the assigned position
172 flags |= (is_cr_c0malformed << QIEStream::CRC0_ERR_POS);
173 flags |= (is_cr_c1malformed << QIEStream::CRC1_ERR_POS);
174 flags |= (is_ci_dunsync << QIEStream::CID_UNSYNC_POS);
175 flags |= (is_ci_dskipped << QIEStream::CID_SKIP_POS);
176 ldmx_log(debug) << "FLAGS: " << std::bitset<8>(flags);
177
178 std::vector<uint8_t> out_word;
179 std::vector<uint8_t> trigger_i_dwords;
180 for (int i_w = QIEStream::TRIGID_LEN_BYTES - 1; i_w >= 0; i_w--) {
181 // assume the whole 2B are written as a single 16-bit word
182 uint8_t t_i_dword = trigger_id >> i_w * 8; // shift by a byte at a time
183 trigger_i_dwords.push_back(t_i_dword);
184 out_word.push_back(t_i_dword);
185 }
186
187 out_word.push_back(flags);
188 out_word.push_back(random_checksum);
189
190 if (verbose_) {
191 std::cout << "header word ";
192 for (auto word : out_word) std::cout << std::bitset<8>(word) << " ";
193 std::cout << std::endl;
194 }
195
196 // now write this in sequence: ADC of all channels, then TDC; repeat for all
197 // samples
198 for (int i_s = 0; i_s < n_samp; i_s++) {
199 for (int i_q = 0; i_q < n_channels_; i_q++) {
200 out_word.push_back(qie_outs.at(i_q).getADC().at(i_s));
201 } // over channels : ADC
202 for (int i_q = 0; i_q < n_channels_; i_q++) {
203 out_word.push_back(qie_outs.at(i_q).getTDC().at(i_s));
204 } // over channels: TDC
205 } // over time samples
206
207 // in verbose mode, print this all to screen
208 if (verbose_) {
209 std::cout << "total word ";
210 int widx = 0;
211 int i_wstart =
212 std::max(std::max(QIEStream::ERROR_POS, QIEStream::CHECKSUM_POS),
213 QIEStream::TRIGID_POS + (QIEStream::TRIGID_LEN_BYTES)) +
214 1; // probably overkill :D should be 4
215 for (auto word : out_word) {
216 if ((widx - i_wstart) % n_channels_ == 0) {
217 int sample = (widx - i_wstart) / n_channels_;
218 if (sample % 2 == 0)
219 std::cout << "\n sample " << sample / 2 << " | ";
220 else
221 std::cout << "\n TDC: ";
222 }
223 std::cout << (unsigned)word << " ";
224 // std::cout << std::bitset<8>(word) << " " ; //for binary output
225 // format
226 widx++;
227 }
228 std::cout << std::endl;
229 } // if verbose
230
231 event.add(output_collection_, out_word);
232}
233
235 ldmx_log(debug) << "Process starts!";
236
237 return;
238}
239
241 ldmx_log(debug) << "Process ends!";
242
243 return;
244}
245
246} // namespace trigscint
247
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Implements an event buffer system for storing event data.
Definition Event.h:40
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
void produce(framework::Event &event) override
Process the event and put new data products into it.
void onProcessStart() override
Callback for the EventProcessor to take any necessary action when the processing of events starts,...
void onProcessEnd() override
Callback for the EventProcessor to take any necessary action when the processing of events finishes,...
void configure(framework::config::Parameters &ps) override
Configure our converter based off the configuration parameters decoded from the passed python script.
class for storing QIE output as a binary stream
Definition QIEStream.h:24
void setADC(const std::vector< int > adc)
Store adcs of all time samples.
Definition QIEStream.h:90
void setElectronicsID(const int elecid)
Store the electronics ID.
Definition QIEStream.h:84
void setCID(const std::vector< int > cid)
Store cids of all time samples.
Definition QIEStream.h:102
void setTDC(const std::vector< int > tdc)
Store tdcs of all time samples.
Definition QIEStream.h:96
class for storing QIE output