Appendix: matplc.conf
#
# sample matplc.conf configuration file
#
######################################################
# #
# C O N F I G U R A T I O N S Y N T A X #
# ========================================= #
# #
######################################################
# G E N E R A L S Y N T A X
# ===========================
#
# (name,value) pairs:
# name = <value>
#
# tables:
# table_name <value_1_1> <value_1_2> <value_1_3> ...
# table_name <value_2_1> <value_2_2> <value_2_3> ...
# ...
#
#
# tables and names are divided into sections.
# (Jiri, do you think you can come up with some good sentences
# explainig how sections work, and how modules look for parameters
# in sections named after their module_name ??)
# Should also explain how #includes are supported, and that it is protected
# against circular includes.
#
#
# NOTES:
# (1) when value is an integer, it may usually be written in
# hexadecimal (0xF45A), octal (0172132) or decimal (62554) formats.
#
# (2) when value or a name is a string with white space characters, it
# must be enclosed within " ("this is a single value")
[PLC]
#
# T h e P L C s e c t i o n
# =============================
#
#
# The PLC section is used to configure parameters related to the PLC, and
# are used by all modules. Some other parameters related to the PLC, but
# module specific, must be specified under those modules' sections.
#
#
# Note that the synchronisation system uses a petri net to synchronise the
# module execution. This petri net may be configured by _one_ of two methods.
# The first, the simplified method, is merely the definition of the sequence
# by which the modules should execute. This method is configured with the
# synch and synch_start tables.
# The second, more complete and complicated method, requires the complete
# definition of the petri net. Although more complex, this method is also
# more powerfull, and supports some synchronisation sequences that can not be
# configured by the simple method. This complex method is configured by the
# place, transition, arc, and synchpt tables, and the synchpt_beg/end values.
#
#
#
# name = value pairs:
# ------------------
# max_modules = <x> : The maximum number of simultaneously active modules
# the MatPLC will ever have.
# If this parameter is not specified, the
# default value STATE_MMC_DEF (currenty = 20) is used.
# Valid values go from 0..MMC_MAX. MMC_MAX depends on
# the operating system currently being used, and the
# number of places in the synchronisation Petri Net.
# (For example, on a typical linux the total of
# max_modules plus number of places may be 250 max.)
#
# Please read on for an explanation on the synchronisation
# Petri Net.
#
# confmap_key = <x> : The key to use for the confmap shared memory. This is
# actually the same parameter configured through
# --PLCplc_id=xxx. The command line argument takes
# precedence over the value configured in this file.
# If this parameter is not specified either way, the
# default value DEF_CONFMAP_KEY (currenty = 23) is used.
# Valid values go from 0..INT_MAX. If 0 is specified,
# then a random key is chosen.
#
# confsem_key = <x> : The id of the sempahore set used by the CMM.
# If no value is specified, then the default
# GMM_DEF_SEM_KEY is used (currently = 0). Valid values
# go from 0..INT_MAX. If 0 is specified, then a random
# key is chosen.
#
# confmap_size = <x> : The size of the confmap given in bytes.
# If this value is left unspecified, the default value
# CMM_DEF_CONFMAP_PG (currently = 8*1024) is used.
#
# globalmap_key = <x> : The key to use for the globalmap shared memory segment.
# If no value is specified, then the default
# DEF_GLOBALMAP_KEY is used (currently = 0). Valid values
# go from 0..INT_MAX. If 0 is specified, then a random
# key is chosen.
#
# globalsem_key = <x> : The key to use for the globalmap semaphore set used by
# the GMM. If no value is specified, then the default
# DEF_SEM_KEY is used (currently = 0). Valid values
# go from 0..INT_MAX. If 0 is specified, then a random
# key is chosen.
#
# globalmap_size= <x> : The size of the globalmap given in bytes
# If this value is left unspecified, the default
# value GMM_DEF_GLOBALMAP_PG (currently = 8*1024) is used.
#
# synchsem_key = <x> : The id of the sempahore set used by the SYNCH sub-system.
# If no value is specified, then the default
# DEF_SYNCH_SEM_KEY is used (currently = 0). Valid values
# go from 0..INT_MAX. If 0 is specified, then a random
# key is chosen.
#
#
# tables:
# ------
# module : defines which modules should be started by the plc setup program.
# point : defines the named points in the plc. See further down for syntax.
# point_alias: defines aliases to the named points in the plc. See further
# down for syntax.
# synch : used by the simple method of configuring module synchronisation.
# It specifies the module depencies and how they should synchronise
# between themselves.
# synch_start: used by the simple method of configuring module synchronisation.
# It specifies which modules should be allowed to execute the first scan
# as soon as the plc is started.
# place : used by the complex method of configuring module synchronisation.
# It specifies the places in the synchronisation Petri net.
# transition : used by the complex method of configuring module synchronisation.
# It specifies the transitions in the synchronisation Petri net.
# arc : used by the complex method of configuring module synchronisation.
# It specifies the arcs in the synchronisation Petri net.
# synchpt : used by the complex method of configuring module synchronisation.
# It specifies the synchpts in the synchronisation Petri net.
#
#
#
# the MODULE table
# ----------------
# syntax:
# module <name> <file> [<options> ...]
#
# where:
# name = the name of the module. This name will be used in sections, module
# synchronisation, etc...
# file = the program that will be executed.
# options = other command line options that need to pe passed to the program.
#
#
#
# The POINT table
# ---------------
# syntax:
# point <name> <full name> <owner> [at <offset>[.<bit>]] [[i|u|f]<length>] [init <init_val>]
#
# where:
# point = 'point' identifier
# name = Name used to search for point in plc_pt_by_name()
# full name = More extensive description of the point
# This information is not loaded into the confmap of the plc
# owner = Name of the module with write permission on the point
# at = 'at' identifier
# This, along with the <offset>.<bit> is optional. When not
# explicitly specified, the plc will try to find an empty slot
# for the point.
# offset = location of word in the globalmap that holds the point's state.
# bit = the bit, in the word, that holds the point's state. This is
# optional, defaulting to 0.
# i | u | f = the 'i', 'u' or 'f' identifiers.
# These are used to specify the format of the data in the plc point.
# At the moment this is only used by the plc code to figure out
# how to interpret the initial value of the point when parsing
# the init_val parameter.
# length = the size in bits of the point. The point must not overflow
# onto the next offset position (i.e. (bit + length) <
# (8*sizeof (u32)).
# The length is optional, defaulting to:
# 1 if the {at <offset>.<bit>} is not explicitly specified.
# 32 if {at <offset>} is specified without explicitly
# specifying the <bit>
# 1 if both {at <offset>.<bit>} are explicitly specified.
# init = 'init' identifier
# init_val = the initial value of the plc point. Defaults to 0.
# If it is not specifically specified how to interpret the init_val
# using the [i|u|f] identifiers before the length of the point,
# then it will be interpreted as a 32 bit float (f32)
# if it contains a floating point (e.g. 1.1) or an exponent (e.g. 1e9)
# If the above is not true, then the init_val will be interpreted
# as an xx bit signed integer if it has a leading '+' or '-' character.
# If none of the above apply, then the value will be interpreted as
# an xx bit unsigned integer.
# The xx is the length of the plc point. Only 32 bit floats, integers
# or unsigned integers are currently supported.
#
#
#
# the POINT_ALIAS table
# ---------------------
# syntax:
# point_alias <name> <full name> <org_name> [<bit> [<length>]]
#
# where:
# point_alias = 'point_alias' identifier
# name = Name used to search for point in plc_pt_by_name()
# full name = More extensive description of the point
# This information is not loaded into the confmap of the plc
# bit = The first bit, of the original point, that this alias will
# reference. This is optional, defaulting to 0.
# length = the size in bits of the point. The point must not overflow
# outside the original point (i.e. (bit + length) <
# (length of org_name point). The length is optional, defaulting
# to the length of the org_name point if no bit is explicitly
# specified, and 1 otherwise.
#
#
#
# the SYNCH table
# ---------------
# syntax:
# synch <module_1> arrow <module_2>
#
# where:
# module_X = The name of a module. Whenever module_1 finishes executing it's scan,
# then module_2 will start executing a new scan.
# arrow = is an arrow with the same syntax as the one specified for the arrow
# in the arc table, but with the additional constraint that weights
# with a value of 0 are not valid for this table.
#
#
#
# the SYNCH_START table
# ---------------------
# syntax:
# synch_start <module_1> [<module_2> ...]
#
# where:
# module_X = The name of a module. Identifies which modules should be allowed to start
# executing their first scan without any synchronisations. In other words,
# which modules should start executing imediately once the PLC is started.
#
#
#
# the PLACE table
# ---------------
# syntax:
# place <name> [<init_tokens>]
#
# where:
# name = The name of the place. The names specified on this table will later be
# used in the arc table.
# init_tokens = The number of tokens the place should have when the PLC is started. If
# not specified, it defaults to 0.
#
#
#
# the TRANSITION table
# --------------------
# syntax:
# transition <name>
#
# where:
# name = The name of the transition. The names specified on this table will
# later be used in the arc and synchpt tables.
#
# NOTE: The transition name "NULL" is reserved for the null transition.
# Wherever a name = value pair requires the name of a transition for the
# value, the name "NULL" may be used to specify the null transition.
#
#
# the ARC table
# -------------
# syntax:
# arc <place> arrow <transition>
# or
# arc <transition> arrow <place>
#
# where:
# place = The name of a place specified in the place table.
# transition = The name of a transition specified in the transition table.
# arrow = is an arrow with the following syntax:
# [-][(][<weight>][)][-]>
# where weight is a non negative integer.
# Possible correct examples are:
# -> # weight = 1
# -----> # weight = 1
# > # weight = 1
# -()-> # weight = 1
# ()> # weight = 1
# (> # weight = 1
# )> # weight = 1
# -7-> # weight = 7
# 8> # weight = 8
# (9)> # weight = 9
# (9> # weight = 9
# 9)> # weight = 9
# etc...
# Even though all above examples are correct, we sugest using:
# -> : for arrows with weight = 1
# -X-> or -(X)-> : for arrows with weight = X
#
# NOTE: arcs with weight 0 are only allowed from <place> --> <transition>
[module_name]
#
# P L C r e l a t e d v a l u e s
# ===================================
#
# PLC related values, specific to each module.
#
# name = value pairs:
# ------------------
# location = <x> : defines how the module should access the shared plc
# resources. Possible values are "shared", "local" and
# "isolate".
# This is the same as the command line --PLClocal,
# --PLCisolate and --PLCshared arguments. The command line
# arguments take precedence over whatever is defined in the
# config file. If no value is specified by either method,
# the default DEF_PLC_LOCATION (currently = local) is used.
# Detailed explanation:
# "shared" provides direct access to the shared plc
# resources, while both "local" and "isolate" use a local
# copy which is synchronised once every scan cycle.
# The "local" version acesses the shared resources directly
# when synchronising to the shared resources, while
# "isolate" asks a proxy process to do the synchronisation.
# The "shared" version has the advantage of not requiring
# to synchronise the local copy to the shared resources,
# which may be somewhat time comsuming. Unfortunately,
# and precisely because it does not use any synchronisation
# mechanisms, it may produce incorrect results if more
# than one module tries to access the shared resources
# simultaneously. This method should only be used if the
# modules are guaranteed not to run simultaneously, for
# example, by correctly configuring the inter-module
# synchronisation mechanism ("synch" table, etc...)
# The "local" and "isolate" methods do not have the above
# limitations since they keeps a local copy of the shared
# resources, which may be safely accessed any time by the
# module. The local copy is then typically synchronised with
# the shared resources once every scan cycle. Since the
# synchronisation is protected by synchronisation mechanisms
# to gurantee that only one module may access the shared
# resources at a time, these methods may be used safely,
# whatever the execution sequence of the modules may be.
# The "isolate" and "local" methods merely differ on who
# does the actual synchronisation between the local copy and
# the shared resources. In the "local" method the module
# itself accesses the shared resources while doing the
# the synchronisation. In the "isolate" method, the
# module asks a proxy process to do the synchronisation.
# Note that the proxy process is launched automagically.
# The "local" method, although faster, has the drawback that
# a bug in the module code may result in the shared
# resources being changed involuntarily (e.g. by a stray
# pointer). For this reason, we recomend that the "isolate"
# method be used when a module is being tested, and the "local"
# method be used during normal runs.
#
# privatemap_key = <x>: defines the key to use for the local map shared memory.
# Valid values go from 0..INT_MAX. A value of 0 has
# diferent meanings, depending on the location value.
# For local access, a value of 0 implies the use of malloc
# to allocate memry for the local map. For isolate access,
# a random key is used for the local map shared memory.
# The default value for every access method is
# DEF_LOCALMAP_KEY (currently = 0)
# NOTE: in the source code the localmap is also sometimes
# refered to as the private map. This is something that
# must be corrected...
#
# scan_period = <x> : defines the scan period, in seconds, of the module. The PLC
# interprets values down to 1 ns, but the precision is limited
# to the resolution of the clock of the hardware on which it is
# running. On plain vanilla linux on x86 hardware the resolution
# is normally 10 ms.
# Note that the effective scan period of a module
# also depends on how it synchronises with every other
# module of the PLC. When a module finishes executing it's scan,
# it will first wait until it's scan period has elapsed, and then
# synchronise with the remaining modules. Only then will it
# actually execute the next scan. This means that the effective
# scan period may end up being larger than the one specified in
# this parameter.
# The scan periods are counted on an absolute time frame. Consider
# t0 the instant the first scan started. The following scans will
# be enabled at t0+T, to+2*T, t0+3*T, etc...
#
# scan_beg = <x> : used by the complex method of specifying the synchronisation
# dependencies.
# Identifies the transition to which the module should synch at the
# begining of every scan. If no transition is specified, the default
# NULL transition is used. Note that synchronising to NULL transition
# always returns without any delay, so by default the module will not
# synchronise to anything.
#
# scan_end = <x> : used by the complex method of specifying the synchronisation
# dependencies.
# Identifies the transition to which the module should synch at the
# end of every scan. If no transition is specified, the default
# NULL transition is used. Note that synchronising to NULL transition
# always returns without any delay, so by default the module will not
# synchronise to anything.
#
#######################################################
# #
# S A M P L E C O N F I G U R A T I O N S #
# =========================================== #
# #
#######################################################
#
# C O N F I G (1) : Absolute Minimum Configuration
# ==================================================
#
[PLC]
# we need some points, otherwise this is a useless exercise...
point P0.0 "full name 0.0" module1 at 0.0 # 1 bit point at 0.0
point P0.1 "full name 0.1" module1 at 0.1 5 # 5 bit point from 0.1 to 0.5
point P1 "full name 1.0" module2 at 1 # 32 bit point from 1.0 to 1.31
[PLC]
# We also need some module to execute...
module module1 /matplc.logic/...
[module1]
# Here we would insert module specific configurations
#
# C O N F I G (2) : Configuration with Simple Synchronisation
# =============================================================
#
[PLC]
# we need some points, otherwise this is a useless exercise...
point P0.0 "full name 0.0" module1 at 0.0 # 1 bit point at 0.0
point P0.1 "full name 0.1" module1 at 0.1 5 # 5 bit point from 0.1 to 0.5
point P1 "full name 1.0" module2 at 1 # 32 bit point from 1.0 to 1.31
[PLC]
# We also need some module to execute...
module module1 /matplc.logic/...
module module2 /matplc.logic/...
[PLC]
# We specify that the modules must run synchronously, one after the other
#
# After module1, run module2, and vice-versa
synch module1 -> module2
synch module2 -> module1
# start off by running module1
synch_start module1
# In addition, if we wanted the scans to execute only every 0.1 seconds, we can
# specify the scan period of one of the modules.
# Since both modules run in lock-step, we must only specify the scan period of *one*
# of the modules...
module1: scan_period = 0.1
[module1]
# Here we would insert module specific configurations
[module2]
# Here we would insert module specific configurations
#
# C O N F I G (3) : Configuration with Complex Synchronisation
# ==============================================================
#
[PLC]
# we need some points, otherwise this is a useless exercise...
point P0.0 "full name 0.0" module1 at 0.0 # 1 bit point at 0.0
point P0.1 "full name 0.1" module1 at 0.1 5 # 5 bit point from 0.1 to 0.5
point P1 "full name 1.0" module2 at 1 # 32 bit point from 1.0 to 1.31
[PLC]
# We also need some module to execute...
module module1 /matplc.logic/...
module module2 /matplc.logic/...
[PLC]
#
# The synchronisation config
# --------------------------
# Each module will use one place (P_module1, P_module2),
# and two transitions (T_module1_beg, T_module1_end, etc...).
#
# The number of tokens in P_module1 indicates the number of times
# module1 must run its scan loop. Likewise for module 2.
# At the beginning of the module1 scan this module waits on the T_module1_beg
# transition. This transition will remove one token from P_module1,
# and let the module start executing.
# At the end of the scan module1 will wait on the T_module1_end
# transition. This transition will place a token in P_module2,
# therfore allowing module2 to run.
#
# Module2 works in exactly the same way as module1.
place P_module1 1 # initialise with 1 token => start off by running this module.
place P_module2 # 0 is not required, it is the default value.
transition T_module1_beg
transition T_module1_end
transition T_module2_beg
transition T_module2_end
arc P_module1 -> T_module1_beg
arc T_module1_end -> P_module2
arc P_module2 -> T_module2_beg
arc T_module2_end -> P_module1
# The only thing left is to tell each module what transitions to use for the beg
# and end of the scan.
module1: scan_beg = T_module1_beg
module1: scan_end = T_module1_end
module2: scan_beg = T_module2_beg
module2: scan_end = T_module2_end
# In addition, if we wanted the scans to execute only every 0.1 seconds, we can
# specify the scan period of one of the modules.
# Since both modules run in lock-step, we must only specify the scan period of *one*
# of the modules...
module1: scan_period = 0.1