Принцип работы коннекторов в Delphi компонентах

В моих компонентах для Delphi коннектор – это объект, осуществляющий связь с внешними объектами(объектом). Внешним объектом может выступать другая программа или другое устройство, которое поддерживает тот же интерфейс или протокол связи. В процессе связи коннектор выступает клиентом. То есть задача коннектора отправить запрос и при необходимости дождаться ответа и отправить его по обратной связи (CallBack).

TKRConnector – это базовый класс всех коннекторов. Ниже представлена схема работы коннектора

Схема работы KRConnector

Для отправки запроса используется метод Send

Задача данного метода отправить информацию о запросе в очередь на обработку. В методе Send передаются следующие параметры:

  • APack – указатель на буфер в котором находятся данные предназначенные для отправки. Если нужно получить ответ, то он сохранится в этот же буфер.
  • ALength – длинна отправляемых данных в байтах.
  • ACallBack – метод обратной связи типа TKRConnectorCallBack. Данный метод будет вызван после обработки запроса. Если нет необходимости в обратной связи, то можно передать nil.
  • AData – указатель на дополнительные данные, который будет передан в метод обратной связи (CallBack). Если есть необходимость передать дополнительную информацию о пакете, которые понадобятся в методе обратной связи, то указатель на эти данные передается в этом параметре. Если нет необходимости что-либо передавать, то устанавливаем nil.
  • AWaitResult – указывает на то, нужно ли ждать ответ на запрос. Если должен прийти ответ, но он не будет получен, то это будет считаться ошибкой ceNoResponse.
  • ARecvLen – если заранее известна длина ответа, то ее нужно указать в этом параметре. Заранее зная длину ответа коннектор будет быстрее обрабатывать входящие данные.
  • ADelimiter – разделитель или последовательность байт разделяющая входящие пакеты. Например в протоколе Modbus ASCII разделителем является последовательность #13#10 и для передачи этой последовательности нужно установить значение $0D0A в данный параметр. Если разделитель не используется, то устанавливаем ноль.
  • ADelimiterLen – длина разделителя в байтах. Если разделитель не используется, то устанавливаем ноль.

После вызова Send, информация о запросе попадает во входящую очередь коннектора, которая из себя представляет сблокированный упорядоченный список типа TKRThreadQueue. Максимальное количество запросов в очереди установлено в константе CE_QUEUE_MAX_ITEMS, а текущее количество можно узнать из свойства коннектора QueueCount. Если в момент вызова метода Send в очереди будет максимально возможное количество запросов, то будет вызван метод обратной связи с ошибкой ceQueueOverflowed.

Из входящей очереди запрос попадает в поток обработки данных типа TKRThread. Свойства коннектора WaitTime и WaitPauseTime являются настройками данного потока. Функционал потока описывается для каждого коннектора отдельно, но основные задачи во всех случаях одинаковы:

  1. Установить соединение. Если связь не установлена, то коннектор пытается подключиться с таймаутом указанным в свойстве ConnectTimeout. Если связи нет, то коннектор будет постоянно пытаться подключиться с периодом между попытками указанным в свойстве ReconnectTime. Все запросы до установки связи будут возвращать ошибку ceNotConnection.
  2. Отправить запрос. Отправка последовательности бай с таймаутом указанным в свойстве WriteTimeout. Если за указанный период данные отправить не удается, то возвращается ошибка ceDataNotSended.
  3. При необходимости дождаться ответа. Если при вызове метода Send в параметре AWaitResult передано True, то будет ожидаться ответ в течении времени указанного в свойстве WaitRespTime. Общий таймаут ожидания ответа устанавливается в свойстве ReadTimeout, но промежутки по времени между частями входящего пакета не должны превышать значение свойства WaitRespTime. То есть , фактически, если в течении времени WaitRespTime ничего не будет получено, то коннектор будет считать, что ответа нет. Если в методе Send передано значение ARecvLen больше нуля, то коннектор считает, что ответ получен, если длина полученных данных больше или ровна ARecvLen и прекращает ожидание дополнительных данных. Если ответ получить не удалось, то возвращается ошибка ceNoResponse.
  4. Результат отправить в исходящую очередь.

Исходящая очередь из себя представляет сблокированный упорядоченный список типа TKRThreadQueue. Максимальное количество запросов в очереди установлено в константе CE_QUEUE_MAX_ITEMS, а текущее количество можно узнать из свойства коннектора QueueOutCount.

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

