A previous article (here) describes the empty daemon and how to install and use it. This article presents some tips on writing new plug-ins.
Overview
Makefile
Readme File
State Data Structure
Resources
Core Logic
Submit Your Plug-in
The next step is to write the readme.txt file that describes your plug-in. The readme should describe how to install any required hardware or software. It should also describe your plug-in's resources.
Implementing the resources API is next. There is no need to tie the resource to the hardware, Just be sure that the set, get, and cat commands all seem to work.
The final step is to tie the hardware to the resources. You may find it easiest to implement and test the get and set resources and to then add the sensor resources.
git clone https://github.com/bob-linuxtoys/eedd.gitAdd a directory for your new plug-in and copy an existing plug-in into the new directory.
cd eedd/plug-ins mkdir new cp hellodemo/* newEdit the Makefile in the plug-ins directory to add your new plug-in. Note that you will have to add a line in four places to build, install, clean, and uninstall. Change to your new directory and rename hellodemo.c to new.c and edit the Makefile to change the target name from hellodemo to new. Edit new.c to change PLUGIN_NAME to "new".
This a good point to start testing. You should be able to build, install,
run, and load new.so.
cd
If everything is working the edlist should show your new plug-in name. It will list the resources for hellodemo but that is OK for now.
The readme is usually broken into four sections. The first section is an overview of the plug-in giving a high level description of what hardware is being used and what the high level application can do with the hardware.
The second section should describe the hardware and software prerequisites for the new plug-in. Your description should tell the reader where to buy or otherwise acquire the hardware and how to connect the hardware to your system. Be sure to describe the installation and configuration of any required software.
The third section describes the resources. List all of the resources and give the syntax and formatting of input and output values. You can have more than one value given in a resource. For example, you could specify a serial port device, its encoding, and its baud rate all in one resource. Explain the resource in enough detail and in terms that the application programmer has a clear of what the resource means and how to use it.
The last section should give a complete example that shows a typical use of the hardware. Try to make the example something that a new user could cut-and-paste and still work.
State Data Structure
Implementing the logic of your plug-in almost certainly requires saving
configuration or other state information. Create a data structure to
hold this state information. The hellodemo reference plug-in uses a
typedef for the data structure but this is certainly not required.
The reason for storing everything in a structure is that it is not
uncommon for a plug-in to be instantiated more than once and statically
allocated variables would lead to confusion. The state structure is
allocated from RAM each time the plug-in is loaded. Initialize the
state information in the Initialize() routine.
The state data structure most often contains open file descriptors, timers, configuration, and cached copies of some hardware data. You will probably want to open any device files and start everything from the Initialize() routine.
Resources
Most of the time getting a new plug-in to work is in getting the
resources to work. It is straightforward but a little tedious.
Start by giving IDs and names to each of your resources. The defines for this should look something like the following:
#define FN_TEXT "messagetext" #define FN_PERIOD "period" #define FN_MESSAGE "message" #define RSC_TEXT 0 #define RSC_PERIOD 1 #define RSC_MESSAGE 2
The default configuration of the empty daemon makes 25 plug-in slots available each with up to 10 resources. The resource IDs given above are an index into the slot's resource table. (FYI: The internal data and design of the empty daemon is described in Docs/design.txt and plug-ins/include/eedd.h respectively.)
Resources are configured in the Initialize() routine. Be sure to
set the flags correctly. If your get or set command does not work
you might want to check that the flags are set correctly. A resource
initialization might appear similar to this:
pslot->rsc[RSC_STATUS].name = FN_MESSAGE;
pslot->rsc[RSC_STATUS].flags = CAN_BROADCAST | IS_READABLE;
pslot->rsc[RSC_STATUS].bkey = 0;
pslot->rsc[RSC_STATUS].pgscb = usercmd;
pslot->rsc[RSC_STATUS].uilock = -1;
pslot->rsc[RSC_STATUS].slot = pslot;
pctx = (HELLODEMO *) pslot->priv; if ((cmd == EDGET) && (rscid == RSC_PERIOD)) { ret = snprintf(buf, *plen, "%d\n", pctx->period); *plen = ret; // (errors are handled in calling routine) } else if ((cmd == EDSET) && (rscid == RSC_PERIOD)) { ret = sscanf(val, "%d", &nperiod); if ((ret != 1) || (nperiod < 1)) { // one value greater than 0 ret = snprintf(buf, *plen, E_BDVAL, pslot->rsc[rscid].name); return; } // record the new period pctx->period = nperiod; } else if ((cmd == EDGET) && (rscid == RSC_TEXT)) { } else if ((cmd == EDSET) && (rscid == RSC_TEXT)) { } return;A good place to stop and test everything is when the get/set callbacks are done. Test all valid combinations of get, set, and cat for each resources. Be sure to test with both valid and invalid inputs.
Core Logic
Once the resources are correctly responding to UI commands it is time
to add the core logic to the plug-in.
A good place to start is with the configuration resources. Configuring a device name might close the old device if open and then open the new device. You can use the lsof command or look in /proc to verify that the new device is open and the old one closed.
If you have a timer you can add a print statement in the timer callback to see when the timer is called. If your timers have a user settable period you should be able to use edset to change the timer period.
A common use of a plug-in is to collect asynchronous data from a device and to broadcast it to listening subscribers. Both GPS and game controllers are examples of this. If your hardware needs asynchronous input you could open the default device in Initialize() and when the user sets the device with an edset command. Add a read callback to the file descriptor with the add_fd() routine. (See eedd.h for more information on add_fd().) In your read callback you can test the resource's bkey to see if there are any subscriptions to the data. If there are, you can format the data as a null terminated line of text and broadcast it using the bcst_ui() routine.
Submit Your Plug-in
While clearly not required, it would be nice if you submitted
your plug-in for inclusion in the empty daemon. It is a great
way to show your work and others may find your plug-in useful.
Since plug-ins are implemented as shared object libraries they
do not need to have the same license. You can use any license
you choose for your plug-in.