Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

For the integration of existing developments into docker/kubernates we use part of the  Diamond flow for a beamline under kubernates.

...

  1. support already present in <ibek-support>
  2. support present as git project
  3. support not present at all → put in the condition 2

Use an existing ibek support
Anchor
existing ibek support
existing ibek support

If a support is present in <ibek-support>, it's very simple to use it just create a yaml that instantiates  your device(s).

...

Code Block
languagebash
titleDocker image creation and run as ioc
docker run -p 5064:5064/udp -p 5064:5064/tcp -p 5065:5065/udp -p 5065:5065/tcp -it -v .:/epics/ioc/config baltig.infn.it:4567/epics-containers/infn-epics-ioc:localdevel 


A generic asyn motor OPI interface  can be used to drive the motor. Motor OPIs Remember to add localhost to your phoebus 

org.phoebus.pv.ca/addr_list settings:

Code Block
languagebash
titlePhoebus settings example
org.phoebus.pv.ca/addr_list=localhost
org.phoebus.pv.ca/auto_addr_list=false
org.csstudio.trends.databrowser3/urls=pbraw://sparc-archiver.apps.okd-datest.lnf.infn.it/retrieval
org.csstudio.trends.databrowser3/archives=pbraw://sparc-archiver.apps.okd-datest.lnf.infn.it/retrieval
org.phoebus.olog.es.api/olog_url=http://sparc-olog.apps.okd-datest.lnf.infn.it/Olog
org.phoebus.olog.api/olog_url=http://sparc-olog.apps.okd-datest.lnf.infn.it/Olog
org.phoebus.logbook/logbook_factory=olog-es
org.phoebus.olog.api/username=epics
org.phoebus.olog.api/password=epics
org.phoebus.channelfinder/channelfinder.serviceURL=http://sparc-channelfinder.apps.okd-datest.lnf.infn.it/ChannelFinder
org.phoebus.applications.saveandrestore.client/jmasar.service.url=http://sparc-saveandrestore.apps.okd-datest.lnf.infn.it/save-restore
org.csstudio.scan.client/host=http://sparc-scanserver.apps.okd-datest.lnf.infn.it
org.csstudio.scan.client/port=4810


Once the IOC runs correctly as docker can be inserted in the EPIK8S configuration


Build a support from existing git support

This is path is more complex, but gives much more satisfaction, in fact each time you add a new support as much generic possible you greatly simplify the life of your self and in principle many other people will use the your support.

Step 1 create a directory inside ibek-support


Create by copy and renaming one of the existing support. Suppose you want to add the support for <mydevmodule>, you should have:

Code Block
languagebash
titleProject layout
.
├── Dockerfile
├── LICENSE
├── README.md
├── build
├── ibek-support
│   ├── ADAravis
│   ├── mydevmodule
│   │   ├── install.sh
│   │   └── mydevmodule.ibek.support.yaml
│   ├── opcua
│   │   └── install.sh
│   ├── pmac
│   │   ├── install.sh
│   │   ├── make_pvi.sh
│   │   ├── pmac.ibek.support.todo
│   │   ├── pmac.ibek.support.yaml
│   │   ├── pmacAxis.pvi.device.yaml
│   │   ├── pmacCSController.pvi.device.yaml
│   │   ├── pmacController.pvi.device.yaml
│   │   └── pmacTrajectory.pvi.device.yaml
│   



So in general just two file must be added: install.sh and mydevmodule.ibek.support.yaml.

install.sh

This file  contains instructions on howto retrieve, compile and link  dependencies of your module mydevmodule. In general if the mydevmodule  is well structured from a build epics point of view needs only to be patched like that:

Code Block
languagebash
titleinstall.sh
#!/bin/bash

# ARGUMENTS:
#  $1 VERSION to install (must match repo tag)
VERSION=${1}
NAME=<mydevmodule>  ## as compare in the git repository
FOLDER=$(dirname $(readlink -f $0))

# log output and abort on failure
set -xe

# get the source and fix up the configure/RELEASE files
ibek support git-clone ${NAME} ${VERSION} --org http://gitrepo ## repository git root
ibek support register ${NAME}

# declare the libs and DBDs that are required in ioc/iocApp/src/Makefile
ibek support add-libs <mydevmodulelib> <support1lib> <support2lib> asyn ## optional libraries that must be linked
ibek support add-dbds <mydevmodule>.dbd <optsupport1.dbd> <optsupport2>.dbd ### optional dbd supports
# global config settings
${FOLDER}/../_global/install.sh ${NAME}