Метод обратной связи представляет из себя процедуру какого либо объекта со следующими параметрами:

  • AError – ошибка типа TKRConnectorError, возникшая при обработке запроса. Если в параметре придёт ноль ceOK, то значит, что в процессе обработки запроса ошибок не возникло. Текстовые представления ошибок находятся в константе CONNECTOR_ERRORS_MSG. Также текстовое представление ошибки можно получить при помощи метода коннектора ErrorMsg.
  • APack – указатель на тот же буфер который был передан в методе Send. В этот буфер записывается ответ, поверх запроса.
  • ALength – длина ответа.
  • AData – указатель на дополнительные данные который был передан в методе коннектора Send.

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

На данный момент есть три коннектора основанные на TKRConnector:

  • KRBTConnector – беспроводная связь Bluetooth
  • KRCOMPortConnector – связь через последовательный порт
  • KRTCPConnector – сетевая связь по стеку протоколов TCP/IP

Пример использования

В приведенном ниже примере через коннектор последовательного порта опрашиваются три переменные удаленного устройства по протоколу Modbus RTU. Первая переменная будет типа Word в регистре 0, вторая типа SmallInt в регистре 1 и третья типа DWORD в регистрах 2 и 3. При корректном ответе устройства значения записываются в поля TEdit, а при ошибке в эти же поля записывается текстовое представление этих ошибок. Для синхронизации метода обратной связи с основным потоком используем оконные сообщения Windows.

Пример использование коннектора на основе класса TKRConnector
 
Поделиться:
0
CyberMan Bat
06.08.2021 16:23
 
Добрый день, использовал данный пример для работы с прибором в режиме ASCII команд (IEEE-488) с признаком конца строки, всё прекрасно работало. Пробую на новой версии библиотек - при компилировании вылетают ошибки. Я так понимаю изменились функции по отправке и приему. Большая просьба добавьте для новой версии библиотек аналогичный пример, так же интересует с фиксированным количеством байт в ответе и с признаком конца строки.
Так же заметил что KRCOMPortConnector не работает в режиме аппаратного управления. Для аппаратного режима вроде понял, что нужно использовать KRAsyncComPort, но заставить его работать не получилось т.к. не нашел описания и примеров.
Показать полностью
13
Руслан Кандирал
09.08.2021 13:40
CyberMan Bat
 
Здравствуйте!

Что вы имеете ввиду "с признаком конца строки"? Вы использовали ADelimiter?

Тут "KRCOMPortConnector не работает в режиме аппаратного управления", не совсем понятно, что именно вам нужно? Вам нужно программно работать с сигналами RTS/CTS/DTR/DSR ?
Показать полностью
0
CyberMan Bat
10.08.2021 17:41
Руслан Кандирал
 
С признаком конца строки я имею ввиду вариант с разделителем между пакетами ответа, для
KRCOMPortConnector есть пример:
В новой версии библиотек - это уже не работает, как это нужно переписать и как тоже самое оформлять для KRAsyncComPort ?

По поводу KRCOMPortConnector не работает в режиме аппаратного управления, в свойстве FlowControl настраиваю на Hardware, но компонент видимо ждёт от прибора изменения состояния какой-то линии и выдает ошибку. Подключение делаю со стареньким Agilent 34401A, отправляю ему запрос *IDN? он в ответ отправляет своё название. В терминале Termite всё работает, по сути прибор для ответа ждёт линию DTR, Termite выставляет эти линии сразу при подключении, типа всегда готов слушать. (картинки полностью открываются в отдельном окне)


В терминале 232Analizer я вручную просто после подключения выставлял линию DTR и прибор после запроса сразу отвечал


В связи с этим и вопрос, почему не работает KRCOMPortConnector в режиме аппаратного управления и можно ли с помощью него программно управлять RTS/CTS/DTR/DSR. Если он для этого не предназначен, то тогда нужен пример для отправки и приёма данных через KRAsyncComPort.
Показать полностью
13
Руслан Кандирал
10.08.2021 20:13
CyberMan Bat
 
KRCOMPortConnector и KRAsyncComPort - это компоненты разного назначения.
KRAsyncComPort и KRComPort - это схожие компоненты. Их отличие в том, что первый заточен под работу из основного потока.

