-
Notifications
You must be signed in to change notification settings - Fork 0
Module Tutorial
Cadence supports the dynamic loading of custom modules written in C++. Typically these are used in one of the following ways:
- To add new agency which responds to events and observes/modifies the Cadence graph. An example would be a new user interface for Cadence or a new hardware device providing IO to Cadence.
- Add new event handlers to provide an alternative internal storage of the graph or virtual parts of the graph such as special arithmetic operators or remote storage.
- Add a new scripting language to replace or work above DASM.
A basic module must implement the functions shown in the example below.
extern "C" void initialise(const cadence::core::OID &base) {
}
extern "C" void cadence_update() {
}
extern "C" void finalise() {
}
The initialise function is called when the module is loaded and is passed an OID corresponding to the base object that this module is associated with. The base object can be chosen in the script that loads the module.
cadence_update is optional and optionally called at a specified frequency or as often as possible. Typically it would be used for polling or maintenance operations that don't correspond to events in Cadence.
Finalise is called when the module is unloaded, usually when Cadence itself is terminated.
A module must be compiled as a shared library (--shared -fPIC
) and linked with the libcadence-embedded library. Finally, a DASM script should be used for loading and configuring a module, an example is given below.
.my_base = (new
);
.modules my_module = (new type=Module
file = (new type=LocalFile
filename = "libcadence_mymodule.so"
)
base = (.my_base)
update = false
frequency = 0.00
);
Unless using an absolute path Cadence will look in @PREFIX@/share/cadence-embedded/modules, the current directory and the systems library folders for the module so file. If installing the module it is best to install to the cadence-embedded/modules folder. Note: @PREFIX@ usually defaults to /usr/local but can be customised using ./configure --prefix="..."
during the build process.
An agent module will provide one or more classes that inherit the cadence::Agent class. The new classes are then registered with Cadence so that they can be constructed, destroyed and notified of any events as appropriate. An instance of one of these agent classes can be associated with a particular cadence OID in order to respond to changes to that (or other) objects and observe/modify the object.
Header Example
#ifndef _CADENCE_CANVU_BACKLIGHT_H_
#define _CADENCE_CANVU_BACKLIGHT_H_
#include <cadence-embedded/agent.h>
class CANvuBacklight : public cadence::Agent {
public:
OBJECT(Agent, CANvuBacklight);
CANvuBacklight(const cadence::core::OID &);
~CANvuBacklight();
PROPERTY_RF(int, lcd, "lcd");
PROPERTY_WF(int, lcd, "lcd");
BEGIN_EVENTS(Agent);
EVENT(evt_lcd, (*this)("lcd"));
END_EVENTS;
};
#endif
This header defines a new agent class called CANvuBacklight
which has a property called lcd
. The PROPERTY_RF
and PROPERTY_WF
macros define accessor methods that get or set the "lcd" property in Cadence. These are equivalent to using get("lcd")
and set("lcd",...)
but can be used as lcd()
and lcd(...)
respectively.
The event macros allow specified C++ methods to be called when a specified property is changed. In this case the evt_lcd
method is called whenever the local "lcd" property changes.
Note the OBJECT
macro at the top, before the constructor, which must be included with first argument as the base class and the second as the name of the new agent class.
Main source example:
#include <cadence-embedded/agent.h>
#include <cadence-embedded/cadence.h>
#include <canvu-vm/backlight.h>
using namespace cadence;
using namespace cadence::core;
using namespace canvu;
CANvuBacklight::CANvuBacklight(const OID &obj) : Agent(obj) {
registerEvents();
}
CANvuBacklight::~CANvuBacklight() {
}
namespace canvu {
OnEvent(CANvuBacklight, evt_lcd) {
int level = lcd();
...
}
};
IMPLEMENT_EVENTS(CANvuBacklight,Agent);
extern "C" void initialise(const cadence::core::OID &base) {
Object::registerType<CANvuBacklight>();
(Object*)base;
}