Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

1.2 Run your first IOC

Create one process variable (PV), run an Input/Output Controller (IOC), and read and write the same value through Channel Access (CA) and pvAccess (PVA).

Open two Bash terminals on the same host with these roles and settings:

TerminalRoleWorking directoryEnvironment
Terminal 1IOC (softIocPVX)~/ioc-training/first/source "$TREE/setEpicsEnv.bash"
Terminal 2CA and PVA clientAny directorysource "$TREE/setEpicsEnv.bash", export EPICS_CA_AUTO_ADDR_LIST=NO EPICS_CA_ADDR_LIST=127.0.0.1, export EPICS_PVA_AUTO_ADDR_LIST=NO EPICS_PVA_ADDR_LIST=127.0.0.1
  1. In two Bash terminals, activate the matching installation from lesson 1.1. Set TREE in each terminal to that installation’s absolute path, then direct clients to this host:

    source "$TREE/setEpicsEnv.bash"
    export EPICS_CA_AUTO_ADDR_LIST=NO EPICS_CA_ADDR_LIST=127.0.0.1
    export EPICS_PVA_AUTO_ADDR_LIST=NO EPICS_PVA_ADDR_LIST=127.0.0.1
    
  2. In terminal 1, create a workspace outside the distribution:

    mkdir -p ~/ioc-training/first
    cd ~/ioc-training/first
    

    Save this database as water.db:

    record(ao, "temperature:water") {
        field(DESC, "Water temperature setpoint")
        field(EGU, "degC")
        field(VAL, "0")
    }
    

    This analog output (ao) record has no hardware connection. A write changes its stored value; EGU identifies its engineering units.

  3. Start the installed PVXS executable in terminal 1:

    softIocPVX -d water.db
    

    Wait for iocRun: All initialization complete. At the IOC prompt, list the records:

    dbl
    

    The IOC shell prints the loaded record name:

    temperature:water
    

    Leave the IOC running in terminal 1.

  4. In terminal 2, read the value and description:

    caget -t temperature:water
    caget -t temperature:water.DESC
    pvxget temperature:water
    

    CA returns the scalar value and description, while PVA displays a typed NTScalar structure:

    0
    Water temperature setpoint
    temperature:water
        value double = 0
        alarm.severity int32_t = 0
        alarm.status int32_t = 2
        alarm.message string = "UDF"
        timeStamp.secondsPastEpoch int64_t = 631152000
        timeStamp.nanoseconds int32_t = 0
        timeStamp.userTag int32_t = 0
        display.limitLow double = 0
        display.limitHigh double = 0
        display.description string = "Water temperature setpoint"
        display.units string = "degC"
        display.precision int32_t = 0
        display.form.index int32_t = 0
        display.form.choices string[] = {7}["Default", "String", "Binary", "Decimal", "Hex", "Exponential", "Engineering"]
        control.limitLow double = 0
        control.limitHigh double = 0
        valueAlarm.lowAlarmLimit double = nan
        valueAlarm.lowWarningLimit double = nan
        valueAlarm.highWarningLimit double = nan
        valueAlarm.highAlarmLimit double = nan
    
  5. Write through CA, then read through both protocols:

    caput temperature:water 24
    caget -t temperature:water
    pvxget temperature:water
    

    Both reads report 24, and the first write clears the initial UDF alarm status and updates timeStamp:

    Old : temperature:water              0
    New : temperature:water              24
    24
    temperature:water
        value double = 24
        alarm.severity int32_t = 0
        alarm.status int32_t = 0
        alarm.message string = ""
        timeStamp.secondsPastEpoch int64_t = 1794424745
        timeStamp.nanoseconds int32_t = 930919750
        timeStamp.userTag int32_t = 0
        display.limitLow double = 0
        display.limitHigh double = 0
        display.description string = "Water temperature setpoint"
        display.units string = "degC"
        display.precision int32_t = 0
        display.form.index int32_t = 0
        display.form.choices string[] = {7}["Default", "String", "Binary", "Decimal", "Hex", "Exponential", "Engineering"]
        control.limitLow double = 0
        control.limitHigh double = 0
        valueAlarm.lowAlarmLimit double = nan
        valueAlarm.lowWarningLimit double = nan
        valueAlarm.highWarningLimit double = nan
        valueAlarm.highAlarmLimit double = nan
    
  6. Write through PVA and read through CA:

    pvxput temperature:water 44
    caget -t temperature:water
    

    pvxput exits quietly on success, and CA returns 44 because both protocols reach the same record:

    44
    
  7. In terminal 1, stop the IOC:

    exit
    

Exercise: Add an air temperature

Add a second ao record to water.db, named temperature:air, with DESC set to Air temperature setpoint, EGU to degC, and VAL to 20. Restart the IOC and read both records:

caget temperature:water temperature:air

The restarted records begin at 0 and 20. Client writes in this lesson are not saved to the database file.

To observe a failed search without changing the host firewall, direct the CA client to an unused local UDP port in terminal 2:

export EPICS_CA_ADDR_LIST=127.0.0.1:59999
caget -w 1 temperature:water

With no IOC search listener on that port, the read times out:

Channel connect timed out: 'temperature:water' not found.

Restore the address and verify that the read succeeds:

export EPICS_CA_ADDR_LIST=127.0.0.1
caget -t temperature:water

An empty address list does not reliably cause failure when automatic broadcast discovery is enabled. Keep it disabled for these local exercises.