Connect a controller and its motors#
The first tutorial rendered one independent entity. This
example connects four: an IP connection, a GeoBrick controller and two motor
records. It uses real definitions from ibek-support to show how id and
object parameters connect startup commands and database macros.
You need ibek and Git. Rendering needs neither EPICS nor a connection to hardware; starting the generated IOC would require an appropriate generic IOC image.
Get the support definitions#
Use a separate directory and a fixed ibek-support release for this example:
mkdir ibek-motion-example
cd ibek-motion-example
git clone --depth 1 --branch 3.4.2 \
https://github.com/epics-containers/ibek-support.git
mkdir config
ibek ioc generate-schema ibek-support/pmac/pmac.ibek.support.yaml \
--no-ibek-defs --output ioc.schema.json
This reads the module’s support YAML; it does not build or install PMAC.
Declare the connected entities#
Save this as config/ioc.yaml:
# yaml-language-server: $schema=../ioc.schema.json
ioc_name: motion
description: One controller with two motor records
entities:
- type: pmac.pmacAsynIPPort
name: BRICK1port
IP: "192.0.2.10:1025"
- type: pmac.GeoBrick
name: BRICK1
pmacAsynPort: BRICK1port
P: "DEMO:CTRL:"
NAXES: 2
- type: pmac.dls_pmac_asyn_motor
Controller: BRICK1
P: "DEMO:"
M: X
ADDR: 1
DESC: Horizontal axis
MRES: 0.001
EGU: mm
DLLM: -10
DHLM: 10
- type: pmac.dls_pmac_asyn_motor
Controller: BRICK1
P: "DEMO:"
M: Y
ADDR: 2
DESC: Vertical axis
MRES: 0.001
EGU: mm
DLLM: -10
DHLM: 10
The connection and controller declare their name parameters as type: id.
The controller’s pmacAsynPort and each motor’s Controller are type: object:
ibek resolves their strings to previously declared entities. Order therefore
matters: connection first, then controller, then motors. These references use
IDs, not entity type names or PV prefixes.
Render and trace the outputs#
IOC=/epics/ioc RUNTIME_DIR=/epics/runtime \
ibek runtime generate2 config \
--definitions ibek-support/pmac/pmac.ibek.support.yaml \
--no-pvi --output generated
cat generated/st.cmd
cat generated/ioc.subst
As in the first tutorial, use a dedicated output directory: generation replaces
its contents. The paths assigned to IOC and RUNTIME_DIR are written into the
startup script and need not exist for this render.
Among the generated startup lines are:
pmacAsynIPConfigure("BRICK1port", "192.0.2.10:1025")
pmacCreateController("BRICK1", "BRICK1port", 0, 2, 100, 500)
pmacCreateAxes("BRICK1", 2)
The connection contributes the first command. The controller contributes the
next two, using {{ pmacAsynPort }} to render the referenced connection’s ID.
The motor entities contribute two rows for dls_pmac_asyn_motor.template in
ioc.subst. Selected macros show how their object references are used:
Macro |
Expression in the support definition |
X motor |
Y motor |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
Own parameter |
|
|
|
Own parameter |
|
|
|
Own parameter |
|
|
An entity can thus contribute startup commands, database instances, or both.
{{ Controller }} yields an ID; {{ Controller.P }} accesses a field on the
same object. Neither requires copying the controller’s settings into each motor.
The connection definition also creates a hardware-wait sub-entity, producing
wait_list.yaml. Generation writes the list without waiting or connecting to
this example address. At real IOC startup, separate tooling processes that list
and expands ioc.subst with EPICS msi.
Try changing only the controller’s P to "DEMO:OTHER:" and rendering again:
both motor rows inherit the new PMAC value while their own P remains
DEMO:. Changing a motor’s Controller to an unknown ID instead produces a
validation error. This is the benefit of declaring relationships explicitly.
For the lookup and rendering rules, see Jinja context. To expose another module’s features, continue with writing support.