Demo¶
You can build an EPICS IOC with the steps described below.
This demo uses virtual CAN interfaces for an IOC on your system.
It also uses sumo to fetch and build all the needed device supports.
The demo shows how data is transferred from one output record via the CAN bus to one input record.
How to build¶
Note
If you are interested in how the demo works in detail, look at: Demo details
Download ioc-multican.tgz.
Unpack with:
tar -xzf ioc-multican.tgz
Build everything with:
cd ioc-multican
./create-ioc.sh
How to run¶
Note
You need ‘sudo’ permissions for this test since the IOC uses real time task priorities that are not allowed for ordinary users.
In one terminal start the ioc with:
./start-ioc.sh
In another terminal you can inspect the records with these commands:
source ./setenv.sh
camonitor ca1testo cantesto ca2testo cantesti
This shows that the records are processed in this order:
ca1testo : get counter, trigger can write
cantesto : write to CAN bus, trigger ca2testo
ca2testo : processed after CAN write
cantesti : read from CAN bus, this comes last
You can also see timestamps with:
source ./setenv.sh
camonitor cantesto_ts.VALA cantesti_ts.VALA
This shows the human readable microsecond timestamp of the CAN write and CAN read object.
With the ‘candump’ utility you can see your CAN bus I/O with:
candump any
What to do next¶
You may extend the database file ‘socanTest.db’ with other records and for example, the SDO protocol.
Demo details¶
The demo uses sumo to build MultiCAN and all supports that it depends on. sumo has a dependency database that contains information where to get an EPICS support and on which other supports it depends.
The demo script creates a first version of a dependency database with command sumo config new and then adds definitions for MultiCAN and the support modules MultiCAN needs.
Here are the relevant parts of the dependency database:
{
"ALARM": {
"R4-5": {
"aliases": {
"BASE": "EPICS_BASE",
"MISC_DBC": "DBC"
},
"dependencies": [
"BASE",
"MISC_DBC"
],
"source": {
"git": {
"tag": "R4-5",
"url": "git://git.code.sf.net/p/almlib-hzb/code"
}
}
}
},
"BASE": {
"R3-15-9": {
"make-recipes": {
"config": [
"echo \"export EPICS_HOST_ARCH=$$(perl $(BASE)/src/tools/EpicsHostArch.pl)\" > $DIR/setenv.sh",
"echo \"export EPICS_BASE=$(BASE)\" >> $DIR/setenv.sh",
"echo \"export PATH=\\$$EPICS_BASE/bin/\\$$EPICS_HOST_ARCH:\\$$PATH\" >> $DIR/setenv.sh"
],
"distclean": [
"$(MAKE) -C $DIR distclean",
"rm -f $DIR/setenv.sh"
]
},
"source": {
"git": {
"tag": "R3.15.9",
"url": "https://github.com/epics-base/epics-base.git"
}
}
}
},
"BSPDEP_TIMER": {
"R6-11": {
"aliases": {
"BASE": "EPICS_BASE"
},
"dependencies": [
"BASE"
],
"source": {
"git": {
"tag": "R6-11",
"url": "git://git.code.sf.net/p/bspdep-timer-hzb/code"
}
}
}
},
"MCAN": {
"R2-9-3-Linux": {
"aliases": {
"BASE": "EPICS_BASE"
},
"dependencies": [
"ALARM",
"BASE",
"MISC_DBC",
"SOCAN",
"SOFT_DEVHWCLIENT",
"TOOLS_HGEN"
],
"make-recipes": {
"config": [
"cd $DIR && sed -i -e 's#^\\(USE_SCAN_Linux\\) *=.*#\\1=NO#;s#^\\(USE_SOCAN_Linux\\) *=.*#\\1=YES#' configure/CONFIG"
]
},
"source": {
"git": {
"tag": "R2-9-3",
"url": "git://git.code.sf.net/p/mcan/code"
}
}
}
},
"MISC_DBC": {
"R3-1": {
"aliases": {
"BASE": "EPICS_BASE"
},
"dependencies": [
"BASE"
],
"source": {
"git": {
"tag": "R3-1",
"url": "git://git.code.sf.net/p/misc-dbc-hzb/code"
}
}
}
},
"SOCAN": {
"1.0.1": {
"make-recipes": {
"all": [
"$(MAKE) -C $DIR epics"
]
},
"source": {
"hg": {
"tag": "1.0.1",
"url": "http://hg.code.sf.net/p/socan/code"
}
}
}
},
"SOFT_DEVHWCLIENT": {
"R3-1": {
"aliases": {
"BASE": "EPICS_BASE"
},
"dependencies": [
"BASE"
],
"source": {
"git": {
"tag": "R3-1",
"url": "git://git.code.sf.net/p/soft-devhwclient-hzb/code"
}
}
}
},
"TOOLS_HGEN": {
"1.8": {
"source": {
"hg": {
"tag": "1.8",
"url": "http://hg.code.sf.net/p/hgen/code"
}
}
}
}
}
The demo script then creates an EPICS ioc with makeBaseApp.pl.
The created directory tree is then modified for the demo application.
File configure/MODULES
defines what support modules the application
needs, this is the content of this file:
{
"alias": [
"BASE:EPICS_BASE",
"BSPDEP_TIMER:TIMER",
"SOFT_DEVHWCLIENT:DEVHWCLIENT"
],
"module": [
"ALARM:R4-5",
"BASE:R3-15-9",
"BSPDEP_TIMER:R6-11",
"MCAN:R2-9-3-Linux",
"SOCAN:1.0.1",
"MISC_DBC:R3-1",
"SOFT_DEVHWCLIENT:R3-1",
"TOOLS_HGEN:1.8"
]
}
The file socanTestApp/src/Makefile
contains these statements to use
MultiCAN:
socanTest_DBD += alm.dbd
socanTest_DBD += hwLowcalRecord.dbd
socanTest_DBD += MultiCAN.dbd
socanTest_DBD += socan.dbd
socanTest_LIBS += socan sci
socanTest_LIBS += alm
socanTest_LIBS += hwLowcalRecord mCANSupport mCANCore
The startup script iocBoot/iocsocanTest/st.cmd
initializes the application.
Here are the relevant parts for the usage of MultiCAN:
# initialize almlib:
alm_init()
# Initialize MCAN:
mcanInit()
gpsInit()
dbg_init()
# Set initHook for MultiCAN:
mCANRegisterInitHooks()
# Enable handshake in LowCAL:
var glbl_lowcal_use_handshake 1
# Override inhibit time with 0 (microseconds):
var glbl_lowcal_override_inhibit 0
# Print messages for errors in GPS layer:
var gpsPrintErrors 0
# init socan
socantest("abc")
#socan_tracelevel(2)
socan_tracelevel(0)
socan_errprintlevel(3)
socan_add_port("vcan0")
socan_add_port("vcan1")
socan_add_port("vcan2")
socan_add_port("vcan3")
socan_init()
All calls to *_init functions up to var gpsPrintErrors 0
are needed
to initialize MultiCAN.
The commands below # init socan
initialize the socan support that
is used by MultiCAN.
socan_tracelevel(0)
defines that socan doean’t print trace output.
socan_errprintlevel(3)
defines that even minor errors are printed to the console.
socan_add_port(INTERFACE)
defines which interface maps to which port number, staring implicitly
with port 0. So “vcan0” maps to port 0, “vcan1” to port 1 and so on.
socan_init()
initializes the socan module.
The database definition file socanTestApp/Db/socanTest.db
defines some records. We show here the two CAN
bus records. Both use the ‘lowCAL’ protocol:
record(longout,"cantesto")
# write to CAN bus:
# variable-type: server basic write-only,
# data-type: unsigned long, length: 4 bytes
# port: 0, out-cob: 2, in-cob: 0,
# inhibit: 1.0 [ms], timeout: 1000 [ms]
{
field(DTYP,"lowcal")
field(OUT,"@b L 4 0 2 0 0 a 3e8 0")
field(DOL, "counter NPP NMS")
field(OMSL, "closed_loop")
field(FLNK, "ca2testo")
}
record(longin,"cantesti")
# read from the CAN bus
# variable-type: server basic write-only,
# data-type: unsigned long, length: 4 bytes,
# port: 1, out-cob: 0, in-cob: 2,
# inhibit: 1.0 [ms], timeout: 1000 [ms],
{
field(DTYP,"lowcal")
field(INP,"@h L 4 1 0 2 0 a 3e8 0")
field(SCAN,"I/O Intr")
field(FLNK, "cantesto_ts")
}
The demo script then compiles the IOC and initializes the virtual
CAN interfaces with the scripts init-can.sh
and link-vcan-devices.sh
that are part of the socan device support.
Finally here is the complete file create-ioc.sh
:
#!/bin/bash
SCRIPT_FULL_NAME=$(readlink -e $0)
MYDIR=$(dirname $SCRIPT_FULL_NAME)
MYNAME=$(basename $SCRIPT_FULL_NAME)
cd "$MYDIR" || exit 1
echo "Creating virtual environment for python."
python -m venv VENV
echo "Activate virtual environment."
source VENV/bin/activate
echo "Installing sumo."
pip install epics-sumo
echo "Creating sumo.config."
sumo config new SUMO github
sumo config make sumo.config --yes --#opt-preload configure/MODULES --#opt-preload configure/MODULES.HOST
echo "Add additional sumo dependency database entries for MultiCAN."
sumo db merge templates/EXTRA.DB
echo "Building EPICS base, please be patient..."
sleep 1
sumo build new BASE:R3-15-9 --makeflags "-sj" --progress
# define BASE environment variable:
eval "$(sumo build use BASE:R3-15-9 -o - | sed -e 's/^EPICS_//')"
echo "EPICS Base is in $BASE."
# set environment variables to use that EPICS base:
source $BASE/setenv.sh
echo "Creating ioc with makeBaseApp.pl."
makeBaseApp.pl -b $EPICS_BASE -t ioc socanTest
makeBaseApp.pl -i -t ioc -p socanTest iocsocanTest
echo "Configure IOC for MultiCAN."
cp -a templates/MODULES configure
cp -a templates/Db/* socanTestApp/Db
cp -a templates/src/* socanTestApp/src
cp -a templates/start-ioc.sh .
cp -a templates/boot/* iocBoot/iocsocanTest
echo "Building all support modules, please be patient."
sleep 1
sumo build new --makeflags "-sj" --progress
echo "Use support modules in ioc application."
sumo build use
echo "Now build the ioc."
make -sj
# define SOCAN environment variable:
eval "$(grep SOCAN configure/RELEASE)"
echo "Define virtual CAN interfaces, this requires sudo rights."
$SOCAN/bin/init-can.sh -d vcan
echo "Link first two CAN interfaces."
$SOCAN/bin/link-vcan-devices.sh link 0 1
echo
echo
echo "source $MYDIR/VENV/bin/activate" > setenv.sh
echo "eval \"\$(sumo help completion-line)\"" >> setenv.sh
echo "BASE=$BASE" >> setenv.sh
echo "source \$BASE/setenv.sh" >> setenv.sh
echo
echo "Finished, you may now start the ioc (requires sudo) with:"
echo "./start-ioc.sh"
echo
echo "In a second window you may enter:"
echo " source ./setenv.sh"
echo "And then run for example:"
echo
echo " camonitor ca1testo cantesto ca2testo cantesti"
echo
echo "This shows that the records are processed in the order:"
echo " ca1testo : get counter, trigger can write"
echo " cantesto : write to CAN bus, trigger ca2testo"
echo " ca2testo : processed after CAN write"
echo " cantesti : read from CAN bus, this comes last"
echo
echo "Second example: get timestamps, enter:"
echo " camonitor cantesto_ts.VALA cantesti_ts.VALA"
echo
echo "This shows the human readable microsecond timestamp of"
echo "the CAN write and CAN read object."