# compile the support module
ibek support compile ${NAME}
# prepare *.bob, *.pvi, *.ibek.support.yaml for access outside the container.
ibek support generate-links ${FOLDER}




mydevmodule.ibek.support.yaml

This also has a very simple syntax and gives instructions on how to expand a future yaml configuration.

The simplest way to proceed is to understand how the st.cmd of your ioc should be constructed and having this in mind build a set of rules that wraps that code.

The best way is look other supports to understand, here below I put a recently support that I added for newport motors. The comments at the beginning is more a general st.cmd of a SMC100 newport motor.

In the example yaml I instruct ibek to correcty replace a file configuration like the previous newport.yaml.


Code Block
languageyml
titleExample
# yaml-language-server: $schema=https://github.com/epics-containers/ibek/releases/download/1.5.0/ibek.support.schema.json

# #errlogInit(5000)
# < envPaths
# # Tell EPICS all about the record types, device-support modules, drivers,
# # etc.
# dbLoadDatabase("../../dbd/newport.dbd")
# newport_registerRecordDeviceDriver(pdbbase)

# ### Motors
# dbLoadTemplate "motor.substitutions.SMC100"

# ### Serial port setup
# drvAsynSerialPortConfigure("serial1", "/dev/ttyS0", 0, 0, 0)
# asynSetOption(serial1,0,baud,57600)
# asynOctetSetInputEos("serial1",0,"\r\n")
# asynOctetSetOutputEos("serial1",0,"\r\n")

# ### Newport SMC100 support
# # (driver port, serial port, axis num, ms mov poll, ms idle poll, egu per step)
# SMC100CreateController("SMC100_1", "serial1",1, 100, 0, "0.00005")

# file "$(TOP)/db/basic_asyn_motor.db"
# {
# pattern
# {P,      N,     M,         DTYP,      PORT,  ADDR,    DESC,        EGU,     DIR,  VELO,  VBAS,  ACCL,  BDST,  BVEL,  BACC,  MRES,  PREC,  DHLM,  DLLM,  INIT, RTRY}
# {IOC:,  1,  "m$(N)",  "asynMotor",  "SMC100_1",  0,  "GTS30V",      mm,     Pos,  1,     0,    .2,    0,     .5,     .2,    0.00001,  6,     25,   -5,  ""}
# }
# iocInit

module: motorNewport

