--
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.
The first step is to create a custom event source and the associated events in the FESA Design-Tool:
- add a
custom-event-source
to the events
of the equipment design.
- add one or two
logical-event
items to the events
of the design. These logical events must reference the custom event source.
- 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.
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.