1. Creating a StreamDevice IOC¶
In this tutorial, we’ll create an EPICS IOC with EPNix that communicates with a power supply using the StreamDevice support module.
1.1. Prerequisites¶
Make sure that you have all prerequisites installed by following the Prerequisites section.
1.2. Running the power supply simulator¶
EPNix provides a power supply simulator for testing your IOC.
To run it:
nix run 'github:epics-extensions/epnix#psu-simulator'
For the rest of the tutorial, leave it running in a separate terminal.
1.3. Creating your top¶
Use these commands to create an EPNix top:
# Initialise an EPNix top
nix flake new -t 'github:epics-extensions/epnix' my-top
cd my-top
# Enter the EPNix development shell,
# which has EPICS base installed.
nix develop
# Create your app and IOC boot folder
makeBaseApp.pl -t ioc example
makeBaseApp.pl -i -t ioc -p example -a linux-x86_64 Example
# Create a Git repository, and make sure all files are tracked
git init
git add .
After that, you can already check that your top builds with:
nix build -L
This nix build command compiles your IOC
and all its dependencies.
This eliminates the need for the usual EPICS environment.
If packages are found in the official Nix cache server, Nix downloads them from there instead of compiling them.
This command creates a ./result symbolic link in your current directory
containing the build output.
Tip
If you want an explanation of the files generated by the template, read Template files.
1.4. Adding StreamDevice to the EPNix environment¶
You can add dependencies to the EPNix environment in the ioc.nix file.
To add StreamDevice, update yours as follows:
ioc.nix¶ # EPICS support modules can only be in propagatedBuildInputs
# --
propagatedBuildInputs = [
- #epnix.support.StreamDevice
+ epnix.support.StreamDevice
];
Then,
exit your EPNix development shell by running exit,
re-enter it with nix develop
and run epicsConfigurePhase.
By changing your package’s dependencies, you have changed build environment: before the change, the build environment didn’t have StreamDevice installed. With this change, StreamDevice is available to build your EPICS top.
Besides being available in the build environment,
the EPICS build system must know where to find StreamDevice.
EPICS uses the configure/RELEASE and configure/RELEASE.local files
to locate EPICS-specific dependencies,
often called “EPICS support modules”.
During the “configure” phase,
EPNix automatically generates the configure/RELEASE.local file,
which is why you need to run epicsConfigurePhase.
Now your development shell has StreamDevice available,
and the EPICS build system can find StreamDevice
by reading the configure/RELEASE.local file.
Tip
As a rule,
each time you edit the ioc.nix file,
exit and re-enter your development shell (exit then nix develop),
and run epicsConfigurePhase.
1.5. Adding StreamDevice to your EPICS app¶
To add StreamDevice to your app, make the following changes:
Edit the exampleApp/src/Makefile
so your App knows the record types of StreamDevice and its dependencies.
Also update it so that it links to the StreamDevice library and its dependencies
during compilation.
exampleApp/src/Makefile¶# ...
# Include dbd files from all support applications:
example_DBD += calc.dbd
example_DBD += asyn.dbd
example_DBD += stream.dbd
example_DBD += drvAsynIPPort.dbd
# Add all the support libraries needed by this IOC
example_LIBS += calc
example_LIBS += asyn
example_LIBS += stream
# ...
Create the exampleApp/Db/example.proto file
which defines the protocol.
This file tells StreamDevice what to send to the power supply
and what to expect in return.
exampleApp/Db/example.proto¶Terminator = LF;
getVoltage {
out ":volt?"; in "%f";
}
setVoltage {
out ":volt %f";
@init { getVoltage; }
}
Create the exampleApp/Db/example.db file.
This file specifies the name, type, and properties of the Process Variables (PVs)
that EPICS exposes over the network.
It also defines how they relate to the functions in the protocol file.
exampleApp/Db/example.db¶record(ai, "${PREFIX}VOLT-RB") {
field(DTYP, "stream")
field(INP, "@example.proto getVoltage ${PORT}")
}
record(ao, "${PREFIX}VOLT") {
field(DTYP, "stream")
field(OUT, "@example.proto setVoltage ${PORT}")
field(FLNK, "${PREFIX}VOLT-RB")
}
Edit exampleApp/Db/Makefile
so that the EPICS build system installs example.proto and example.db:
exampleApp/Db/Makefile¶# ...
#----------------------------------------------------
# Create and install (or just install) into <top>/db
# databases, templates, substitutions like this
DB += example.db
DB += example.proto
# ...
Edit your st.cmd file
so it knows where to load the protocol file
and how to connect to the remote power supply.
iocBoot/iocExample/st.cmd¶#!../../bin/linux-x86_64/example
< envPaths
## Register all support components
dbLoadDatabase("${TOP}/dbd/example.dbd")
example_registerRecordDeviceDriver(pdbbase)
# Where to find the protocol files
epicsEnvSet("STREAM_PROTOCOL_PATH", "${TOP}/db")
# The TCP/IP address of the power supply
drvAsynIPPortConfigure("PS1", "localhost:9999")
## Load record instances
dbLoadRecords("${TOP}/db/example.db", "PREFIX=, PORT=PS1")
iocInit()
Run chmod +x iocBoot/iocExample/st.cmd
so you can run your command file as-is.
You can test that your top builds by running:
nix build -L
You will see that your IOC does not build. This is because Git isn’t tracking the newly added files, so Nix ignores them too.
Run git add . so Git and Nix track all files,
then try nix build -L again.
If everything goes well,
you can inspect your compiled top under ./result.
You can observe that the EPICS build system:
installs the
exampleapp inbin/linux-x86_64and links to the correct librariesinstalls
example.protoandexample.dbunderdb/generates
example.dbdand installs it underdbd/
1.6. Running your IOC¶
To run your IOC,
build it first with nix build -L,
then change directory into the ./result/iocBoot/iocExample folder.
Run:
./st.cmd
You should see the IOC starting and connecting to localhost:9999.
Tip
./result is a symbolic link,
so if you make any changes to your IOC and re-run nix build,
a terminal already in ./result/iocBoot/iocExample would still point to the old version.
To run the new version,
either open a new window
and cd into the new ./result/,
or in the old location,
run:
user@machine .../result/iocBoot/iocExample $ cd .
For quickly re-running an IOC, you can use this command:
user@machine .../result/iocBoot/iocExample $ cd . ; ./st.cmd
1.7. Recompiling with make¶
Using nix build to compile your IOC each time might feel slow
because Nix recompiles your IOC from scratch each time.
If you prefer a more traditional edit/compile/run workflow,
enter the development shell with nix develop
and use make from here.
Be sure to exit and re-enter the development shell
each time you edit Nix files,
and re-run epicsConfigurePhase.
1.8. Next steps¶
The power supply simulator supports more commands. To view them, stop your IOC and open a direct connection to the simulator:
nc localhost 9999
# or
telnet localhost 9999
You can install the nc command from the netcat package,
or you can install the telnet command from the telnet package,
Either command opens a prompt
where you can type help and press Enter
to view the available commands.
Try editing the protocol file and the database file to add those features to your IOC.
For more information about writing the StreamDevice protocol, see the Protocol Files documentation.
You might also want to read Setting up the flake registry.
1.9. Pitfalls¶
Although EPNix tries to closely follow standard EPICS development, some differences might cause confusion. You can find more information in the Frequently Asked Questions.