You are here: Foswiki>FESA Web>HowTo>StepByStep>StepByStepCoding (18 Mar 2009, HaraldBraeuning)Edit Attach
-- HaraldBraeuning - 18 Mar 2009

Creating and Modifying the C++ code

Setting up after the initial design

After the initial design is finished and save in the designer, there is still no code to execute. To setup the directory structure and create stubs for the C++ code, execute the Fesa script:

Fesa Setup class-name version scratch

where class-name is the name you gave to the class on saving and version is the version number, usually 0 at the beginning. This will create the following directory structure beneath your current working directory:

  • class-name
    • v0
      • COMMON
      • GENERATED_CODE
      • RT
      • SERVER
      • TEST

plus a liberal dose of directories called CVS, which we will ignore. The various directories contain various parts of the final Fesa class:

COMMON
This directory should contain code / libraries needed by the class but totally independent on the class design.
GENERATED_CODE
This directory contains the major part of code generated from your class design. It may be educational to browse it, but do not change anything. It will most probably break the class and be lost anyway after a change in the design.
RT
This directory contains the code for the real time (RT) actions. For each RT action defined in the design, a stub header and source file will be generated. These files can and usually must be modified to implement the desired functionality. The Fesa scripts are intelligent enough to keep your modifications when the design changes.
SERVER
Like with the RT directory, this directory contains all code associated with server actions.
TEST
In this directory the executable of the class will be created. Also instantiation files should be generated here.

Synchronizing design changes

If you changed the design in the designer tool, you have to synchronize your code with your design. To do this, change to the directory class-name /v0 and execute the Fesa script

Fesa Synchronize class-name version

Coding the functionality

For the simple class described here, we have to provide the code for the 'Acquire' and 'AcquireStatus' real time actions.

Acquire RT action

The code for the 'Acquire' RT action resides in the Acquire.cpp file (and the Acquire.h file, which we do not need to edit however). For each call of the RT action, the methode Acquire::execute is called. Our code thus has to go into the body of this methode:

void Acquire::execute(RTEvent * pEv)
{
  log << "executing RT action: HBrTrivialAcquire"<<endInfo;
  MultiplexingContext *pContext = pEv->getMultiplexingContext();
  for (unsigned int i=0; i < deviceCollection.size(); i++)
    {
      HBrTrivialDevice * pDev = deviceCollection[i];
      log << "Acquire operates on device " << pDev->name.get() << endInfo;
      long r = pDev->range.get(pContext);
      long v = pDev->offset.get(pContext) + random() % r - r / 2;
      pDev->value.set(v,pContext);
    }
}

Some explanations are necessary. In contrast to server actions, real time actions are triggered by events, normally external events. A single Fesa class can handle several identical devices (instances) like for example to identical scalers in a VME crate. We want to handle all devices (instances) of the class in a RT action. The instances of the various devices are found in the deviceCollection. We therefore loop over all devices in the deviceCollection. (As an excersize create two instances of this simple class with different values for 'offset' and 'range' and observer what happens.)

The rest of the code inside the loop is fairly straight forward. We obtain the values for 'offset' and 'range' and calculate the random value 'v'. This we store in the 'value' field of the device. The parameter 'pContext' describes the virtual accellerator currently operating. It has no meaning in this class and can also be omitted, but it is always good style to provide it.

AcquireStatus RT action

Similar, the code for the 'AcquireStatus' RT action resides in the AcquireStatus.cpp file (and the AcquireStatus.h). The code for AqcuireStatus::execute method is shown here:

void AcquireStatus::execute(RTEvent * pEv)
{
  log << "executing RT action: HBrTrivialAcquireStatus"<<endInfo;
  for (unsigned int i=0; i < deviceCollection.size(); i++)
    {
      HBrTrivialDevice * pDev = deviceCollection[i];
      log << "AcquireStatus operates on device " << pDev->name.get() << endInfo;
      long dt = time(NULL) - pDev->startTime.get();
      pDev->runTime.set(dt);
    }
}

It is similar to the code for the Acquire RT action discussed above. In the body of the loop, the current unix time is obtained, the unix time at the start of the server is subracted and the result is stored in the 'runTime' field of the device.

But: how and where is the value for the 'startTime' field set ?

Initializing data

In the RT directory, there are two files class-name Realtime.cpp and class-name Realtime.h which are not associated with any RT action. These files provide code called when the RT part is first instantiated. Any class specific setup like setting up VME hardware addresses etc. should go in the 'specificInit' method. Two similar files called class-name Interface.cpp and class-name Interface.h reside in the SERVER directory and provide a 'specificInit' method for the server part of the class.

We put the initialization of the 'startTime' field in the 'specificInit' method of the RT part:

void HBrTrivialRT::specificInit(int argc, char ** argv) 
{
  cout << " HBrTrivialRT::specificInit is called" << endl;
  vector<HBrTrivialDevice*> *deviceCollection = HBrTrivialDevice::getDeviceCollection();
  for (unsigned int i=0;i<deviceCollection->size();i++)
    {
      HBrTrivialDevice *pDev = (*deviceCollection)[i];
      log << "Initialize device " << pDev->name.get() << endInfo;
      long start = (long)time(NULL);
      pDev->startTime.set(start);
    }
}

Creating the executable

In principle, the following is obvious, but we mention it anyway. After creating / modfying all the code, exectue make from the directory class-name /v0. You have graduated the first level, when the code compiles without error.
Topic revision: r1 - 18 Mar 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