Вопрос сбора информации с приборов учета при разнообразии существующих протоколов обмена стоит очень остро. В статье рассмотрена работа с европейским протоколом DLMS\COSEM и его российской локализацией СПОДЭС. Описано устройство кадров на прикладном, промежуточном и канальном (в следующей части статьи) уровнях. Предложенная информация позволяет анализировать имеющиеся последовательности обмена, самому разрабатывать библиотеки, выполняющие роль клиента или сервера, встраивать поддержку протокола в свои системы сбора показаний или счетчики.

Введение

В соответствии с моделью взаимодействия открытых систем OSI протокол использует уровни физический, канальный и прикладной. В первой части статьи были описаны кадры прикладного уровня, используемые для установления и разрыва соединения. В данной части статьи будут описаны кадры прикладного уровня, позволяющие провести опрос прибора учета. В третьей части статьи будут рассмотрены кадры протокола канального уровня HDLC.

Протокол DLMS/COSEM в нашей стране закреплен в стандарте СТО Россетей [1] и ГОСТ P 58940-2020 [2]. В данной работе поставлена цель написания русскоязычного руководства по работе с данным протоколом для заинтересованных инженеров и программистов встроенных систем. Понимание тонкостей его работы позволит расширить круг разработчиков и инженеров, способных его поддерживать.

Руководствами для выполнения работы служили уже упомянутые стандарты Россетей и ГОСТ, а также описывающие стандарт DLMS/COSEM документы [3, 4] (Синяя и Зеленая книги).

Так как тестирование проводились на коммуникационном профиле HDLC, то вся дальнейшая информация относится только к этому профилю.

1. Описание модели взаимодействия клиента и сервера при получении данных

Сервисы прикладного уровня для получения данных разделены на две группы: 1) обращающиеся к данным через короткие имена (SN); 2) обращающиеся к данным через длинные имена (LN).

Использующие LN-имена сервисы:

GET, SET, ACTION, EventNotification

Использующие SN-имена сервисы:

Read, Write, UnconfirmedWrite, InformationReport, Parameterized Access

В данном руководстве описан только сервис GET, как наиболее часто используемый при опросе приборов учета. Сервис GET предназначен для получения одного или нескольких атрибутов у имеющихся COSEM-объектов сервера. Подробнее про модель прибора учета COSEM можно почитать в blue book [5] и на хабре [6,7]. Кратко – прибор учета представляется набором объектов. Каждый объект принадлежит предопределенному классу (Пример класса: регистр. Пример объекта класса регистр: регистр, хранящий значение текущего потребления энергии) и имеет свой уникальный идентификатор (ID). У каждого класса (а значит и у каждого объекта) имеется набор атрибутов (например, у регистра есть атрибуты значение, единицы измерения и т.п.). Целью запроса всегда являются атрибуты объектов в адресном пространстве прибора учета.

Обмен идет по схеме запрос-ответ. При этом запрос должен укладываться строго в один кадр PDU, а ответ на запрос может как укладываться в один кадр, так и передаваться несколькими кадрами (блочный режим). Поддержка блочного режима обговаривается клиентом и сервером в процессе установления соединения с помощью бита 11 в блоке совместимости (conformance block) [см. Часть 1].

Механизм блоковой передачи на прикладном уровне необходимо отличать от механизма сегментов на уровне канальном (HDLC). Эти механизмы прозрачны друг для друга и действуют независимо.

2. Кадр запроса данных

Кадр для запроса данных обозначается Get-request и оформлен как BER-объект с тэгом 0xC0, но без блока длины. Для простоты дальше будем называть кадром содержимое данного объекта.

В зависимости от того, используется блоковая передача или нет, первый байт кадра определяет тип запроса:

1 – первоначальный кадр запроса (.NORMAL)

2 – запрос следующего блока (.NEXT). Используется только в передаче блоками и описан подробнее в п.4.

3 – запрос списка атрибутов (.WITH LIST)

Интерпретация полей кадра запроса представлена на рис.1. Длина каждого поля приводится в байтах слева от его названия.

