Найти в Дзене

С2000-ПП. Чтение событий

Есть у компании Болид прибор, называется С2000-ПП . Преобразователь протоколов

https://bolid.ru/production/orion/signal-transfer/s2000-pp.html

С одной стороны прибор работает внутри системы ИСО Орион (интегрированной системы охраны и пожарной сигнализации), с другой стороны из него можно вычитать события используя протокол Modbus.

Алгоритмов опроса данного прибора может быть множество,

предлагаемый ниже алгоритм вычитывания событий для версии прошивки прибора 1.31 следующий:

1) по таймеру
- запрос номера самого нового события [регистр 46160]
  * сохранить в EvNew
- запрос номера самого старого события [регистр 46161]
  * сохранить в EvOld

- если (EvNew + EvOld) = 0, то:
  - выходим
иначе:
  - запрос самого старого события: [регистр 46264]

- если в ответе ошибка, то:
  - выходим
иначе:
  - парсинг (28 байт ответа)
  - отметить событие как прочитанное [регистр 46163]
    * записать EvOld

После чего данные события стоит разобрать и правильно интерпретировать.

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

- если общая длина ответа меньше 3, то
  - выходим

- байт 0 – адрес slave (Addr)
- байт 1 – функция модбас (Func)
- байт 2 – счётчик байт (Count)

- если общая длина ответа меньше 5, то
- выходим

- байты 3,4 – номер события
- собираем из них переменную (Index) = UInt16(3 и 4)

- если Index = 0, то
  - выходим

- если общая длина ответа меньше 6, то
  - выходим

- байт 5 – длина описания события (Len)

- если Len < 4, то
  - выходим

- байт 6 – код события (Code)

n = 7
НАЧАЛО ЦИКЛА

- если n >= Len, то
  - выходим

- байт n – код типа поля (Codetype)

- в зависимости от Codetype разбираем каждый блок
(стандартная реализация через case/switch, тут для универсальности, через условия)

- если Codetype = 1, то: (порядковый номер пользователя в базе данных С2000-ПП)
- Codelen := ОТВЕТ[n + 1];
- если Codelen < 2, то
  - выходим
- иначе:
  - User := UInt16(ОТВЕТ[n + 3], ОТВЕТ[n + 2])
  - увеличиваем n на (Codelen + 2)

- если Codetype = 2, то: (раздел – номер раздела Modbus)
- Codelen := ОТВЕТ[n + 1];
- если Codelen < 2, то
  - выходим
- иначе:
  - Razdel := UInt16(ОТВЕТ[n + 3], ОТВЕТ[n + 2])
  - увеличиваем n на (Codelen + 2)

- если Codetype = 3, то: (зона – порядковый номер зоны Modbus)
- Codelen := ОТВЕТ[n + 1];
- если Codelen < 2, то
  - выходим
- иначе:
  - Zone := UInt16(ОТВЕТ[n + 3], ОТВЕТ[n + 2])
  - увеличиваем n на (Codelen + 2)

- если Codetype = 5, то: (реле – порядковый номер реле Modbus)
- Codelen := ОТВЕТ[n + 1];
- если Codelen < 2, то
  - выходим
- иначе:
  - RelayNum := UInt16(ОТВЕТ[n + 3], ОТВЕТ[n + 2])
  - увеличиваем n на (Codelen + 2)

- если Codetype = 7, то: (реле – состояние реле)
- Codelen := ОТВЕТ[n + 1];
- если Codelen < 2, то
  - выходим
- иначе:
  - RelayStatus := UInt16(ОТВЕТ[n + 3], ОТВЕТ[n + 2])
  - увеличиваем n на (Codelen + 2)

- если Codetype = 11, то: (время и дата – часы, минуты, секунды, день, месяц, год)
- Codelen := ОТВЕТ[n + 1];
- если Codelen < 6, то
  - выходим
- иначе:
  - Hour := ОТВЕТ[n + 2] and $3F;
  - Min := ОТВЕТ[n + 3];
  - Sec := ОТВЕТ[n + 4];

- Day := ОТВЕТ[n + 5];
  - Month := ОТВЕТ[n + 6];
  - Year := ОТВЕТ[n + 7];

- если четвёртый бит Hour = 0, то:
  - ВРЕМЯ = Hour:Min:Sec

- если третий бит Hour = 0, то:
  - ДАТА = Day.Month.Year

- увеличиваем n на (Codelen + 8)

- если Codetype = 24, то: (id раздела – идентификатор раздела Modbus)
- Codelen := ОТВЕТ[n + 1];
- если Codelen < 2, то
  - выходим
- иначе:
  - ID := UInt16(ОТВЕТ[n + 3], ОТВЕТ[n + 2])
  - увеличиваем n на (Codelen + 2)

КОНЕЦ ЦИКЛА

Ну и в конце Собираем текст события из кусочков (в нужном порядке):
- Addr, Index, Code, User, Razdel, Zone, RelayNum, RelayStatus, ВРЕМЯ, ДАТА, ID.

По итогу, событие прочитано и его можно описать в удобочитаемом виде.