Российский производитель и разработчик сертифицированного измерительного оборудования с 1987 года


LTR114,51,27: вопросы по движению кадров из модуля до клиента

Вы не вошли.

 Поиск | Регистрация | Вход 

14.10.2025 17:43:33
#1

Участник
Здесь с 07.10.2025
Сообщений: 7

LTR114,51,27: вопросы по движению кадров из модуля до клиента

Добрый день,

Дано:
    1. LTR-EU-16-1 16-местный крейт
    2. Модуль LTR114 с поверкой
    3. Модуль LTR27 c поверкой
    4. Модуль LTR51 с поверкой
    5. Субмодуль H-27I-20
    6. Субмодуль H-27T
    7. Субмодуль H-27U-10
    8. Субмодуль H-51FL
    9. Работаем в одном из Debian подобных дистрибутивов Linux, ядро сконфигурировано на частоту 250HZ т. е. Один тик ядра = 4мс.

Пишем программу, которая с настраиваемой частотой одновременно собирает данные со всех модулей.
Чтобы написать все корректно, вероятно, нужно понимать, как в целом двигаются данные от модулей до клиента(нашей программы).

Насколько я понял из разных документаций, примерно по такому сценарию двигаются данные наших модулей(LTR114, LTR,27, LTR51).
1. После конфигурации модулей и запуска сбора данных(LTR*_Start()), модули начинают генерировать данные(которые приходят в ltrd и позже к клиенту в виде слов).
Для LTR114 единица данных, насколько я понял - это данные только с одного из всех каналов, которые мы опрашиваем.
Для LTR27 единица данных - это полноценный кадр, то есть, грубо говоря, снимок данных со всех 16 физ.каналов модуля/сабмодуля.
Для LTR51 единица данных - это параметры частотного сигнала {N,M}, которые генерятся с частотой F_Base.
2. Поскольку у наших модулей нет внутреннего буфера, то далее данные со всех модулей сразу же отправляются в единый FIFO буфер, расположенный в контроллере крейта.
3. Далее данные из FIFO буфера отправляются(через ethernet кабель в нашем случае) в ltrd, который в свою очередь фассует данные по своим внутренним буферам, созданным под каждый зарегестрированный модуль.
4. В это время клиент должен откачивать данные из ltrd буферов путем цикличного вызова функции LTR*_Recv(..., timeout_value).

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

Если движение данных выше в целом описано корректно, то есть следующие вопросы:
а) я правильно понимаю, что отправка данных из FIFO очереди крейта в ltrd происходит по мере поступления данных из самих модулей?
То есть, если данные пришли от модуля и если очередь пуста, то данные тут же будут отправлены в ltrd.
Если очередь не пуста, данные будут отправлены сразу же после того, как предыдущие данные будут отправлены.

б) насколько я понял, модули, которые мы используем + сам крейт - не являются оборудованием реального времени, соответственно, во время обработки данных внутри крейта(в том числе внутри модулей) возможны некоторые "запоздания".
Есть ли возможность определить максимальные опоздания в обработке данных внутри крейта(сеть, ltrd не берем в расчет)?
Например, если контроллер крейта "тикает" каждые 4мс, то быть может и максимальное опоздание может быть +4мс..?

в) опоздания в сети измерим самостоятельно. опоздания в работе ltrd, судя по коду - минимальные(все работает в одном потоке, но зато без каких-либо блокировок).

г) есть ли возможность определить, сколько слов/кадров/данных в данный момент находится в буфере? Нормально ли использовать информацию о буфере из функции LTR_GetModuleStatistic()?
По идее, если бы постоянно можно было иметь актуальную информацию о ltrd буфере модуля, то тогда бы работа в цикле выглядела бы так:
1. получить кол-во слов, насколько заполнен буфер
2. LTR*_Recv(, <size = кол-во слов из пункта 1>)
Была попытка реализовать что-то подобное, однако это не привело к успеху, потому что в большинстве случае функция статистики по модули выше говорила, что буфер абсолютно пуст(это также подтверждалось в выводе `ltrctl mstat <номер_слота>`). Помимо этого, мы заметили, что статистика по модулю в целом немного "запаздывает"(после 30минутной сессии мы перестали выгребать данные из ltrd буфера, при этом LTR*_Stop не был вызван. В это время `ltrctl mstat <slot>` все еще показывал, что данные отправляются клиенту, что неправда. Через примерно 10-15секунд `ltrctl mstat <slot>` начал показывать актуальное состояние).

