Digitization
Each EPU creates a self-contained stream of LSEP datagrams segmented into CCSDS packets. In order to reconstruct the complete sequence of events read out from the detector, it is necessary to merge these streams at the event level. Some prototype code has been implemented to perform this function, making use of the following underlying utilities:
- The RawArchive library to retrieve CCSDS packets for a specified timespan
- the DFI library to assemble and parse the LSEP datagrams
- the LDF library to extract the low-level contribution data from each event.
The prototype code implements an EventMerger object with the following declaration:
Code Block |
---|
class EventMerger { public: typedef void (*valcb_t)( const LDFContext&, const LDFData&, void* ); EventMerger( const RetDef& rd, valcb_t valCB, void* cbData ); ~EventMerger(); void merge(); private: void operator()(); static void* threadCB( void* tdata ); std::vector< EventRetriever* > m_readers; pthread_t m_thread; valcb_t m_valCB; void* m_cbData; }; |
This object is constructed from the following items:
- a RetDef object, which defines the CCSDS APIDS and timespans to be retrieved, as well as the "spacecraft ID" of the entity that originated the data, and the root of the raw-packet archive.
- a user-specified function obeying the "valcb_t" prototype to receive the event and context data
- a pointer to a user-defined argument to the callback function
As each event in the merged stream becomes available, the EventMerger will call the user-defined function with objects containing the context and data for that event.
An example of usage is as follows:
Code Block |
---|
#include <stdio.h> #include "MRG/RetDef.hh" #include "MRG/EventMerger.hh" #include "MRG/LDFContext.hh" #include "MRG/LDFData.hh" #include "LATdatagramIterator.h" #include "EBFeventIterator.h" class EBFevent; class MyLATcomponentIterator; class MyEBFeventIterator : public EBFeventIterator { public: MyEBFeventIterator(); virtual ~MyEBFeventIterator(); virtual int handleError(EBFevent* evt, unsigned code, unsigned p1=0, unsigned p2=0) const; virtual int process(EBFevent*); private: MyLATcomponentIterator* _lci; }; void valCB( const LpaMerge::LDFContext& ctx, const LpaMerge::LDFData& ldf, void* userData ) { printf( "==========================================\n" ); printf( "\nEvent %lld context:", ctx.scalers.sequence ); printf( "\n------------------\n" ); ctx.dump(); printf( "\nEvent %lld data:", ctx.scalers.sequence ); printf( "\n---------------\n" ); MyEBFeventIterator eei; eei.iterate( const_cast< EBFevent* >( ldf.start() ), const_cast< EBFevent* >( ldf.end() ) ); printf( "\n" ); } int main( int argc, char* argv[] ) { LpaMerge::RetDef rd( "./arch", 99 ); rd.add( LpaMerge::ApidSpan( 955, 1137447000.0, 1137447160.0 ) ); rd.add( LpaMerge::ApidSpan( 956, 1137447000.0, 1137447160.0 ) ); LpaMerge::EventMerger em( rd, valCB, NULL ); em.merge(); } |
The first part of the sample output for this program is as follows (the LDF dump has been truncated):
No Format |
---|
========================================== Event 0 context: ccsds: apid = 955, utc = 1137447034.808804 meta: hwkey = 0x00000000, swkey = 0x00000000 current: secs = 159139827 tics = 0x00625AC8, hacks = 0x00000000 previous: secs = 159139826 tics = 0x01312DC8, hacks = 0x0000007F scalers: elapsed = 0x006f9db7 = 7314871 scalers: livetime = 0x006f9c27 = 7314471 scalers: prescaled = 0x00000000 = 0 scalers: discarded = 0x00000000 = 0 scalers: deadzone = 0x00000000 = 0 run: groundid = 0x00BEEF, started = 0x00000000 (0 ) run: platform = testbed (1) run: origin = montecarlo (1) open: nmodes = 0, ndgms = 0 open: action = start (0) open: reason = unknown (5) open: crate = epu0 (0) open: mode = normal (0) close: action = continue (3) close: reason = full (4) Event 0 data: EBF format identity = 0x104f0010 Event status = 0x0000 = 0 Event length = 0x0b88 = 2952 Bytes Event summary = 0x8a000000 GEM: Contribution length = 64 Bytes Contribution error = 0x0 Contribution sequence = 0 LCB Header = 0x0000c0a1 source = 0x10 destination = 0x20 respond = 1 protocol = 1 parity = 1 Summary = 0x8a000000 eventSequence = 0 = 0x00000000 = ((eventNumber << 2) | tag) eventNumber = 0 tag = 0 calStrobe = 0 TACK = 1 readout4 = 0 zeroSuppress = 1 marker = 0 error = 0 diagnostic = 0 trgParityError = 0 Data: 0ccc08c0, 008008c0, 000f0000, 00008100 80400000, 00002008, 00000002, 006f9c27 00000000, 00000000, 00000001, 006f9db7 00625ac8, 006f9db7 GEM: ROI vector = 0x0ccc TKR vector = 0x08c0 CAL HE vector = 0x0080 CAL LE vector = 0x08c0 Condition summary = 0x0f Missed (deadZone) = 0x00 CNO vector = 0x0000 tile list: XZM, XZP = 0x8100, 0x0000 YZM, YZP = 0x0000, 0x8040 XY = 0x00002008 RBN, NA = 0x0002, 0x0000 Live time = 0x006f9c27 = 7314471 Prescaled = 0x00000000 = 0 Discarded = 0x00000000 = 0 Condition arrival: raw = 0x00000001 external = 0x00 = 0 cno = 0x00 = 0 ... |
The code as-is handles only LSEP data. I'm contemplating how I might template it to handle the three flavors of LSEC data as well, but I haven't yet come up with a good scheme to keep the client from having to have a lot of advance knowledge about what's coming down the pipe.