Modules, Definitions and Entities#

This page is a top down explanation of the above key terms by referencing the example IOC instance bl45p-mo-ioc-02 used in the system tests for this project.

The explanations rely on an understanding of the difference between generic IOCs and IOC instances. See Generic IOCs and instances.

Modules#

Every generic IOC image will include a number of EPICS support modules.

The bl45p-mo-ioc-02 ioc instance example uses the generic IOC container image ioc-pmac . This image contains the support modules pmac and motor plus the common support modules from epics-modules

Each IOC instance will mount a generic IOC image and therefore be able to make use of the libraries and DB templates in any of those support modules.

The goal of ibek is to allow a developer to define an instance of an IOC and make use of functions of its support modules.

ibek uses a support module definition file to determine what features of a support module may be instantiated.

Hence there is a collection of support module definition files inside of each generic IOC.

In the code the class GenericIoc is used to represent a generic IOC and an instance of that class represent an IOC instance.

Definition#

Each support module has its own support module definition file . This is a YAML file whose name is by convention <support_module>.ibek.support.yaml

These will all reside in a folder called /ibek in the container image.

The support module definition file contains Definitions which determine what Entities an IOC instance may instantiate.

For example the pmac support module declares the following Definitions in pmac.ibek.support.yaml (currently this is limited to 3 - the full implementation would have more):

  • Geobrick

  • DlsPmacAsynIPPort

  • DlsPmacAsynMotor

Each Definition describes a class of Entity by providing:

  • Entity class name

  • a list of arguments to supply when declaring an Entity

  • boot script entries to add for the Entity in the form of a jinja template that may refer to the above arguments

  • database templates to instantiate for the Entity with macro values from the above arguments

Expand below for the example support module definition file:

objects.ibek.support.yaml
# yaml-language-server: $schema=../schemas/ibek.support.schema.json

# slightly extended version of motorMotorSim.ibek.support.yaml from ibek-support.
# the extra things are fictitious but are here to exercise all of the features
# of the ibek.support schema
module: motorSim

entity_models:
  - name: simMotorController
    description: |-
      Creates a simulation motion controller
    parameters:
      controllerName:
        type: id
        description: |-
          The name of the controller and its Asyn Port Name

      P:
        type: str
        description: |-
          Device PV Prefix

      numAxes:
        type: int
        description: |-
          The number of axes to create

      port:
        type: object
        description: |-
          a reference to the asyn port for communication with the controller

      DESC:
        type: str
        description: |-
          The description of the controller
        default: "Simulated Motion Controller testing escaping: {% raw %} {{enclosed in escaped curly braces}} {% endraw %}"

    pre_init:
      - value: |
          # motorSimCreateController(controller_asyn_port_name, axis_count)
          # testing escaping: {% raw %} {{enclosed in escaped curly braces}} {% endraw %}
          motorSimCreateController({{controllerName}}, {{numAxes}})

    databases:
      - file: sim_motor.db
        args:
          controllerName:
          P:
          DESC:

    pvi:
      yaml_path: simple.pvi.device.yaml
      ui_macros:
        P:
      pv: true
      pv_prefix: $(P)

  - name: simMotorAxis
    description: |-
      Creates a simulation motor axis
    parameters:
      controller:
        type: object
        description: |-
          a reference to the motion controller

      M:
        type: str
        description: |-
          PV suffix for the motor record

      ADDR:
        type: int
        description: |-
          The axis number (allowed to be from 0 to controller.numAxes-1)

      DESC:
        type: str
        description: |-
          The description of the axis
        default: Motor {{ADDR}}

      DLLM:
        type: int
        description: |-
          The low limit of the axis (in counts)
        default: -20000

      DHLM:
        type: int
        description: |-
          The high limit of the axis (in counts)
        default: 20000

      home:
        type: int
        description: |-
          The home position of the axis (in counts)
        default: 0

      start:
        type: str # int or jinja string
        description: |-
          The starting position of the axis (in counts)
        default: "{{home}}"

      DIR:
        type: enum
        description: |-
          The direction of the axis
        default: 0
        values:
          Pos: 0
          Neg: 1

      VELO:
        type: float
        description: |-
          The velocity of the axis (in counts/sec)
        default: 10.0

      VMAX:
        type: str # float or jinja string
        description: |-
          The maximum velocity of the axis (in counts/sec)
        default: "{{VELO}}"

      is_cs:
        type: bool
        description: |-
          Set to True if this axis a coordinate system axis
        default: false

      CS_NUM:
        type: int
        description: |-
          The coordinate system number for this axis
        default: 0

    post_init:
      - when: once
        value: |
          # motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)

      - value: |
          motorSimConfigAxis({{controller}}, {{ADDR}}, {{DHLM}}, {{DLLM}}, {{home}}, {{start}})

    databases:
      - file: basic_asyn_motor.db
        enabled: "{{not is_cs}}"
        args:
          P: "{{controller.P}}"
          M:
          DTYP: asynMotor
          PORT: "{{controller}}"
          ADDR:
          DESC:
          EGU: degrees
          DIR:
          VELO:
          VMAX:
          MRES: ".01"
          DHLM:
          DLLM:
          INIT: ""

      - file: basic_cs_asyn_motor.db
        enabled: "{{is_cs}}"
        args:
          P: "{{controller.P}}"
          CS_NUM:
          DTYP: asynMotor
          PORT: "{{controller}}"
          ADDR:
          DESC:
          EGU: degrees
          DIR:
          VELO:
          VMAX:
          MRES: ".01"
          DHLM:
          DLLM:
          INIT: ""

