Протокол нужен, чтобы хранить описания сообщений, которыми может обмениваться какая-то группа модулей. Это описание выполняется на структурированном языке описания мета-данных M.
Протоколы состоят из описания сообщений, перечислимых типов и флагов.
Сообщение — пакет с данными, передаваемый через коммуникационную среду (шину) от модуля-отправителя модулю-получателю. Каждое сообщение имеет уникальный идентификатор типа и принадлежит единственному протоколу. Структура сообщения показана на рисунке ниже:
В некоторых случаях в качестве аргумента сообщения в протоколе могут использоваться какие-то ограниченные множества возможных значений. Чтобы ограничить такие значения явно, используются перечислимые типы. При конструировании сообщений такие аргументы могут быть установлены только в значение из явно заданного при определении типа набора.
При определении аргументов сообщений могут использоваться флаги. Флаги это специальный тип данных, определяющий набор именованных битовых масок.
У каждого типа флагов есть уникальное имя. Именно это имя следует использовать в качестве типа аргументов сообщения. У каждого флага есть непустое множество возможных значений. Каждое значение в этом множестве имеет уникальное имя и битовую маску.
При работе с протоколами следует учитывать такое понятие, как поколение протокола. В соответствии с решаемыми задачами и предъявляемыми требованиями протоколы модулей могут претерпевать изменения. Как в сторону увеличения, так и в сторону уменьшения может меняться число сообщений, типов. Поколение протокола позволяет избежать «хаоса версий» при эволюционном развитии протокола, оперировать понятными, идентифицируемыми «диалектами» протокола.
При накоплении изменений, меняющих в итоге принципиальные характеристики протокола, принимается, что это единица уже нового, следующего поколения. Небольшие эволюционные изменения, не меняющие имеющиеся ранее сообщения, относятся, обычно, к одному поколению. Изменение набора доступных в протоколе сообщений или изменение аргументов сообщений всегда возможно только в новом поколении протокола.
Для удобства эволюционного развития протокола и обеспечения механизма обратной совместимости атрибут поколения в обязательном порядке устанавливается не только для всего описания протокола, но и для всех сущностей, описанных в протоколе. Это дает необходимый уровень гибкости в случаях, когда нужно иметь протоколы, содержащие несколько поколений (диалектов).
Протокол описывается следующим образом:
: Kernel\Protocols Имя протокола : Код протокола ; Комментарий Namespace : Пространство имен Generations : {1} Enumerations ; Перечислимые типы ; Описание нужного числа перечислимых типов Messages ; Сообщения ; Описание нужного числа сообщений
Пример:
: Kernel\Protocols CrossroadController : 110 Namespace : Uniteller.CrossroadController Generations : {1} Enumerations ; Перечислимые типы ColorType | Цвет светофора 1 : 3 ; Поколение : 1 / Число значений : 3 Red : 1 |- Красный цвет Yellow : 2 |- Желтый цвет Green : 3 |- Зеленый цвет Messages ; Сообщения SetLight : 1 | Установить новый сигнал 1 : 1 Color : ColorType |- Требуемый цвет сигнала Success : 2 | Команда контроллеру отработана 1 : 0 Fail : 3 | Ошибка в работе контроллера (авария) 1 : 0
Созданное описанным выше образом описание протокола широко используется как во время работы модуля, так и при его разработке. В частности, описание протокола является источником информации, по которым специальными утилитами генерируются код, связанный с протоколом и документация по протоколу.
При кодировании модулей требуется оперировать сущностями, определенными в протоколе - флагами, перечислимыми типами, сообщениями. Описание их на целевом языке программирования естественно может быть выполнено и вручную, но при наличии описания на языке M этот этап не требует трудозатрат, так как все необходимые определения могут быть сгенерированы специальным конвертером. Например, для языка C++ по описанию протокола на языке M таким конвертером генерируется заголовочный файл с именем <Имя протокола>.h.