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

Для отправки запроса используется метод 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 являются настройками данного потока. Функционал потока описывается для каждого коннектора отдельно, но основные задачи во всех случаях одинаковы:
- Установить соединение. Если связь не установлена, то коннектор пытается подключиться с таймаутом указанным в свойстве ConnectTimeout. Если связи нет, то коннектор будет постоянно пытаться подключиться с периодом между попытками указанным в свойстве ReconnectTime. Все запросы до установки связи будут возвращать ошибку ceNotConnection.
- Отправить запрос. Отправка последовательности бай с таймаутом указанным в свойстве WriteTimeout. Если за указанный период данные отправить не удается, то возвращается ошибка ceDataNotSended.
- При необходимости дождаться ответа. Если при вызове метода Send в параметре AWaitResult передано True, то будет ожидаться ответ в течении времени указанного в свойстве WaitRespTime. Общий таймаут ожидания ответа устанавливается в свойстве ReadTimeout, но промежутки по времени между частями входящего пакета не должны превышать значение свойства WaitRespTime. То есть , фактически, если в течении времени WaitRespTime ничего не будет получено, то коннектор будет считать, что ответа нет. Если в методе Send передано значение ARecvLen больше нуля, то коннектор считает, что ответ получен, если длина полученных данных больше или ровна ARecvLen и прекращает ожидание дополнительных данных. Если ответ получить не удалось, то возвращается ошибка ceNoResponse.
- Результат отправить в исходящую очередь.
Исходящая очередь из себя представляет сблокированный упорядоченный список типа 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 |
Так же заметил что KRCOMPortConnector не работает в режиме аппаратного управления. Для аппаратного режима вроде понял, что нужно использовать KRAsyncComPort, но заставить его работать не получилось т.к. не нашел описания и примеров.
Что вы имеете ввиду "с признаком конца строки"? Вы использовали ADelimiter?
Тут "KRCOMPortConnector не работает в режиме аппаратного управления", не совсем понятно, что именно вам нужно? Вам нужно программно работать с сигналами RTS/CTS/DTR/DSR ?
KRCOMPortConnector есть пример:
В новой версии библиотек - это уже не работает, как это нужно переписать и как тоже самое оформлять для KRAsyncComPort ?
По поводу KRCOMPortConnector не работает в режиме аппаратного управления, в свойстве FlowControl настраиваю на Hardware, но компонент видимо ждёт от прибора изменения состояния какой-то линии и выдает ошибку. Подключение делаю со стареньким Agilent 34401A, отправляю ему запрос *IDN? он в ответ отправляет своё название. В терминале Termite всё работает, по сути прибор для ответа ждёт линию DTR, Termite выставляет эти линии сразу при подключении, типа всегда готов слушать. (картинки полностью открываются в отдельном окне)
В терминале 232Analizer я вручную просто после подключения выставлял линию DTR и прибор после запроса сразу отвечал
В связи с этим и вопрос, почему не работает KRCOMPortConnector в режиме аппаратного управления и можно ли с помощью него программно управлять RTS/CTS/DTR/DSR. Если он для этого не предназначен, то тогда нужен пример для отправки и приёма данных через KRAsyncComPort.
KRAsyncComPort и KRComPort - это схожие компоненты. Их отличие в том, что первый заточен под работу из основного потока.
KRCOMPortConnector для связи с портом использует KRComPort. И если первые два компонента предназначены просто для управления портом, то задача этого организовать связь через COM порт по принципу запрос-ответ. Да, разделитель в новой версии я убрал, ответ определяется теперь только по таймингам.
В KRCOMPortConnector есть доступ к Handle открытого порта, через него вы можете включать/выключать RTS/DTR
KRAsyncComPort - это переписанный под новую версию Delphi, очень старый компонент ComPort. У меня есть файл справки от него, только в формате hlp, новые версии Windows его не открывают, но есть онлайн просмоторщики или можно его переконвертировать в другой формат
Внес изменения в файл, добавил функции SetDTR и SetRTS и сделал доступ к Handle порта
но функции SetDTR и SetRTS работаю только после подключения, то есть только в том случае когда Handle порта не равен INVALID_HANDLE_VALUE
CallBack - это обратная связь с коннекторам. Мы не можем получить ответ от коннектора сразу, так как нужно дождаться ответа от удаленного устройства. По этому, для получения ответа от коннектора мы ему передаем указатель на нашу функцию CallBack:
После того как коннектор получит ответ от удаленного устройства или при ошибке он вызывает функцию CallBack. То есть коннектор вызывает функцию CallBack и вкладывает в нее параметры:
AError - это код ошибки или ноль, если ошибки нет
APack - указатель на буфер который был передан коннектору. Ответ коннектор вкладывает в тот же буфер в котором вы ему передали запрос. Если буфер был зарезервирован в памяти с помощью процедур New или GetMem, то в CallBack нужно очистить память процедурой Dispose или FreeMem
ALength - длина ответного пакета, который находится в буфере
AData - указатель на дополнительные данные, если нужно. Мы его передаем коннектору просто для того, чтобы он его вернул в CallBack
Нужно всегда учитывать тот факт, что CallBack коннектор вызывает из потока. По-этому нужно позаботится о синхронизации с основным потоком.