Definition is implemented in the code using a class of the same name.

Entity#

ibek can generate an IOC instance using an IOC instance entity file. This is a YAML file with name of the form <ioc_name>.<container>.yaml.

The IOC instance entity file declares the Entities that the IOC instance requires.

An Entity represents any piece of functionality of an IOC that is configured through EPICS database and/or startup script.

The classes of Entity that can be instantiated for a given generic IOC are declared in the Definitions files described above.

Declaring an Entity for an IOC instance will cause ibek to generate lines in the startup script. The generated startup script will also supply the EPICS database entries using dbLoadRecords and database templates.

The example motion IOC instance bl45p-mo-ioc-02 has the following entities:

  • DlsPmacAsynIPPort (one instance)

    • represents a connection to a motion controller

    • configured via

      • pmacAsynIPConfigure in the boot script

  • Geobrick (one instance)

    • represents the motion controller itself

    • configured via

      • pmacCreateController in boot script

      • pmacCreateAxes in the boot script

      • dbLoadRecords of pmacController.template and pmacStatus.template

  • DlsPmacAsynMotor (two instances)

    • represents a single motor connected to the controller

    • configured via:

      • dbLoadRecords of dls_pmac_asyn_motor.template

The example IOC instance entity file is shown below along with the st.cmd file that ibek will generate from it.

Click the arrows to reveal the files.

all.ibek.ioc.yaml
# yaml-language-server: $schema=../schemas/motorSim.ibek.ioc.schema.json

ioc_name: "{{ ioc_yaml_file_name }}"
description: Example simulated motion IOC for Testing ibek

entities:
  - type: asyn.AsynIP
    name: controllerOnePort
    port: 192.168.0.55:2002

  - type: motorSim.simMotorController
    port: controllerOnePort
    controllerName: controllerOne
    numAxes: 4
    P: "IBEK-MO-TST-01:"

  - type: motorSim.simMotorAxis
    controller: controllerOne
    # Use ADDR in other fields to verify jinja templating between Args
    M: M{{ADDR}}
    ADDR: 0
    # Also use ioc_name to verify jinja templating of ioc_name
    DESC: Motor {{ADDR}} for ioc {{ioc_name}}
    home: 500

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: M{{ADDR}}
    ADDR: 1
    # verify escaping for jinja templating
    DESC: Motor {{ADDR}} {% raw %} {{enclosed in escaped curly braces}} {% endraw %}
    home: 500

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: M{{ADDR}}
    ADDR: 2
    # testing default DESC
    home: 1500

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: M{{ADDR}}
    ADDR: 3
    DESC: Motor {{ADDR}}
    home: 2500

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: CS_M{{ADDR}}
    ADDR: 1
    DESC: CS Motor {{ADDR}}
    home: 100
    CS_NUM: 3
    is_cs: true

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: CS_M{{ADDR}}
    ADDR: 2
    DESC: CS Motor {{ADDR}}
    home: 100
    CS_NUM: 3
    is_cs: true
