Skip to content

Latest commit

 

History

History
316 lines (274 loc) · 13.7 KB

Manual_commsdsl2comms.md

File metadata and controls

316 lines (274 loc) · 13.7 KB

Manual of commsdsl2comms

How to Run

The commsdsl2comms utility uses libcommsdsl shared library to parse the XML schema files. On Windows system the shared library is installed in the same directory with commsdsl2comms.exe binary. As the result when executing## Overview The commsdsl2comms utility generates a full CMake project. Since v1.4 it also generates test application which can be used to test the generated protocol code. Fuzz testing with AFL is also supported.

After reading this documentation page it is also recommended to read GeneratedProjectWalkthrough.md to get familiar with the structure of the generated output project as well as TestingGeneratedProtocolCode.md to understand how to fuzz test the generated protocol definition code.

Command Line Arguments

The commsds2comms utility has multiple command line arguments, please use -h option for the full list as well as default option values. Note, that all the examples below will be for Linux systems (using commsdsl2comms.sh script). On Windows system just use commsdsl2comms.exe binary directly.

$> /path/to/commsdsl2comms.sh -h

Below is a summary of most important ones.

Selecting Schema Files

In case there are only few schema files, it is possible to pass them at the end of the arguments list.

$> /path/to/commsdsl2comms.sh schema1.xml schema2.xml schema3.xml ...

The schema files will be processed in order of their listing.

In case there are lots of schema files (for example every message is defined in separate schema file), it is recommended to create a separate text file with list of all schema files and use -i option.

$> /path/to/commsdsl2comms.sh -i schemas_list.txt

The schemas in the list file may use use absolute or relative path. In case of the latter please also provide absolute path prefix using -p option. The prefix will be prepended to every relative path inside the list file to locate the schema file.

$> /path/to/commsdsl2comms.sh -i schemas_list.txt -p /path/to/schemas/dir

Output Directory

By default the output CMake project is written to the current directory. It is possible to change that using -o option.

$> /path/to/commsdsl2comms.sh -o /some/output/dir schema.xml

Injecting Custom Code

The commsdsl2comms utility allows injection of custom C++ code into the generated one in case the default code is incorrect and/or incomplete. For this purpose -c option with path to directory containing custom code snippets is used.

$> /path/to/commsdsl2comms.sh -c /path/to/custom/code/snippets schema.xml

Please read Custom Code section below for more details on how to format and where to place the custom code.

Changing Main Namespace

By default the protocol name defined in the schema file(s) is used as the main namespace for the generated code. It is possible to change it using -n option.

$> /path/to/commsdsl2comms.sh -n other_ns_name schema.xml

Selecting Protocol Version

The schema file(s) is expected to specify protocol numeric version. By default the generated code will be for the latest version including all the fields that were introduced at some stage and omitting all the deprecated and removed ones. However, the commsdsl2comms utility allows generation of the code for any version of the protocol by using --force-schema-version option.

$> /path/to/commsdsl2comms.sh --force-schema-version 2 schema.xml

Selecting Minimal Remote Version

For version dependent protocols (where the used protocol version is reported to the other side in transport framing or payload of one of the messages), the assumed minimal remote version is 0. In means all the fields that were introduced at later stage will be optional ones that can exist or be missing. If it is known for sure that the other side of communication won't use some early versions, it is possible to generate more efficient code by passing -m option.

$> /path/to/commsdsl2comms.sh -m 5 schema.xml

In the example above, all the fields that were introduced before or in version 5, will be regular ones (instead of optional).

Customization Level

The code generated by the commsdsl2comms utility can allow extra compile time customizations (such as choosing custom storage type and/or having extra functionality). There are 3 levels of available customizations:

  • full - All fields and messages are going to be customizable.
  • limited - Only variable length fields (such as <string>, <data>, and <list>) and uni-directional messages will be customizable.
  • none - No fields or messages will allow extra compile time customization.

The recommended (and default) customization level is limited. However, when protocol schema being developed (i.e. new fields / and messages are being constantly added) it is recommended to temporarily use none as customization level in order to reduce (re)compilation times of the target project.

The customization level can be selected using --customization option.

$> /path/to/commsdsl2comms.sh --customization=none schema.xml

Tag / Branch of CommsChampion Project

The commsdsl2comms utility produces CMake project, which depends on and uses comms_champioin one. If the latter is not provided as external build, it is checked out and built automatically. The --cc-tag option can be used to specify tag / branch of comms_champion project that is going to be used in such build.

$> /path/to/commsdsl2comms.sh --cc-tag=develop schema.xml

Custom Bundling of Messages

The commsdsl2comms utility creates multiple bundles of messages based on their direction (server vs client) as well as relevant code for dispatching messages from such bundles to appropriate handlers. It is possible to provide extra independent list of message types for extra bundles and extra relevant dispatching code generation. For such purpose \n separated list of message names needs to be created in a sepeare file and --extra-messages-bundle option to be used (can be used multiple times). The format of the option value is Name:File, where Name is the name of the bundle, while File is a path to file containing message names (as defined in CommsDSL schema).

$> /path/to/commsdsl2comms.sh \
    --extra-messages-bundle=Set1:extra-set1.txt \
    --extra-messages-bundle=Set2:extra-set2.txt \
    schema.xml

