Appendix: linuxplc.conf
#
# sample linuxplc.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:
# ------------------
# 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_pg = <x> : The size of the confmap given in number of memory pages.
# If this value is left unspecified, the default value
# DEF_CONFMAP_PG (currently = 2) is used.
# The size of each memory page is given by PAGE_SIZE
# defined in asm/page.h or sys/user.h (which is the
# correct include?) (for linux on intel (?) PAGE_SIZE
# is 4 kBytes).
#
# 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_pg = <x> : The size of the globalmap given in number of memory
# pages. If this value is left unspecified, the default
# value DEF_CONFMAP_PG (currently = 2) 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 only weights
# with a value of 1 are 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.
#
#
#
# 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 positive 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-> : for arrows with weight = X
#
#
# the SYNCHPT table
# -----------------
# syntax:
# synchpt <name> <type> <parameter>
#
# where:
# name = The name of the synchpt. This name will be used as a value for the
# synchpt_beg and synchpt_end, and in the plc_synchpt_by_name(...)
# function call.
# parameter = A parameter that will depend on the transition type.
# type = {transition | transition.beg | transition.end}
# Identifies the synchpt type.
# transition: Requires that <parameter> identifies a transition.
# Synching to a synchpt of this type will block until the
# transition can be fired. Before continuing the transition
# will be fully fired, i.e. the required number of tokens
# will be removed from the places with arcs pointing to
# this transition, and tokens will be inserted into the
# places pointed to by the arcs emanating from this
# transition.
# transition.beg: Requires that <parameter> identifies a transition.
# Synching to a synchpt of this type will block until
# the transition can be fired. Before continuing the
# transition will be partially fired, i.e. the required
# number of tokens will be removed from the places with
# arcs pointing to this transition, but *no* token will
# be inserted into the places pointed to by the arcs
# emanating from this transition.
# transition.end: Requires that <parameter> identifies a transition.
# Synching to a synchpt of this type will never block.
# Before continuing the transition will be partially
# fired, i.e. *no* token will be removed from the places
# with arcs pointing to this transition, but tokens will
# be inserted into the places pointed to by the arcs
# emanating from this transition.
#
# NOTE: The synchpt name "NULL" is reserved for the null synchpt.
# Wherever a name = value pair requires the name of a synchpt for the
# value, the name "NULL" may be used to specify the null synchpt.
[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 "local" for direct access,
# and "isolate" for access through proxy process.
# This is the same as the command line --PLClocal and
# --PLCisolate 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.
#
# 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 synchpt to which the module should synch at the
# begining of every scan. If no synchpt is specified, the default
# NULL synchpt is used. Note that synchronising to the NULL synchpt
# 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 synchpt to which the module should synch at the
# end of every scan. If no synchpt is specified, the default
# NULL synchpt is used. Note that synchronising to the NULL synchpt
# 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 /linuxplc/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 /linuxplc/logic/...
module module2 /linuxplc/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 /linuxplc/logic/...
module module2 /linuxplc/logic/...
[PLC]
#
# The synchronisation config
# --------------------------
# For demonstartion purposes, we shall use two methods to synchronise each of
# the two modules.
#
# The first module will use two places (P_module1_run, P_module1_running),
# and two transitions (T_module1_beg, T_module1_end).
# The number of tokens in P_module1_run indicates the number of times
# module1 must run its scan loop.
# The P_module1_running will contain one token whenever the chaser module is busy
# running its scan loop.
# 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_run,
# put one token in P_module1_running, and let the module start executing.
# At the end of the scan module1 will wait on the T_module1_end
# transition. This transition removes the token from P_module1_running, which
# will therefore become empty.
#
place P_module1_run 1 # initialise with 1 token => start off by running this module.
place P_module1_running 0 # 0 is not required, it is the default value.
transition T_module1_beg
transition T_module1_end
arc P_module1_run -> T_module1_beg
arc T_module1_beg -> P_module1_running
arc P_module1_running -> T_module1_end
# The modules will wait on synchronisation points (synchpt), and not the
# transitions themselves. We therefore define two synchpts mapped onto the
# relevant transitions.
synchpt module1_beg transition T_module1_beg
synchpt module1_end transition T_module1_end
# The second module, will use only one place and one transition to synchronise.
# The number of tokens in the P_module2_run place will indicate the number
# of times module2 must execute its scan loop.
# The T_module2 transition will remove a token from the P_module2_run place
# and run the vitrine module scan loop synchronously, i.e.:
# 1) remove the token from the places indicated by the arcs terminating at
# the transition;
# 2) runs the module's scan loop once
# 3) place tokens in the places indicated by the arcs leaving the transition.
#
place P_module2_run
transition T_module2
arc P_module2_run -> T_module2
# once again, the module will actually synchronize on synchpts, and not the
# transition itself. But since it will synchronize synchronously, we
# use two distinct types of mapping between the synchpts and the relevant
# transition.
# One synchpt to remove the tokens indicated by the arcs arriving at
# the transition. This is the transition.beg type of synchpt.
synchpt module2_beg transition.beg T_module2
# One synchpt to place the tokens indicated by the arcs leaving
# the transition. This is the transition.end type of synchpt.
synchpt module2_end transition.end T_module2
# Now that the synch of each module is established, we define what happens when
# each module finishes executing.
#
# When module1 finishes, we tell module2 to run once
arc T_module1_end -> P_module2_run
# When the vitrine finishes, we tell the chaser to run once
arc T_module2 -> P_module1_run
# The only thing left is to tell each module what synchpts to use for the beg
# and end of the scan.
module1: scan_beg = module1_beg
module1: scan_end = module1_end
module2: scan_beg = module2_beg
module2: scan_end = 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