Транзакции протокола Modbus

Коллеги, вопрос касается реализации протокола modbus в драйвере Wiren Board 4.
Как известно, сам протокол не обеспечивает организацию транзакции типа запрос/ответ. В каждый момент времени в последовательной шине может происходить только одна операция обмена - либо мастер передает запрос, либо слейв - ответ. А связывание запроса и ответа должно выполняться внешними по отношению к микросети (шине RS-485, например) средствами. Самый простой - организация очереди запросов, которая должна обеспечить передачу очередного запроса в шину не раньше, чем получен ответ от предыдущего.
Есть ли что-нибудь похожее в реализации драйвера modbus в Wiren Board?
Меня интересует этот вопрос с точки зрения управления исполнительными устройствами, подключенными к контроллеру по шине RS-485. Управление выполняется из внешней по отношению к контроллеру программы по протоколу MQTT.

Я не очень понял вопрос. Наш драйвер modbus полностью берёт на себя цикл опроса устройств. Т.е. там реализована не очередь команд, а, скорее, очередь состояний, которые надо обновить.

Если очень упрощать, то драйвер в бесконечном цикле перебирает подряд все устройства, смотрит, есть ли какие-то состояния у конкретного устройства, которые нужно запизать, и если есть, то записывает их в устройство. Дальше опрашивает все регистры с устройства. Код тут: https://github.com/contactless/wb-homa-drivers/blob/master/wb-homa-modbus/modbus_client.cpp#L521

Когда вы управлеяете устройствами по MQTT, то наш драйвер Modbus при получении значения из MQTT меняет у себя локально переменную и запоминает, что соотвествующий регистр нужно записать в устройство в очередном цикле опроса.

Евгений, вы когда-нибудь отдыхаете?

Теперь, кажется, понял… Вы сначала все изменения в топиках последовательно пишете в устройства, ответы при этом игнорируются. А потом, точнее, сразу после записи, - выполняете чтение регистров, в которые писали. Иными словами, одна операция (запись) выливается в пару последовательных операций (запись, чтение). При этом операции чтения в цикле выполняются через заданный интервал.

Наверное, это снимает проблему, поскольку принципиально не требуется связывать полученные данные с первоначальным запросом по изменению состояния. Все это делается в брокере. Здорово. Чем больше я вникаю в mqtt, тем мне больше нравится ваш контроллер :wink:

Хотя, наверное, устойчивость работы будет зависеть от интервала: при малом - могут теряться ответы устройств, при большом - упадет скорость опроса. Кроме того, чтение состояния сразу после записи, тоже наверное, чревато. Все это справедливо при интесивном обмене.

Кстати, в libmodbus запись/чтение реализовано асинхронно? Судя по тому, как используются у вас вызовы, к примеру, modbus_read_bits, - режим блокирующий. Значит, при неисправности устройства на шине будут тормоза.
PS. Надо видимо, мне самому разобраться с libmodbus…

Так вот же: отвечаю на форуме и отдыхаю.

Похоже вы всё поняли немного не так. Хотя ваше описание я тоже не совсем понял

По тексту:

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

Да

Можно и так сказать. Но чтения выполняются, даже если писать нечего. Логически они с операциями записи никак и не связаны.

В реальности цикл крутится практически без задержек, на скорости порта: значение для интервала по-умолчанию что-то вроде 20мс.

Брокер на самом деле тоже никак не связывает данные с запросом. MQTT и наши соглашения работают не как запрос-ответ:

  • в /devices/device_id/controls/control_id/on вы отправляете желаемое новое состояние.
  • в /devices/device_id/controls/control_id драйвер отправляет текущее фактическое состояние когда считает это нужным.

Поэтому отправка в /on асинхронная. Драйвера тоже работают не по принципу запрос-ответ, а занимаются синхронизацией состояний между MQTT и устройством.

Ответы теряться не будут в любом случае.
Если вы говорите не про интервал, а про таймаут - тогда да, но, опять же, зависит от устройств.

Чревато только в случае кривых устройств. Некоторые устройства, очевидно в нарушение стандарта, задумываются после некоторых команд. Если это происходит, можно увеличить значение интервала.

Да, именно так. Проблема не в том, что вызов блокирующий, а в том, что физическая шина у нас одна. Мы не можем по ней ничего слать, пока ждём ответ от устройства.

Поэтому действительно, сбойное/отсутствующее устройство будет вызывать таймауты на каждый запрос и замедлит работу.

Правильно было бы это обнаруживать и исключать устройство из цикла опроса, но это пока не реализовано.

Спасибо огромное!