defs:
  - name: SMC100CreateController
    description: |-
      Creates a SMC100 motion controller connected to an ethernetToSerialServer

    args:
      - type: id
        name: controllerName
        description: |-
          The name of the controller and its Asyn Port Name
      
      - type: str
        name: P
        description: |-
          Device PV Prefix

      - type: str
        name: IP
        description: |-
          IP address of the ethernet2serial
        default: 127.0.0.1 ## localhost

      - type: int
        name: TCPPORT
        description: |-
          Port of the ethernet2serial
        default: 4001
      
      - type: int
        name: POLL
        description: |-
          Movement poll ms
        default: 100
      
      - type: float
        name: EGUXSTEP
        description: |-
          EGU PER STEP
        default: 0.00005

      - type: int
        name: ASYNPRIO
        description: |-
          ASYN   PRIORITY, Default : 0
        default: 0

      - type: int
        name: AUTOCONNECT
        description: |-
          Asyn auto connect
          0: Auto connection
          1: no Auto connection
        default: 0

      - type: int
        name: NOPRECESSESOS
        description: |-
          ASYN   noProcessEos, Default : 0
          https://epics.anl.gov/tech-talk/2020/msg01705.php
        default: 0

      

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

    pre_init:

      - value: |
          # epicsEnvSet "STREAM_PROTOCOL_PATH", "$(MOTORNEWPORT)/protocol/"
          # Create Asyn Port
          drvAsynIPPortConfigure("{{controllerName}}_ASYN", "{{IP}}:{{TCPPORT}}", {{ASYNPRIO}}, {{AUTOCONNECT}}, {{NOPRECESSESOS}})
          # asynInterposeEosConfig("{{controllerName}}_ASYN",0,2000,0)
          SMC100CreateController("SMC100_{{controllerName}}", "{{controllerName}}_ASYN","{{numAxes}}", "{{POLL}}", 0, "{{EGUXSTEP}}")
          asynOctetSetInputEos({{controllerName}}_ASYN,0,"\r\n")
          asynOctetSetOutputEos({{controllerName}}_ASYN,0,"\r\n")
          asynReport 10
          

  - name: motorAxis
    description: |-
      Creates a motor axis

    args:
      - type: object
        name: controller
        description: |-
          a reference to the motion controller

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

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

      - type: str
        name: DESC
        description: |-
          The description of the axis

      - type: int
        name: DLLM
        description: |-
          The low limit of the axis
        default: -5

      - type: int
        name: DHLM
        description: |-
          The high limit of the axis
        default: 25

      - type: int
        name: VELO
        description: |-
          Velocity
        default: 1

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

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

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

      - type: str
        name: EGU
        description: |-
          Engineering Units
        default: "mm"
      
      - type: float
        name: VBAS
        description: |-
          Base Velocity (EGU/s)
        default: 0.2

      - type: float
        name: ACCL
        description: |-
          Seconds to Velocity
        default: 0.2

      - type: int
        name: BDST
        description: |-
          BL Distance (EGU)
        default: 0

      - type: float
        name: BVEL
        description: |-
          BL Velocity (EGU/s)
        default: 0.5

      - type: float
        name: BACC
        description: |-
          BL Seconds to Veloc.
        default: 0.2

      - type: float
        name: MRES
        description: |-
          Motor Step Size (EGU)
        default: 0.00001

      - type: int
        name: PREC
        description: |-
          Display precision (EGU)
        default: 6
      
    databases:
      # TODO as this is a simulation I have hard coded some of the DB fields,
      # but these could easily be made into arguments above
      #
      # Note: supplying no value means that the argument of the same name is used
      # (the most common case - if you contrive to make args and db fields the same.
      # Which is  good idea for ease of transition from traditional IOCs)
      - file: basic_asyn_motor.db
        args:
          P: "{{controller.P}}"
          N: "{{ADDR +1 }}"
          M:
          DTYP: "asynMotor"
          PORT: "SMC100_{{controller}}"
          ADDR:
          DESC:
          EGU: 
          DIR:
          VELO:
          VBAS:
          ACCL:
          BDST:
          BVEL:
          BACC:
          MRES: 
          PREC:
          DHLM: 
          DLLM: 
          INIT: ""
    post_init:
      - value: |
          dbl


Step 2 add an entry into Dockerfile

Modify the Dockerfile in the project:

Code Block
titleDockerfile
##### build stage ##############################################################

ARG TARGET_ARCHITECTURE
ARG BASE=7.0.8ec1b3
ARG REGISTRY=ghcr.io/epics-containers

FROM  ${REGISTRY}/epics-base-${TARGET_ARCHITECTURE}-developer:${BASE} AS developer


# The devcontainer mounts the project root to /epics/generic-source
# Using the same location here makes devcontainer/runtime differences transparent.
ENV SOURCE_FOLDER=/epics/generic-source
# connect ioc source folder to its know location
RUN ln -s ${SOURCE_FOLDER}/ioc ${IOC}

# Get latest ibek while in development. Will come from epics-base when stable
COPY requirements.txt requirements.txt
RUN pip install --upgrade -r requirements.txt

WORKDIR ${SOURCE_FOLDER}/ibek-support

# copy the global ibek files
COPY ibek-support/_global/ _global

COPY ibek-support/iocStats/ iocStats
RUN iocStats/install.sh 3.2.0

################################################################################
#  TODO - Add further support module installations here
################################################################################

COPY ibek-support/asyn/ asyn/
RUN asyn/install.sh R4-44

COPY ibek-support/autosave/ autosave/
RUN autosave/install.sh R5-11

COPY ibek-support/busy/ busy/
RUN busy/install.sh R1-7-3

COPY ibek-support/StreamDevice/ StreamDevice/
RUN StreamDevice/install.sh 2.8.24

COPY ibek-support/sscan/ sscan/
RUN sscan/install.sh R2-11-6

COPY ibek-support/calc/ calc/
RUN calc/install.sh R3-7-5

COPY ibek-support/motor/ motor/
RUN motor/install.sh R7-3

COPY ibek-support/motorMotorSim/ motorMotorSim/
RUN motorMotorSim/install.sh R1-2