st.cmd
# EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek

cd "/epics/ioc"

epicsEnvSet NAME_AS_ENV_VAR my name is controllerOnePort

dbLoadDatabase dbd/ioc.dbd
ioc_registerRecordDeviceDriver pdbbase

# Setting up Asyn Port controllerOnePort on 192.168.0.55:2002:
# AsynIPConfigure({{name}}, {{port}}, {{stop}}, {{parity}}, {{bits}}) 
AsynIPConfigure(controllerOnePort, 192.168.0.55:2002, 1, none, 8)
asynSetOption(9600, 0, N, Y)
asynOctetSetInputEos("\n")
asynOctetSetOutputEos("\n")
# motorSimCreateController(controller_asyn_port_name, axis_count)
# testing escaping:  {{enclosed in escaped curly braces}} 
motorSimCreateController(controllerOne, 4)

dbLoadRecords /epics/runtime/ioc.db
iocInit


# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 0, 20000, -20000, 500, 500)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 1, 20000, -20000, 500, 500)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 2, 20000, -20000, 1500, 1500)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 3, 20000, -20000, 2500, 2500)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 1, 20000, -20000, 100, 100)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 2, 20000, -20000, 100, 100)

Entity is implemented in the code using a class of the same name.

Schemas#

The YAML files described above are constrained by schemas. These schemas are available to the developer and may be used to assist in generating the YAML.

Note that the author of an IOC instance needs access to <container>.schema.json in order to correctly craft a correct <ioc>.<container>.yaml. For this reason the container schema file is published as a github artifact along with the release of the container image. All other ibek operations happen within the container or during container development.

Thus, the sequence of files is as follows:

Summary of ibek files sequence#

num

Name

Description

1

ibek.defs.schema.json

Global Schema for 2

2

<support>.ibek.support.yaml

Definition file for a support module. Generates part of 3

3

<container>.entities.schema.json

Schema for 4. Generated by combining all of 2 from a container

4

<ioc>.ibek.ioc.yaml

Description of Entities for an IOC instance.

5

IOC Startup Script st.cmd

Startup script for booting the IOC

The Global Schema and example IOC instance schema are below:

