ModBoss.Schema (modboss v0.1.0)

Macros for establishing Modbus schema.

The schema allows names to be assigned to individual registers or groups of contiguous registers along with encoder/decoder functions. It also allows registers to be flagged as readable and/or writable.

Naming an address

You'll name a Modbus address with this format:

holding_register 17, :outdoor_temp, as: {ModBoss.Encoding, :signed_int}

This establishes address 17 as a holding register with the name :outdoor_temp. The raw value from the register will be passed to ModBoss.Encoding.decode_signed_int/1 before being returned.

Similarly, to set aside a group of registers to hold a single logical value, it would look like:

holding_register 20..23, :model_name, as: {ModBoss.Encoding, :ascii}

This establishes addresses 20–23 as holding registers with the name :model_name. The raw values from these registers will be passed (as a list) to ModBoss.Encoding.decode_ascii/1 before being returned.

Mode

All registers are read-only by default. Use mode: :rw to allow both reads & writes. Or use mode: :w to mark a register as write-only.

Automatic encoding/decoding

Depending on whether a mapping is flagged as readable/writable, it is expected that you will provide functions with encode_ or decode_ prepended to the value provided by the :as option.

For example, if you specify as: :on_off for a read-only register, ModBoss will expect that the schema module defines an encode_on_off/1 function that accepts the value to encode and returns either {:ok, encoded_value} or {:error, messsage}.

If the function to be used lives outside of the current module, a tuple including the module name can be passed. For example, you can use built-in translation from ModBoss.Encoding such as :boolean, :signed_int, :unsigned_int, and :ascii.

output of encode_*

Your encode function may need to encode for one or multiple registers, depending on the mapping. You are free to return either a single value or a list of values—the important thing is that the number of values returned needs to match the number of registers for your mapping. If it doesn't, ModBoss will detect that and return an error during encoding.

For example, if encoding "ABC!" as ascii into a mapping with 3 registers, this would technically only "require" 2 registers (one 16-bit register for every 2 characters). However, your encoding should return a list of 3 values if that's what you've assigned to the mapping in your schema.

input to decode_*

When decoding a single register, the decode function will be passed the single value from that register as provided by your read function.

When decoding multiple registers (e.g. in ModBoss.Encoding.decode_ascii/1), the decode function will be passed a List of values.

Example

defmodule MyDevice.Schema do
  use ModBoss.Schema

  modbus_schema do
    holding_register 1..5, :model, as: {ModBoss.Encoding, :ascii}
    holding_register 6, :outdoor_temp, as: {ModBoss.Encoding, :signed_int}
    holding_register 7, :indoor_temp, as: {ModBoss.Encoding, :unsigned_int}

    input_register 200, :foo, as: {ModBoss.Encoding, :unsigned_int}
    coil 300, :bar, as: :on_off, mode: :rw
    discrete_input 400, :baz, as: {ModBoss.Encoding, :boolean}
  end

  def encode_on_off(:on), do: {:ok, 1}
  def encode_on_off(:off), do: {:ok, 0}

  def decode_on_off(1), do: {:ok, :on}
  def decode_on_off(0), do: {:ok, :off}
end

Summary

Functions

Adds a coil to a schema.

Adds a read-only discrete input to a schema.

Adds a holding register to a schema.

Adds a read-only input register to a schema.

Establishes a Modbus schema in the current module.

Functions

coil(addresses, name, opts \\ [])

(macro)

Adds a coil to a schema.

Opts

  • :mode — Makes the mapping readable/writable — can be one of [:r, :rw, :w] (default: :r)
  • :as — Determines which encoding/decoding functions to use when writing/reading values. See explanation of automatic encoding/decoding.

discrete_input(addresses, name, opts \\ [])

(macro)

Adds a read-only discrete input to a schema.

Opts

holding_register(addresses, name, opts \\ [])

(macro)

Adds a holding register to a schema.

Opts

  • :mode — Makes the mapping readable/writable — can be one of [:r, :rw, :w] (default: :r)
  • :as — Determines which encoding/decoding functions to use when writing/reading values. See explanation of automatic encoding/decoding.

input_register(addresses, name, opts \\ [])

(macro)

Adds a read-only input register to a schema.

Opts

modbus_schema(list)

(macro)

Establishes a Modbus schema in the current module.