...
| Code Block |
|---|
|
// For format details, see https://containers.dev/implementors/json_reference/
{
"name": "Native IOC development container",
"image": "baltig.infn.it:4567/epics-containers/infn-epics-ioc:devel",
"remoteEnv": {
// allows X11 apps to run inside the container
"DISPLAY": "${localEnv:DISPLAY}",
// provides a name for epics-containers to use in bash prompt etc.
"EC_PROJECT": "${localWorkspaceFolderBasename}"
},
"features": {
},
// IMPORTANT for this devcontainer to work with docker EC_REMOTE_USER must be
// set to vscode. For podman it should be left blank.
"remoteUser": "${localEnv:EC_REMOTE_USER}",
"customizations": {
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"tamasfe.even-better-toml",
"redhat.vscode-yaml",
"ryanluker.vscode-coverage-gutters",
"epicsdeb.vscode-epics",
"ms-python.black-formatter"
]
}
},
// Make sure the files we are mapping into the container exist on the host
// You can place any other outside of the container before-launch commands here
//"initializeCommand": "bash .devcontainer/initializeCommand ${devcontainerId}",
// Hooks the global .bashprofile_dev_container but also can add any other commands
// to run in the container at creation in here
//"postCreateCommand": "bash .devcontainer/postCreateCommand ${devcontainerId}",
// forward ports to clients
"appPort": [5064,"5064:5064/udp","5065:5065/udp"],
"runArgs": [
// Allow the container to access the host X11 display and EPICS CA
//"--net=host",
// Make sure SELinux does not disable with access to host filesystems like tmp
"--security-opt=label=disable"
],
"workspaceMount": "source=${localWorkspaceFolder},target=/app/${localWorkspaceFolderBasename},type=bind",
"workspaceFolder": "/app/${localWorkspaceFolderBasename}",
"mounts": [
// Mount some useful local files from the user's home directory
// By mounting the parent of the workspace we can work on multiple peer projects
"source=${localWorkspaceFolder}/../,target=/repos,type=bind",
]
} |
GIGE Camera
Gigavision cameras that support GIGE protocol can be acquired by ADAravis support that is already included in production/development infn-epics-ioc container, remember this container must be launched with the --network=host to access GIGE cameras.
Devel example
Example development the arv-tool command inside the container can be used to explore cameras that can be accessed:
| Code Block |
|---|
| language | bash |
|---|
| title | Camera development start |
|---|
|
docker run --network=host -v .:/epics/ioc/config -it baltig.infn.it:4567/epics-containers/infn-epics-ioc:devel bash
..
root@chaost-camera01:/epics/generic-source/ioc/config# arv-tool-0.8
Basler-a2A1920-51gmBAS-40426579 (192.168.115.49)
Basler-a2A2600-20gmBAS-40437925 (192.168.115.48)
Basler-scA640-70gm-24159532 (192.168.115.50) |
Production example
The configuration and pipelining of plugin can be very difficult and error prone, so the IBEK + templating support is highly recommended.
Create a directory <test> and create a camera_template.j2 file like that:
camera template
| Code Block |
|---|
| language | yaml |
|---|
| title | Camera template.j2 |
|---|
|
# yaml-language-server: $schema=../schemas/ibek.support.schema.json
ioc_name: {{name}}
description: Camera SIM model with plugins
entities:
{%- if devtype == "camerasim" %}
- type: ADSimDetector.simDetector
{% else %}
- type: ADAravis.aravisCamera
ID: {{CAMERA_ID}}
CLASS: {{CAMERA_CLASS}}
{% endif %}
PORT: {{iocroot}}
P: "{{iocprefix}}:"
R: "{{iocroot}}:"
- type: ADCore.NDROI
PORT: {{iocroot}}.ROI1
NDARRAY_PORT: {{iocroot}}
P: "{{iocprefix}}:{{iocroot}}"
R: ":Roi1:"
ENABLED: 1
- type: ADCore.NDProcess
PORT: {{iocroot}}.PROC
P: "{{iocprefix}}:{{iocroot}}"
R: ":Proc1:"
NDARRAY_PORT: {{iocroot}}.ROI1
ENABLED: 1
- type: ADCore.NDOverlay
PORT: {{iocroot}}.OVERLAY1
NDARRAY_PORT: {{iocroot}}
P: "{{iocprefix}}:{{iocroot}}"
R: ":Overlay1:"
NAME: "Reference"
NOverlays: 8
SHAPE: "3"
XPOS: ""
YPOS: ""
XCENT: ""
YCENT: ""
XSIZE: ""
YSIZE: ""
XWIDTH: ""
YWIDTH: ""
O: "1:"
# Want to have also high throuput PVA protocol
- type: ADCore.NDPvaPlugin
PORT: {{iocroot}}.PVA
PVNAME: "{{iocprefix}}:{{iocroot}}:PVA:OUTPUT"
P: "{{iocprefix}}:{{iocroot}}"
R: ":Pva1:"
NDARRAY_PORT: {{iocroot}}
ENABLED: 1
- type: ADCore.NDPvaPlugin
PORT: {{iocroot}}.PVA2
PVNAME: "{{iocprefix}}:{{iocroot}}:PROC:OUTPUT"
P: "{{iocprefix}}:{{iocroot}}"
R: ":Proc1:Pva1:"
NDARRAY_PORT: {{iocroot}}.PROC
ENABLED: 1
- type: ADCore.NDPvaPlugin
PORT: {{iocroot}}.PVA3
PVNAME: "{{iocprefix}}:{{iocroot}}:ROI1:OUTPUT"
P: "{{iocprefix}}:{{iocroot}}"
R: ":Roi1:Pva1:"
NDARRAY_PORT: {{iocroot}}.ROI1
ENABLED: 1
- type: ADCore.NDStdArrays
P: "{{iocprefix}}:{{iocroot}}"
R: ":image1:"
PORT: {{iocroot}}.NTD
NDARRAY_PORT: {{iocroot}}
TYPE: {{CAMERA_TYPE}}
FTVL: {{CAMERA_FTVL}}
NELEMENTS: {{CAMERA_ELEMS}}
ENABLED: 1
- type: ADCore.NDPvaPlugin
PORT: {{iocroot}}.PVA4
PVNAME: "{{iocprefix}}:{{iocroot}}:OVERLAY1:OUTPUT"
P: "{{iocprefix}}:{{iocroot}}"
R: ":Overlay1:Pva1:"
NDARRAY_PORT: {{iocroot}}.OVERLAY1
ENABLED: 1
- type: ADCore.NDStdArrays
P: "{{iocprefix}}:{{iocroot}}"
R: ":image2:"
PORT: {{iocroot}}.NTD2
NDARRAY_PORT: {{iocroot}}.PROC
TYPE: {{CAMERA_TYPE}}
FTVL: {{CAMERA_FTVL}}
NELEMENTS: {{CAMERA_ELEMS}}
ENABLED: 1
- type: ADCore.NDStats
PORT: {{iocroot}}.STATS
NDARRAY_PORT: {{iocroot}}
HIST_SIZE: 50
P: "{{iocprefix}}:{{iocroot}}"
R: ":Stats1:"
XSIZE: {{CAMERA_STATS_XSIZE}}
YSIZE: {{CAMERA_STATS_YSIZE}}
ENABLED: 1
- type: ADCore.NDStats
PORT: {{iocroot}}.STATS2
NDARRAY_PORT: {{iocroot}}.PROC
HIST_SIZE: 50
P: "{{iocprefix}}:{{iocroot}}"
R: ":Proc1:Stats1:"
XSIZE: {{CAMERA_STATS_XSIZE}}
YSIZE: {{CAMERA_STATS_YSIZE}}
ENABLED: 1
- type: ADCore.NDStats
PORT: {{iocroot}}.STATS3
NDARRAY_PORT: {{iocroot}}.ROI1
HIST_SIZE: 50
P: "{{iocprefix}}:{{iocroot}}"
R: ":Roi1:Stats1:"
XSIZE: {{CAMERA_STATS_XSIZE}}
YSIZE: {{CAMERA_STATS_YSIZE}}
ENABLED: 1
- type: ADCore.NDFileTIFF
PORT: {{iocroot}}.TIFF
NDARRAY_PORT: {{iocroot}}
P: "{{iocprefix}}:{{iocroot}}"
R: ":TIFF1:"
ENABLED: 1
- type: ADCore.NDFileTIFF
PORT: {{iocroot}}.TIFF2
NDARRAY_PORT: {{iocroot}}.PROC
P: "{{iocprefix}}:{{iocroot}}"
R: ":Proc1:TIFF1:"
ENABLED: 1
- type: ADCore.NDFileTIFF
PORT: {{iocroot}}.TIFF3
NDARRAY_PORT: {{iocroot}}.ROI1
P: "{{iocprefix}}:{{iocroot}}"
R: ":Roi1:TIFF1:"
ENABLED: 1
- type: ADCore.NDFileTIFF
PORT: {{iocroot}}.TIFF4
NDARRAY_PORT: {{iocroot}}.OVERLAY1
P: "{{iocprefix}}:{{iocroot}}"
R: ":Overlay1:TIFF1:"
ENABLED: 1
- type: epics.PostStartupCommand
command: dbl ## dumps PV NAMES
- type: epics.PostStartupCommand
command: |
dbl("*") > {{data_config}}/pvlist.txt
dbpf("{{iocprefix}}:{{iocroot}}:TIFF1:FilePath", "{{data_dir}}")
dbpf("{{iocprefix}}:{{iocroot}}:TIFF1:FileWriteMode",2)
dbpf("{{iocprefix}}:{{iocroot}}:TIFF1:FileName","camera")
dbpf("{{iocprefix}}:{{iocroot}}:TIFF1:AutoIncrement",1)
dbpf("{{iocprefix}}:{{iocroot}}:TIFF1:FileTemplate","%s%s_%3.3d.tiff")
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF1:FilePath", "{{data_dir}}")
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF1:FileWriteMode",2)
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF1:FileName","{{iocroot}}")
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF1:AutoIncrement",1)
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF1:FileTemplate","%s%s_proc_%3.3d.tiff")
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF:FilePath", "{{data_dir}}")
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF:FileWriteMode",2)
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF:FileName","{{iocroot}}")
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF:AutoIncrement",1)
dbpf("{{iocprefix}}:{{iocroot}}:Proc1:TIFF:FileTemplate","%s%s_proc_%3.3d.tiff")
dbpf("{{iocprefix}}:{{iocroot}}:Roi1:TIFF1:FilePath", "{{data_dir}}")
dbpf("{{iocprefix}}:{{iocroot}}:Roi1:TIFF1:FileWriteMode",2)
dbpf("{{iocprefix}}:{{iocroot}}:Roi1:TIFF1:FileName","{{iocroot}}")
dbpf("{{iocprefix}}:{{iocroot}}:Roi1:TIFF1:AutoIncrement",1)
dbpf("{{iocprefix}}:{{iocroot}}:Roi1:TIFF1:FileTemplate","%s%s_roi_%3.3d.tiff")
dbpf("{{iocprefix}}:{{iocroot}}:Overlay1:TIFF1:FilePath", "{{data_dir}}")
dbpf("{{iocprefix}}:{{iocroot}}:Overlay1:TIFF1:FileWriteMode",2)
dbpf("{{iocprefix}}:{{iocroot}}:Overlay1:TIFF1:FileTemplate","%s%s_overlay_%3.3d.tiff")
dbpf("{{iocprefix}}:{{iocroot}}:Overlay1:TIFF1:FileName","{{iocroot}}")
dbpf("{{iocprefix}}:{{iocroot}}:Overlay1:EnableCallbacks","1")
{%- for param in iocinit %}
dbpf("{{iocprefix}}:{{iocroot}}:{{param.name}}","{{param.value}}")
{%- endfor %}
- type: epics.EpicsCaMaxArrayBytes
max_bytes: 10000000 |
camera ibek specific rendering
And a camerainit.yml that produce the ibek yaml for the given camera:
| Code Block |
|---|
| language | yaml |
|---|
| title | camera ini |
|---|
|
name: "SCOUT640"
asset: "https://confluence.infn.it/x/nYD8DQ"
charturl: 'https://baltig.infn.it/epics-containers/ioc-launcher-chart.git'
host: "192.168.197.24"
user: "root"
iocdir: "camera"
ca_server_port: 5264
pva_server_port: 5275
docker:
enable: true
image: baltig.infn.it:4567/epics-containers/infn-epics-ioc:latest
devtype: camera
devgroup: diag
iocprefix: "EUAPS:CAM"
iocroot: "SCOUT64"
autosync: false ## restart automatically on changes
opi:
url: https://baltig.infn.it/infn-epics/camera-opi.git
main: Camera_Main.bob
macro:
- name: "DEVICE"
value: EUAPS:CAM
- name: "CAM"
value: "SCOUT64"
CAMERA_ID: "Basler-scA640-70gm-24159532"
CAMERA_CLASS: "Basler-scA640-70gm"
CAMERA_TYPE: "Int8"
CAMERA_FTVL: "USHORT"
CAMERA_ELEMS: 5616000
CAMERA_STATS_XSIZE: 1024
CAMERA_STATS_YSIZE: 768 |
The application jnjrender (pip install jnjrender) will render a valid ibek yaml camera_template.yaml
| Code Block |
|---|
| language | yaml |
|---|
| title | camera ini |
|---|
|
jnjrender camera_template.j2 camerainit.yml --output camera_template.yaml |
camera run
Now launch the docker mounting the directory that contains the camera_template.yaml in/epics/ioc/config
| Code Block |
|---|
| language | bash |
|---|
| title | Camera development start |
|---|
|
docker run --network=host -v .:/epics/ioc/config -it baltig.infn.it:4567/epics-containers/infn-epics-ioc
|
Deploy on the target EPIK8S
...