Содержание


Справка по &ModbusProxy

Драйвер &ModbusProxy - это прокси (посредник), через который подключаются драйверы устройств на шине MODBUS. Он решает задачу виртуализации ввода-вывода и сериализации (выстраивания в очередь) запросов от множества устройств, работающих в разных программных потоках. Это позволяет упростить взаимодействие драйверов MODBUS устройств и сделать их программирование проще.

Перейти к Содержанию


Назначение

Клиент &ModbusProxy:

Таким образом, клиент "закрывает" сразу большой спектр задач.

Клиент &ModbusProxy является универсальным посредником, связующим звеном между подчиненными драйверами и устройствами MODBUS. Клиент &ModbusProxy ничего не делает сам по себе, он лишь обеспечивает прием и передачу данных через порты по протоколу MODBUS, выстраивая опросы от драйверов в очередь и предотвращая конфликты при наличии множества устройств на каждом порте. В то же время подчиненные драйверы напрямую не работают с физическими портами (TCP,COM), они работают с логическими портами (номерами 1..16). Всю работу, связанную с физическими портами, берет на себя клиент &ModbusProxy.

Подчиненные драйверы периодически посылают в консоль &ModbusProxy команду [@Modbus.Poll](#poll_logic) которая помещается в очередь для последующего выполнения. Когда приходит очередь, клиент &ModbusProxy инициирует опрос физического порта, связанного с указанным в запросе логическим портом и по результатам опроса посылает драйверу результат в виде консольной команды (одной из @Modbus.Reply, @Modbus.Refuse, @Modbus.TimeOut).

&ModbusProxy не требует регистрации драйверов, которые к нему обращаются, поскольку в каждом запросе указывается имя (или ссылка) драйвера, которому надо передать ответ для последующей обработки. Таким образом, драйверы могут пользоваться услугами клиента &ModbusProxy в довольно свободном режиме. Например, драйвер может обрабатывать ввод-вывод нескольких модулей на разных портах, а разные драйверы могут опрашивать один модуль. Клиент &ModbusProxy обеспечивает бесконфликтную сериализацию (выстраивание опросов в очередь) и канальный уровень приемо-передачи (порты, заголовки, контрольные суммы, отработка таймаутов). Таким образом, подчиненные драйверы могут сосредоточиться на обработке данных.

При написании подчиненных драйверов (как и самого клиента &ModbusProxy) используется библиотека NetLibrary.

Имеется работающий пример demo_mdbs.

Перейти к Содержанию


Конфигурирование

Конфигурация клиента &ModbusProxy имеет примерно такой вид:

[DeviceList]
&ModbusProxy = device software program
[&ModbusProxy]
Comment       = MODBUS PROXY MASTER.
InquiryPeriod = 0
DevicePolling = 1, tpTimeCritical
ProgramSource = ~~\resource\daqsite\modbusproxy\modbusproxy.pas
DebugFlags    = 3
OpenConsole   = 2
StdInFifo     = 512
StdOutFifo    = 512
StartingOrder = -1024
StoppingOrder = +1024
StartupScript = [&ModbusProxy.StartupScript]
FinallyScript = [&ModbusProxy.FinallyScript]
[]

  либо просто делается ссылка на стандартную Конфигурацию

[ConfigFileList]
ConfigFile = ~~\resource\daqsite\default\modbusproxy.cfg
[]

  при этом

в секцию [&ModbusProxy.StartupScript] надо поместить описание портов MODBUS.

Таблица логических портов MODBUS задается в секции [&ModbusProxy.StartupScript] через консольные команды, описанные ниже. Поэтому эта секция обязательно должна быть описана. Хотя, строго говоря, все описание может генерироваться и динамически, через посылку сообщений. При этом размер буфера StdInFifo должен быть достаточным для размещения таблиц из секции StartupScript.

@port 1 IP tcp port 502 client localhost
   - логический порт №1 работает по протоколу IP, использует TCP порт №502 (это стандартный порт MODBUS)
   - клиент соединяется с сервером localhost.

@port 2 RTU com port 4 baudrate 9600 parity even databits 8 stopbits 1
   - логический порт №2 работает по протоколу RTU, использует COM порт №4, скорость 9600 бит/сек,
   - контроль четности EVEN, 8 бит данных, 1 стоповый бит.

Допускается любая комбинация типов портов и протоколов, например "RTU over TCP/IP".

Аналогично задаются теги для подсчета траффика:

Теги счетчиков могут иметь тип Integer или Real (лучше Real). При необходимости общего счетчика допустимо многократно ссылаться на один и тот же тег, в этом случае счета из разных источников будут складываться.

Использование тегов счетчиков является необязательным. Если счетчики не нужны, их можно не описывать.

В случае, если теги ошибок не указаны, будут инкрементироваться стандартные счетчики ошибок, общие для всех портов. Эти стандартные ошибки влияют на статус DAQ-системы (улыбающийся человечек пожелтеет и покраснеет). В случае, когда теги ошибок указаны, они будут инкрементироваться при ошибках на данном порте, но при этом стандартные счетчики задействованы не будут (поэтому статус DAQ-системы при ошибках не изменится). Это позволяет делать индивидуальную обработку ошибок, по выбору прикладного программиста.

Краткое описание команд в секции StartupScript:

    @Reset
    @View
    @View port
    @Port port prot decl
    @Node node port neta
    @PortErrorRates port Rx Tx Ex
    @PortErrorCounters port Rx Tx Ex
    @PortPollRates port Rx Tx
    @PortPollCounters port Rx Tx
    @PortByteRates port Rx Tx
    @PortByteCounters port Rx Tx
    @CheckOpt port opt
    @TimeGap port gap
  где
    port - логический порт, 1..16
    prot - протокол IP,RTU,ASCII
    decl - описание порта: (tcp port 502 client localhost),(com port 1 baudrate 9600 parity even databits 8 stopbits 1)
    Rx   - имя тега (integer,real) для накопления счетчиков приема/передачи/ошибок приемника
    Tx   - имя тега (integer,real) для накопления счетчиков приема/передачи/ошибок передатчика
    Ex   - имя тега (integer,real) для накопления счетчиков приема/передачи/ошибок - исключений
    opt  - опции проверки протокола, строка LPTUF, сокращение от Length,Protocol,Transaction,Unit,Function
           влияет на строгость проверки данных при анализе сообщений, например, надо ли считать ошибкой
           неверное значение поля Protocol (некотрые PLC неверно его задают)
           символ * задает значение опции по умолчанию
    gap  - временной зазор (пауза) между опросами, мс
           пауза необходима для разделения сообщений в Modbus RTU,
           для других протоколов (IP,ASCII) может отсутствовать (=0)
    
  Например:
  
    [&ModbusProxy.StartupScript]
    ;--- Задание таблицы портов (порт,протокол,описание)
    ;--- Задание счетчиков приема/передачи/ошибок
    ;--- Логический порт 1
    @Port 1 ip  tcp port 502 client localhost
    @PortByteCounters 1 BYTECOUNT.RX BYTECOUNT.TX
    @PortPollCounters 1 POLLCOUNT.RX POLLCOUNT.TX
    @PortErrorCounters 1 BUGSCOUNT.RX BUGSCOUNT.TX BUGSCOUNT.EX
    @PortByteRates 1 BYTERATE.RX BYTERATE.TX
    @PortPollRates 1 POLLRATE.RX POLLRATE.TX
    @PortErrorRates 1 BUGSRATE.RX BUGSRATE.TX BUGSRATE.EX
    @CheckOpt 1 LPTUF
    @TimeGap 1 0
    ;--- Логический порт 2
    @Port 2 rtu com port 4 baudrate 9600 parity even databits 8 stopbits 1
    @PortByteCounters 2 BYTECOUNT.RX BYTECOUNT.TX
    @PortPollCounters 2 POLLCOUNT.RX POLLCOUNT.TX
    @PortErrorCounters 2 BUGSCOUNT.RX BUGSCOUNT.TX BUGSCOUNT.EX
    @PortByteRates 2 BYTERATE.RX BYTERATE.TX
    @PortPollRates 2 POLLRATE.RX POLLRATE.TX
    @PortErrorRates 2 BUGSRATE.RX BUGSRATE.TX BUGSRATE.EX
    @CheckOpt 2 *
    @TimeGap 2 10
    ;--- Очистка счетчиков ошибок
    @ZeroPortCounters
    ;--- Просмотр состояния
    @View
    []

Перейти к Содержанию


Команда @Modbus.Poll

Работа клиента &ModbusProxy происходит в пассивном режиме ожидания запросов со стороны подчиненных драйверов. Предполагается, что драйверы периодически посылают сообщение @Modbus.Poll ... и ждут ответа. При этом драйверы формируют и интерпретируют только данные протокольного уровня PDU (Protocol Data Unit), не заботясь об их передаче и приеме по протоколам канального уровня (IP,RTU,ASCII).

Клиент &ModbusProxy самостоятельно переводит данные PDU к нужному для приемо-передачи формату ADU (Application Data Unit), добавляя требуемые заголовки и контрольные суммы.

Для отказоустойчивости драйверы должны периодически (скажем, раз в минуту) проверять наличие ответа на посланный запрос и генерировать новый запрос, если ответ все еще не пришел (эта ситуация возможна при перезапуске клиента &ModbusProxy).

Команда @Modbus.Poll ref cid tot port uid fid $$dat служит для инициирования операции опроса данных для данного порта.

  @Modbus.Poll ref cid tot port uid fid $$dat
   ref  - reference, числовая ссылка или имя драйвера, инициировавшего опрос. Ответное сообщение будут послано ему.
   cid  - command id, пользовательская команда - любое число, идентифицирующее команду, которая возвращается в ответе
   tot  - максимальное время ожидания ответа, ms, (1..MaxInt). Время ожидания должно быть положительным числом.
   port - номер логического порта, (1..16). Порт должен быть открыт командой @Port.
   uid  - идентификатор (адрес) устройства, (1..247).
   fid  - функция MODBUS, (1,2,3,4,5,6,15,16).
   dat  - данные запроса (request) в формате HEX_ENCODE, зависящие от функции fid.
   
  например:
  
   @Modbus.Poll &demo.driver 33 200 1 5 3 $$00090006
   
    Инициировать опрос модуля с адресом 5, подключенного к порту 1,
    ждать не более 200 ms, ответ переслать драйверу &demo.driver.
    При опросе вызывается MODBUS функция 3 (чтение регистров), читать
    6 регистров начиная с адреса 9 (адресация начинается с нуля).
    В запросе передается номер команды 33 для использования драйвером.

В результате выполнения команды @Modbus.Poll в ответ устройству &sender посылается одно из следующих сообщений: @Modbus.Refuse (опрос отклонен), @Modbus.Reply (опрос выполнен, получен ответ), @Modbus.TimeOut (время ожидания истекло).

  @Modbus.Refuse  ref cid tim port uid fid   msg
  @Modbus.Reply   ref cid tim port uid fid $$ans
  @Modbus.TimeOut ref cid tim port uid fid $$dat
   ref    - reference, имя или ссылка устройства, пославшего ответ; значение должно быть ссылкой &ModbusProxy
   cid    - command id, идентификатор команды; значение должно совпадать с посланным
   tim    - измеренное время выполнения цикла запрос-ответ, ms; значение должно быть неотрицательным
   port   - логический порт, значение должно быть неотрицательным и совпадать с посланным
   uid    - адрес устройства, значение должно быть (1..247) и совпадать с посланным
   fid    - номер функции; значение должно совпадать с посланным, но возможно, с установленным флагом ошибки (128)
   ans    - ответ устройства в формате HEX_ENCODE, возвращаемый при Reply
   req    - исходный запрос  в формате HEX_ENCODE, возвращаемый при TimeOut
   msg    - строка с описанием причины, по которой запрос был отклонен - например, "Bad Func"= неверный номер функции
   
  например:
  
   @Modbus.Reply   1049090 33 10 1 5 3 $$0C4148890D00004159BFB90000
   @Modbus.TimeOut 1049090 33 210 1 5 3 $$00090006
   @Modbus.Refuse &ModbusProxy 33 0 1 5 3 Bad Port 0
   
  здесь 1049090 - ссылка устройства &ModbusProxy

Данные req для передачи и ответ ans передаются в формате HEX_ENCODE и интерпретируются в соответствии с описанием протокола MODBUS.

Перейти к Содержанию


Настройка портов под Linux

Для использования MODBUS через COM порт пользователь должен иметь разрешение на доступ к COM портам.
Для этого пользователя надо включить в группу dialout:

groups                              # получить список групп для пользователя
id -Gn                              # получить список групп для пользователя
sudo usermod -a -G dialout $USER    # включить пользователя в группу dialout

В случае использования MODBUS over TCP обычно используется порт TCP 502.
Проблема состоит в том, что по умолчанию порты 0-1023 недоступны для обычных (не root) пользователей.

В этом случае предлагается сделать следующее:

  1. Разрешить порт tcp 502 для входящих и исходящих соединений:
sudo iptables -A INPUT   -p tcp --dport 502 -j ACCEPT   # разрешить входящий  tcp:502
sudo iptables -A OUTPUT  -p tcp --dport 502 -j ACCEPT   # разрешить исходящий tcp:502
sudo iptables -A FORWARD -p tcp --dport 502 -j ACCEPT   # разрешить проходной tcp:502
  1. Разрешить программе (в данном случае /opt/crwdaq/crwdaq) делать подключения, см. тут и там:
sudo setcap cap_net_bind_service=ep $(readlink -f /opt/crwdaq/crwdaq)
  1. Убедиться, что правила созданы, сохранены и порт прослушивается:
sudo iptables -L           # посмотреть таблицу правил IPTABLES
sudo /sbin/iptables-save   # сохранить  таблицу правил IPTABLES для автозагрузки
ss -tuln                   # посмотреть список программ, слушающих (LISTEN) TCP порты

После проведения этих настроек программа /opt/crwdaq/crwdaq должна получить постоянные права на работу с портом TCP 502 для MODBUS.

Перейти к Содержанию


Желаем успешного использования &ModbusProxy.


CRW-DAQ Copyright (c) 2001-2024 Alexey Kuryakin daqgroup@mail.ru.