source: trunk/FACT++/src/DataWriteFits.cc@ 20115

Last change on this file since 20115 was 17657, checked in by tbretz, 11 years ago
Use the trigger counter from the last event when writing the footer data; this might need another update when we start to discarde events due to software triggers and the like; it fixes a problem which occured in cases with fadloss when an inavlid event is posted to the queue and the runClose used that data to write the footer; updated the comments in the FITS header
File size: 10.1 KB
Line 
1#include "DataWriteFits.h"
2
3#include "HeadersFAD.h"
4#include "EventBuilder.h"
5#include "Converter.h"
6
7
8using namespace std;
9
10DataWriteFits::~DataWriteFits()
11{
12 if (fFile.IsOpen())
13 {
14 WriteFooter();
15 fFile.Close();
16 }
17
18 delete fConv;
19}
20
21template <typename T>
22 void DataWriteFits::WriteKey(const string &name, const int idx, const T &value, const string &comment)
23{
24 ostringstream str;
25 str << name << idx;
26
27 ostringstream com;
28 com << "Board " << setw(2) << idx << ": " << comment;
29
30 fFile.WriteKey(str.str(), value, com.str());
31}
32
33// --------------------------------------------------------------------------
34//
35//! DataWriteFits constructor. This is the one that should be used, not the default one (parameter-less)
36//! @param runid This parameter should probably be removed. I first thought it was the run number, but apparently it is not
37//! @param h a pointer to the RUN_HEAD structure that contains the informations relative to this run
38//
39bool DataWriteFits::Open(const RUN_HEAD &h, const FAD::RunDescription &d)
40{
41 if (fConv)
42 {
43 Error("DataWriteFits::Open called twice.");
44 return false;
45 }
46
47 const int16_t realRoiTM = (h.NroiTM >= 2*h.Nroi && h.Nroi<=512) ? h.Nroi : 0;
48
49 fFile.AddColumn('I', "EventNum");
50 fFile.AddColumn('I', "TriggerNum");
51 fFile.AddColumn('S', "TriggerType");
52 fFile.AddColumn('I', "NumBoards");
53 fFile.AddColumn('C', "Errors", 4);
54 fFile.AddColumn('I', "SoftTrig");
55 fFile.AddColumn('I', "UnixTimeUTC", 2);
56 fFile.AddColumn('I', "BoardTime", NBOARDS);
57 fFile.AddColumn('S', "StartCellData", NPIX);
58 fFile.AddColumn('S', "StartCellTimeMarker", NTMARK);
59 fFile.AddColumn('S', "Data", h.NPix*h.Nroi);
60 fFile.AddColumn('S', "TimeMarker", h.NTm*realRoiTM);
61
62 // Write length of physical pipeline (1024)
63 fConv = new Converter(Converter::ToFormat(fFile.GetColumnTypes()));
64
65 const size_t sz = (h.NPix*h.Nroi + h.NTm*realRoiTM)*2;
66 if (fConv->GetSize()-sz+4!=sizeof(EVENT))
67 {
68 ostringstream str;
69 str << "The EVENT structure size (" << sizeof(EVENT) << ") doesn't match the described FITS row (";
70 str << fConv->GetSize()-sz+4 << ")";
71 Error(str);
72 return false;
73 }
74
75 //Form filename, based on runid and run-type
76 fFileName = FormFileName("fits");
77
78 if (!fFile.OpenFile(fFileName))
79 return false;
80
81 if (!fFile.OpenTable("Events"))
82 return false;
83
84 if (!fFile.WriteDefaultKeys("fadctrl"))
85 return false;
86
87 Info("==> TODO: Write sampling frequency...");
88
89 //write header data
90 //first the "standard" keys
91 try
92 {
93 fFile.WriteKey("BLDVER", h.Version, "Builder version");
94 fFile.WriteKey("RUNID", GetRunId(), "Run number");
95// fFile.WriteKey("RUNTYPE", h.RunType, "Type of run");
96 fFile.WriteKey("NBOARD", h.NBoard, "Number of acquisition boards");
97 fFile.WriteKey("NPIX", h.NPix, "Number of pixels");
98 fFile.WriteKey("NTMARK", h.NTm, "Number of time marker channels");
99 fFile.WriteKey("NCELLS", 1024, "Maximum number of slices per pixels");
100 fFile.WriteKey("NROI", h.Nroi, "Number of slices per pixels");
101 fFile.WriteKey("NROITM", realRoiTM, "Number of slices per time-marker");
102
103 const uint16_t realOffset = (h.NroiTM > h.Nroi) ? h.NroiTM - 2*h.Nroi : 0;
104 fFile.WriteKey("TMSHIFT", realOffset, "Shift of the start of the time marker readout wrt to data");
105
106 //FIXME should we also put the start and stop time of the received data ?
107 //now the events header related variables
108 fFile.WriteKey("CAMERA", "MGeomCamFACT", "");
109 fFile.WriteKey("DAQ", "DRS4", "");
110 fFile.WriteKey("ADCRANGE", 2000, "Dynamic range in mV");
111 fFile.WriteKey("ADC", 12, "Resolution in bits");
112 fFile.WriteKey("RUNTYPE", d.name, "File type according to FAD configuration");
113
114 // Write a single key for:
115 // -----------------------
116 // Start package flag
117 // package length
118 // version number
119 // status
120 // Prescaler
121
122 // Write 40 kays for (?)
123 // Phaseshift
124 // DAC
125
126 for (int i=0; i<h.NBoard; i++)
127 {
128 const PEVNT_HEADER &hh = h.FADhead[i];
129
130 // Header values whihc won't change during the run
131 WriteKey("ID", i, hh.board_id, "Board ID");
132 WriteKey("FWVER", i, hh.version_no, "Firmware Version");
133
134 ostringstream dna;
135 dna << "0x" << hex << hh.DNA;
136 WriteKey("DNA", i, dna.str(), "Unique FPGA device identifier (DNA)");
137 }
138
139 // FIXME: Calculate average ref clock frequency
140 for (int i=0; i<h.NBoard; i++)
141 {
142 const PEVNT_HEADER &hh = h.FADhead[i];
143
144 if (hh.start_package_flag==0)
145 continue;
146
147 fFile.WriteKey("BOARD", i, "Board number for RUN, PRESC, PHASE and DAC");
148 // fFile.WriteKey("RUN", hh.runnumber, "Run number");
149 fFile.WriteKey("PRESC", hh.trigger_generator_prescaler, "Trigger generator prescaler");
150 fFile.WriteKey("PHASE", (int16_t)hh.adc_clock_phase_shift, "ADC clock phase shift");
151
152 for (int j=0; j<8; j++)
153 {
154 ostringstream dac, cmt;
155 dac << "DAC" << j;
156 cmt << "Command value for " << dac.str();
157 fFile.WriteKey(dac.str(), hh.dac[j], cmt.str());
158 }
159
160 break;
161 }
162
163 double avg = 0;
164 int cnt = 0;
165 for (int i=0; i<h.NBoard; i++)
166 {
167 const PEVNT_HEADER &hh = h.FADhead[i];
168
169 if (hh.start_package_flag==0)
170 continue;
171
172 avg += hh.REFCLK_frequency;
173 cnt ++;
174 }
175
176 // FIXME: I cannot write a double! WHY?
177 fFile.WriteKey("REFCLK", avg/cnt*2.048, "Average reference clock frequency in Hz");
178
179 fFile.WriteKey("DRSCALIB", GetDrsStep()>=0, "This file belongs to a DRS calibration");
180 if (GetDrsStep()>=0)
181 fFile.WriteKey("DRSSTEP", GetDrsStep(), "Step of the DRS calibration");
182
183 }
184 catch (const CCfits::FitsException &e)
185 {
186 Error("CCfits::Table::addKey failed in '"+fFileName+"': "+e.message());
187 return false;
188 }
189
190 fTstart[0] = h.RunTime;
191 fTstart[1] = h.RunUsec;
192
193 fTstop[0] = 0;
194 fTstop[1] = 0;
195
196 fTriggerCounter.fill(0);
197
198 //Last but not least, add header keys that will be updated when closing the file
199 return WriteFooter();
200}
201
202// --------------------------------------------------------------------------
203//
204//! This writes one event to the file
205//! @param e the pointer to the EVENT
206//
207bool DataWriteFits::WriteEvt(const EVT_CTRL2 &evt)
208{
209 if (!fFile.AddRow())
210 return false;
211
212 // Remember the counter of the last written event
213 fTriggerCounter = evt.triggerCounter;
214
215 // Remember the time of the last event
216 fTstop[0] = evt.time.tv_sec;
217 fTstop[1] = evt.time.tv_usec;
218
219 const EVENT &e = *evt.fEvent;
220
221 const int realRoiTM = (e.RoiTM > e.Roi) ? e.Roi : 0;
222 const size_t sz = sizeof(EVENT) + sizeof(e.StartPix)*e.Roi+sizeof(e.StartTM)*realRoiTM; //ETIENNE from RoiTm to Roi
223
224 const vector<char> data = fConv->ToFits(reinterpret_cast<const char*>(&e)+4, sz-4);
225
226 return fFile.WriteData(data.data(), data.size());
227}
228
229bool DataWriteFits::WriteFooter()
230{
231 try
232 {
233 /*
234 fFile.WriteKey("NBEVTOK", rt ? rt->nEventsOk : uint32_t(0),
235 "How many events were written");
236
237 fFile.WriteKey("NBEVTREJ", rt ? rt->nEventsRej : uint32_t(0),
238 "How many events were rejected by SW-trig");
239
240 fFile.WriteKey("NBEVTBAD", rt ? rt->nEventsBad : uint32_t(0),
241 "How many events were rejected by Error");
242 */
243
244 //FIXME shouldn't we convert start and stop time to MjD first ?
245 //FIXME shouldn't we also add an MjD reference ?
246
247 const Time start(fTstart[0], fTstart[1]);
248 const Time stop (fTstop[0], fTstop[1]);
249
250 fFile.WriteKey("TSTARTI", uint32_t(floor(start.UnixDate())),
251 "Time when first event received (integral part)");
252 fFile.WriteKey("TSTARTF", fmod(start.UnixDate(), 1),
253 "Time when first event received (fractional part)");
254 fFile.WriteKey("TSTOPI", uint32_t(floor(stop.UnixDate())),
255 "Time when last event received (integral part)");
256 fFile.WriteKey("TSTOPF", fmod(stop.UnixDate(), 1),
257 "Time when last event received (fractional part)");
258 fFile.WriteKey("DATE-OBS", start.Iso(),
259 "Time when first event received");
260 fFile.WriteKey("DATE-END", stop.Iso(),
261 "Time when last event received");
262
263 fFile.WriteKey("NTRG", fTriggerCounter[0], "No of physics triggered events");
264 fFile.WriteKey("NTRGPED", fTriggerCounter[1], "No of pure pedestal triggered events");
265 fFile.WriteKey("NTRGLPE", fTriggerCounter[2], "No of external light pulser triggered events");
266 fFile.WriteKey("NTRGTIM", fTriggerCounter[3], "No of time calibration triggered events");
267 fFile.WriteKey("NTRGLPI", fTriggerCounter[4], "No of internal light pulser triggered events");
268 fFile.WriteKey("NTRGEXT1", fTriggerCounter[5], "No of triggers from ext1 triggered events");
269 fFile.WriteKey("NTRGEXT2", fTriggerCounter[6], "No of triggers from ext2 triggered events");
270 fFile.WriteKey("NTRGMISC", fTriggerCounter[7], "No of all other triggered events");
271 }
272 catch (const CCfits::FitsException &e)
273 {
274 Error("CCfits::Table::addKey failed in '"+fFile.GetName()+"': "+e.message());
275 return false;
276 }
277 return true;
278}
279
280// --------------------------------------------------------------------------
281//
282//! Closes the file, and before this it write the TAIL data
283//! @param rt the pointer to the RUN_TAIL data structure
284//
285bool DataWriteFits::Close(const EVT_CTRL2 &)
286{
287 if (!fFile.IsOpen())
288 return false;
289
290 WriteFooter();
291
292 fFile.Close();
293
294 return true;
295}
Note: See TracBrowser for help on using the repository browser.