You are here: Foswiki>FESA Web>ExternalTriggersViaCTRVInFESA (13 Nov 2009, HaraldBraeuning)Edit Attach
-- TobiasHoffmann - 09 Dec 2008

-- HaraldBraeuning - 21 Jan 2009

How to use external triggers (max.2) within FESA?

To use external triggers with FESA a CTRV module is required, which provides two inputs for ext. triggers. The required programming of the CTRV board is described here.

Definition in the Design-Tool

The first step is to create a custom event source and the associated events in the FESA Design-Tool:

  1. add a custom-event-source to the events of the equipment design.
  2. add one or two logical-event items to the events of the design. These logical events must reference the custom event source.
  3. add the appropriate scheduling-units to the scheduling with triggers referencing the appropriate logical events defined above.

The image shows the definition of a custom event source named CTRVSource in the FESA-Design tool. The custom event source produced two logical events (CTRVEvent1 and CTRVEvent2) which are used to schedule the Arm and Acquire real time actions.

CustomEventSourceExample.png

Implementation of the custom event source

The second step now is to implement the custom event source in the C++ code. The FESA-Tools will have created two files names <SourceName>.h and <SourceName>.cpp, where SourceName is the name of the custom event source in the Design-Tool (i.e. CTRVSource in the above example). Access to the CTRV module is done by the Tim-Library, which is installed with FESA.

In the constructor, the TimLib must be initialzed as shown in the code for the above example:
CTRVSource::CTRVSource():AbstractEventSource("CTRVSource")
{
  // Initialize low level timing interface to recieve events from any timing device
  TimLibError err= TimLibInitialize(TimLibDevice_ANY);
  if (err != TimLibErrorSUCCESS) 
    {
      cout << "TimLibInitialize fails: " << TimLibErrorToString(err) << endl;
    }
}

In the connect method, the TimLib must be connected to the hardware interrupts of the counters, which are started by the external triggers. In the above eaxmple, these are counters 1 and 2:

void CTRVSource::connect(const string& eventName)
{
  cout <<"Now connecting event " << eventName << endl;
  TimLibError err = TimLibConnect(TimLibClassHARDWARE,TimLibHardwareCOUNTER_1|TimLibHardwareCOUNTER_2,1);
  if (err != TimLibErrorSUCCESS) 
    {
      string s("TimingEventSource::connect() TimLibConnect error when trying to connect event ");
      s.append(": ");
      s.append(TimLibErrorToString(err));
      throw FesaBadConfig("Fesa_FWK",err,s.c_str());
    }
}

This completes the initialization part of the custom event source. The workhorse function is the wait() method. In this method, the code must wait for a signal from the TimLib, create the real time event structure with the appropriate event name as defined in the design tool and return a pointer to it. The code below demonstrates this for our example.

Note: Be careful that the event names in the source code are typed exactly as in the Design-Tool. Any spelling mistakes will not be caught at compile time. Everything will appear to run fine, but the associated real time action will never be called because the correct event is not generated.

RTEvent *CTRVSource::wait()
{
  // This custom event-source may fire any of the following events: 
  static char *eventName[] = { "CTRVEvent1", "CTRVEvent2" };
   
  // Rely on POSIX nanosleep which is protected against signals
  struct timespec time_left_before_wakeup;
  struct timespec delay;
  delay.tv_sec = 1; // wake-up every 1 seconds
  delay.tv_nsec = 0;
     
  TimLibError    err;
  TimLibClass    t_class; /* Class of interrupt */
  unsigned long  equip;   /* PTIM CTIM or hardware mask */
  unsigned long  plnum;   /* Ptim line number 1..n or 0 */
  TimLibHardware source;  /* Hardware source of interrupt: 
                             NOTE this is the counter number (1,2,3,...) and NOT the mask as indicated 
                             in the documentation of the TimLib header file */
  TimLibTime     onzero;  /* Time of interrupt/output */
  TimLibTime     trigger; /* Time of counters load */
  TimLibTime     start;   /* Time of counters start */
  unsigned long  ctim;    /* CTIM trigger equipment ID */
  unsigned long  payload = 0; /* Payload of trigger event */
  unsigned long  module = 0;  /* Module that interrupted */
  unsigned long  missed = 0;  /* Number of missed interrupts */
  unsigned long  qsize = 0;   /* Remaining interrupts on queue */
  TgmMachine     tgmMachine;
    
  // This loop is necessary in case of error on TimLib call. For errors other
  // than TimLibTIMEOUT we have to insert our own delay to avoid to loop
  // in TimLibCall very fast consuming all CPU time.
  for(;;) 
    {
      err = TimLibWait(&t_class, &equip, &plnum, &source, &onzero, &trigger, &start, 
                       &ctim, &payload, &module, &missed, &qsize, &tgmMachine);
      if (err != TimLibErrorSUCCESS) 
        {
          if (err != TimLibErrorTIMEOUT) // Severe error: wait to avoid hogging all CPU time
            {
              nanosleep(&delay,&time_left_before_wakeup);
            }
          continue; // try again
        }
      
      TimingContext* tc = new TimingContext();     //Empty timingContext no cycleStamp
      int event = 0;
      if ((equip & TimLibHardwareCOUNTER_2) != 0) event = 1;
      RTEvent* theEvent = new RTEvent(eventName[event],tc,this);
      return theEvent;
    }
  return NULL;
}

Finally it is also the task of the event source to delete the event and its payload. This is done in the consume() method:
void CTRVSource::consume(RTEvent *evt)
{
  if(evt->getPayload()) delete evt->getPayload();
  if(evt->getMultiplexingContext()) delete evt->getMultiplexingContext();
  delete evt;
}

The complete source code can be found in the attachments. The header file created by the FESA Synchronize-Tool has not been edited and is thus not shown here.

Creation of the custom event source

In the final step, an object of the custom event source must be created. This must be done in the initialization of the real time part of the FESA class at start-up. To do this, the method specificInit() in the file <ClassName>Realtime.cpp must be added. The code below shows this for a FESA class called SIS3350:

WARNING: this is for FESA 2.9!
void SIS3350RT::specificInit(int argc, char ** argv) 
{
  // Create a acustom event source object and connect to it 
  createAndConnectCustomEventSource("CTRVSource","null");
}

Note for FESA 2.10:

In FESA 2.10 the custom event source will be created automatically by the framework. Only if a pointer to the event source is required for further use, the event source must be created in the specificInit() method:
void SIS3350RT::specificInit(int argc, char ** argv) 
{
  // Create a acustom event source object and connect to it 
  CustomEventSource *src = (CustomEventSource*)createCustomEventSource("CTRVSource");
}
Please not also the slightly different call to create the event source which automatically connects it.

That's it! If the CTRV module is programmed correctly, this will work fine.
I Attachment Action Size Date Who Comment
CTRVSource.cppcpp CTRVSource.cpp manage 4 K 21 Jan 2009 - 16:36 HaraldBraeuning Source code for a custom event source named CTRVSource
CustomEventSource.jpgjpg CustomEventSource.jpg manage 15 K 09 Dec 2008 - 09:16 TobiasHoffmann  
CustomEventSourceExample.pngpng CustomEventSourceExample.png manage 7 K 21 Jan 2009 - 16:48 HaraldBraeuning Definition of a custom event source in the Design-Tool
Topic revision: r7 - 13 Nov 2009, HaraldBraeuning
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback