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):
| Terminal | Role | Working directory | Environment |
|---|---|---|---|
| Terminal 1 | Simulator 1 (9399) | jeonglee_Demo/simulator/ | No EPICS environment required |
| Terminal 2 | Simulator 2 (9400) | jeonglee_Demo/simulator/ | No EPICS environment required |
| Terminal 3 | Simulator 3 (9401) | jeonglee_Demo/simulator/ | No EPICS environment required |
| Terminal 4 | Compiled IOC (./st3.cmd) | jeonglee_Demo/iocBoot/iocB46_182-jeonglee_Demo/ | source "$TREE/setEpicsEnv.bash" |
| Terminal 5 | CA and PVA client | Any directory | 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 |
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 prefix | Asyn port | TCP port |
|---|---|---|
MYDEMO:SIM1: | TCP1 | 9399 |
MYDEMO:SIM2: | TCP2 | 9400 |
MYDEMO:SIM3: | TCP3 | 9401 |
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
-
Start the command-aware simulator in terminals 1, 2, and 3 from
jeonglee_Demo/simulator/. In terminal 1, listen on port9399:./tcpserver.bash 9399 advanced_connection_handler.shIn terminal 2, listen on port
9400:./tcpserver.bash 9400 advanced_connection_handler.shIn terminal 3, listen on port
9401:./tcpserver.bash 9401 advanced_connection_handler.sh -
In terminal 4 inside
jeonglee_Demo/iocBoot/iocB46_182-jeonglee_Demo/, start the IOC:./st3.cmd -
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-RBcaput -cwaits for each asynchronous command to finish before the next command runs, andcagetprints three distinct numeric process IDs:MYDEMO:SIM1:Cmd-RB 764328 MYDEMO:SIM2:Cmd-RB 764331 MYDEMO:SIM3:Cmd-RB 764335 -
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-RBEach reply returns an integer between
0and100:MYDEMO:SIM1:Cmd-RB 32 MYDEMO:SIM2:Cmd-RB 26 MYDEMO:SIM3:Cmd-RB 61In terminal 4,
TCP3printsasyntrace lines for the 9-byte"GetTemp?\n"write and 3-byte"61\n"reply on127.0.0.1:9401, whileTCP1andTCP2stay 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.