Рис.1. Интерпретация различных типов в кадре запроса
Рис.1. Интерпретация различных типов в кадре запроса

Следующий байт запроса – invoke-id-and-priority – присутствует во всех типах запросов. Значение этого байта содержит следующую информацию: первые 4 бита (биты 0-3) – invoke-id, 6-й бит – service class (должен ли сервер отвечать на данный запрос), 7-й бит – priority (0, если запрос имеет обычный приоритет, 1 – высокий приоритет).

Поле invoke-id показывает уникальный идентификатор запроса. В соответствии со стандартом, клиенту разрешается послать серверу сразу несколько запросов, не дожидаясь ответа на каждый. В свою очередь, сервер после этого отправляет клиенту несколько кадров с ответами. Чтобы клиент мог различить, какой ответ соответствует какому отправленному ранее запросу, он присваивает каждому запросу уникальный номер (invoke-id). Сервер в кадре ответа на данный запрос должен повторить указанный клиентом в запросе invoke-id.

С этим же связано использование поля приоритета. Без его использования сервер обрабатывает запросы в том порядке, в котором получает их от клиента. Но если очередной запрос имеет установленное поле приоритета – он будет обработан сервером в первую очередь, даже если сервер к этому моменту не успел ответить на все ранее полученные им запросы.

Клиент может запросить данные одним из трех способов:

1. запросить один атрибут одного объекта (используется тип запроса .NORMAL и в запросе указывается ненулевой номер атрибута attribute-id)

2. запросить все атрибуты одного объекта (используется тип запроса .NORMAL и в запросе указывается нулевой номер атрибута)

3. запросить набор из разных атрибутов разных объектов (используется тип запроса .WITH-LIST)

Возможность запроса способами 2. и 3. проговаривается клиентом и сервером при установлении соединения соответствующими битами в conformance block [см. Часть 1].

Для запроса данных способом 1 клиент отправляет кадр с типом запроса .NORMAL. В данном кадре кроме байта invoke-id-and-priority указывается, значение какого атрибута из какого объекта требуется получить (левая ветка на рисунке 1). Для идентификации используется дескриптор атрибута, который состоит из:

  • class-id – идентификатор интерфейсного класса, описанный как двухбайтовое целое (Пример: 3 – Register (регистр), 8 – Clock (отсчет времени) и т.п.);

  • instance-id – идентификатор объекта COSEM, представляет собой строку из шести байт;

  • attribute-id – идентификатор атрибута внутри класса, целое число размером 1 байт (Пример атрибутов для класса register: 2 – value (значение); 3 – scaler_unit (единицы измерения) и т.п.).

Пример кадра прикладного уровня с типом GET-Request:

[C0 01 41 00 03 01 00 03 08 00 FF 03 00]

И его расшифровка в виде полей:

Рис.2. Кадр запроса без селективного доступа.
Рис.2. Кадр запроса без селективного доступа.

Для некоторых атрибутов стандартом COSEM предусмотрена возможность получить только часть его значений (например, для атрибутов, хранящих массив записей). Эта возможность названа в стандарте селективный доступ (selective access) и реализована путем добавления к кадру запроса дополнительного байта selection после attribute-id. Ненулевое значение этого байта показывает, что за ним идет блок дескриптора селективного доступа (selective-access-descriptor). Данный блок начинается с байта селектора (selector). Этот байт дополнительно уточняет, какую часть атрибута следует вернуть в ответе на запрос. Например, для атрибута типа «буфер из записей» данный селектор может содержать 1 (запрашиваются записи, удовлетворяющие заданным условиям) или 2 (запрашивается подмножество всех записей из буфера, начиная и кончая заданной). После байта селектора идет структура, описывающая данные запроса (например, с какой и по какую записи нужно вернуть). Формат данной структуры аналогичен структуре с данными в кадре ответа и будет подробнее рассмотрен в п.3.

Пример кадра с запросом селективного вида:

