Table of Contents
- Application Main Setup
- Application Task
The application module is the final step. It should be the goal of your project. For instance, my work consisted in implementing a game of pong as biofeedback.
Close the existing project (“File” → “Close all”) before continuing. Creating a new project like you did for your signal processing module:
- “Project” → “Add New Project…“
- Close the two windows without saving.
- Create a new cpp file with the same code as in the signal processing module.
(you can add a title by writing Application→Title = <your Application Title>);
- Add all shared files to the project, the same way you added them to your signal processing module.
- Check that the project options are the same as for the signal processing module, except that “MODTYPE=3” should replace “MODTYPE=2”.
- “Save project as” your application name in a new folder under contrib\Application\<yourAppName>.
You can now create a new unit. Again, you can erase the ”#pragma package(smart_init)” from the cpp file.
In the header, you will need to include “ApplicationBase.h”. Then you can declare your application class. It has to inherit from ApplicationBase (public derivation). It usually has the “Task” suffix. For instance, the “Pong” application has a “PongTask” class.
In the public field, you will have to declare the inherited methods as well as the constructor and destructor:
( const GUI::GraphicDisplay* = NULL);
- virtual ~ <Name of the class>();
- virtual void Preflight( const SignalProperties&, SignalProperties& ) const;
- virtual void Initialize( const SignalProperties&, const SignalProperties& );
- virtual void Process(const GenericSignal&, GenericSignal& );
- virtual void StartRun();
- virtual void StopRun();
- virtual void Halt();
These methods will be explained later on.
In the private field, you will probably want a TForm pointer to create a window and a couple of shapes and/or labels. These are all part of the Borland VCL library mentioned in the requirements section. For instance, the Pong game uses these:
- class TForm * window;
- class Tlabel * textLabel;
- class TShape * paddle1;
- class TShape * paddle2;
- class TShape * ball;
You will have to include the usual “PCHIncludes.h” and <vcl.h>. It is a good idea to include “Color.h” too. You may want to include “Localization.h” if you plan to translate your application.
You then have to register the filter, the same way you did the signal processing one. The rank has to be 3 since it is an application filter.
The constructor has to inherit from ApplicationBase, as well as create the class-typed attributes of your class. Here's an example from my PongTask class:
PongTask::PongTask( const GUI::GraphDisplay* inDisplay ) : ApplicationBase( inDisplay ), window( new TForm( reinterpret_cast
( NULL ) ) ), textLabel( new TLabel( window ) ), ball( new TShape( window ) ),
The content of the constructor is basically the same as in the signal processing filter. Start by defining your parameters and state variables if you have any. The protocol is the same as before.
You can also start personalizing the application window (border, color, etc.).
The Destructor should at least call the “Halt” method and delete the window (“delete window;”).
The Preflight method is used the same way as in the filter. You should at least call each Parameter (Parameter( “ParamName” );) to check the boundaries. Check all other conditions with normal “if” instructions. Also, make good use of the “bcierr” and “bciout” output streams, knowing that the first blocks the process, the second being just a warning.
The initialize method should set every Tform, Tshape or Tlabel parameters (size, color, visibility, position, etc.), and anything else you need to be done before the application starts running. It is also a good place to “transfer” the Parameters to variables.
The StartRun and StopRun are called when you “Suspend” or “Resume” the application (StartRun is also called at the beginning). Usually they will have a “Pause” message appear or disappear in the middle of the screen. The actual pause in the process is done automatically.
The Halt method is called when the application is stopped. It is mostly used by the acquisition module, but you may have a use for it if your application initiates asynchronous operations such as executing threads or acquiring data.
The Process method is the same as for the signal processing filter. It is the core method, but do not hesitate to create private methods to “divide” the work and have clean code. Remember that the function is called for each block, so the timing is hard, since it depends on the sampling rate and the sample block size, which are determined in the source module.