Creating a Device Type - FREEDM-DGI/FREEDM GitHub Wiki

This tutorial will demonstrate how to create a new device class within the FREEDM-DGI code base. To aid the explanation, the tutorial will detail an example implementation of a new device class with the name DeviceExample. The new version of DGI no longer allows devices to be implemented as individual classes. Instead, devices are specified using an XML configuration file. A sample configuration file can be found in config/samples/device.xml.

Defining the Device Type

Open the device.xml configuration file and add a new tag <deviceType> under root. All of the data in this tag will be used to specify the parameters of the new DeviceExample device type. Each <deviceType> tag requires a unique identifier that serves as the device name in DGI. Add a tag with the name <id> as a child of <deviceType> and give it the value of DeviceExample. The configuration file should now resemble:

<root>
  <deviceType>
    <id>DeviceExample</id>
  </deviceType>
</root>

At this point the device has been defined and can be used inside of DGI. Instances of the device could be added to an adapter (if the adapter had a means to add a device without variables, which is not true for all adapters) and accesses through the device manager using the device type DeviceExample. However, the device stores no data that can be read by the DGI and has no settings that can be set by the DGI. These must be added with additional tags.

The DeviceExample has a Readable state which reads a value from some physical meter for use in the DGI. It uses this state to generate a Writable command that is used to control the operation of the meter. These are the only two types of device variables supported by the DGI: states that are read by the DGI, and commands that are issued by the DGI to control the physical system. These variables are defined in the configuration file using the <state> and <command> tags, followed by a unique identifier that names the state or command. In the example:

<root>
  <deviceType>
    <id>DeviceExample</id>
    <state>Readable</state>
    <command>Writable</command>
  </deviceType>
</root>

A device can have any number of states and commands. If there is a SampleDevice with two states but no commands, it could be specified through repeated use of the <state> tag:

  <deviceType>
    <id>SampleDevice</id>
    <state>StateA</state>
    <state>StateB</state>
  </deviceType>

There are no other recognized tags for the device.xml configuration file. Once the <id>, <state>, and <command> tags are set, declaration of the device for use within the DGI has been completed.

Using the Device Type

All devices are accessed in DGI using the CDeviceManager. Refer to the wiki page on the device manager to see how to use it to collect a set of devices. In order to access the new device you have defined, use the string identifier in the <id> tag (ExampleDevice) in the device manager function calls. The following discussion will discuss the various ways in which a CDevice pointer can be used once it has been retrieved from the device manager.

Reading a Device State

It is possible to read each value specified as a <state> in the device.xml specification using the device pointer. This is done through the CDevice::GetState function. To access the current value of Readable on a device pointer retrieved from the device manager:

SignalValue value = device->GetState("Readable");

The string passed to the CDevice::GetState function must correspond to some value in a <state> tag or the code will throw an exception. The function CDevice::HasState can be used to check if an exception will be thrown in advance. In general, the following code is safer than the code above:

if( device->HasState("Readable") )
  value = device->GetState("Readable");

The CDevice::HasState function will return false if the state is not recognized (and thus would throw an exception), which will prevent the CDevice::GetState function from executing.

Setting a Device Command

It is possible to set each value specified as a <command> in device.xml. These commands cannot be read by the DGI, so it is impossible for the current version of DGI to read the value of a command it has issued to some device. To set a command, the following function calls can be used:

if( device->HasCommand("Writable") )
  device->SetCommand("Writable", 1.0);

The CDevice::HasCommand function works the same as its state counter-part. The CDevice::SetCommand function in this instance would set the Writable command of the device object to 1. All commands in the DGI have the type SignalValue which is defined to be a float. It is not possible to set a non-numeric command.

Devices and Inheritance

The device types in device.xml support inheritance in that one device type can inherit all the states and commands of another type. There is no limit on the number of types one device can inherit from, or the depth of the inheritance. Inheritance can be defined using the <extends>type</extends> tag.

⚠️ **GitHub.com Fallback** ⚠️