ibek.support.schema.json
{
  "$defs": {
    "BoolParam": {
      "additionalProperties": false,
      "description": "An argument with an bool value",
      "properties": {
        "type": {
          "const": "bool",
          "default": "bool",
          "enum": [
            "bool"
          ],
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "description": "A Jinja2 template string",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "BoolParam",
      "type": "object"
    },
    "Comment": {
      "additionalProperties": false,
      "description": "A script snippet that will have '# ' prepended to every line\nfor insertion into the startup script",
      "properties": {
        "type": {
          "const": "comment",
          "default": "comment",
          "enum": [
            "comment"
          ],
          "title": "Type",
          "type": "string"
        },
        "when": {
          "allOf": [
            {
              "$ref": "#/$defs/When"
            }
          ],
          "default": "every",
          "description": "One of first / every / last"
        },
        "value": {
          "default": "",
          "description": "A comment to add into the startup script",
          "title": "Value",
          "type": "string"
        }
      },
      "title": "Comment",
      "type": "object"
    },
    "Database": {
      "additionalProperties": false,
      "description": "A database file that should be loaded by the startup script and its args",
      "properties": {
        "file": {
          "description": "Filename of the database template in <module_root>/db",
          "title": "File",
          "type": "string"
        },
        "enabled": {
          "default": "True",
          "description": "Set to False to disable loading this database",
          "title": "Enabled",
          "type": "string"
        },
        "args": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "description": "Dictionary of args and values to pass through to database. A value of None is equivalent to ARG: '{{ ARG }}'. See `UTILS.render_map` for more details.",
          "title": "Args",
          "type": "object"
        }
      },
      "required": [
        "file",
        "args"
      ],
      "title": "Database",
      "type": "object"
    },
    "Define": {
      "additionalProperties": false,
      "description": "A calculated value for an Entity Model",
      "properties": {
        "description": {
          "description": "Description of what the value will be used for",
          "title": "Description",
          "type": "string"
        },
        "value": {
          "description": "The contents of the value",
          "title": "Value"
        },
        "type": {
          "anyOf": [
            {
              "$ref": "#/$defs/DefineType"
            },
            {
              "type": "null"
            }
          ],
          "default": "str",
          "description": "The type of the value"
        }
      },
      "required": [
        "description",
        "value"
      ],
      "title": "Define",
      "type": "object"
    },
    "DefineType": {
      "description": "The type of a value",
      "enum": [
        "str",
        "float",
        "int",
        "bool",
        "list"
      ],
      "title": "DefineType",
      "type": "string"
    },
    "EntityModel": {
      "additionalProperties": false,
      "description": "A Model for a class of Entity that an IOC instance may instantiate",
      "properties": {
        "name": {
          "description": "Publish EntityModel as type <module>.<name> for IOC instances",
          "title": "Name",
          "type": "string"
        },
        "description": {
          "description": "A description of the Support module defined here",
          "title": "Description",
          "type": "string"
        },
        "pre_defines": {
          "additionalProperties": {
            "$ref": "#/$defs/Define"
          },
          "default": [],
          "description": "Calculated values to use as additional arguments With Jinja evaluation before all Args",
          "title": "Pre Defines",
          "type": "object"
        },
        "parameters": {
          "additionalProperties": {
            "description": "union of arg types",
            "discriminator": {
              "mapping": {
                "bool": "#/$defs/BoolParam",
                "enum": "#/$defs/EnumParam",
                "float": "#/$defs/FloatParam",
                "id": "#/$defs/IdParam",
                "int": "#/$defs/IntParam",
                "object": "#/$defs/ObjectParam",
                "str": "#/$defs/StrParam"
              },
              "propertyName": "type"
            },
            "oneOf": [
              {
                "$ref": "#/$defs/FloatParam"
              },
              {
                "$ref": "#/$defs/StrParam"
              },
              {
                "$ref": "#/$defs/IntParam"
              },
              {
                "$ref": "#/$defs/BoolParam"
              },
              {
                "$ref": "#/$defs/ObjectParam"
              },
              {
                "$ref": "#/$defs/IdParam"
              },
              {
                "$ref": "#/$defs/EnumParam"
              }
            ]
          },
          "default": [],
          "description": "The arguments IOC instance should supply",
          "title": "Parameters",
          "type": "object"
        },
        "post_defines": {
          "additionalProperties": {
            "$ref": "#/$defs/Define"
          },
          "default": [],
          "description": "Calculated values to use as additional arguments With Jinja evaluation after all Args",
          "title": "Post Defines",
          "type": "object"
        },
        "pre_init": {
          "default": [],
          "description": "Startup script snippets to add before iocInit()",
          "items": {
            "anyOf": [
              {
                "$ref": "#/$defs/Text"
              },
              {
                "$ref": "#/$defs/Comment"
              }
            ]
          },
          "title": "Pre Init",
          "type": "array"
        },
        "post_init": {
          "default": [],
          "description": "Startup script snippets to add post iocInit(), such as dbpf",
          "items": {
            "anyOf": [
              {
                "$ref": "#/$defs/Text"
              },
              {
                "$ref": "#/$defs/Comment"
              }
            ]
          },
          "title": "Post Init",
          "type": "array"
        },
        "databases": {
          "default": [],
          "description": "Databases to instantiate",
          "items": {
            "$ref": "#/$defs/Database"
          },
          "title": "Databases",
          "type": "array"
        },
        "env_vars": {
          "default": [],
          "description": "Environment variables to set in the boot script",
          "items": {
            "$ref": "#/$defs/EnvironmentVariable"
          },
          "title": "Env Vars",
          "type": "array"
        },
        "pvi": {
          "anyOf": [
            {
              "$ref": "#/$defs/EntityPVI"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "PVI definition for Entity"
        },
        "sub_entities": {
          "default": [],
          "description": "The sub-entity instances that this collection is to instantiate",
          "items": {
            "$ref": "#/$defs/SubEntity"
          },
          "title": "Sub Entities",
          "type": "array"
        },
        "shared": {
          "default": [],
          "description": "A place to create any anchors required for repeating YAML",
          "items": {},
          "title": "Shared",
          "type": "array"
        }
      },
      "required": [
        "name",
        "description"
      ],
      "title": "EntityModel",
      "type": "object"
    },
    "EntityPVI": {
      "additionalProperties": false,
      "description": "Entity PVI definition",
      "properties": {
        "yaml_path": {
          "description": "Path to .pvi.device.yaml - absolute or relative to PVI_DEFS",
          "title": "Yaml Path",
          "type": "string"
        },
        "ui_index": {
          "default": true,
          "description": "Whether to add the UI to the IOC index.",
          "title": "Ui Index",
          "type": "boolean"
        },
        "ui_macros": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "default": null,
          "description": "Macros to launch the UI on the IOC index. These must be args of the Entity this is attached to.",
          "title": "Ui Macros",
          "type": "object"
        },
        "pv": {
          "default": false,
          "description": "Whether to generate a PVI PV. This adds a database template with info tags that create a PVAccess PV representing the device structure.",
          "title": "Pv",
          "type": "boolean"
        },
        "pv_prefix": {
          "default": "",
          "description": "PV prefix for PVI PV - e.g. \"$(P)\"",
          "title": "Pv Prefix",
          "type": "string"
        }
      },
      "required": [
        "yaml_path"
      ],
      "title": "EntityPVI",
      "type": "object"
    },
    "EnumParam": {
      "additionalProperties": false,
      "description": "An argument with an enum value",
      "properties": {
        "type": {
          "const": "enum",
          "default": "enum",
          "enum": [
            "enum"
          ],
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {},
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        },
        "values": {
          "description": "provides a list of values to make this argument an Enum",
          "title": "Values",
          "type": "object"
        }
      },
      "required": [
        "description",
        "values"
      ],
      "title": "EnumParam",
      "type": "object"
    },
    "EnvironmentVariable": {
      "additionalProperties": false,
      "description": "An environment variable that should be set in the startup script",
      "properties": {
        "name": {
          "description": "Name of environment variable",
          "title": "Name",
          "type": "string"
        },
        "value": {
          "description": "Value to set",
          "title": "Value",
          "type": "string"
        }
      },
      "required": [
        "name",
        "value"
      ],
      "title": "EnvironmentVariable",
      "type": "object"
    },
    "FloatParam": {
      "additionalProperties": false,
      "description": "An argument with a float value",
      "properties": {
        "type": {
          "const": "float",
          "default": "float",
          "enum": [
            "float"
          ],
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "description": "A Jinja2 template string",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "FloatParam",
      "type": "object"
    },
    "IdParam": {
      "additionalProperties": false,
      "description": "Explicit ID argument that an object can refer to",
      "properties": {
        "type": {
          "const": "id",
          "default": "id",
          "enum": [
            "id"
          ],
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "IdParam",
      "type": "object"
    },
    "IntParam": {
      "additionalProperties": false,
      "description": "An argument with an int value",
      "properties": {
        "type": {
          "const": "int",
          "default": "int",
          "enum": [
            "int"
          ],
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "description": "A Jinja2 template string",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "IntParam",
      "type": "object"
    },
    "ObjectParam": {
      "additionalProperties": false,
      "description": "A reference to another entity defined in this IOC",
      "properties": {
        "type": {
          "const": "object",
          "default": "object",
          "enum": [
            "object"
          ],
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "string"
            },
            {},
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "ObjectParam",
      "type": "object"
    },
    "StrParam": {
      "additionalProperties": false,
      "description": "An argument with a str value",
      "properties": {
        "type": {
          "const": "str",
          "default": "str",
          "enum": [
            "str"
          ],
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "StrParam",
      "type": "object"
    },
    "SubEntity": {
      "additionalProperties": true,
      "description": "A loosely defined class to declare the Entities\nin an ibek.support.yaml file in the 'sub_entities' property of an Entity\nsection",
      "properties": {
        "type": {
          "description": "The type of this entity",
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        }
      },
      "required": [
        "type"
      ],
      "title": "SubEntity",
      "type": "object"
    },
    "Text": {
      "additionalProperties": false,
      "description": "A script snippet to insert into the startup script",
      "properties": {
        "type": {
          "const": "text",
          "default": "text",
          "enum": [
            "text"
          ],
          "title": "Type",
          "type": "string"
        },
        "when": {
          "default": "every",
          "description": "One of first / every / last",
          "title": "When",
          "type": "string"
        },
        "value": {
          "default": "",
          "description": "raw text to add to the startup script",
          "title": "Value",
          "type": "string"
        }
      },
      "title": "Text",
      "type": "object"
    },
    "When": {
      "enum": [
        "first",
        "every",
        "last"
      ],
      "title": "When",
      "type": "string"
    }
  },
  "additionalProperties": false,
  "description": "Lists the EntityModels for a support module, this defines what Entities it supports",
  "properties": {
    "shared": {
      "default": [],
      "description": "A place to create any anchors required for repeating YAML",
      "items": {},
      "title": "Shared",
      "type": "array"
    },
    "module": {
      "description": "Support module name, normally the repo name",
      "title": "Module",
      "type": "string"
    },
    "entity_models": {
      "description": "The Entity Models an IOC can create using this module",
      "items": {
        "$ref": "#/$defs/EntityModel"
      },
      "title": "Entity Models",
      "type": "array"
    }
  },
  "required": [
    "module",
    "entity_models"
  ],
  "title": "Support",
  "type": "object"
}
multiple.ibek.ioc.schema.json
{
  "$defs": {
    "DIR": {
      "enum": [
        "Pos",
        "Neg"
      ],
      "title": "DIR",
      "type": "string"
    },
    "motorSim_simMotorAxis": {
      "additionalProperties": false,
      "properties": {
        "type": {
          "const": "motorSim.simMotorAxis",
          "description": "Creates a simulation motor axis",
          "enum": [
            "motorSim.simMotorAxis"
          ],
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        },
        "controller": {
          "description": "a reference to the motion controller",
          "title": "Controller"
        },
        "M": {
          "description": "PV suffix for the motor record",
          "title": "M",
          "type": "string"
        },
        "ADDR": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The axis number (allowed to be from 0 to controller.numAxes-1)",
              "type": "integer"
            }
          ],
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Addr"
        },
        "DESC": {
          "default": "Motor {{ADDR}}",
          "description": "The description of the axis",
          "title": "Desc",
          "type": "string"
        },
        "DLLM": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The low limit of the axis (in counts)",
              "type": "integer"
            }
          ],
          "default": -20000,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Dllm"
        },
        "DHLM": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The high limit of the axis (in counts)",
              "type": "integer"
            }
          ],
          "default": 20000,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Dhlm"
        },
        "home": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The home position of the axis (in counts)",
              "type": "integer"
            }
          ],
          "default": 0,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Home"
        },
        "start": {
          "default": "{{home}}",
          "description": "The starting position of the axis (in counts)",
          "title": "Start",
          "type": "string"
        },
        "DIR": {
          "allOf": [
            {
              "$ref": "#/$defs/DIR"
            }
          ],
          "default": 0,
          "description": "The direction of the axis"
        },
        "VELO": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'float'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The velocity of the axis (in counts/sec)",
              "type": "number"
            }
          ],
          "default": 10.0,
          "description": "union of <class 'float'> and jinja representation of {typ}",
          "title": "Velo"
        },
        "VMAX": {
          "default": "{{VELO}}",
          "description": "The maximum velocity of the axis (in counts/sec)",
          "title": "Vmax",
          "type": "string"
        },
        "is_cs": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'bool'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "Set to True if this axis a coordinate system axis",
              "type": "boolean"
            }
          ],
          "default": false,
          "description": "union of <class 'bool'> and jinja representation of {typ}",
          "title": "Is Cs"
        },
        "CS_NUM": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The coordinate system number for this axis",
              "type": "integer"
            }
          ],
          "default": 0,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Cs Num"
        }
      },
      "required": [
        "type",
        "controller",
        "M",
        "ADDR"
      ],
      "title": "motorSim_simMotorAxis",
      "type": "object"
    },
    "motorSim_simMotorController": {
      "additionalProperties": false,
      "properties": {
        "type": {
          "const": "motorSim.simMotorController",
          "description": "Creates a simulation motion controller",
          "enum": [
            "motorSim.simMotorController"
          ],
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        },
        "controllerName": {
          "description": "The name of the controller and its Asyn Port Name",
          "title": "Controllername",
          "type": "string"
        },
        "P": {
          "description": "Device PV Prefix",
          "title": "P",
          "type": "string"
        },
        "numAxes": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The number of axes to create",
              "type": "integer"
            }
          ],
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Numaxes"
        },
        "port": {
          "description": "a reference to the asyn port for communication with the controller",
          "title": "Port"
        },
        "DESC": {
          "default": "Simulated Motion Controller testing escaping: {% raw %} {{enclosed in escaped curly braces}} {% endraw %}",
          "description": "The description of the controller",
          "title": "Desc",
          "type": "string"
        }
      },
      "required": [
        "type",
        "controllerName",
        "P",
        "numAxes",
        "port"
      ],
      "title": "motorSim_simMotorController",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "properties": {
    "ioc_name": {
      "description": "Name of IOC instance",
      "title": "Ioc Name",
      "type": "string"
    },
    "description": {
      "description": "Description of what the IOC does",
      "title": "Description",
      "type": "string"
    },
    "entities": {
      "description": "List of entities this IOC instantiates",
      "items": {
        "discriminator": {
          "mapping": {
            "motorSim.simMotorAxis": "#/$defs/motorSim_simMotorAxis",
            "motorSim.simMotorController": "#/$defs/motorSim_simMotorController"
          },
          "propertyName": "type"
        },
        "oneOf": [
          {
            "$ref": "#/$defs/motorSim_simMotorController"
          },
          {
            "$ref": "#/$defs/motorSim_simMotorAxis"
          }
        ]
      },
      "title": "Entities",
      "type": "array"
    },
    "shared": {
      "default": [],
      "description": "A place to create any anchors required for repeating YAML",
      "items": {},
      "title": "Shared",
      "type": "array"
    }
  },
  "required": [
    "ioc_name",
    "description",
    "entities"
  ],
  "title": "NewIOC",
  "type": "object"
}

This results in the overall generated file structure:

ibek.defs.schema.jsonpmac.ibek.support.yamlasyn.ibek.support.yamlcontainer.ibek.entities.schema.jsonioc.ibek.ioc.yaml

Commands#

The ibek commands to progress through the file sequence above are as follows

Summary of ibek stages#

num

Name

Command

1

ibek.defs.schema.json

ibek ibek-schema

2

<support>.ibek.support.yaml

Hand crafted by the container developer. Held in the container.

3

<container>.ibek.entities.schema.json

ibek ioc-schema ... run at container build time. ... == all <support>.ibek.support.yaml within the container.

4

<ioc>.ibek.ioc.yaml

Hand crafted at IOC instance design time

5

IOC startup script

ibek build-startup <ioc>.ibek.ioc.yaml .... Run at IOC startup time in the container. ... == all <support>.ibek.support.yaml within the container.