CbmRoot
Loading...
Searching...
No Matches
trd2d/UnpackMS.cxx
Go to the documentation of this file.
1/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Pascal Raisig, Alexandru Bercuci, Dominik Smith [committer] */
4
6
8
9#include <algorithm>
10#include <cassert>
11#include <iomanip>
12#include <iostream>
13#include <sstream>
14#include <vector>
15
16using std::unique_ptr;
17
18namespace cbm::algo::trd2d
19{
20 // ---- Fasp message constructor ----------------------------------------
21 FaspMessage::FaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t asic)
22 : ch(c)
24 , tlab(t)
25 , data(d)
26 , fasp(asic)
27 {
28 if (typ == uint8_t(eMessageType::kData))
30 else if (typ == uint8_t(eMessageType::kEpoch))
32 }
33
34 std::string FaspMessage::print() const
35 {
36 std::stringstream ss;
37 switch (type) {
39 ss << " DATA : fasp=" << std::setw(2) << (int) fasp << " ch=" << std::setw(2) << (int) ch
40 << " t=" << std::setw(3) << (int) tlab << " data=" << std::setw(4) << (int) data << std::endl;
41 break;
42 case eMessageType::kEpoch: ss << " EPOCH: ch=" << (int) ch << " epoch=" << (int) epoch << std::endl; break;
43 default: ss << " MTYPE: unknown" << std::endl; break;
44 }
45
46 return ss.str();
47 }
48
49 // ---- Data type descriptor ---------------------------------------------
50 template<uint8_t mess_ver>
55
56 template<>
58 {
60
61 if ((w >> 31) & 0x1) return eMessageType::kEpoch;
63 }
64
65 // ---- Unpacking a DATA WORD ---------------------------------------------
66 template<uint8_t mess_ver>
67 void FaspMessage::readDW(uint32_t)
68 {
69 return;
70 }
71
72 template<>
74 {
76
77 uint8_t shift(0);
78 uint16_t adc_data = (w >> shift) & 0x3fff;
79 // TODO This data format version delivers the ADC value as bit_sgn + 13 significant bits
80 // TODO The CbmTrdDigi supports digi data with only 12bits unsigned. The first tests will
81 // TODO convert the measurement to the old format leaving the implementation of the new storage to // TODO later time. (AB 14.06.2024)
82 uint16_t sign = adc_data >> 13; // sign
83 int value_i;
84 if (!sign)
85 value_i = adc_data;
86 else
87 value_i = (-1) * ((adc_data ^ 0xffff) & 0x1fff);
88 // convert to 12bit unsigned
89 data = (value_i + 0x1fff) >> 2;
90 shift += uint8_t(eMessageLength::kMessData);
91 tlab = (w >> shift) & 0x7f;
92 shift += uint8_t(eMessageLength::kMessTlab);
93 ch = (w >> shift) & 0xf;
94 shift += uint8_t(eMessageLength::kMessCh);
95 fasp = ((w >> shift) & 0x3f);
96 shift += uint8_t(eMessageLength::kMessFasp);
97 type = eMessageType((w >> shift) & 0x1);
98 shift += uint8_t(eMessageLength::kMessType);
99
100 // if (VERBOSE >= 2) {
101 // printf("v06.24Mess_readDW[%x] signed charge = %+d\n", w, value_i);
102 // print();
103 // }
104 return;
105 }
106
107 // ---- Unpacking an EPOCH WORD ---------------------------------------------
108 template<uint8_t mess_ver>
109 void FaspMessage::readEW(uint32_t)
110 {
111 return;
112 }
113
114 template<>
116 {
118
119 uint8_t shift(0);
120 epoch = (w >> shift) & 0x1fffff;
121 shift += uint8_t(eMessageLength::kMessEpoch);
122 ch = (w >> shift) & 0xf;
123 shift += uint8_t(eMessageLength::kMessCh);
124 fasp = (w >> shift) & 0x3f;
125 shift += uint8_t(eMessageLength::kMessFasp);
126 type = eMessageType((w >> shift) & 0x1);
127 shift += uint8_t(eMessageLength::kMessType);
128
129 // if (VERBOSE >= 2) {
130 // printf("v06.24Mess_readEW[%x]\n", w);
131 // print();
132 // }
133 return;
134 }
135
136 void UnpackPar::dump() const
137 {
138 L_(debug) << "UnpackPar::dump() mod=" << fModId << " SysOff=" << fSystemTimeOffset << " sRef=" << fRefSignal;
139 L_(debug) << " elink[" << (int) fEqId << "]=0x" << std::hex << (int) fEqAdd << " nAsics=" << std::dec
140 << fAsicParams.size();
141 for (const auto& [fasp, par] : fAsicParams) {
142 L_(debug) << " fasp=" << int(fasp) << " par=" << std::hex << &par;
143 }
144 for (int ipad(0); ipad < NFASPMOD * NFASPCH; ipad++) {
145 float gn(fCalibParams[ipad].fGainFee), bl(fCalibParams[ipad].fBaseline);
146 if (gn < 0) continue;
147 L_(debug) << " pad=" << ipad << " bl=" << bl << " gn=" << gn;
148 }
149 L_(debug) << "UnpackPar::dump(-----------------------)";
150 }
151
152 template<>
154 {
158 L_(debug) << "<vLegacy> Eq[" << (int) fEqId << "] = 0x" << std::hex << fEqAdd;
159 return fEqId * NFASPROB + fasp_id;
160 }
161
162 template<>
164 {
168
169 int rob = fEqId / 2; // ROB on the current chamber
170 //L_(debug) << "<v24> ROB=" << rob << " Eq[" << (int)fEqId << "] = 0x" << std::hex << fEqAdd;
171
172 return rob * NFASPROB + fasp_id;
173 }
174
175 // ---- Algorithm execution ---------------------------------------------
176 template<>
177 typename UnpackMS<uint8_t(eMessageVersion::kMessLegacy)>::Result_t
178 UnpackMS<uint8_t(eMessageVersion::kMessLegacy)>::operator()(const uint8_t* msContent,
179 const fles::MicrosliceDescriptor& msDescr,
180 const uint64_t tTimeslice) const
181 {
185 // --- Output data
186 Result_t result = {};
187
188 MsContext ctx = {};
189
190 // define time wrt start of time slice in TRD/FASP clks [80 MHz].
191 uint64_t time = uint64_t((msDescr.idx - tTimeslice) / 25); // guaranteed by CBM-DAQ
192 time <<= 1; // time expressed in 12.5 ns clks
193
194 // Get the number of complete words in the input MS buffer.
195 const uint32_t nwords = msDescr.size / 4;
196 L_(debug) << "UnpackMS<kMessLegacy>::op() param.olink[" << (int) fParams.fEqId << "]=0x" << std::hex
197 << (int) fParams.fEqAdd << " data.rob=0x" << int(msDescr.eq_id) << " words=" << std::dec << nwords;
198 // We have 32 bit FASP frames in this readout version
199 const uint32_t* wd = reinterpret_cast<const uint32_t*>(msContent);
200
201 unsigned char lFaspOld(0xff);
202 std::vector<FaspMessage> vMess;
203 for (uint64_t j = 0; j < nwords; j++, wd++) {
204 uint32_t w = *wd;
205 uint8_t ch_id = w & 0xf;
206 uint8_t isaux = (w >> 4) & 0x1;
207 uint8_t slice = (w >> 5) & 0x7f;
208 uint16_t data = (w >> 12) & 0x3fff;
209 uint8_t fasp_id = ((w >> 26) & 0x3f);
210
211 if (isaux) {
212 if (ch_id == 0) {
213 // clear buffer
214 if (vMess.size()) {
215 pushDigis(vMess, time, ctx);
216 }
217 vMess.clear();
218
219 lFaspOld = 0xff;
220 time += FASP_EPOCH_LENGTH;
221 }
222 continue;
223 }
224 if (lFaspOld != fasp_id) {
225 if (vMess.size()) {
226 pushDigis(vMess, time, ctx);
227 }
228 vMess.clear();
229 lFaspOld = fasp_id;
230 }
231 if (data & 0x1) {
233 continue;
234 }
235 if (data & 0x2000) {
237 data &= 0x1fff;
238 }
239 vMess.emplace_back(ch_id, (uint8_t) eMessageType::kData, slice, data >> 1, lFaspOld);
240 }
241 std::get<0>(result) = FinalizeComponent(ctx); //TO DO: Original (non-algo) version calls this after MS loop!!
242 std::get<1>(result) = ctx.fMonitor;
243
244 return result;
245 }
246 //_________________________________________________________________________________
247 template<uint8_t sys_ver>
248 bool UnpackMS<sys_ver>::pushDigis(std::vector<FaspMessage> messes, const uint64_t time, MsContext& ctx) const
249 {
250 constexpr uint8_t mLegacy =
251 uint8_t(eMessageVersion::kMessLegacy); // message versions compatible with the current algo specialization
252 const uint16_t mod_id = fParams.fModId;
253 const uint8_t fasp_mod_id = fParams.mapFaspId2Mod<mLegacy>(messes[0].fasp);
254 const UnpackAsicPar& asicPar = fParams.fAsicParams.at(fasp_mod_id);
255
256 for (auto imess : messes) {
257 const UnpackChannelPar& chPar = asicPar.fChanParams[imess.ch];
258 //std::cout << imess.print();
259 const int32_t pad = std::abs(chPar.fPadAddress) / 2;
260 const bool hasPairingR = bool(chPar.fPadAddress > 0);
261 const uint8_t tdaqOffset = chPar.fDaqOffset;
262 const uint64_t lTime = time + tdaqOffset + imess.tlab;
263 const uint16_t lchR = hasPairingR ? imess.data : 0;
264 const uint16_t lchT = hasPairingR ? 0 : imess.data;
265 std::vector<CbmTrdDigi>& digiBuffer = ctx.fDigiBuffer[pad];
266
267 if (digiBuffer.size() == 0) { // init pad position in map and build digi for message
268 digiBuffer.emplace_back(pad, lchT, lchR, lTime);
269 digiBuffer.back().SetAddressModule(mod_id);
270 continue;
272
273 // check if last digi has both R/T message components. Update if not and is within time window
274 auto id = digiBuffer.rbegin(); // Should always be valid here.
275 // No need to extra check
276 double r, t;
277 int32_t dt;
278 const int32_t dtime = (*id).GetTime() - lTime;
279 bool use(false);
280
281 if (abs(dtime) < 5) { // test message part of (last) digi
282 r = (*id).GetCharge(t, dt);
283 if (lchR && r < 0.1) { // set R charge on an empty slot
284 (*id).SetCharge(t, lchR, -dtime);
285 use = true;
286 }
287 else if (lchT && t < 0.1) { // set T charge on an empty slot
288 (*id).SetCharge(lchT, r, +dtime);
289 (*id).SetTime(lTime);
290 use = true;
291 }
292 }
293
294 // build digi for message when update failed
295 if (!use) {
296 digiBuffer.emplace_back(pad, lchT, lchR, lTime);
297 digiBuffer.back().SetAddressModule(mod_id);
298 id = digiBuffer.rbegin();
299 }
300
301 // update charge for previously allocated digis to account for FASPRO ADC buffering and read-out feature
302 for (++id; id != digiBuffer.rend(); ++id) {
303 r = (*id).GetCharge(t, dt);
304 if (lchR && int(r)) { // update R charge and mark on digi
305 (*id).SetCharge(t, lchR, dt);
306 (*id).SetFlag(1);
307 break;
308 }
309 else if (lchT && int(t)) { // update T charge and mark on digi
310 (*id).SetCharge(lchT, r, dt);
311 (*id).SetFlag(0);
312 break;
313 }
314 }
315 }
316 messes.clear();
317
318 return true;
319 }
320
321 template<uint8_t sys_ver>
322 std::vector<CbmTrdDigi> UnpackMS<sys_ver>::FinalizeComponent(MsContext& ctx) const
323 {
324 std::vector<CbmTrdDigi> outputDigis;
325
326 for (uint16_t ipad(0); ipad < NFASPMOD * NFASPPAD; ipad++) {
327 if (!ctx.fDigiBuffer[ipad].size()) continue;
328 uint nIncomplete(0);
329 for (auto id = ctx.fDigiBuffer[ipad].begin(); id != ctx.fDigiBuffer[ipad].end(); id++) {
330 double r, t;
331 int32_t dt;
332 r = (*id).GetCharge(t, dt);
333 // check if digi has all signals CORRECTED
334 if (((t > 0) != (*id).IsFlagged(0)) || ((r > 0) != (*id).IsFlagged(1))) {
335 nIncomplete++;
336 continue;
337 }
338 // reset flags as they were used only to mark the correctly setting of the charge/digi
339 (*id).SetFlag(0, false);
340 (*id).SetFlag(1, false);
343 uint64_t gtime = (*id).GetTime() * fAsicClockPeriod;
344 gtime >>= 1;
345 if (gtime >= uint64_t(fParams.fSystemTimeOffset)) gtime -= fParams.fSystemTimeOffset;
346 (*id).SetTime(gtime);
347 outputDigis.emplace_back(std::move((*id)));
348 }
349 // clear digi buffer wrt the digi which was forwarded to higher structures
350 ctx.fDigiBuffer[ipad].clear();
351 if (nIncomplete > 2) {
352 ctx.fMonitor.fNumIncompleteDigis++; //TO DO: This must be moved if finalization is done after MS loop
353 }
354 }
355 return outputDigis;
356 }
357
358 // ------------- Specialization kMess24 --------------------------------
359 typename UnpackMS<uint8_t(eMessageVersion::kMess24)>::Result_t
360 UnpackMS<uint8_t(eMessageVersion::kMess24)>::operator()(const uint8_t* msContent,
361 const fles::MicrosliceDescriptor& msDescr,
362 const uint64_t tTimeslice) const
363 {
367
368 constexpr uint8_t m24 =
369 uint8_t(eMessageVersion::kMess24); // message versions compatible with the current algo specialization
370 Result_t result = {};
371 MsContext ctx = {};
372
373 // // define time wrt start of time slice in TRD/FASP clks [80 MHz]. Contains:
374 // // - relative offset of the MS wrt the TS
375 // // - FASP epoch offset for current CROB
376 // // - TRD2D system offset wrt to experiment time
377 // uint64_t time = uint64_t((msDescr.idx - tTimeslice - fParams.fSystemTimeOffset) * fAsicClockFreq);
378
379 //define the time in run as function of CBM 40MHz clk
380 uint64_t timeClk = (msDescr.idx - tTimeslice) / 25;
381 //convert to TRD2D 80MHz clk
382 timeClk <<= 1;
383
384 // Get the number of complete words in the input MS buffer.
385 const uint32_t nwords = msDescr.size / 4;
386 L_(debug) << "UnpackMS<kMess24>::op() param.olink[" << (int) fParams.fEqId << "]=0x" << std::hex
387 << (int) fParams.fEqAdd << " data.rob=0x" << int(msDescr.eq_id) << " words=" << std::dec << nwords;
388
389 // We have 32 bit FASP frames in this readout version
390 const uint32_t* wd = reinterpret_cast<const uint32_t*>(msContent);
391
392 unsigned char lFaspOld(0xff);
393 std::vector<FaspMessage> vMess;
394 for (uint32_t j = 0; j < nwords; j++, wd++) {
395 uint32_t w = *wd;
396 // Select the appropriate conversion type of the word according to
397 // the current message version and type
398 switch (FaspMessage::getType<m24>(w)) {
399 case eMessageType::kData: ctx.fMess.readDW<m24>(w); break;
400 case eMessageType::kEpoch: ctx.fMess.readEW<m24>(w); break;
401 default: break; // no way to reach this line
402 }
403 // PROCESS EPOCH MESSAGES
404 if (ctx.fMess.type == eMessageType::kEpoch) {
405 if (ctx.fMess.ch == 0) { // check word integrity
406 // clear buffer
407 if (vMess.size()) {
408 pushDigis(vMess, timeClk, ctx);
409 }
410 vMess.clear();
411
412 lFaspOld = 0xff;
413 timeClk += FASP_EPOCH_LENGTH;
414 }
415 else {
416 L_(error) << "FASP message[Epoch] with wrong signature.";
418 }
419 continue;
420 }
421
422 // PROCESS DATA MESSAGES
423 // clear buffer when switching to other FASP
424 if (ctx.fMess.fasp != lFaspOld) {
425 if (vMess.size()) pushDigis(vMess, timeClk, ctx);
426 vMess.clear();
427 lFaspOld = ctx.fMess.fasp;
428 }
429 if (ctx.fMess.data & 0x2000) { // kept for backward compatibility TODO
431 ctx.fMess.data &= 0x1fff;
432 }
433 vMess.emplace_back(ctx.fMess);
434 }
435
436 // combine all digis from this ROB
437 std::vector<CbmTrdDigi> outputDigis;
438 for (uint16_t ipad(0); ipad < NFASPMOD * NFASPPAD; ipad++) {
439 if (!ctx.fRobDigi[ipad].size()) continue;
440 for (auto id : ctx.fRobDigi[ipad]) {
443 uint64_t gtime = id.GetTime() * fAsicClockPeriod;
444 gtime >>= 1;
445 int toffGlobalCorrection = fParams.fSystemTimeOffset + fParams.toff[ipad];
446 if (toffGlobalCorrection > 0 && gtime < uint64_t(toffGlobalCorrection))
447 gtime = 0;
448 else
449 gtime -= (fParams.fSystemTimeOffset + fParams.toff[ipad]);
450 id.SetTime(gtime);
451 outputDigis.emplace_back(std::move(id));
452 }
453 }
454 std::get<0>(result) = outputDigis;
455 std::get<1>(result) = ctx.fMonitor;
456
457 return result;
458 }
459 bool UnpackMS<uint8_t(eMessageVersion::kMess24)>::pushDigis(std::vector<FaspMessage> messes, const uint64_t time,
460 MsContext& ctx) const
461 {
462 constexpr uint8_t m24 =
463 uint8_t(eMessageVersion::kMess24); // message versions compatible with the current algo specialization
464 const uint8_t fasp_mod_id = fParams.mapFaspId2Mod<m24>(messes[0].fasp);
465 L_(debug) << "pushDigis<v24> fasp=" << (int) messes[0].fasp << "/" << (int) fasp_mod_id << " ns=" << messes.size();
466 if (fParams.fAsicParams.find(fasp_mod_id) == fParams.fAsicParams.end()) {
467 L_(error) << "pushDigis<v24> fasp=" << (int) messes[0].fasp << "/" << (int) fasp_mod_id
468 << " not mapped to param.olink[" << (int) fParams.fEqId << "]=0x" << std::hex << (int) fParams.fEqAdd;
469 return false;
470 }
471 const UnpackAsicPar& asicPar = fParams.fAsicParams.at(fasp_mod_id);
472
473 for (auto imess : messes) {
474 const UnpackChannelPar& chPar = asicPar.fChanParams[imess.ch];
475 const uint32_t mch = std::abs(chPar.fPadAddress);
476 const CalibChannelPar& calPar = fParams.fCalibParams.at(mch);
477 // skip message if threshold set and signal under
478 if (calPar.noise.fSignalThres && imess.data <= calPar.noise.fSignalThres) continue;
479 const uint32_t pad = mch / 2;
480 const bool hasPairingR = bool(chPar.fPadAddress > 0);
481 const uint64_t lTime = time + imess.tlab;
482 const uint16_t sgn =
483 uint16_t((imess.data - fParams.fRefSignal) * calPar.fGainFee - calPar.fBaseline + fParams.fRefSignal);
484 const uint16_t lchR = hasPairingR ? sgn : 0;
485 const uint16_t lchT = hasPairingR ? 0 : sgn;
486 std::vector<CbmTrdDigi>& digiBuffer = ctx.fRobDigi[pad];
487
488 // init pad position in array and build digi for message
489 if (digiBuffer.size() == 0) {
490 digiBuffer.emplace_back(pad, lchT, lchR, lTime);
491 digiBuffer.back().SetAddressModule(fParams.fModId);
492 continue;
493 }
494
495 // check if last digi has both R/T message components.
496 // Update if not and is within time window
497 auto& id = digiBuffer.back(); // Should always be valid here.
498 // No need to extra check
499 double r, t;
500 int32_t dt;
501 const int32_t dtime = id.GetTime() - lTime;
502 bool use(false), noise(false);
503 if (abs(dtime) < 5) { // test message part of (last) digi
504 r = id.GetCharge(t, dt);
505 if (lchR && r < 0.1) { // set R charge on an empty slot
506 id.SetCharge(t, lchR, -dtime);
507 use = true;
508 }
509 else if (lchT && t < 0.1) { // set T charge on an empty slot
510 id.SetCharge(lchT, r, +dtime);
511 id.SetTime(lTime);
512 use = true;
513 }
514 }
515
516 // check if signal can be flagged as dynamic noise
517 if (!use && calPar.noise.tWindow > 0) {
518 if (lchR) {
519 if (lchR < calPar.noise.lThreshold && std::abs(-dtime * 12.5 - calPar.noise.tDelay) < calPar.noise.tWindow)
520 noise = true;
521 }
522 else {
523 if (lchT < calPar.noise.lThreshold && std::abs(-dtime * 12.5 - calPar.noise.tDelay) < calPar.noise.tWindow)
524 noise = true;
525 }
526 }
527
528 // build digi for message when update failed
529 if (!use && !noise) {
530 digiBuffer.emplace_back(pad, lchT, lchR, lTime);
531 digiBuffer.back().SetAddressModule(fParams.fModId);
532 }
533 }
534 messes.clear();
535
536 return true;
537 }
538} // namespace cbm::algo::trd2d
#define L_(level)
friend fscal sgn(fscal x)
std::tuple< std::vector< Digi_t >, Monitor_t, Aux_t > Result_t
bool pushDigis(std::vector< FaspMessage > messages, const uint64_t time, MsContext &ctx) const
UnpackMS(const UnpackPar &pars)
Construct from parameters.
Unpack algorithm for TRD2D.
std::vector< CbmTrdDigi > FinalizeComponent(MsContext &ctx) const
bool pushDigis(std::vector< FaspMessage > messages, const uint64_t time, MsContext &ctx) const
UnpackPar fParams
Parameter container.
static constexpr uint fAsicClockPeriod
Clock period of FASP 12.5ns. Use 25ns follow by division by 2.
@ kMess24
unpacker version for 2-board FASPRO+GETS HW
TRD2D Calibration parameters for one Asic channel.
float fGainFee
gain correction wrt to reference
NoiseChannelPar noise
noise channel parametrisation
float fBaseline
baseline correction
uint8_t tlab
time of the digi inside the epoch
void readDW(uint32_t w)
Read DATA WORD and store the content locally.
uint32_t epoch
epoch id (not used for the moment)
uint8_t ch
ch id in the FASP
void readEW(uint32_t w)
Read EPOCH WORD and store the content locally.
uint8_t fasp
FASP id in the module.
eMessageType type
message type 0 = data, 1 = epoch (not used for the moment)
static eMessageType getType(uint32_t w)
Implementation of message type descriptor according to message version.
uint16_t fSignalThres
Signal threshold for independent - static noise.
uint16_t tWindow
time [clk] delay wrt to causing primary signal
uint16_t lThreshold
time [clk] window to search for noisy signal
TRD2D Unpacking parameters for one Asic.
std::vector< UnpackChannelPar > fChanParams
Parameters for different channels.
TRD2D Unpacking parameters for one Asic channel.
int32_t fPadAddress
Pad address for channel.
int8_t fDaqOffset
Time calibration parameter.
UnpackMonitorData fMonitor
Container for monitoring data.
std::array< std::vector< CbmTrdDigi >, NFASPMOD *NFASPCH > fDigiBuffer
std::array< std::vector< CbmTrdDigi >, NFASPMOD *NFASPPAD > fRobDigi
uint32_t fNumSelfTriggeredData
word fulfills data & 0x2000
uint32_t fNumIncompleteDigis
incomplete digis left in pads after finalization
uint32_t fNumErrEndBitSet
Corrupted data with end bit set.
void dump() const
Write to the debug stream the content of the current param object.
uint8_t fEqId
Equipment (optical fiber) ID of component.
uint16_t fModId
Module ID of component.
int32_t fSystemTimeOffset
Time calibration parameter.
float fRefSignal
reference signal for calibration
std::map< uint8_t, UnpackAsicPar > fAsicParams
Parameters for each ASIC.
std::array< CalibChannelPar, NFASPMOD *NFASPCH > fCalibParams
Parameters for each ASIC channel for each module.
uint8_t mapFaspId2Mod(uint8_t fasp_id) const
Calculate the module wise FASP id from the FASP id provided at the level of equipment Id (optical fib...
uint16_t fEqAdd
Equipment (optical fiber) address [HEX].
#define NFASPCH
#define NFASPROB
#define NFASPPAD
#define NFASPMOD
#define FASP_EPOCH_LENGTH