Skip to content

A* stream multiplexor

a-mx is a multiplexer or joiner between different data sources and controllers using the A* protocol and is intended to be used for building up A* systems. A typical use

This document is intended to be used by developers and assumes some familiarity with the UNIX command line and networking.

The requirements are:

  1. Create a number of processes which communicate via a-mx.
  2. Changes in values such as Generator 1 Power Actual are passed to the other processes, e.g. a MODBUS reader would send Gen1P = 102 to a-mx which in turn would pass it to the HMI.
  3. There are configurable limits

The a-mx command is used to set up a collection of interconnected components which communicate with the A* protocol via a-mx.

The components are processes, files or fifos such as data recorders, time series data, HMI, models and controls.

For example the HMI a-hmi system can read and write values where as the a-console only receives data from a-mx. For example:

G a_mx a-mx a_npvt a-npvt a_mx->a_npvt a_console a-console a_mx->a_console sim_model sim-model a_mx->sim_model a_hmi a-hmi a_hmi->a_mx sim_control sim-control sim_control->a_mx

The values are passed to stdin and stdout for the various components using the A* protocol described below but one example would be:

  1. sim-model - updates PvAvailP because of the time of day and then sends the new value upstream to a-mx via stdout.
  2. a-mx records the new value and then passes it to a-hmi, a-npvt, a-console via each components stdin.
  3. Each connection can have limits, e.g. a-npvt cannot set values or a-hmi can only set values matchin *Cmd.

This particular setup would be started with:

% ./a-mx -rw a-hmi sim-model -w sim-control -r a-console a-npvt
TODO: rewrite example arguments

Any changes from the HMI would be recorded in a-mx and passed onto the appropriate components via stdin. The -rw option applies to the following components.

There are access control limits which can be set per component on the command line which are described later.

G a_mx_0 a-mx_0 a_mx_1 a-mx_1 a_mx_0->a_mx_1 DataStore0 DataStore0 a_mx_0->DataStore0 HMI HMI a_mx_1->HMI Analyser2 Analyser2 a_mx_1->Analyser2 Gen1 Gen1 Gen1->a_mx_0 Gen2 Gen2 Gen2->a_mx_0 Wtg1 Wtg1 Wtg1->a_mx_1

The A* protocol is a minimalist plain text npvt format using a flat namespace as described in a-protocol which also describes the’ broadcast variants.

Each command started by a-mx has its stdin and stdout connected back to a-mx. The commands on both steams are terminated by any of ‘\n’, ‘\r’, ‘\r\n’, i.e. a command is executed when line termination is seen.

The four commands are:

  1. Set a name x property to value, e.g. Gen1StartCmd = 1 or Gen1SetP -typical 0..100.
  2. Time stamped npvt variant, e.g. Gen1P = 100 1233332232.2
  3. Send variables ? ... - send all the state matching the description in ... back to sender, e.g. ? *P would send all npvt values matching *P
  4. Watch variables ! ... - send the variables when they change. Note that there can be only a single watch for each stream.
  5. Do we need an echo or comments??? TBA

The values for Send and Watch are used to identify the values to using names (npat), properties (ppat), values (‘vpat’) and ’:’ property (isapat). They are whitespace separated and default to *, e.g.

? - send all the state back.

? *P|*Q - send back all the state for names ending in P or Q.

? * = - send back the current values for all names.

? *Al = 1 - send any alarms that are 1.

? * -en * point - send -en for any name with its : property being point.

? *P = * point *Q = * point -

The inputs to watch are the same, e.g.

! *P - sends any changes to names ending in P to you.

There is a single watch list per channel and any changes to matching npv data are send via the usual means.

% ./DevSim -prefix Pm -unit 10 | head -n 10
Pm10P -units kW 1773802162.168
Pm10P = 201.66678153521698 1773802162.168
Pm10Q = 21.798631195816505 1773802162.168
Pm10S = 238.37803235202006 1773802162.168
Pm10F = 50.95897404009428 1773802162.168
Pm10P = 202.38345932326442 1773802162.404
Pm10Q = 24.400423052441525 1773802162.404

The a-mx combines multiple streams into one or more output streams, e.g. to simulate two Generators you could use:

% ./a-mx "./DevSim -unit 2" "./DevSim -unit 3" | head -20
Gen2P -units kW 1773802432.017
Gen2P = 209.87005127122163 1773802432.017
Gen2Q = 22.97585771092021 1773802432.017
Gen2S = 220.96218974374338 1773802432.017
Gen2F = 50.15230230947598 1773802432.017
Gen3P -units kW 1773802432.02
Gen3P = 205.03645661987198 1773802432.021
Gen3Q = 23.86320509429239 1773802432.021
Gen3S = 235.55207908877733 1773802432.021
Gen3F = 49.379324508076216 1773802432.021

The a-mx commands takes options including -show_stdout which limit the values that limits the values that are sent by a-mx to stdout, e.g.

% ./a-mx -show_stdout "*P" "./DevSim -unit 1" "./DevSim -unit 3"

Print -unit properties

% ./a-mx -show_stdout "* -units" "./DevSim -unit 1" "./DevSim -unit 3"

Finally you can filter on values, e.g. Gen2StartCmd = 1

The option -show_stderrhas the same syntax but sends it output to stderr for debugging/

Draft

TBA

% ./a-mx "./DevSim -unit 10" "./DevSim -unit 11"

Details on the implementation

Details on the security implications

Other sources…

\appendix

1

The protocol is just:

NameP = value
NameP = value time

The special names are used for modelling and limiting communication.

Watch = Gen*P

Noting Watch is a per link value! kept by a-mx.

You can of course have multiple instances