[C0 01 41 00 07 01 00 63 01 00 FF 02 01 01 02 04 02 04 12 00 08 09 06 00 00 01 00 00 FF 0F 02 12 00 00 09 0C 07 E4 02 1B 04 00 00 00 00 80 00 00 09 0C 07 E4 02 1C 05 00 00 00 00 80 00 00 01 00]

Расшифровка его полей выглядит следующим образом:

Рис.3. Кадр запроса с селективным доступом.
Рис.3. Кадр запроса с селективным доступом.

Возвращаясь к рис.1. можно сказать, что способ запроса 2 отличается от способа 1 тем, что поле attribute-id содержит 0. Это показывает серверу, что необходимо вернуть все атрибуты данного объекта.

Способ запроса 3 отличается от способа запроса 1 тем, что тип запроса меняется на запрос списка (.WITH-LIST) – правая ветка на рис.1. После байта invoke-id-and-priority следует байт, содержащий количество запрашиваемых атрибутов. После данного байта идут одно за другим описания атрибутов в такой же форме, как и при запросе с типом .NORMAL.

3. Кадр ответа с данными

В ответ на кадр запроса сервер формирует и отправляет кадр ответа (Get-response), который оформлен как BER-объект с тэгом 0xC4. Для простоты дальше будем называть кадром содержимое данного объекта.

Первый байт кадра ответа определяет информацию и ее порядок в ответе на запрос:

1 – (.NORMAL) – кадр ответа содержит полный ответ на запрос.

2 – (.WITH-BLOCK) – кадр ответа содержит только часть данных. Данный тип используется в блоковой передаче, которая описана в п.4.

3 – (.WITH-LIST) – кадр ответа содержит значения атрибутов нескольких объектов.

Интерпретация полей кадра ответа представлена на рис.4. Длина каждого поля приводится в байтах слева от его названия.

Рис.4. Интерпретация различных типов кадра ответа
Рис.4. Интерпретация различных типов кадра ответа

 Следующий байт кадра ответа invoke-id-and-priority аналогичен соответствующему байту в запросе и должен повторять его.

Ответ с типом .NORMAL (левая ветка на рис.2) содержит либо значение запрошенного атрибута, либо диагностический байт, показывающий причину невозможности вернуть данное значение. Определить дальнейшее содержимое кадра позволяет байт get-data-result. Если запрос обработан успешно, его содержимое равно 0.

В случае успешного запроса кадр содержит значение атрибута data в формате, зависящем от типа содержимого. Последовательность data кодируется в формате A-XDR (IEC 61334-6), который является упрощенной версией рассмотренного ранее формата BER (X.690).  Структура объекта data так же состоит из трех блоков: тип, длина, значение. Но есть важные отличия от BER-кодировки:

-          Тип занимает строго 1 байт и кодирует только универсальные типы данных. Причем значения для типов в A-XDR отличаются от типов в BER. Например, строка байт OCTET STRING имеет значение типа 9, а не 4, как в X.690.

-          Для типов, длина которых заранее известна (например, float32) блок длины отсутствует.

Пример для кодирования целого 32-хбитного числа без знака (тип – 06) со значением 0xFFFFFFFF будет иметь вид:

Тип

Значение

06

FF

FF

FF

FF

Так как тип имеет постоянную длину, блока длины нет.

Пример кодирования строки OCTET STRING, состоящей из трех байт:

Тип

Длина

Значение

09

03

01

02

03

Для кодирования сложных типов: структуры и массива имеются специальные значения типов (01 – массив, 02 – структура). Для объекта массива после байта с типом следует байт, хранящий количество элементов массива. После него идет байт, хранящий тип элементов массива. Далее идут байты, содержащие значения элементов массива один за другим. Для объекта структуры после байта с типом следует байт, хранящий количество элементов структуры, после которого идут объекты, составляющие структуру. Каждый объект внутри структуры является самостоятельным объектом с явным указанием его типа.

Полная таблица значений для типов содержится в [4].

Пример кадра прикладного уровня с ответом:

[C4 01 C1 00 09 0C 07 E4 03 03 02 10 20 18 00 80 00 00]

