====
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."