д) какие основные принципы нужно соблюдать при цикличном сборе данных из ltrd буфера?
правильно ли я понимаю, что основной алгоритм примерно такой:
1. измерить время между предыдущей и текущей итерацией цикла;
2. на основе измерения из пункта 1 высчитать "потенциальное" кол-во кадров/данных, которое модуль должен сгенерить за это время;
3. вызвать LTR*_Recv() со значениями size = колву данных из пункта 2. Помимо этого, необходимо выставить таймаут такой величины, чтобы он покрывал всевозможные запоздания;

е) если принцип реализации цикличного сбора выше корректен, то есть ли какие то рекомендации по установке таймаута на сбор данных(LTR*_Recv()) ?
Быть может есть какое-то минимальное значение, которое учитывает потенциальные опоздания внутри крейта?
Мы отправляли письмо с таким(и другими) вопросом и нам для частоты опроса 10Гц(наша программа собирает данные каждые 100мс) рекомендовали выставить таймаут в 1 секунду.

15.10.2025 04:57:07
#2

Сотрудник "Л Кард"
Здесь с 17.04.2014
Сообщений: 1,354

Re: LTR114,51,27: вопросы по движению кадров из модуля до клиента

По поводу описания передачи данных, то в принципе корректно, только во фразе:

Для LTR114 единица данных, насколько я понял - это данные только с одного из всех каналов, которые мы опрашиваем.
Для LTR27 единица данных - это полноценный кадр, то есть, грубо говоря, снимок данных со всех 16 физ.каналов модуля/сабмодуля.
Для LTR51 единица данных - это параметры частотного сигнала {N,M}, которые генерятся с частотой F_Base.

не совсем понятно, что имеется ввиду под "единица данных". Единицей передачи данных независимо от модуля является 32-битное слово (которые принимаются в LTRxxx_Recv()). Отличие в том, что в LTR114 во первых одному отсчету соответствует 2 слова, во вторых, так как это модуль с коммутацией каналов и измерения происходят последовательно, то он передает по одному отсчету (2 слова), как только очередные данные будут готовы, т.е. данные будут передаваться по два слова равномерно с частой АЦП. В LTR27 одному отсчету соответствует одно слово, при этом в этом модуле каналы АЦП работают параллельно и модуль сразу выдает все 16 слов (по одному отчету на канал) раз в заданный период дискретизации АЦП. В LTR51 передача идет аналогично LTR27, но одному отсчету соответствует два слова, со значениями M и N. Но все это передается в общий буфер и при передаче в ПК один кадр даже переданный одновременно от модуля, как для LTR27? может быть разбит например на разные пакеты TCP, в середину кадра попасть данные другого модуля если придут в момент передачи слов кадра и т.п.

a) идея в принципе правильная, правда при передаче по Ethernet это все немного сложнее. Корректнее сказать, что данные поступают в общий буфер в крейте, прошивка процессора крейта на сколько я помню раз в 1 мс проверяет наличия новых данных в FIFO и при их наличии ставит их на передачу по интерфейсу, в Вашем случае через TCP по Ethernet. Далее уже действуют алгоритмы передачи самого TCP, на которые влияет реализация TCP с обоих сторон соединения, в частности Алгоритм Нейгла  (данные передаются либо когда все отправленные были подтверждены другой стороной, либо накопился целый новый пакет для отправки по TCP), подверждения от ПК  так же могут при этом быть отложены и не переданы сразу (delayed ACK) и т.п.

б) Если говорить о задержках в модулях и в крейте до попадания данных в FIFO буфер крейта, то тут они будут либо фиксированы для каждого типа модуля, либо иметь небольшой дребезг, но явно они не измерялись для каждого режима работы каждого модуля. Но они не должны превышать единиц мс и остальные факторы по идее должны иметь большее значение при обработке данных на ПК.

