SLACM Applications
The developer is expected to follow strict structure for the application. In the description below APP stands for the name of an application, and COMP* for some component.
Single host applications
An application packages should be created in a folder hierarchy as shown below.
APP/
- APP.slacm (required)
- COMP1.py
....
- COMPN.py
- APP.params (required if app expects parameters)
- slacm.conf (optional)
- slacm-log.conf
- other files for the application (source, data, etc.)
APP.slacm is the application model file, and COMP1.py… COMPN.py are the application components.
The names of the components, and the component files must match the names used in the model. See the example below.
// App model
app HelloApp:
message Msg
component Hello2Pub:
timer clock 1000
pub port : Msg
component Hello2Sub:
sub port : Msg
actor HelloActor:
local Msg
thePub : Hello2Pub
theSub : Hello2Sub
...
Note the local Msg clause in the actor: this is a ‘scoping’ rule for the Msg messages. If this clause is present,
messages of this topic are restricted to the host the actor is running on. This is useful in cases where messages generated
on one hosts should not be distributed through the entire network.
The two component files show examples for components, the implementation of message handlers, and the use of the ports.
Hello2Pub.py:
from slacm.component import Component # Must import base class
class Hello2Pub(Component): # Must derive from Component
def __init__(self, arg1,arg2=None):
super().__init__() # Base class initialization
self.logger.info('-(%r,%r)' % (arg1,arg2)) # Python standard logger
self.cnt = 0
def on_clock(self): # Implements the message handler for `clock`
now = self.clock.recv_pyobj() # Must receive message (clock value)
self.logger.info('on_clock(): %s', str(now))
msg = "msg" + str(self.cnt)
self.cnt += 1
self.port.send_pyobj(msg) # Send message out via 'port'
self.logger.info("send: %s" % msg)
Hello2Sub.py:
from slacm.component import Component
class Hello2Sub(Component):
def __init__(self, arg3, arg4):
super().__init__()
self.logger.info('-(%r,%r)' % (arg3,arg4))
def on_port(self): # Message handler for `port`
msg = self.port.recv_pyobj() # Must receive message
self.logger.info('on_port(): recv = %s', msg)
In addition to the application model, an optional parameter file (APP.params) can be added to the package.
This file defines the values for the parameters of the component constructors (arg1, arg2 in Hello2Pub
and arg3,arg4 in Hello2Sub). The is a YAML file, which does not allow TAB-s, only spaces.
In the file strict tabulation establishes a hierarchy, and the data types for values can be anything that YAML accepts.
Example below shows the parameter file for the app.
# Single host version
root:
HelloActor:
thePub:
arg1: "this is arg1"
# arg2: use default for this one
theSub:
arg3: dir/file
arg4: 1.23456
The file sets the parameter values for the application deployed on the root node (i.e. the host it is running on),
for the specific actor (HelloActor), and the specific components (thePub and theSub). The parameters are
identified by name. Note that arg2 is optional (because the constructor has provided a default value.
The model, the parameter and component files are sufficient for runnig an application using the slacm_run tool, as follows:
$ slacm_run APP.slacm
Note that the application model did not have host clauses, i.e. this application is run on the host where the source code is located.
Note: If the app needs to access physical devices, the above command should be started with a sudo prefix.
The application can be terminated with a Ctrl-C (SIGTERM) on the terminal.
Distributed applications
The above application can be easily converted to a distributed one, where the two components run in separate actors, on different host machines. NOte: the hosts must have SLACM installed, and password-less ssh-access must be enabled. See section on ‘Setting up SLACM’.
The application model is modified as follows:
app HelloApp:
message Msg
component Hello2Pub:
timer clock 1000
pub port : Msg
component Hello2Sub:
sub port : Msg
actor PubActor:
thePub : Hello2Pub
actor SubActor:
theSub : Hello2Sub
// Distributed version
host (rpi4car) PubActor
host root SubActor
The root hosts runs the SubActor and the rpi4car runs the PubActor. For the latter, one can use the IP address of the specific
host as well.
Because the application architecture has changed, the parameter file must be upated as well.
# root + rpi4car version
rpi4car:
PubActor:
thePub:
arg1: "this is arg1"
# arg2: use default for this one
root:
SubActor:
theSub:
arg3: dir/file
arg4: 1.23456
Now the same command can be executed (on the root):
$ slacm_run APP.slacm
The (command running on root) will collect all the files in the application folder, transfers them to the peer node rpi4car and starts iself. The two slacm_run processes communicate with each other via the messages.
Note: If the app needs to access physical devices, the above command should be started with a sudo prefix.
SLACM configuration for the application
There two, optional files in the application folder that provide configuration information for the application.
slacm.conf is for setting global parameters for SLACM intself. The file follows the config file syntax, as shown on the example
below. The example is used for single host applications.
[SLACM]
# User name on remote hosts
target_user = slacm
# Timeout for send operations
send_timeout = 10000
# Timeout for recv operations
# recv_timeout = 1000
# NIC name
# Typical network interface
nic_name = eth0
# Typical WLAN interface
# nic_name = wlan0
sudo = True
app_logs = std
The target_user specifies that name for the user accounts on the remote hosts, and the next two are for
setting timeouts on send and receive operations (in milliseconds).
The nic_name parameter selects the network interface (as shown by the ifconfig command) used in accessing
the network with the SLACM hosts.
The ‘sudo option (default: True) controls whether the remote hosts will run the application with root privileges. This is needed
if the application needs to access physical devices. Note that this value should go into the configuration of the host
the application is launched from.
The app_logs option configures where to send the log messages produced by the component’s loggers.
The following values are possible:
‘std’: standard output
‘log’: logs are written into a file called
ACTOR.COMPONENT_NAME.TYPE_NAME.log.‘’ : logs are discarded
For multi-host deployments the configuration file can have multiple sections, one for each hosts. An example is shown below.
# Section for all hosts
[SLACM]
# Timeout for send operations
send_timeout = 10000
# recv_timeout = 1000
# NIC name
# Typical network interface
nic_name = eth0
# Typical WLAN interface
# nic_name = wlan0
sudo = True
app_logs = std
# Section for host called `rpi4car`
[SLACM.rpi4car]
# Timeout for send operations
send_timeout = 10000
# recv_timeout = 1000
# NIC name
# Typical network interface
nic_name = eth0
# Typical WLAN interface
nic_name = wlan0
app_logs = std
Note the section marker identifying a host.
slacm-log.yaml is for configuring the logging system. It requires intricate knowledge of the architecture of
SLACM and the Python logging system, and it is subject, so it is not documented here. The default file is shown here,
and it is useful for most applications.
# SLACM logging configuration file
version: 1
disable_existing_loggers: true
formatters:
simpleFormatter:
format: "%(levelname)s:%(asctime)s:[%(hostname)s.%(process)d]:%(name)s:%(message)s"
# datefmt=
default_time_format: "%H:%M:%S"
default_msec_format: "%s,%03d"
filters:
hostnameFilter:
"()": "slacm.config.HostnameFilter"
handlers:
consoleHandler:
class: logging.StreamHandler
level: INFO
formatter: simpleFormatter
filters: [hostnameFilter]
stream: ext://sys.stdout
root:
level: INFO
propagate: 0
handlers: [consoleHandler]
# SLAM loggers
# slam_x:
# level: INFO
# propagate: 0
# handlers: [console]
# qualname: slam.x
The above configuration enables all INFO level logging in SLACM, and is recommended for use in application development.