KRCOMPortConnector для связи с портом использует KRComPort. И если первые два компонента предназначены просто для управления портом, то задача этого организовать связь через COM порт по принципу запрос-ответ. Да, разделитель в новой версии я убрал, ответ определяется теперь только по таймингам.

В KRCOMPortConnector есть доступ к Handle открытого порта, через него вы можете включать/выключать RTS/DTR

KRAsyncComPort - это переписанный под новую версию Delphi, очень старый компонент ComPort. У меня есть файл справки от него, только в формате hlp, новые версии Windows его не открывают, но есть онлайн просмоторщики или можно его переконвертировать в другой формат

https://kandiral.ru/downloads/CPort.hlp....
Показать полностью
0
CyberMan Bat
11.08.2021 10:56
Руслан Кандирал
 
Спасибо за ответы, "В KRCOMPortConnector есть доступ к Handle открытого порта, через него вы можете включать/выключать RTS/DTR" - вот это было бы очень полезно, не приведете пример, как это сделать?
Показать полностью
13
Руслан Кандирал
11.08.2021 19:06
CyberMan Bat
 
Я ошибся. Handle в KRComPortConnector скрыт.

Внес изменения в файл, добавил функции SetDTR и SetRTS и сделал доступ к Handle порта

https://kandiral.ru/downloads/KRCOMPortC...

но функции SetDTR и SetRTS работаю только после подключения, то есть только в том случае когда Handle порта не равен INVALID_HANDLE_VALUE
Показать полностью
0
Владимиров Константин
01.12.2020 19:26
 
Здравствуйте! Спасибо за ваш труд. Возможно глупый вопрос, но: как заполняются параметры в TForm1.callBack, откуда они попадают в метод?
Показать полностью
13
Руслан Кандирал
01.12.2020 21:03
Владимиров Константин
 
Здравствуйте, Константин!

CallBack - это обратная связь с коннекторам. Мы не можем получить ответ от коннектора сразу, так как нужно дождаться ответа от удаленного устройства. По этому, для получения ответа от коннектора мы ему передаем указатель на нашу функцию CallBack:
После того как коннектор получит ответ от удаленного устройства или при ошибке он вызывает функцию CallBack. То есть коннектор вызывает функцию CallBack и вкладывает в нее параметры:
AError - это код ошибки или ноль, если ошибки нет
APack - указатель на буфер который был передан коннектору. Ответ коннектор вкладывает в тот же буфер в котором вы ему передали запрос. Если буфер был зарезервирован в памяти с помощью процедур New или GetMem, то в CallBack нужно очистить память процедурой Dispose или FreeMem
ALength - длина ответного пакета, который находится в буфере
AData - указатель на дополнительные данные, если нужно. Мы его передаем коннектору просто для того, чтобы он его вернул в CallBack

Нужно всегда учитывать тот факт, что CallBack коннектор вызывает из потока. По-этому нужно позаботится о синхронизации с основным потоком.
Показать полностью

Новости сайта

18.07.2021 14:30
Новая статья по экспорту Google Sheet в MS Excel
Экспорт таблиц Google Sheets в файл MS Excel с помощью Google Script, а также сохранение на Google Drive и отправка на e-mail
30.03.2021 14:53
Обновлен набор компонентов для Delphi
Пакет компонентов для Delphi обновлен до версии от 30.03.2021 г.
14.03.2021 04:54
Обновлен скрипт экспорта Google таблиц в PDF
Добавлены новые возможности при экспорте Google таблиц в PDF файл
22.01.2021 11:45
Обновлен пакет компонентов для Delphi
В пакет компонентов для Delphi было внесено большое количество изменений, касающиеся протокола Modbus и мультиязычности

Популярные статьи

Modbus Slave на Arduino
Реализация клиентской части протокола Modbus RTU и Modbus ASCII для контроллеров Arduino
Инструкция по установке компонентов на Delphi
Подробная инструкция по установке компонентов на Delphi с видео обзором
Экспорт таблиц Google Sheets в PDF файл, на email и на Google диск
Экспорт таблиц Google Sheets в PDF файл с помощью Google Script с последующим скачиванием или сохранением на Google Drive или отправкой на почту
Пример передачи данных по протоколу Modbus на Delphi
Пример передачи данных с контроллера ОВЕН ПЛК100 в программу на Delphi по протоколу Modbus