Skip to content

Repository files navigation

yaml2epics

CI Python 3.8+ License: MIT

Write EPICS IOC databases in human-readable YAML. Compile to standard .db files.

yaml2epics modernizes the EPICS developer experience without breaking compatibility with existing infrastructure. Define your entire control system in a single YAML file — the compiler generates validated .db databases, startup scripts, and documentation.


The Problem

EPICS .db files are powerful but painful to author. Field names are cryptic, typos are silently ignored, and there's no built-in validation:

record(ai, "XRAY:HV:VoltRead") {
    field(DESC, "Voltage Readback")
    field(INP,  "XRAY:HV:VoltRamp CP")
    field(EGU,  "kV")
    field(PREC, "1")
    field(HOPR, "160")
    field(HIHI, "155")
    field(HIGH, "140")
    field(HHSV, "MAJOR")
    field(HSV,  "MINOR")
}

The Solution

- name: "HV:VoltRead"
  type: ai
  description: Voltage Readback
  input: XRAY:HV:VoltRamp
  link_mode: cp
  units: kV
  precision: 1
  range: [0, 160]
  alarms:
    minor_high: 140
    major_high: 155

Same output. Validated before compilation. Self-documenting.


Quick Start

# Install
pip install pyyaml
pip install -e .

# Compile an example
yaml2epics examples/xray_imaging/xray_system.yaml -o ./generated -v

# Run the IOC
cd generated
softIoc -d x-ray_imaging_system.db

What It Generates

generated/
├── detector.db                     # Per-device database files
├── xraytube.db
├── shutter.db
├── cabinet.db
├── lowvoltage.db
├── x-ray_imaging_system.db         # Combined system database
├── st.cmd                          # IOC startup script (with asyn config)
└── interfaces.md                   # Auto-generated documentation

Features

Schema Validation

Catches real mistakes before your IOC loads them:

  • calc record with output field → error (should use calcout)
  • Duplicate PV names → error
  • Invalid scan rates → error
  • Alarm thresholds in wrong order → error
  • Description exceeding 40 characters → warning

Simplified Syntax

Alarms — one block instead of eight fields:

alarms:
  major_high: 155    # → HIHI=155, HHSV=MAJOR
  minor_high: 140    # → HIGH=140, HSV=MINOR
  minor_low: 10      # → LOW=10,   LSV=MINOR
  major_low: 5       # → LOLO=5,   LLSV=MAJOR
  deadband: 0.5      # → HYST=0.5

Links — readable mode names:

input: DET:TempSim
link_mode: cp          # instead of "DET:TempSim CP"

Short name resolution — forward links auto-resolve:

# In a device with prefix "XRAY"
forward_link: "HV:Status"   # → FLNK = "XRAY:HV:Status"

Named calculation inputs:

expression: "A*B"
inputs:
  a: { pv: XRAY:HV:VoltRead, mode: cp }
  b: { pv: XRAY:HV:CurrRead, mode: cp }

Interface Metadata

Document your physical connections alongside the records:

interfaces:
  - id: det_gige
    type: gige
    address: 192.168.1.100
    port: 8080

  - id: hv_serial
    type: serial
    address: /dev/ttyS0
    baud: 9600

devices:
  - id: detector
    prefix: DET
    interface_ref: det_gige
    records: [...]

The startup script auto-generates drvAsynIPPortConfigure / drvAsynSerialPortConfigure comments for each interface.

Escape Hatch

For any EPICS field not in the simplified schema:

raw_fields:
  ADEL: "0.1"
  MDEL: "0.01"
  SMOO: "0.5"

System YAML Structure

name: X-Ray Imaging System
author: Your Name
version: "1.0.0"
ioc_name: xray-sim

interfaces:
  - id: detector_eth
    type: gige              # gige | serial | modbus_tcp | modbus_rtu | gpib | simulated
    address: 192.168.1.100
    port: 8080

devices:
  - id: detector
    name: Pixel Detector
    prefix: DET
    interface_ref: detector_eth
    records:
      - name: Temperature
        type: ai
        description: Detector Temperature
        units: C
        scan: 2s
        precision: 1
        input: DET:TempSim
        link_mode: cp
        range: [-30, 60]
        alarms:
          minor_high: 40
          major_high: 50

Supported Record Types

Type Description
ai / ao Analog input / output
bi / bo Binary input / output
calc Calculation (no output)
calcout Calculation with output
mbbi / mbbo Multi-bit binary (up to 16 states)
longin / longout Long integer input / output
stringin / stringout String input / output
seq Sequence with delays

CLI Options

yaml2epics <input.yaml> [options]

Options:
  -o, --output-dir DIR    Output directory (default: ./generated)
  -V, --validate-only     Validate without generating files
  -v, --verbose           Show detailed output

Example: X-Ray Imaging System

The examples/xray_imaging/ directory contains a complete control system definition with five subsystems, including a linear pixel detector with GigE readout, X-ray tube HV control (RS-232), shutter with interlocks (Modbus TCP), cabinet safety system, and low voltage power supplies (GPIB/SCPI). All subsystems include simulated physics (HV ramping, temperature drift, radiation levels) that run in softIoc.

yaml2epics examples/xray_imaging/xray_system.yaml -o ./out -v
cd out && softIoc -d x-ray_imaging_system.db

Development

git clone https://github.com/ElmaddinGuliyev/yaml2epics.git
cd yaml2epics
pip install -e ".[dev]"
pytest -v

See CONTRIBUTING.md for guidelines.

Roadmap

  • epics2yaml reverse compiler — import existing .db files
  • Node.js WebSocket dashboard — real-time web UI from YAML definitions
  • Template inheritance — define reusable device types
  • Auto-generated Phoebus .bob operator screens
  • VS Code extension with YAML schema autocomplete
  • Waveform and areaDetector record support
  • Integration testing with softIoc

License

MIT — see LICENSE.

Author

Elmaddin Guliyev — Staff Scientist, Thermo Fisher Scientific

About

No description, website, or topics provided.

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages