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.

Categories

The OpenAg system defines a list of “categories” which can be used to describe the functionality contained in a firmware/software module/input/output. For example, the firmware module for the am2315 sensor itself belongs to the “sensors” and “calibration” category because it outputs sensor data and has inputs for calibration. The air temperature and air humidity outputs from this firmware module belong to the “sensors” category because they represent sensor readings, and the inputs to this module used for calibration belong to the “calibration” category.

When flashing an Arduino, it is possible to specify a list of categories that should be enabled. By default, all categories are enabled except for “calibration”. This allows the codegen system to generate one Arduino sketch to use during normal operation and a different sketch to use for calibration that enables the “calibration” inputs and disables the “actators”, for example.

Examples

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