Рис.5. Кадр прикладного уровня с ответом в виде строки байт.
Рис.5. Кадр прикладного уровня с ответом в виде строки байт.

Кадр ответа с типом .WITH-LIST может содержать несколько объектов, закодированных в A-XDR кодировке.

При невозможности выполнить запрос сервер вкладывает в кадр ответа поле data-access-result с диагностическими данными. Перечень возможных причин отказа приведен в [4]. Примеры: 1 – hardware-fault, 2 – temporary-failure, 3 – read-write-denied  и т.д.

4. Передача данных блоками

В протоколе DLMS\COSEM используется два независимых механизма разделения длинных последовательностей информации на части: на прикладном и на канальном уровне:

- блоковая передача (block transfer) – механизм разделения кадров на прикладном уровне. Необходимость разделения кадров на прикладном уровне обусловлена максимальным размером кадра прикладного уровня, который определяется в процессе установления соединения с помощью кадров AARQ и AARE и называется max-pdu-size:

Рис.6. Иллюстрация указания максимальной длины кадра в AARE.
Рис.6. Иллюстрация указания максимальной длины кадра в AARE.

Управление при блоковой передаче выполняется с помощью поля типов в запросе и ответе.

- сегментация (segmentation) – механизм разделения кадров на канальном уровне. Необходимость сегментации кадров на канальном уровне вызвана ограничением на максимальную длину кадра канального уровня, которое определяется путем обмена кадрами SNRM и UA (более подробно будут описаны в части 3). Пример кадра UA, содержащего параметры приведен на рис.7.

Рис.7. Иллюстрация указания максимальной длины кадра в UA.
Рис.7. Иллюстрация указания максимальной длины кадра в UA.

Из рисунков 6 и 7 видно, что в данном обмене кадр прикладного уровня ограничен 256 байтами, а кадр канального уровня – 128 байтами. Таким образом, если ответ на запрос клиента содержит больше 256 байт, то он будет разделен на блоки по 256 байт с помощью метода блочной передачи. Но даже блоки длиной 256 байт не могут быть переданы канальным уровнем, поэтому канальный уровень дополнительно разделит их на сегменты длиной не более 117 байт (остальное займут заголовок протокола HDLC и концевик), т.е. понадобится максимум три сегмента для передачи одного блока). После этого к каждому сегменту добавляются заголовок и концевик, и полученный кадр выдается в физическую линию связи.

Рис.8. Иллюстрация разделения данных на кадры при ограничениях 256 и 128 байт.
Рис.8. Иллюстрация разделения данных на кадры при ограничениях 256 и 128 байт.

Метод блоковой передачи описан в данной части статьи, а метод сегментации будет описан в третьей части, посвященной канальному уровню.

При блоковой передаче каждый кадр с данными от сервера содержит в поле типа значение 02 (.WITH-BLOCK). В ответ клиент должен выслать кадр, подтверждающий прием. Подтверждение является кадром запроса, в поле типа которого содержится значение 02 (.NEXT), а в поле block-number – номер блока, который клиент принял последним. Получив кадр с подтверждением, сервер может отправлять следующую часть данных. Если по каким-то причинам очередной блок не принят клиентом, то клиент в следующем запросе с типом NEXT указывает с помощью поля block-number необходимость передать этот блок повторно. На последний кадр с данными подтверждение клиентом не высылается. Особенностью всех кадров, принадлежащих к блочному обмену, является одинаковое значение поля invoke-id, нужное для того, чтобы клиент смог собрать из них полный ответ сервера.

