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:

  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:

#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):

==========================================
                                                                                                                                    
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.

  • No labels