|
1 | 1 | # Tutorial 25 |
2 | 2 | Dealing with big protocols. |
3 | 3 |
|
| 4 | +Most of the binary communication protocols use numeric message ID information reported in the |
| 5 | +message frame. The [CommsDSL](https://github.com/commschamp/CommsDSL-Specification) specification |
| 6 | +provides [<id>](https://commschamp.github.io/commsdsl_spec/#frames-id) framing layer for this purpose, while the generated code uses |
| 7 | +[comms::protocol::MsgIdLayer](https://commschamp.github.io/comms_doc/classcomms_1_1protocol_1_1MsgIdLayer.html) class |
| 8 | +to implement the required functionality. During the **read** operation the |
| 9 | +[comms::protocol::MsgIdLayer](https://commschamp.github.io/comms_doc/classcomms_1_1protocol_1_1MsgIdLayer.html) class |
| 10 | +is responsible to provide the functionality for reading the message ID and create appropriate message object before forwarding |
| 11 | +the request to the next framing layer. The |
| 12 | +default mapping of the numeric message ID to the actual message type is implemented using |
| 13 | +[comms::MsgFactory](https://commschamp.github.io/comms_doc/classcomms_1_1MsgFactory.html) class. |
| 14 | +The latter receives a `tuple` of all the message classes it is expected to support as its second template parameter |
| 15 | +and uses multiple meta-programming techniques to analyze the provided messages at **compile-time** and |
| 16 | +create proper mapping of numeric message IDs to their respective actual types. Such compile time analysis may incur |
| 17 | +a significant burden on compilation time as well as memory consumption of the compiler. Depending on the |
| 18 | +development machine characteristics, the compilation performance issues may get noticeable when number of the |
| 19 | +messages approaches 30 - 50. In some specific cases (like small RAM and/or compiler being 32 bit application) |
| 20 | +the compilation may report an error due to being out of heap space. |
4 | 21 |
|
| 22 | +To mitigate this problem / annoyance the **v6.1** of the **commsdsl2comms** code generator added extra `switch` |
| 23 | +based message factories in the [<protocol_namespace>/factory](include/tutorial25/factory) folder. |
| 24 | + |
| 25 | +- [<protocol_namespace>::factory::AllMessagesDynMemMsgFactory](include/tutorial25/factory/AllMessagesDynMemMsgFactory.h) class - |
| 26 | + a factory for all the messages of the protocol. |
| 27 | +- [<protocol_namespace>::factory::ClientInputMessagesDynMemMsgFactory](include/tutorial25/factory/ClientInputMessagesDynMemMsgFactory.h) class - |
| 28 | + a factory for the client input messages of the protocol. |
| 29 | +- [<protocol_namespace>::factory::ServerInputMessagesDynMemMsgFactory](include/tutorial25/factory/ServerInputMessagesDynMemMsgFactory.h) class - |
| 30 | + a factory for the server input messages of the protocol. |
| 31 | + |
| 32 | +The **DynMem** part of the name implies dynamic memory allocation. |
| 33 | + |
| 34 | +Note that in this tutorial **sender** property hasn't been used, i.e. all the messages are sent both ways. It means that all the message factories |
| 35 | +mentioned above contain the same code. For the cases when uni-directional messages are present they'll differ. |
| 36 | + |
| 37 | +The [comms::protocol::MsgIdLayer](https://commschamp.github.io/comms_doc/classcomms_1_1protocol_1_1MsgIdLayer.html) layer provided by the |
| 38 | +[COMMS Library](https://github.com/commschamp/comms) allows replacing the default message factory |
| 39 | +([comms::MsgFactory](https://commschamp.github.io/comms_doc/classcomms_1_1MsgFactory.html)) |
| 40 | +using the **comms::option::app::MsgFactory** or **comms::option::app::MsgFactoryTempl** application specific customization options. |
| 41 | + |
| 42 | +The **v6.1** of the **commsdsl2comms** code generator also generates extra protocol options that can be used to apply the relevant |
| 43 | +option to the [comms::protocol::MsgIdLayer](https://commschamp.github.io/comms_doc/classcomms_1_1protocol_1_1MsgIdLayer.html) class: |
| 44 | + |
| 45 | +- [<protocol_namespace>::optoins::AllMessagesDynMemMsgFactoryDefaultOptions](include/tutorial25/options/AllMessagesDynMemMsgFactoryDefaultOptions.h) - the options forcing usage |
| 46 | + of the [<protocol_namespace>::factory::AllMessagesDynMemMsgFactory](include/tutorial25/factory/AllMessagesDynMemMsgFactory.h). |
| 47 | +- [<protocol_namespace>::optoins::ClientInputMessagesDynMemMsgFactoryDefaultOptions](include/tutorial25/options/ClientInputMessagesDynMemMsgFactoryDefaultOptions.h) - |
| 48 | + the options forcing usage of the [<protocol_namespace>::factory::ClientInputMessagesDynMemMsgFactory](include/tutorial25/factory/ClientInputMessagesDynMemMsgFactory.h). |
| 49 | +- [<protocol_namespace>::optoins::ServerInputMessagesDynMemMsgFactoryDefaultOptions](include/tutorial25/options/ServerInputMessagesDynMemMsgFactoryDefaultOptions.h) - |
| 50 | + the options forcing usage of the [<protocol_namespace>::factory::ServerInputMessagesDynMemMsgFactory](include/tutorial25/factory/ServerInputMessagesDynMemMsgFactory.h). |
| 51 | + |
| 52 | +Let's take a look how the protocol options above can be used to force usage of the more efficient message factories. |
| 53 | + |
| 54 | +The [ServerSession](src/ServerSession.h) defines its protocol options like this: |
| 55 | +```cpp |
| 56 | +using ServerProtocolOptions = |
| 57 | + ServerInputMessagesDynMemMsgFactoryDefaultOptionsT< |
| 58 | + tutorial25::options::ServerDefaultOptions |
| 59 | + >; |
| 60 | +``` |
| 61 | + |
| 62 | +The definition used by the [ClientSession](src/ClientSession.h) is very similar: |
| 63 | +```cpp |
| 64 | +using ClientProtocolOptions = |
| 65 | + tutorial25::options::ClientInputMessagesDynMemMsgFactoryDefaultOptionsT< |
| 66 | + tutorial25::options::ClientDefaultOptions |
| 67 | + >; |
| 68 | +``` |
| 69 | + |
| 70 | +When it comes to aliasing of the message types, the **v6.1** of the commsdsl2comms code generator added |
| 71 | +convenience macros to the definitions of the input messages: |
| 72 | + |
| 73 | +- **<PROT_NS>_ALIASES_FOR_ALL_MESSAGES** and **<PROT_NS>_ALIASES_FOR_ALL_MESSAGES_DEFULT_OPTIONS** in |
| 74 | + [<protocol_namespace>/input/AllMessages.h](include/tutorial25/input/AllMessages.h) |
| 75 | +- **<PROT_NS>_ALIASES_FOR_CLIENT_INPUT_MESSAGES** and **<PROT_NS>_ALIASES_FOR_CLIENT_INPUT_MESSAGES_DEFULT_OPTIONS** in |
| 76 | + [<protocol_namespace>/input/ClientInputMessages.h](include/tutorial25/input/ClientInputMessages.h) |
| 77 | +- **<PROT_NS>_ALIASES_FOR_SERVER_INPUT_MESSAGES** and **<PROT_NS>_ALIASES_FOR_SERVER_INPUT_MESSAGES_DEFULT_OPTIONS** in |
| 78 | + [<protocol_namespace>/input/ServerInputMessages.h](include/tutorial25/input/ServerInputMessages.h) |
| 79 | + |
| 80 | +Please take a look at the definition: |
| 81 | +```cpp |
| 82 | +/// @brief Create type aliases for the all messages of the protocol. |
| 83 | +/// @param prefix_ Prefix of the alias message type. |
| 84 | +/// @param suffix_ Suffix of the alias message type. |
| 85 | +/// @param interface_ Type of the common message interface. |
| 86 | +/// @param opts_ Type of the used protocol definition options. |
| 87 | +#define TUTORIAL25_ALIASES_FOR_ALL_MESSAGES(prefix_, suffix_, interface_, opts_) \ |
| 88 | + using prefix_ ## Msg1 ## suffix_ = tutorial25::message::Msg1<interface_, opts_>; \ |
| 89 | + using prefix_ ## Msg2 ## suffix_ = tutorial25::message::Msg2<interface_, opts_>; \ |
| 90 | + ... |
| 91 | +``` |
| 92 | +
|
| 93 | +The [ClientSession](src/ClientSession.h) uses the **TUTORIAL25_ALIASES_FOR_ALL_MESSAGES** macro to alias all message types: |
| 94 | +```cpp |
| 95 | +TUTORIAL25_ALIASES_FOR_ALL_MESSAGES(,,Message,ClientProtocolOptions); |
| 96 | +``` |
| 97 | + |
| 98 | +Please note the empty `prefix_` and `suffix_` parameters. |
| 99 | + |
| 100 | +It is equivalent of having the following alias types defined: |
| 101 | +```cpp |
| 102 | +using Msg1 = tutorial25::message::Msg1<Message, ClientProtocolOptions>; |
| 103 | +using Msg2 = tutorial25::message::Msg2<Message, ClientProtocolOptions>; |
| 104 | +using Msg3 = tutorial25::message::Msg3<Message, ClientProtocolOptions>; |
| 105 | +... |
| 106 | +``` |
| 107 | + |
| 108 | +These alias types are used when sending messages to the **server**: |
| 109 | +```cpp |
| 110 | +void ClientSession::sendMsg1() |
| 111 | +{ |
| 112 | + Msg1 msg; |
| 113 | + sendMessage(msg); // Should get received and echoed back |
| 114 | +} |
| 115 | + |
| 116 | +void ClientSession::sendMsg2() |
| 117 | +{ |
| 118 | + Msg2 msg; |
| 119 | + sendMessage(msg); // Should get received and echoed back |
| 120 | +} |
| 121 | + |
| 122 | +... |
| 123 | +``` |
5 | 124 |
|
6 | 125 | ## Summary |
7 | 126 |
|
| 127 | +- As the number of messages in the protocol grow, the burden on the compilation time and memory consumption can grow exponentially. |
| 128 | +- When number of the messages exceeds 20-30 messages, it is recommended to use more optimized generated message factories. |
| 129 | +- The message factory classes reside in the **<protocol_namespace>/factory** folder. |
| 130 | +- The **<protocol_namespace>/options** folder will also contain new relevant option classes which can be used to |
| 131 | + force usage of the new factories. |
| 132 | +- The files containing definitions of relevant input messages in the **<protocol_namespace>/input** folder also contain |
| 133 | + definition of the macros helping with message type aliasing. |
8 | 134 |
|
9 | 135 | [Read Previous Tutorial](../tutorial24) <----------------------- |
0 commit comments