cc_tools_qt
Common Environment for Protocol Analysis.
|
Developing the protocol plugins is significantly more complex than developing the socket or filter ones. Please follow this tutorial, while observing the implementation of the Demo Protocol (the sources are here) provided as part of the CommsChampion Tools Project.
The protocol messages as well as wrapping transport information need to be implemented using COMMS Library in a certain generic way, which will allow it to be compiled and used in any application, whether it is bare-metal platform with limited resouces or protocol plugin for CommsChampion Tools.
First of all, the common message interface class needs to inherit from or be alias to comms::Message class, while providing only endian and type of ID information as options. It must also provide variadic template parameter to allow extension of the interface with more options.
Such definition leaves room for the application to define the required polymorphic interface as well as choose iterators for read/write operations.
All the actual message definition classes are expected to receive their interface class as a template parameter.
NOTE, that the message definition class inherits from comms::MessageBase, which will inherit from provided TMsgBase template parameter. The provided template parameter must be alias to, or inherit (directly or indirectly) from comms::Message.
When defining transport layers, allow selection of the common interface class as well as input messages as template parameters (see Stack.h as an example).
When developing plugin for CommsChampion Tools, there is a need to define separate message interface class, which inherits from cc_tools_qt::MessageBase and provides the defined earlier interface class as its template parameter. See cc_plugin/DemoMessage.h as an example.
Please note, that the first template parameter of cc_tools_qt::MessageBase is a "template template" one, and the common interface class name defined earlier (demo::DemoMessage) is passed to it "as-is" without angle brackets.
The cc_tools_qt::MessageBase uses multiple inheritance to extend both cc_tools_qt::Message and provided custom protocol message interface class (demo::DemoMessage). When extending provided interface class, additional options are passed to it to allow full available polymorphic interface (read, write, length retrieval, validity check, etc...). The cc_tools_qt::Message is the main interface class used by the CommsChampion Tools to manipulate messages.
The class hierarchy will look like this:
The cc_tools_qt::Message interface class has multiple pure virtual functions, many of them are implemented inside cc_tools_qt::MessageBase. One of them is cc_tools_qt::Message::idAsStringImpl(). It is used to convert the message numeric ID into string representation to display it to user. The default implementation inside cc_tools_qt::MessageBase will convert it as is. However, it is recommended to override this function and provide better formatting.
Please note, that there are two polymorphic interface classes: cc_tools_qt::Message and comms::Message (or demo::DemoMessage). The latter defines its virtual functions, which are implemented as part of protocol message definition (using comms::MessageBase). The cc_tools_qt::Message is used only by CommsChampion Tools and defines its own (pure) virtual functions which are expected to be overridden by the message implementation class. One of them is message name retrieval.
In order to be able to instantiate message object this pure virtual function needs to be implemented. In order to do this, there is a need to extend the existing implementation of the defined protocol message and implement missing function. Let's take IntValues.h and cc_plugin/message/IntValues.h as an example. The latter is implemented in the following way:
Please note that the class inherits from cc_tools_qt::ProtocolMessageBase, which overrides and implements two pure virtual functions defined by cc_tools_qt::Message:
Also note, that cc_tools_qt::ProtocolMessageBase class receives two template parameters. The first one is the protocol message class the cc_tools_qt::ProtocolMessageBase will inherit from (demo::message::IntValues<demo::cc_plugin::DemoMessage>). The second one is the type of the message class itself (IntValues).
One more thing to note, is the previously defined demo::cc_plugin::DemoMessage is passed as interface class to demo::message::IntValues (as a template parameter).
The full inheritence hierarchy will look like this:
The CommsChampion Tools are there to help visualise and debug custom binary protocols. The definition of the messages using COMMS library is used to define serialisation and deserialisation of the protocol messages. However, such definitions do not contain any extra information on how the message fields need to be displayed. For example, when displaying a value of comms::field::EnumValue field, there is a need to display a human readable "name" of the value in addition to its serialised raw bytes.
In order to provide the required information, the message definition class for the protocol plugin (demo::cc_plugin::IntValues) is expected to override inherited cc_tools_qt::Message::fieldsPropertiesImpl() and provide the required properties of the fields.
NOTE, that the properties are defined as static const
variable and created only once upon first entry. The field's properties are the description on the way how the fields need to be displayed and do not depend on the field's value.
Also note, that the properties are stored in QVariantList, size of which must be equal to number of fields, the message contains.
One more thing to note is that set of properties for a single field are stored in QVariantMap. However, it is implicitly converted to QVariant when inserted into the QVariantList.
If the message doesn't have any fields, there is no need to override cc_tools_qt::Message::fieldsPropertiesImpl(). The cc_tools_qt::Message class itself provides default implementation which returns empty list.
The helper classes that allow definition of the fields' properties reside in cc_tools_qt::property::field namespace, please refer to Defining Fields' Properties separate tutorial page for details on how to use them.
Afther all the message classes for the protocol plagin were defined, they need to be bundled into std::tuple (see cc_plugin/AllMessages.h).
The Protocol Definition section above defined how protocol stack should be defined when implementing common protocol definition. Usage of the template parameters leaves us space to redefine it for CommsChampion Tools plugin environment (see cc_plugin/DemoStack.h).
NOTE, that the passed first template parameter is the common interface class for all the message classes in the plugin environment (defined in the Messages in Plugin Environment section), and the second template parameter is the messages themselves.
In order to understand what the "Transport Message" is, let's take a look how the cc_view (main GUI application of the CommsChampion Tools) displays a message. The bottom right area allows to request a display of "Transport" information instead of message itself with its fields.
When clicked it displays the transport information instead of application message.
The displayed transport information is presented like any other message, but with fields difined by the "protocol stack".
In order to support displaying of the transport information for the newly developed protocol plugin, there is a need to create a dummy message, which will contain all the fields defined by the protocol stack. Please see the cc_plugin/DemoTransportMessage.h and cc_plugin/DemoTransportMessage.cpp as an example.
Note, that the demo::cc_plugin::DemoTransportMessage class inherits from cc_tools_qt::TransportMessageBase providing two template parameters. The first one is common message interface class (demo::cc_plugin::Message) defined in Messages in Plugin Environment section. The second parameter is std::tuple of all the fields used to defined "protocol stack", but appearing in order of their serialisation.
The "protocol stack" defines its internal type AllFields, which contains all the "transport" fields in order of their appearance in protocol stack definition. If order of fields' serialisation is the same as order of fields' appearance in protocol stack, the AllFields internal type could be reused. However, this is not the case for demo protocol. The latter defines its protocol stack in the following way:
The CHECKSUM layer wraps the LENGTH. As the result the fields are defined in the following order.
In case of direct reusing of demo::Stack::AllFields the transport information would be displayed incorrectly.
The DemoTransportMessage is a descendent of common message interface class defined for the plugin (demo::cc_plugin::DemoMessage) and is expected to provide properties of its fields.
The cc_plugin/DemoTransportMessage.cpp file contains code of this function. Please refer to Defining Fields' Properties tutorial page to learn how to set field's properties.
the TransportMessage is also a descendent of common message interface class defined as part of the protocol definition (demo::DemoMessage). One of the base classes up the inheritance chain provides default implementation of comms::Message::readImpl() virtual function. However, in case of the demo protocol, the default implementation is incorrect. An attempt to deserialise such message will fail. This is because the PAYLOAD field doesn't have any length limitation and will consume all input without leaving anything to the CHECKSUM value. In order to fix it the implementation of demo::cc_plugin::DemoTransportMessage needs to override it and provide correct implementation.
The readFieldsUntil() and readFieldsFrom() functions are provided by comms::MessageBase class, which is also one of the ancestors to the TransportMessage class.
The CommsChampion Tools use cc_tools_qt::Protocol polymorphic interface class to create and update messages. It means that our protocol definition class needs to be a descendent of cc_tools_qt::Protocol. The latter defines multiple pure virtual functions, which the derived class must implement. The cc_tools_qt library also provides cc_tools_qt::ProtocolBase template class, which inherits from cc_tools_qt::Protocol and implements most of the required virtual functions using info from provided template parameters. Hence, the custom protocol definition class needs to inherit from cc_tools_qt::ProtocolBase and provide necessary info.
The demo protocol defines its Protocol class in cc_plugin/DemoProtocol.h and cc_plugin/DemoProtocol.cpp files.
Please note the following:
The final thing to do is to define the actual plugin class. Please read the Defining a Plugin page first to understand the way the plugins are defined.
The demo protocol defines its Plugin class in cc_plugin/DemoPlugin.h and cc_plugin/DemoPlugin.cpp files.
If the protocol requires configuration, please also provide a callback which creates the widget when invoked (see Configuration Widget).