Overview
My programming may be inadequate to the task.
We’re all more than the sum of our parts, Data.
You’ll have to be more than the sum of your programming.
Star Trek - The Next Generation: In Theory
This document describes the JSON files used by the Core system to define all its main actors:
-
messages
-
nodes
-
configurations
-
packages
-
modules
-
build targets
References
Each JSON file has it’s own Apache AVRO [1] schema.
Package
Overview
A Core package is a bundle of reusable code and meta-data.
A package can include:
-
message definitions
-
node definitions
-
node source code
-
node configuration definitions
-
… other code
Packages are processed by the CorePackage.py and CoreWorkspace.py command line tool.
From a Core user point of view a package is nothing but a directory that meets the following requirements:
-
it contains a file named
CORE_PACKAGE.json
-
it contains a license file
LICENSE
-
it have a well defined structure
CORE_PACKAGE.json
The CORE_PACKAGE.json
file describes the package, and it is used by the Core build system either to manage the dependencies or to generate the makefiles.
The file must be valid according to an Apache Avro [1] schema.
CORE_PACKAGE.json
file for led
package
1
2
3
4
5
{
"name": "led", (1)
"description": "LED Nodes", (2)
"provider": "core" (3)
}
1 | the name of the message field must match the name of the package directory |
2 | a brief description |
3 | provider is used to avoid a name clash between packages |
provider
is used to generate a namespace that will enclose all the code generated from the contents of the package (i.e.: core::led
).
The same name is used to keep the header files well separated (i.e.: #include <core/led/Publisher.hpp>
).
For the packages provided by Nova Labs, it will be core
.
Package directory structure
There are two kinds of packages, depending on their content: messages or non-messages.
It is surely possible to have messages in a non-messages package, but this is strongly discouraged.
Messages packages
Message packages must contain nothing but message definition files.
These files must be inside a directory called messages
.
It is customary that message packages name ends with _msgs .
|
led_msgs
PackageNon-Messages packages
Non-Messages package must not contain any message definition files.
Source code must be put inside the include
and src
directories.
Nodes definitions must reside in nodes
directory, while node configuration definitions must be in configurations
.
led
PackageMessage
Overview
Messages represent the data type exchanged between publishers and subscribers.
From a Core user perspective messages are defined using a JSON file.
The file must be valid according to an Apache Avro [1] schema.
JSON definition file
Led.json
message definition file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"name": "Led", (1)
"description": "Status LED", (2)
"namespace": "@", (3)
"fields": [ (4)
{
"name": "led", (5)
"description": "Which led?", (6)
"type": "UINT32", (7)
"size": 1 (8)
},
{
"name": "value",
"description": "Value of the led",
"type": "UINT8",
"size": 1
}
]
}
1 | the name of the message field must match the name of the JSON file; name must be at most 15 characters long |
2 | a brief description |
3 | by default ('@') the namespace will be the name of the package the message resides in; namespace can be used to override it |
4 | messges cannot have nested data structures |
5 | field name must be at most 15 characters long |
6 | a brief description |
7 | the supported field types are CHAR , INT8 , UINT8 , INT16 , UINT16 , INT32 , UINT32 , INT64 , UINT64 , FLOAT32 , FLOAT64 , TIMESTAMP |
8 | array type fields are specified using the size attribute, scalar types require to specify 1 as the size of the field |
Generated file
Messages are converted to source code using the command line tools. The code generator relies on the C preprocessor to keep the generated code clean and readable.
Led.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma once
#include <core/mw/CoreMessage.hpp>
namespace core {
namespace common_msgs {
CORE_MESSAGE_BEGIN(Led) //Status LED
CORE_MESSAGE_FIELD(led, UINT32, 1) // Which led
CORE_MESSAGE_FIELD(value, UINT8, 1) // Value of the led
CORE_MESSAGE_END
}
}
Array type fields will be implemented using core::Array
class template (that is a stripped down std::array).
From the source code point of view, messages are classes that inherit from core::mw::Message
class.
Node
Overview
Coming soon…
Configuration
Overview
From a Core user perspective node configurations are defined using a JSON file.
The file must be valid according to an Apache Avro [1] schema.
JSON definition file
LedPublisherConfiguration.json
message definition file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"name": "LedPublisherConfiguration", (1)
"description": "LED Publisher node configuration", (2)
"namespace": "@", (3)
"fields": [ (4)
{
"name": "topic", (5)
"description": "Name of the topic to publish to", (6)
"type": "CHAR", (7)
"size": 16 (8)
},
{
"name": "led",
"description": "Which led",
"type": "UINT32",
"size": 1
}
]
}
1 | the name of the message field must match the name of the JSON file; name must be at most 15 characters long |
2 | a brief description |
3 | by default ('@') the namespace will be the name of the package the configuration resides in; namespace can be used to override it |
4 | configurations cannot have nested data structures |
5 | field name must be at most 15 characters long |
6 | a brief description |
7 | the supported field types are CHAR , INT8 , UINT8 , INT16 , UINT16 , INT32 , UINT32 , INT64 , UINT64 , FLOAT32 , FLOAT64 , TIMESTAMP |
8 | array type fields are specified using the size attribute, scalar types require to specify 1 as the size of the field |
Generated file
Configurations are converted to source code using the command line tools. The code generator relies on the C preprocessor to keep the generated code clean and readable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#pragma once
#include <core/mw/CoreConfiguration.hpp>
namespace core {
namespace led {
CORE_CONFIGURATION_BEGIN(PublisherConfiguration) //LED Publisher node configuration
CORE_CONFIGURATION_FIELD(topic, CHAR, 16) // Name of the topic to publish to
CORE_CONFIGURATION_FIELD(led, UINT32, 1) // Which led
CORE_CONFIGURATION_MAP_BEGIN(2)
CORE_CONFIGURATION_MAP_ENTRY(PublisherConfiguration, topic)
CORE_CONFIGURATION_MAP_ENTRY(PublisherConfiguration, led)
CORE_CONFIGURATION_MAP_END()
CORE_CONFIGURATION_SIGNATURE(0x73fc44ae)
CORE_CONFIGURATION_END()
}
}
Array type fields will be implemented using core::Array
class template (that is a stripped down std::array).
From the source code point of view, messages are classes that inherit from core::mw::CoreConfiguration
class.
Module
Overview
Coming soon…
Workspace
Overview
A workspace comprehends:
-
build targets
-
custom packages
-
custom modules
Workspaces are processed by the CoreWorkspace.py command line tool.
From a Core user point of view a workspace is nothing but a directory that meets the following requirements:
-
it contains a file named
WORKSPACE.json
-
it have a well defined structure
WORKSPACE.json
The WORKSPACE.json
file describes the workspace.
The file must be valid according to an Apache Avro [1] schema.
WORKSPACE.json
file
1
2
3
4
{
"name": "Workspace", (1)
"description": "Testing Workspace", (2)
}
1 | the name of the workspace field must match the name of the package directory |
2 | a brief description |
Module Target
Overview
Module Target represent the firmware that will be compiled and deployed to a module.
Module Targets are processed by the CoreWorkspace.py command line tool.
From a Core user point of view a target is nothing but a directory that meets the following requirements:
-
it contains a file named
MODULE_TARGET.json
-
it have a well defined structure
MODULE_TARGET.json
MODULE_TARGET.json
for an IMU target
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "imu", (1)
"description": "IMU", (2)
"module": "imu", (3)
"required_packages": [ (4)
"led",
"balancing_robot",
"actuator_msgs",
"differential_drive_msgs",
"sensor_msgs",
"pid",
"pid_msgs"
],
"sources": [ (5)
"main.cpp"
],
"includes": [] (6)
}
1 | the name of the target; it will be used as the module name |
2 | a brief description |
3 | the module on which the firmware will run |
4 | list of required packages |
5 | list of source files to be compiled (relative to target directory) |
6 | list of include directories for header files (relative to target directory) |
Generated file
Module Target are converted to CMake [2] code using the command line tools.
CMakeLists.txt
generated from MODULE_TARGET.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Generated by ModuleTarget.py
# Remove a "#" from the line below to stop generating this file every time you call CoreWorkspace generate
## TARGET MODULE imu (1)
PROJECT( imu )
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
FIND_PACKAGE( CORE_BUILD CONFIG REQUIRED )
INCLUDE ( CoreTarget NO_POLICY_SCOPE )
SET( PROJECT_INCLUDE_DIRECTORIES
)
SET( PROJECT_SOURCES
main.cpp
)
core_target_module(
MODULE imu
PACKAGES
led
balancing_robot
actuator_msgs
differential_drive_msgs
sensor_msgs
pid
pid_msgs
)
1 | remove a # to stop generating this file every time you call CoreWorkspace generate |
CMakeLists.txt file is generated every time if it contains a line starting with ## TARGET MODULE
|