COPY ibek-support/ADCore/ ADCore/
RUN ADCore/install.sh R3-13

COPY ibek-support/ADGenICam ADGenICam/
RUN ADGenICam/install.sh R1-9
COPY ibek-support/ADSimDetector ADSimDetector/
RUN ADSimDetector/install.sh R2-10

COPY ibek-support/modbus/ modbus/
RUN modbus/install.sh R3-3

COPY ibek-support/screen-epics-ioc screen-epics-ioc/
RUN screen-epics-ioc/install.sh v1.3.1

COPY ibek-support/motorNewport motorNewport/
RUN motorNewport/install.sh R1-2-1

# COPY ibek-support/easy-driver-epics/ easy-driver-epics/
# RUN easy-driver-epics/install.sh master

COPY ibek-support/mydevmodule mydevmodule          ### HERE
RUN mydevmodule/install.sh master				   ## HERE


# get the ioc source and build it
COPY ioc/ ${SOURCE_FOLDER}/ioc
RUN cd ${IOC} && ./install.sh && make

##### runtime preparation stage ################################################

FROM developer AS runtime_prep

# get the products from the build stage and reduce to runtime assets only
RUN ibek ioc extract-runtime-assets /assets ${SOURCE_FOLDER}/ibek*

##### runtime stage ############################################################

FROM ${REGISTRY}/epics-base-${TARGET_ARCHITECTURE}-runtime:${BASE} AS runtime

# get runtime assets from the preparation stage
COPY --from=runtime_prep /assets /

# install runtime system dependencies, collected from install.sh scripts
RUN ibek support apt-install-runtime-packages --skip-non-native

ENV TARGET_ARCHITECTURE ${TARGET_ARCHITECTURE}

CMD ["/bin/bash", "-c", "${IOC}/start.sh"]


Step 3 build docker image


building:

Code Block
titleBuild Image
git clone https://baltig.infn.it/epics-containers/infn-epics-ioc.git --recurse-submodules
cd infn-epics-ioc
docker build --build-arg TARGET_ARCHITECTURE="linux" --build-arg TARGETARCH="amd64" -t baltig.infn.it:4567/epics-containers/infn-epics-ioc:local .

building development:

Code Block
titleBuild Image
git clone https://baltig.infn.it/epics-containers/infn-epics-ioc.git --recurse-submodules
cd infn-epics-ioc
docker build -f Dockerfile.devel --build-arg TARGET_ARCHITECTURE="linux" --build-arg TARGETARCH="amd64" -t baltig.infn.it:4567/epics-containers/infn-epics-ioc:devel .

Step 4 motor yaml instance

Write a mymotor.yaml ibek instance of the support just created and built:

Code Block
languageyaml
titleYAML instance
gioc_name: rfmotors
description: RF motors 

entities:

  - type: motorNewport.SMC100CreateController
    controllerName: NEWPORT001
    P: "SPARC:RF:"
    IP: 192.168.190.56
    TCPPORT: 4001
    numAxes: 1

  
  - type: motorNewport.motorAxis
    controller: NEWPORT001
    M: "m0"
    DESC: "Axis"
    ADDR: 0
    DLLM: -25
    DHLM: 25
    home: 1
    start: 10
    VELO: 1
test instance

the following lines will mount the current directory that contains mymotor.yaml in the container /epics/ioc/config and will expose CA ports, then run the support just created:

Code Block
languagebash
titleRun Image and test
docker run -p 5064:5064/udp -p 5064:5064/tcp -p 5065:5065/udp -p 5065:5065/tcp -p 5075:5075/tcp  -p 5076:5076/udp -it -v .:/epics/ioc/config -v .:/epics/ioc/config baltig.infn.it:4567/epics-containers/infn-epics-ioc:local
root@3870c1890419:/epics/generic-source/ioc/config# /epics/ioc/start.sh
... io log
....
....

the following lines use the development image:

Code Block
languagebash
titleRun devel image
cd <myibek yaml instance>
docker run -p 5064:5064/udp -p 5064:5064/tcp -p 5065:5065/udp -p 5065:5065/tcp -p 5075:5075/tcp -p 5076:5076/udp -it -v .:/epics/ioc/config baltig.infn.it:4567/epics-containers/infn-epics-ioc:devel
root@3870c1890419:/epics/generic-source/ioc/config# /epics/ioc/start.sh
...
log
...

For test refer to existing ibek support