Building a microblx application typically involves instantiating blocks, configuring and interconnecting their ports and finally starting all blocks. The recommended way to do this is by specifying the system using the microblx composition DSL.
usc
are declarative descriptions of microblx systems that can be validated and instantiated using the ubx-launch
tool. A usc model describes one microblx system, as illustrated by the following minimal example:
local bd = require("blockdiagram")
return bd.system
{
-- import microblx modules
imports = {
"stdtypes", "ptrig", "lfds_cyclic", "myblocks",
},
-- describe which blocks to instantiate
blocks = {
{ name="x1", type="myblocks/x" },
{ name="y1", type="myblocks/y" },
{ name="ptrig1", type="ubx/ptrig" },
...
},
-- connect blocks
connections = {
{ src="x1.out", tgt="y1.in" },
{ src="y1.out", tgt="x1.in", buffer_len=16 },
},
-- configure blocks
configurations = {
{ name="x1", config = { cfg1="foo", cfg2=33.4 } },
{ name="y1", config = { cfgA={ p=1,z=22.3 }, cfg2=33.4 } },
-- configure a trigger
{ name="trig1", config = { period = {sec=0, usec=100000 },
sched_policy="SCHED_OTHER",
sched_priority=0,
chain0={
-- the #<blockname> directive will
-- be resolved to an actual
-- reference to the respective
-- block once instantiated
{ b="#x1", num_steps=1, measure=0 },
{ b="#y1", num_steps=1, measure=0 } } } }
},
}
usc files like the above example can be launched using ubx-launch
tool. Run with -h
for further information. The following example
$ cd /usr/local/share/ubx/examples/usc/pid/
$ ubx-launch -webif -c pid_test.usc,ptrig_nrt.usc
...
will launch the given system composition and in addition create and configure a web server block to allow the system to be introspected via browser.
Unless the -nostart
option is provided, all blocks will be initialized, configured and started. ubx-launch
handles this in safe way by starting up active blocks after all other blocks (In earlier versions, there was start
directive to list the blocks to be started, however now this information is obtained by means of the block attributes BLOCK_ATTR_ACTIVE
and BLOCK_ATTR_TRIGGER
.)
Node configs allow to assign the same configuration to multiple blocks. This is useful to avoid repeating global configuration values that are identical for multiple blocks.
The node_configurations
keyword allows to define one or more named node configurations.
node_configurations = {
global_rnd_conf = {
type = "struct random_config",
config = { min=333, max=999 },
}
}
These configurations can then be assigned to multiple blocks:
{ name="b1", config = { min_max_config = "&global_rnd_conf"} },
{ name="b2", config = { min_max_config = "&global_rnd_conf"} },
Please refer to examples/systemmodels/node_config_demo.usc
for a full example.
The powerful connections
keyword supports connecting blocks in multiple ways:
- cblocks to cblocks
- cblocks to iblocks
- cblocks to non-existing iblocks (the latter are created on the fly)
The syntax for these variants is discussed below.
The following example shows how to create ports among cblock ports:
{ src="blkA.portX", tgt="blkB.portY", type="lfds_cyclic", config = { ... }
- both
src
andtgt
are of the formCBLOCK.PORT
. Both blocks and ports must exist. type
specifies the type of iblock to create for the connection. If unset it defaults toubx/lfds_cyclic
config
is the optional configuration to apply to the newly created iblock. The configstype_name
anddata_len
are set automatically unless specified.
The following examples illustrates creating connections to/from an existing iblock myMq
:
{ src="blkX.portZ", tgt="myMQ" }
-- or
{ src="myMQ", tgt="blkX.portZ" }
- the iblock must exist and be of the form
IBLOCK
(i.e. no port). - the cblock must exist and be of the form
CBLOCK.PORT
type
andconfig
must not be set (they will be ignored with a warning).
The following example creates a new mqueue with an automatic, unique name, configures it with config
and connect blkX.portZ
to it:
{ src="blkX.portZ", type="ubx/mqueue", config={ buffer_len=32 } }
type
must be set to desired iblock type and one ofsrc
ortgt
must be unsettype_name
,data_len
andbuffer_len
are set automatically unless defined inconfig
.- for type
ubx/mqueue
: if nomq_id
is set inconfig
, thenmq_id
is set to the corresponding peer "BLOCK.PORT", e.g. toblkX.portZ
in the example above.
This form is useful to create one-line connections via mqueues or similar.
Using hierarchical composition1 an application can be composed from other compositions. The motivation is to permit reuse of the individual compositions.
The subsystems
keyword accepts a list of namespace-subsystem entries:
return bd.system {
import = ...
subsystems = {
subsys1 = bd.load("subsys1.usc"),
subsys2 = bd.load("subsys1.usc"),
}
}
Subsystem elements like configs can be accessed by higher levels by adding the subsystem namespace. For example, the following lines override a configuration value of the blk
block in subsystems sub11
and sub11/sub21
:
configurations = {
{ name="sub11/blk", config = { cfgA=1, cfgB=2 } },
{ name="sub11/sub21/blk", config = { cfgA=5, cfgB=6 } },
}
Note how the subsystem namespaces prevent name collisions of the two identically names blocks. Similar to configurations, connections can be added among subsystems blocks:
connections = {
{ src="sub11/sub21/blk.portX", tgt="sub11/blk.portY" },
},
When launched, a hierarchical system is instantiated in a similar way to a non-hierarchical one, however:
- modules are only imported once
- blocks from all hierarchy levels are instantiated, configured and started together, i.e. the hierarchy has no implications on the startup sequence.
- microblx block names use the fully qualified name including the namespace. Therefore, the #blockname syntax for resolving block pointers works just the same.
- if multiple configs for the same block exist, only the highest one in the hierarchy will be applied.
- node configs are always global, hence no prefix is required. In case of multiple identically named node configs, the one at the highest level will be selected.
It is possible to add a subsystem without a namespace, as shown by the following snippet:
return bd.system {
subsystems = {
bd.load("subsys1.usc"),
}
}
In this case, the subsys1.usc
system will be merged directly into the parent system. Note that entries of the parent system take precedence, so in case of conflicts elements of the subsystem will be skipped.
This feature is useful to avoid an extra hierarchy level.
To obtain a reusable composition, it is important to avoid introducing platform specifics such as ptrig
blocks and their configurations. Instead, passive trig
blocks can be used to encapsulate the trigger schedule. ptrig
or similar active blocks can then be added at launch time by merging them (encapsulated in an usc file) into the primary model by specifying both on the ubx-launch
command line.
For example, consider the example in examples/systemmodels/composition
:
ubx-launch -webif -c deep_composition.usc,ptrig.usc
Note: unlike merging from within the usc using an unnamed subsystems
entry (see merging-subsystems
), models merged on the command line will override existing entries.
Although using usc
model is the preferred approach, there are others way to launch a microblx application:
It is possible to avoid the Lua scripting layer entirely and launch an application in C/C++. A small self-contained example c-launch.c <../../examples/C/c-launch.c>
is available under examples/C/
(see the README
for further details).
For a more complete example, checkout the respective tutorial section c-deployment
. Please note that such launching code is a likely candidate for code generation and there are plans for a usc-to-C compiler. Please ask on the mailing if you are interested.
One can write a Lua "deployment script" similar to the ubx-launch
. Checkout the scripts in the tools
section. This approach not recommended under normally, but can be useful in specific cases such as for building dedicated test tools.
Footnotes
This feature was introduced in the context of the COCORF RobMoSys Integrated Technical Project. Please see docs/dev/001-blockdiagram-composition.md for background information.↩