Custom Code

As was already mentioned earlier, commsds2comms utility allows injection of custom C++11 code snippets in the generated code. The Injecting Custom Code section above described -c option that can be used to specify directory with custom code snippets. Every file inside that directory must have the same relative path to the file its going to update, as the generated file inside the output directory.

Every global field and/or message class will be defined in a separate file and will have the following basic operations:

  • read - Read operation
  • write - Write operation
  • length - Serialization length calculation
  • valid - Contained value validity check
  • refresh - Bring the contents into consistent state
  • name - Get a descriptive name of the field / message

In order to replace the default implementation of any of these operations, the file with the same name (and relative path) must be created, but also have additional suffix with the operation name. For example let's assume we have protocol named demo, with message Msg1. The class for the message will reside in include/demo/message/Msg1.h. In order to replace the default read operation, there is a need to create include/demo/message/Msg1.h.read file which will define custom read() function. Following the same logic to replace all the operations there is a need to have the following files:

  • include/demo/message/Msg1.h.read
  • include/demo/message/Msg1.h.write
  • include/demo/message/Msg1.h.length
  • include/demo/message/Msg1.h.valid
  • include/demo/message/Msg1.h.refresh
  • include/demo/message/Msg1.h.name

Note that for fields the provided functions are expected to have the following signatures.

template <typename TIter>
comms::ErrorStatus read(TIter& iter, std::size_t len);

template <typename TIter>
comms::ErrorStatus write(TIter& iter, std::size_t len) const;

std::size_t length() const;

bool valid() const;

bool refresh();

static const char* name();

For messages it is similar, but with do* prefix.

template <typename TIter>
comms::ErrorStatus doRead(TIter& iter, std::size_t len);

template <typename TIter>
comms::ErrorStatus dowrite(TIter& iter, std::size_t len) const;

std::size_t doLength() const;

bool doValid() const;

bool doRefresh();

static const char* doName();

It is also possible to add unrelated custom code to public, protected, and/or private areas by using relevant suffix.

  • include/demo/message/Msg1.h.public
  • include/demo/message/Msg1.h.protected
  • include/demo/message/Msg1.h.private

In case there is a need for a custom constructor / destructor / assignment operator, use public section to define it.

The custom operation may required additional includes, which may be provided by using appropriate definition file with .inc suffix. The contents of this file will be added after all the default includes.

  • include/demo/message/Msg1.h.inc

It may happen that provided above customization options are not sufficient, and need to be completely rewritten. In this case it is possible to create appropriate file with .replace suffix, contents of which will completely replace the file generated by commsdsl2comms.

  • include/demo/message/Msg1.h.replace

The commsdsl2comms also allows to reuse the class it generates by default and extend the existing functionality with the new one. It can be achieved by defining a file with .extend suffix. Similar to .replace, it must define the full class, but it is expected to extend and reuse default definition which will reside in another file with Orig suffix added to its name (include/demo/message/Msg1Orig.h).

There are cases when commsdsl2comms cannot generate some pieces of code and they must be provided externally. For example, custom checksum algorithm and/or custom framing layer. The custom definition files are expected to be found in the following relative paths:

  • include/<main_namespace>/frame/checksum/<checksum_name>.h
  • include/<main_namespace>/frame/layer/<layer_name>.h

The example of checksum definition can be found at UbloxChecksum.h file from cc.ublox.commsdsl protocol definition.

The example of custom layer can be found at IdAndFlags.h file from cc.mqtt311.commsdsl protocol definition (defines custom ID layer that also contains extra flags) or at Length.h file from cc.mqttsn.commsdsl protocol definition.

Please note that custom layer that replaces <id> one is expected to use the following template parameters.

/// @tparam TField Used field type
/// @tparam TMessage Interface class
/// @tparam TAllMessages Input messages
/// @tparam TNext Layer Next frame layer
/// @tparam TExtraOpt Extra options passed to @b comms::MsgFactory
template <
    typename TField,
    typename TMessage,
    typename TAllMessages,
    typename TNextLayer,
    typename... TExtraOpt>
class MyIdLayer : public ...
{
    ...
};

Any other custom layer is expected to use the following template parameters

/// @tparam TField Used field type
/// @tparam TNext Layer Next frame layer
/// @tparam TExtraOpt Extra options passed to @b comms::MsgFactory
template <
    typename TField,
    typename TNextLayer,
    typename... TExtraOpts>
class MyCustomLayer : public ...
{
    ...
};

NOTE, that customization is available for global fields (including ones that defined in any separate namespace) as well as messages. At this stage injecting custom code to the fields defined inside message body is not supported.

For more code customization examples it is recommended to take a look at the following real-life protocols.

The commsdsl2comms also allows appending any text to any generated file (not necessarily C++ code). It is done by creating appropriate file with .append suffix. For example, adding extra logic to the generated CMake file(s) are possible by creating CMakeLists.txt.append file with custom content.

The commsdsl2comms utility will also copy all the files, residing in the source directory and not having any of the special suffixes (.read, .write, .length, etc...), as-is without modification into the output directory preserving their relative path. It is recommended to read through the GeneratedProjectWalkthrough.md documentation page to get to know what directories / namespaces are used to contain particular classes.