Кадры с частичным ответом формируются сервером следующим образом. Последовательность байт Data, представляющая собой ответ на запрос в формате A-XDR нарезается на блоки длиной k, и байты D1,D2,…Dk вкладываются в BER-объект типа OCTET-STRING. Сам объект строки вкладывается в структуру datablock-G, которая состоит из полей:

  • last-block – признак, содержит ли данный блок последнюю часть или нет;

  • block-number – беззнаковое число, определяющее номер текущего блока, начиная с единицы;

  • result – байт, определяющий, есть ли в данном кадре полезная нагрузка (result = 0), или в нем содержится причина невозможности выполнить запрос (result = 1);

  • если result = 0, то оставшаяся часть структуры datablock-G заполнена объектом OCTET-STRING, содержащим очередные k байт ответа (raw-data). Если result != 0, то оставшаяся часть datablock-G содержит байт с диагностикой сервера о причинах невозможности выполнить запрос (data-access-result).

Есть несколько особенностей в случае, когда кадр ответа содержит данные raw-data. Данные представляют собой BER-объект типа OCTET-STRING, у которого отсутствует блок с тэгом. Блок длины string-length кодируется в соответствии с протоколом X.690: в зависимости от хранимой длины он может занимать один или больше одного байта. Если длина k блока значения raw-bytes не превосходит 127 байт, то блок длины string-length занимает 1 байт и хранит фактическую длину (число k). В этом случае старший бит байта string-length равен 0. Если длина блока с данными больше 127, то в первом байте блока длины старший бит равен 1, а оставшиеся биты содержат кол-во дополнительных байт блока длины. Оставшиеся байты блока длины содержат фактическую длину в виде целого числа (старшие байты числа идут первыми).

Пример кодирования блока длины string-length, если длина блока с данными raw-bytes составляет 511 байт:

Байт 1

Байт 2

Байт 3

10000010 (0x82)

0x01

0xFF

Здесь старший бит первого байта содержит 1. Это признак того, что остальные биты данного байта содержат количество дополнительных байтов в блоке длины (2). Эти дополнительные 2 байта содержат число 0x01FF, которое обозначает фактическую длину блока с данными.

Нарезанные на блоки кадры с ответом пересылаются сервером на канальный уровень и отправляются клиенту. Каждый блок клиент должен подтвердить отправкой кадра с типом запроса (.NEXT). В кадре запроса пересылается номер последнего принятого клиентом блока block-number (см. рис.8). В последнем кадре с ответом сервер устанавливает признак last-block, сообщающий клиенту, что блоковая передача завершена.

Рис.8. Временная диаграмма обмена сообщениями на прикладном уровне.
Рис.8. Временная диаграмма обмена сообщениями на прикладном уровне.

Заключение

В данной части рассмотрен процесс получения данных с прибора учета по протоколу DLMS\COSEM на прикладном уровне. Рассмотрена структура кадров запроса и ответа, способы запросов, блоковая передача. В следующей части будет рассмотрено использование канального уровня HDLC для работы с данным протоколом.

Список источников

1.      ГОСТ Р 58940-2020. Требования к протоколам обмена информацией между компонентами интеллектуальной системы учета и приборами учета. – Москва. – Стандартинформ. – 2020. – 101 с.

2.      СТО 34.01-5.1-006-2019 Приборы учета электрической энергии. Требования к информационной модели обмена данными. Стандарт организации ПАО «Россети». [Электронный ресурс]. URL:  http://www.rosseti.ru/investment/standart/corp_standart/doc/%D0%A1%D0%A2%D0%9E_34.01-5.1-006-2019.pdf (дата обращения 28.01.2022)

3.      DLMS User Association. COSEM Identification system and interface classes. Technical report. 8th edition. – 2007. –  168 p. (Blue Book)

4.      DLMS User Association. DLMS\COSEM Architecture and protocols. Technical report. 6th edition. – 2007. –  219 p. (Green Book)

5.      А. Мамаев. DLMS\COSEM – открытый протокол для обмена данными с приборами учета. Часть 1: краткий обзор. [Электронный ресурс] URL: https://habr.com/ru/post/302246/ (дата обращения 28.01.2022)

6.     А. Мамаев. DLMS\COSEM – открытый протокол для обмена данными с приборами учета. Часть 2:интерфейсные классы, модель прибора учета. [Электронный ресурс] URL: https://habr.com/ru/post/303606/ (дата обращения 28.01.2022)

 

Комментарии (0)