# Create an IOC Instance In {any}`create-beamline` you generated `t01-services` with a single example IOC instance (`example-test-01`). Now you will add your own: a simulated area detector built on the public `ioc-adsimdetector` Generic IOC. Substitute your own names throughout. :::{note} A little familiarity with the EPICS [AreaDetector](https://areadetector.github.io/areaDetector/index.html) framework is helpful but not required. ::: (create-new-ioc-instance)= ## Add a New IOC Instance An IOC instance is just a folder under `services/`. Its folder name is the IOC name, and it contains two things: | Item | Purpose | |---|---| | `compose.yml` | Boilerplate that says *which container image* to run and *what to call it*. | | `config/` | The IOC configuration, normally a single `ibek` file named `ioc.yaml`. | Your services repo ships a `.ioc_template` skeleton to copy. In a terminal at the repo root: ```bash cd t01-services cp -r services/.ioc_template services/bl01t-ea-cam-01 code . ``` :::{note} **DLS users:** `module load vscode` first, then `code .`. ::: ### compose.yml The skeleton's `compose.yml` has two placeholders. In `services/bl01t-ea-cam-01/compose.yml`, replace **every** `ioc_default_name` with `bl01t-ea-cam-01`, and replace `replace_with_image_uri` with the SimDetector Generic IOC image: ```yaml image: ghcr.io/epics-containers/ioc-adsimdetector-runtime:2.11ec3 ``` That name and that image are the only per-IOC content; everything else is boilerplate. `extends` merges in the shared IOC definition from `include/ioc.yml`, and `configs` mounts your `config/` folder at `/epics/ioc/config` inside the container. The [compose file format](https://docs.docker.com/compose/compose-file) covers the rest. ### config/ioc.yaml An `ibek` `ioc.yaml` is a list of `entities`; each instantiates an `entity_model` from a support module, which turns its named parameters into startup-script lines and database records. The Generic IOC bakes in all the support it can instantiate, so nothing extra is downloaded here. Open `services/bl01t-ea-cam-01/config/ioc.yaml`, point the schema line at the SimDetector Generic IOC, and add a `simDetector` plus a Standard Arrays plugin wired to it: ```yaml # yaml-language-server: $schema=https://github.com/epics-containers/ioc-adsimdetector/releases/download/2.11ec3/ibek.ioc.schema.json ioc_name: "{{ _global.get_env('IOC_NAME') }}" description: An IOC that simulates an area detector entities: - type: epics.EpicsEnvSet name: EPICS_TZ value: GMT0BST - type: devIocStats.iocAdminSoft IOC: "{{ ioc_name | upper }}" - type: ADSimDetector.simDetector PORT: DET.DET P: BL01T-EA-CAM-01 R: ":DET:" - type: ADCore.NDStdArrays PORT: DET.ARR P: BL01T-EA-CAM-01 R: ":ARR:" NDARRAY_PORT: DET.DET TYPE: Int8 FTVL: CHAR NELEMENTS: 1048576 ``` This creates a simulation detector with PV prefix `BL01T-EA-CAM-01:DET:` on the Asyn port `DET.DET`, and a Standard Arrays plugin that publishes its image over Channel Access. :::{note} YAML indentation is significant: each `- type:` starts a new entity. Quote any value that begins with `:` or `{` (as with `R: ":DET:"`). ::: Finally register the instance by adding it to the `include:` list in the repo-root `compose.yml`: ```yaml include: - services/example-test-01/compose.yml - services/bl01t-ea-cam-01/compose.yml ... ``` (change-the-opi-screen)= ## Run It and View the Screens By default Phoebus opens `opi/demo.bob`, the hand-coded overview of the *shipped* `example-test-01` IOC. The template also ships `opi/demo-simdet.bob`, a ready-made screen wired to your new `BL01T-EA-CAM-01` detector — so have Phoebus open that one instead. Edit the `command:` line of the `phoebus` service in `services/phoebus/compose.yml`, changing `-resource /opi/demo.bob` to `-resource /opi/demo-simdet.bob`: ```yaml command: phoebus-product/phoebus.sh -settings /config/settings.ini -resource /opi/demo-simdet.bob -server 7010 ``` Now bring the beamline up: ```bash source ./environment.sh docker compose up -d ``` Phoebus opens the detector screen directly. On the **CAMERA** pane hit **Acquire**, and on the **Standard Array** pane **Enable** the plugin — a moving simulation image appears in the **Image** pane. The screen's **`bl01t-ea-cam-01`** button opens the engineering screens that PVI auto-generates for every entity at startup (into `opi/auto-generated/bl01t-ea-cam-01/`), giving you full control over each PV. Manage the running IOC with the same `docker compose` commands from {any}`deploy_example`. :::{note} This IOC is reused by later tutorials, so commit it now: ```bash git add . git commit -m "Create bl01t-ea-cam-01 IOC" ``` ::: **Next:** add the standard AreaDetector plugins to this IOC in {any}`detector_plugins`. ## How ibek Builds the IOC You wrote no startup script or database. At container start, `ibek runtime generate2` reads `config/ioc.yaml` plus the support definitions baked into the image and writes the `st.cmd` and database into `/epics/runtime/`. The schema line at the top of `ioc.yaml` also drives completion and validation in VSCode. The [Red Hat YAML extension](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) will read the schema line and help you edit your `ioc.yaml`, install it now if you have not already done so. To learn where entity models come from and build your own, see {any}`generic_ioc`. (raw-startup-assets)= ## Raw Startup Script and Database Prefer to hand-write startup assets? Drop your own `st.cmd` and `ioc.subst` (or an `ioc.db`) into `config/` instead of `ioc.yaml` — `start.sh` copies those files straight through, and a `config/start.sh` overrides startup entirely. To start from what `ibek` generated, copy it out of the running container, delete `ioc.yaml`, and restart: ```bash podman cp t01-services-bl01t-ea-cam-01-1:/epics/runtime/st.cmd services/bl01t-ea-cam-01/config podman cp t01-services-bl01t-ea-cam-01-1:/epics/runtime/ioc.subst services/bl01t-ea-cam-01/config rm services/bl01t-ea-cam-01/config/ioc.yaml docker compose restart bl01t-ea-cam-01 ``` The IOC then behaves as before, minus the auto-generated engineering screens: drop the `.pvi`-named template lines from `ioc.subst`, since those screens are only produced by the `ibek` path. :::{note} Later tutorials assume the `ioc.yaml` version, so keep this experiment on a branch: ```bash git checkout -b raw-startup git add . && git commit -m "use raw startup script and database" git checkout main ``` :::