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

4.3 Connect three devices to one IOC

Use one reusable iocshLoad fragment to configure three independent TCP connections. Each device needs a unique PV name, asyn port, and TCP port.

Complete Reuse a device startup fragment and Run a command-aware TCP simulator first. Open five Bash terminals on the same host with these roles and settings (or launch the three simulators from one terminal with GNU Parallel as shown in lesson 4.2):

TerminalRoleWorking directoryEnvironment
Terminal 1Simulator 1 (9399)jeonglee_Demo/simulator/No EPICS environment required
Terminal 2Simulator 2 (9400)jeonglee_Demo/simulator/No EPICS environment required
Terminal 3Simulator 3 (9401)jeonglee_Demo/simulator/No EPICS environment required
Terminal 4Compiled IOC (./st3.cmd)jeonglee_Demo/iocBoot/iocB46_182-jeonglee_Demo/source "$TREE/setEpicsEnv.bash"
Terminal 5CA 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

In each EPICS terminal, set TREE to your installation path from lesson 1.1 (such as "$HOME/epics/1.5.0/debian-13/7.0.10") before running source "$TREE/setEpicsEnv.bash".

Configure the three connections

The example uses these names:

PV prefixAsyn portTCP port
MYDEMO:SIM1:TCP19399
MYDEMO:SIM2:TCP29400
MYDEMO:SIM3:TCP39401

In terminal 4 inside iocBoot/iocB46_182-jeonglee_Demo/, save this as st3.cmd:

#!../../bin/linux-x86_64/jeonglee_Demo
on error break
< envPaths

epicsEnvSet("DB_TOP", "$(TOP)/db")
epicsEnvSet("DATABASE_TOP", "$(DB_TOP)")
epicsEnvSet("STREAM_PROTOCOL_PATH", "$(DB_TOP)")
epicsEnvSet("PREFIX", "MYDEMO:")
dbLoadDatabase("$(TOP)/dbd/jeonglee_Demo.dbd")
jeonglee_Demo_registerRecordDeviceDriver(pdbbase)

iocshLoad("$(TOP)/iocsh/training_device.iocsh", "DEVICE=SIM1:,PORT_NAME=TCP1,PORT=9399")
iocshLoad("$(TOP)/iocsh/training_device.iocsh", "DEVICE=SIM2:,PORT_NAME=TCP2,PORT=9400")
iocshLoad("$(TOP)/iocsh/training_device.iocsh", "DEVICE=SIM3:,PORT_NAME=TCP3,PORT=9401,ASYNTRACE=")
iocInit()
dbl

The fragment reads PREFIX and DATABASE_TOP from the IOC environment. Each iocshLoad call supplies its device-specific values. ASYNTRACE= enables tracing for the third connection.

Make the startup executable:

chmod +x st3.cmd

Run and test all three devices

  1. Start the command-aware simulator in terminals 1, 2, and 3 from jeonglee_Demo/simulator/. In terminal 1, listen on port 9399:

    ./tcpserver.bash 9399 advanced_connection_handler.sh
    

    In terminal 2, listen on port 9400:

    ./tcpserver.bash 9400 advanced_connection_handler.sh
    

    In terminal 3, listen on port 9401:

    ./tcpserver.bash 9401 advanced_connection_handler.sh
    
  2. In terminal 4 inside jeonglee_Demo/iocBoot/iocB46_182-jeonglee_Demo/, start the IOC:

    ./st3.cmd
    
  3. In terminal 5, direct CA and PVA searches to loopback and request each handler’s identity:

    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
    caput -c MYDEMO:SIM1:Cmd "GetID?"
    caput -c MYDEMO:SIM2:Cmd "GetID?"
    caput -c MYDEMO:SIM3:Cmd "GetID?"
    caget MYDEMO:SIM1:Cmd-RB MYDEMO:SIM2:Cmd-RB MYDEMO:SIM3:Cmd-RB
    

    caput -c waits for each asynchronous command to finish before the next command runs, and caget prints three distinct numeric process IDs:

    MYDEMO:SIM1:Cmd-RB             764328
    MYDEMO:SIM2:Cmd-RB             764331
    MYDEMO:SIM3:Cmd-RB             764335
    
  4. Request a simulated temperature from each device:

    caput -c MYDEMO:SIM1:Cmd "GetTemp?"
    caput -c MYDEMO:SIM2:Cmd "GetTemp?"
    caput -c MYDEMO:SIM3:Cmd "GetTemp?"
    caget MYDEMO:SIM1:Cmd-RB MYDEMO:SIM2:Cmd-RB MYDEMO:SIM3:Cmd-RB
    

    Each reply returns an integer between 0 and 100:

    MYDEMO:SIM1:Cmd-RB             32
    MYDEMO:SIM2:Cmd-RB             26
    MYDEMO:SIM3:Cmd-RB             61
    

    In terminal 4, TCP3 prints asyn trace lines for the 9-byte "GetTemp?\n" write and 3-byte "61\n" reply on 127.0.0.1:9401, while TCP1 and TCP2 stay quiet:

    2026/11/11 11:19:33.450 TCP3 addr -1 queueRequest priority 0 not lockHolder
    2026/11/11 11:19:33.450 TCP3 schedule queueRequest timeout in 5.000000 seconds
    2026/11/11 11:19:33.450 asynManager::portThread port=TCP3 callback
    2026/11/11 11:19:33.450 TCP3 addr -1 queueRequest priority 0 not lockHolder
    2026/11/11 11:19:33.450 TCP3 schedule queueRequest timeout in 0.100000 seconds
    2026/11/11 11:19:33.450 asynManager::portThread port=TCP3 callback
    2026/11/11 11:19:33.450 127.0.0.1:9401 read.
    2026/11/11 11:19:33.452 127.0.0.1:9401 write.
    2026/11/11 11:19:33.452 127.0.0.1:9401 write 9
    
    2026/11/11 11:19:33.452 wrote 9 to 127.0.0.1:9401, return asynSuccess.
    2026/11/11 11:19:33.452 TCP3 addr -1 queueRequest priority 0 from lockHolder
    2026/11/11 11:19:33.452 TCP3 schedule queueRequest timeout in 1.000000 seconds
    2026/11/11 11:19:33.452 asynManager::portThread port=TCP3 callback
    2026/11/11 11:19:33.452 127.0.0.1:9401 read.
    2026/11/11 11:19:33.452 127.0.0.1:9401 read 3
    

Verification

Enter dbl in the IOC console. All six records, Cmd and Cmd-RB for each device, must be present. Tracing for TCP3 must appear when you send its commands.

Comment out one iocshLoad line and restart the IOC. That device’s records must be absent while the other devices continue to work. Restore the line, restart, and confirm that all three devices respond.

Enter exit in the IOC terminal and stop each simulator with Ctrl+C.