в)  Задержки в сети измерить выглядит не так просто, если под ними подразумевать не только физическое время передачи пакета, но и задержки в планировании отправки пакетов сетевого стека с обоих сторон соединения. Про ltrd так, но опять же ОС общего назначения вполне имеет право вносить задержки при переключении задач на выполнения ltrd, при передаче программе сигнала готовности данных принятых по сети в сокете и т.п., и они в общем случае не нормированы, хотя и в частном случае малозагруженной системы могут быть минимальными
г) помимо буфера ltrd нужно иметь ввиду, что обмен ltrd с клиентом также выполняется через локальные сокеты, у которых тоже есть свой внутренний буфер. Если в нем есть место, то ltrd сразу принятые слова записывает в сокет на передачу клиенту и они в собственно буфере данных модуля в самом ltrd  не задерживаются. Заполняться буфер будет в том случае, если сокет клиента не может принять на передачу данные из-за того, что его буфер заполнен. Таким образом действительно, если клиент своевременно откачивает данные, то этот буфер должен быть пуст или минимально заполнен.
В теории (если это действительно нужно, см. дальше) определить число готовых к приему слов по статистике можно, но если использовать счетчик принятых от модуля слов (wrd_recv). Т.е. можно перед LTRxxx_Start() прочитать это значение, далее с учетом того, что по крайней мере для используемых у Вас модулей, по вызову Start происходит посылка одной команды с одним ответом (для LTR114 предполагается, что начальная калибровка уже выполнена до старта), то прибавить к этому числу 1 и взять это значение за начало отчета. Далее проверяя статистику и вычисляя разницу между новым wrd_recv и взятым за начало отсчета, можно понять, сколько слов данных было принято от модуля. При этом нужно также завести счетчик принятых слов клиентом (т.е. Вашей программой) увеличиваемый при каждом успешном Recv на количество принятых слов. Соответственно разница числа принятых слов от модуля и принятых слов клиентом и будет числом принятых ltrd, но не считанных клиентом слов, т.е. той самой общей заполненностью буферов сокета клиента и буфера модуля в ltrd.

д) Подходы могут быть разные... С моей стороны самым простым и удобным является выделение под каждый модуль потока, и в нем реализовывать принцип, который и приводится в консольных примерах на модуль. Т.е. исходя из интервала обработки и настроенных частоты сбора и прочих настроек можно получить, сколько слов мы должны обработать за один цикл программы, а далее вызывается в этом потоке Recv на этот размер с заведомо большим таймаутом (время цикла плюс несколько секунд). В этом случае при корректной работе Recv ожидает заданное число слов и как только они дойдут до клиента, Recv вернет управление (по сути то, что Вы пытаетесь сделать). Таймаута функция при штатной работе не дожидается (т.к. завершение работы функции выполняется по тому событию, которое было первым - пришло нужное число данных или истек таймаут), и служит только как указание через сколько выйти из функции в случае каких-либо ошибочных ситуациях, и завышенное значение негативно на нормальную работу не влияет. Далее уже идет ProcessData, возможно какая-то своя обработка и далее при необходимости передача полученного блока данных за цикл в другой поток для обработки/сохранения в зависимости от задачи. После переход к новому циклу ожидания. В этом случае время цикла обработки определяется временем прихода нужного числа данных, нет требования измерять время или заполненность буфера вручную и если время обработки меньше времени цикла, то гарантирует своевременную откачку данных. Так как на каждый модуль свой поток, то то, что он спит, ожидая новую порцию данных внутри Recv, не является проблемой, все равно ему нечего выполнять, пока нет новых данных. Если есть желание принимать данные всех модулей в одном потоке, тогда общий поток не должен зависать в Recv, тогда имеет смысл получать число непрочитанных слов через статистики описанным выше методом, а при потоке на модуль не уверен в целесообразности этого...
e) ну тут опять же зависит от Вашей программы, если как описано выше Recv используется для ожидания новых данных, то таймаут может быть взят с большим запасом на несколько секунд больше интервала сбора и это ничему не вредит, в варианте со статистикой он может быть и небольшим (в пределах секунды или десятков/сотен мс), тут только задержки самой ОС могут влиять, хотя опять же увеличение его не влияет негативно на штатную работу.

Контакты

Адрес: 117105, Москва, Варшавское шоссе, д. 5, корп. 4

Многоканальный телефон:+7 (495) 785-95-25

Письма и запросы: lcard@lcard.ru
Отдел продаж: sale@lcard.ru
Техническая поддержка: support@lcard.ru

Время работы: с 9-00 до 19-00 мск