Writing Firmware Modules

Overview

Firmware modules should be subclasses of the Module class defined in the OpenAg Firmware Module repository. They must define a begin() function that initializes the module itself. This begin() function will be called in the setup() function of the Arduino sketch generated for the project. They must also define an update() function that updates the module (e.g. reads from a sensor at some rate). This update() function will be called in the loop() function of the Arduino sketch generated for the project. The Module superclass defines a status_level attribute which the firmware module should use to report its current status. Valid value for this attribute (all defined in the header file for the Module superclass) are OK (which means that the module is “ok”), WARN (which means that there is some warning for the module), and ERROR (which means that there is an error preventing the module from working as desired). The superclass also defines a status_msg attribute which is a String that the firmware module should use to describe the status of the module. This is generally an empty string when the status level is “ok” and an error message when the status level is “warn” or “error”. Finally, the superclass defines a status_code attribute which is a :spp:class:`uint8_t` value that the firmware module should use to describe the status of the module. This serves the same purpose as the status_msg field. The module.json file (described in more detail below) should contain a dictionary explaining the meaning of all valid status_code values for the module.

In addition to these standard functions and attributes (which are all defined in the header file for the Module class), the module must define a get function for each of its outputs and a set function for each of its inputs. In particular, it must define a get function of the following form for each output.

bool get_OUTPUT_NAME(OUTPUT_TYPE &msg)

The function takes as argument an object of the desired message type, populates the object with the current value of the output and returns True if and only if the message should be published on the module output.

The module must also define a set function of the following form for each input.

void set_INPUT_NAME(INPUT_TYPE msg)

The function takes as argument an object of the desired message type populated with the value being passed in as input and should immediately process the message.

In addition the module should define a module.json file containing all of the metadata about the firmware module. In particular, it should be an instance of the openag.models.FirmwareModuleType schema encoded as JSON.

The system uses PlatformIO to compile Arduino sketches, so modules must also define a library.json file meeting the PlatformIO specifications. To work with our system, this file need only contain the fields name and framework. The name field should be the name of the module, and the framework field should have the value arduino.

I/O Categories

Inputs and output can define a list of “categories” to which they belong. There are currenty only 3 valid categories: “sensors” (for sensor outputs), “actuators” (for actuator outputs), and “calibration”. The “sensors” and “actuators” categories should be fairly self explanatory. The “calibration” category is for inputs or output that should only be active when the use is in the process of calibrating their system. This allows the codegen system to generate one Arduino sketch to use during normal operation with all of the “actuators” and “sensors” inputs and outputs and a different sketch to use for calibration with only the “calibration” inputs and outputs.

Examples

The repository openag_firmware_examples provides some examples of well-documented, simple firmware modules for reference.