Block Structure

To describe how a Block is structured, we will use the pvData Meta Language. It is important to note that although many EPICS conventions are followed in Malcolm, it is not a required part of it. The typeid of structures (before the indented block) will appear as a string typeid field in JSON serialized messages, and as the typeid in pvData serialized messages.

There are a number of operations that can be performed on the Block structure, such as Get, Put, Subscribe, Post. These will be described in the Message Structure section.

Note

Operations such as Get and Subscribe will by default operate on the entire Block structure to avoid race conditions between substructure updates, but some of the protocols supported (like pvAccess) will allow the substructures to be operated on independently.

Also note the placement of meta objects in the Block structure. The presence of a meta element in the structure allows separation of the current value from the metadata about the element.

A Block looks like this:

Block :=

malcolm:core/Block:1.0
    BlockMeta   meta
    Attribute   health      // HealthMeta
    {Attribute | Method  <field-name>}0+


BlockMeta :=

malcolm:core/BlockMeta:1.0
    string      description     // Description of Block
    string[]    tags       :opt // For future use
    bool        writeable  :opt // For future use
    string      label      :opt // Short label if different to name
    string[]    fields     :opt // The list of fields currently in the Block

The health Attribute will have value “OK” if everything is fine, otherwise will be in alarm status and report what is wrong. The other Attribute and Method objects define the interface for this particular Block and may change, appear and disappear depending on the state of the Block.

The meta BlockMeta defines a description and label for this Block. All meta objects have Tags that are defined in the Supported Tags page.

An Attribute looks like this:

Attribute := Scalar | ScalarArray | Table | PointGenerator


Scalar :=

epics:nt/NTScalar:1.0 // Conformant but optional fields -> meta
    scalar_t    value
    alarm_t     alarm       :opt
    time_t      timeStamp   :opt
    ScalarMeta  meta        :opt


ScalarArray :=

epics:nt/NTScalarArray:1.0 // Conformant but optional fields -> meta
    scalar_t[]      value
    alarm_t         alarm       :opt
    time_t          timeStamp   :opt
    ScalarArrayMeta meta        :opt


Table :=

malcolm:core/NTTable:1.0 // Conformant but optional fields -> meta
    string[]    labels
    TableValue  value
    alarm_t     alarm       :opt
    time_t      timeStamp   :opt
    TableMeta   meta        :opt


TableValue :=

structure
    {scalar_t[] <colname>}0+


PointGenerator :=

malcolm:core/PointGenerator:1.0
    PointGeneratorValue value
    alarm_t             alarm       :opt
    time_t              timeStamp   :opt
    PointGeneratorMeta  meta        :opt

The structures are very similar, and all hold the current value in whatever type is appropriate for the Attribute. Each structure contains a meta field that describes the values that are allowed to be passed to the value field of the structure:

ScalarMeta := BooleanMeta | StringMeta | ChoiceMeta | NumberMeta


BooleanMeta :=

malcolm:core/BooleanMeta:1.0
    string      description     // Description of attribute
    string[]    tags       :opt // e.g. "widget:led"
    bool        writeable  :opt // True if you can Put at the moment
    string      label      :opt // Short label if different to name


StringMeta :=

malcolm:core/StringMeta:1.0
    string      description     // Description of attribute
    string[]    tags       :opt // e.g. "widget:textinput"
    bool        writeable  :opt // True if you can Put at the moment
    string      label      :opt // Short label if different to name


ChoiceMeta :=

malcolm:core/ChoiceMeta:1.0
    string[]    choices         // Value will be one of these
    string      description     // Description of attribute
    string[]    tags       :opt // e.g. "widget:combo"
    bool        writeable  :opt // True if you can Put at the moment
    string      label      :opt // Short label if different to name


NumberMeta :=

malcolm:core/NumberMeta:1.0
    string      dtype           // e.g. int8, uint32, float64
    string      description     // Description of attribute
    string[]    tags       :opt // e.g. "widget:textupdate"
    bool        writeable  :opt // True if you can Put at the moment
    string      label      :opt // Short label if different to name
    display_t   display    :opt // Display limits, units, etc

The ScalarArrayMeta structures are identical to the ScalarMeta structures, but have “Array” in their typeid. TableMeta has similar fields:

TableMeta :=

malcolm:core/TableMeta:1.0
    structure   elements        // Metadata for each column
        {ScalarArrayMeta <elname>}0+
    string      description     // Description of attribute
    string[]    tags       :opt // e.g. "widget:table"
    bool        writeable  :opt // True if you can Put at the moment
    string      label      :opt // Short label if different to name

It contains a structure of elements that describe the subelements that are allowed in the Table.

A PointGeneratorMeta looks similar:

PointGeneratorMeta :=

malcolm:core/PointGeneratorMeta:1.0
    string      description     // Description of attribute
    string[]    tags       :opt // e.g. "widget:generatorpicker"
    bool        writeable  :opt // True if you can Put at the moment
    string      label      :opt // Short label if different to name

A Method looks like this:

Method :=

malcolm:core/Method:1.1
    MethodMeta  meta            // Spec for args and returns
    MethodLog   took       :opt // The last args the method was called with
    MethodLog   returned   :opt // The last return value the method produced

Argument := scalar_t | scalar_t[] | TableValue | PointGeneratorValue

MethodMeta :=

malcolm:core/MethodMeta:1.1
    MapMeta     takes           // Argument spec
    structure   defaults
        {Argument   <argname>}0+    // The defaults if not supplied
    string      description     // Docstring
    string[]    tags       :opt // e.g. "widget:confirmbutton"
    bool        writeable  :opt // True if you can Post at the moment
    string      label      :opt // Short label if different to name
    MapMeta     returns    :opt // Return value spec if any

ArgumentMeta := ScalarMeta | ScalarArrayMeta | TableMeta |
    PointGeneratorMeta


MapMeta :=

malcolm:core/MapMeta:1.0
    structure   elements            // Metadata for each element in map
        {ArgumentMeta <elname>}0+
    string[]    required       :opt // These fields will always be present

MethodLog :=

malcolm:core/MethodLog:1.0
    structure   value               // The arguments supplied or returned
        {Argument   <argname>}0+    // Including any server defaults
    string[]    present             // The keys of value sent
    alarm_t     alarm       :opt    // If something went wrong, what
    time_t      timeStamp   :opt    // Time it was called/returned

The takes structure describes the arguments that should be passed to the Method. The returns structure describes what will be returned as a result. The defaults structure contains default values that will be used if the argument is not supplied.

Methods are called by sending a Post message to the block with the name of the method and the arguments described in the takes MapMeta.

The Map just looks like this:

Map :=

structure
    {Argument   <argname>}0+