Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.99/103: Рейтинг темы: голосов - 103, средняя оценка - 4.99
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1

Правильный подход обмена данных с устройствами через COM-порт. Целостность пакетов и производительность обмена

26.02.2018, 23:52. Показов 21327. Ответов 71
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую вас, коллеги!
Хочу с вами посоветоваться, ибо мне кажется, что я делаю это не совсем правильно, либо что-то не учёл...
Делаю обмен данными с устройством через COM-порт (RS-232) по алгоритму: послал команду в порт (через .Write(...)), поставил задержку (Threading.Sleep(200)), читаю ответ (через .Read(...)). И вот тут меня смущает эта самая задержка. Если ответные пакеты приходят большие (ну например более 60 байтов), то что бы вычитать весь буфер, этой задержки как буд-то не хватает, пакет получаю не весь. Если увеличиваю задержку, то буфер весь вычитывается, однако, во-первых, буфера могут быть разной длины, и для каждого так подбирать задержки - не реально, во-вторых, если с устройством есть возможность обмениваться на разных скоростях (бод), это вообще дур-дом и всякая актуальность, например, выбора более высокой скорости обмена теряется, т.к. задержки будут одинаковыми, если их так железно задавать... В-третьих, когда такая функция обмена, с железно заданным Sleep'ом (подобранным на вскидку, чтоб не потерять большие пакеты), в цикле, например, ведёт обмен, то для более мелких пакетов, такая задержка, опять же, становится не актуальной, т.к. увеличивается драгоценное время простоя, и обмен происходит дольше, чем мог бы быть... Вот по этому я и задаюсь вопросом: как в таком случае правильно следует поступать? Не ужели чем длиннее ответный пакет, тем дольше его нужно ждать, чтоб он вычитался? Как избежать таких диких задержек? У кого был подобный опыт с обменом по СОМ-порту с устройствами, подскажите, пожалуйста, или поделитесь идеями, кто хотя бы понял суть вопроса.

P.S. слышал что-то про подход асинхронного чтения данных из порта, но пока не понял что это и с чем это едят, и мой ли это вообще случай. Если да, то расскажите про такой подход, кто в курсе вообще. Только по понятнее пожалуйста, с примерами, если можно, а то про асинхронные приёмы работы пока вообще не в теме... Особо не доводилось использовать.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.02.2018, 23:52
Ответы с готовыми решениями:

Организация обмена данными через LPT-порт
разработайте программу определения адреса LPT - порта и вывода информации через LPT - порт, При этом светодиоды стенда должны отображать: ...

Функция для обмена HEX данными через COM порт
Помогите реализовать функцию работы с COM портом в консольном приложении. Алгоритм такой: Слушаем порт и при появлении HEX команды,...

Синхронизация обмена данных через LiFi
Здравствуйте. Никак не могу придумать способ реализации обмена через свет. Алгоритмом все вроде бы хорошо: "отмигиваем"...

71
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
07.04.2018, 18:54
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Cha1000000 Посмотреть сообщение
я стремлюсь максимально, на сколько это возможно, уменьшить время, за которое будет проходить обмен.
У всех разные цели. Я предпочел стабильность выгадыванию миллисекунд (как-никак, моих пользователей интересует не лишняя миллисекунда времени, а стабильность программы).

Добавлено через 1 минуту
Цитата Сообщение от Rius Посмотреть сообщение
посылки у вас были заранее известного объёма?
Ну да, у меня заранее известный протокол обмена (то есть я всегда знаю, что я отправляю и что должно прийти в ответ на такой запрос).
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
07.04.2018, 18:56
insite2012, ну вот, если вы точно знаете, сколько должно прийти байт в ответ, это в корне меняет проблему...
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
07.04.2018, 18:59
Rius, кстати, было бы интересно как-нибудь декомпилировать C-шную библиотеку для обмена и посмотреть, как там это реализовано. Я вот сейчас пишу программу, но там весь обмен как раз в C-шной либе скрыт, а я только через импортом пользуюсь методами оттуда.

Добавлено через 1 минуту
Цитата Сообщение от Rius Посмотреть сообщение
точно знаете, сколько должно прийти байт в ответ
Да, знаю. Но вот когда они придут (и придут ли все сразу, или кусками, или не придут вообще)-в том и проблема. И естественно, что, например, через живой COM ответ придет в разы быстрее, чем по БТ каналу. Потому и проходилось мудрить...
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
07.04.2018, 19:00
Если библиотека сделана по канонам, то скорее всего оно описано в известном документе Serial Communication in Win32.

Добавлено через 1 минуту
Цитата Сообщение от insite2012 Посмотреть сообщение
Да, знаю. Но вот когда они придут (и придут ли все сразу, или кусками, или не придут вообще)-в том и проблема. И естественно, что, например, через живой COM ответ придет в разы быстрее, чем по БТ каналу. Потому и проходилось мудрить...
А как минимизировать время ожидания, если байты так и не пришли? Подсчитывать время от начала ожидания в цикле?
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
07.04.2018, 19:05
Цитата Сообщение от Rius Посмотреть сообщение
скорее всего оно описано в известном документе
Так-то да, но там тоже свой, жестко определенный протокол обмена. И вот как они реализовали его там-пока вопрос.
Хотя он больше для интереса, в общем я просто беру и использую импорт из тех либ.

Добавлено через 1 минуту
Цитата Сообщение от Rius Посмотреть сообщение
как минимизировать время ожидания, если байты так и не пришли?
Rius, мы вроде это обсуждали в какой-то теме, и я там даже выкладывал несколько своих вариантов реализации. У меня исходников не осталось (тогда я Гитом еще не пользовался), может вы вспомните ту тему?
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
07.04.2018, 19:09
Чтение из COM-порта, странная ошибка ?

Добавлено через 2 минуты
Мне всё это пришлось выдумывать из-за приборов с HART, которые работают на 1200 бодах. Если пакет в ответ не пришёл, напрасно потрачена секунда или две. А если надо проверить наличие 15-ти приборов на линии, это ппц...
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
07.04.2018, 19:13  [ТС]
Цитата Сообщение от insite2012 Посмотреть сообщение
У всех разные цели. Я предпочел стабильность выгадыванию миллисекунд (как-никак, моих пользователей интересует не лишняя миллисекунда времени, а стабильность программы).
Ну да, не зная подробностей целей, может показаться, что это не столько важно и не над чем тут заморачиваться... Но, для лучшего понимания идеи и целей, кратко опишу суть.
У моей программы, общающейся с устройством, есть как одиночные команды, с одиночными ответными буферами на них, так и команды-запросы, на которые устройство циклом в 500, 2000, и даже 11000 итераций выдаёт данные, ну скажем, по 180-250 байт за одну итерацию. И вот когда пользователю нужно считать из устройства его базу, например, в 6000, или тем более в 11000 (это пока максимум) полей (строк), раньше в алгоритме обмена со слипом, это занимало около 40 минут... +/-
А вот с методом двух тайм-аутов это время уже сократилось до 5 минут (тоже примерно. точно сейчас не припомню). Но при этом методе, как уже неоднократно упоминал, на ПК разных мощностей, эти показатели разнятся...
В общем в моём случае, пользователям (хотя скорее больше моему начальству) не особо хочется долго ждать выполнения чтения столь не малого кол-ва данных. Особенно, если за время работы с программой, это нужно повторять неоднократно...
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
07.04.2018, 19:15
Rius, нет, значит не там... Там всего один вариант, а я точно помню, что экспериментировал по разному. Сейчас залез в исходники, остался только метод с комментом Вариант №1, остальные я стер. Попробую поискать, точно помню, что как минимум три варианта было. И да, ваш вариант я пробовал. Он работает побыстрее чем мой, но опять же, нет той стабильности. А мне это важно, мне за это деньги платят)))
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
07.04.2018, 19:16
Cha1000000, а объём посылки, которая должна прийти в ответ на запрос, вам заранее известен?
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
07.04.2018, 19:22  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
а объём посылки, которая должна прийти в ответ на запрос, вам заранее известен?
Да, у меня так же, как и у insite2012 , работа программы осуществляется по чёткому протоколу обмена. В котором на каждую команду прописано какой длины будет ответ.
И в принципе, согласно протоколу, в ответной посылке на все команды, второй байт - это и есть длина пакета.
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
07.04.2018, 19:23
Cha1000000, тогда попробуйте, что говорит insite2012.
Я принципиально рассчитываю на неизвестную длину пакета, что в прогах на МК, что на ПК. А это немного иное.
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
07.04.2018, 19:25
Rius, да, кстати, вот кусок кода из промышленной либы (на шарпе, которая использует импорт). Как видите, при работе с портом многие не гнушаются использованием слипов)))
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public virtual ProtocolResult ReadWithAttempts(bool high_byte_first, uint ui32Address, ushort ui16Size, ref byte[] pui8Buffer, CommandCode BankAndFlags, bool enable_sector_select, ref ushort curr_sector_idx) {
            for (int i = 0; i < 4; i++) {
                if (BankAndFlags != CommandCode.BANK_0) {
                    if (DaasAPI.SendExternalRead(this.m_i16PortNr, ui32Address, ui16Size, ref pui8Buffer, BankAndFlags) == GeneralResult.DAAS_OK) {
                        return ProtocolResult.OK;
                    }
                    Thread.Sleep(70);
                }
                else if (enable_sector_select) {
                    if (this.memory_reader.Read(this.m_i16PortNr, ui32Address, ui16Size, ref pui8Buffer, ref curr_sector_idx, high_byte_first)) {
                        return ProtocolResult.OK;
                    }
                }
                else {
                    if (DaasAPI.SendRead(this.m_i16PortNr, ui32Address, ui16Size, ref pui8Buffer) == GeneralResult.DAAS_OK) {
                        return ProtocolResult.OK;
                    }
                    Thread.Sleep(70);
                }
            }
            return ProtocolResult.READ_ERROR;
        }
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
07.04.2018, 19:28
Цитата Сообщение от insite2012 Посмотреть сообщение
из промышленной либы ... при работе с портом многие не гнушаются
Тут где-то показывали код из программы для трейдинга на бирже, то ли очень популярной, то ли от очень крутой фирмы. И там - лютый говнокод. Так что, это не показатель
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
07.04.2018, 19:33
Цитата Сообщение от Rius Посмотреть сообщение
это не показатель
Это понятно. Но просто надо четко понимать цель: одно дело, когда пишешь для себя, исследуешь что-то и другое, когда пишешь для массового применения. Естественно, во втором случае мы просто физически не сможем проверить программу на множестве вариантов конфигураций ПК, где она, возможно, будет применяться. Поэтому приходится чем-то жертвовать, идти на компромиссы ради стабильности программы.
0
07.04.2018, 19:35

Не по теме:

Цитата Сообщение от insite2012 Посмотреть сообщение
кусок кода из промышленной либы
Ога, я тоже сталкивался с "примышленными либами". Такого ужаса еще поискать. Качество ниже плинтуса, и кучи (не просто кучи, а КУЧИ) слипов. Я думаю это связано с тем, что железятники - обычно не программисты и пишется это ПО на коленке, абы було.

0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
07.04.2018, 19:38  [ТС]
Цитата Сообщение от insite2012 Посмотреть сообщение
Поэтому приходится чем-то жертвовать, идти на компромиссы ради стабильности программы.
Вот и я это пытаюсь начальству объяснить... Но они что-то пока в скорость упёрлись и всё тут... Типа у конкурентов аналогичное устройство "за 2 (или 5) минут выгружает базу в 20000 строк" со слов начальника...
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
07.04.2018, 19:41
insite2012, да я только за. Пусть ТС пробует по-вашему. С известным размером пакета сам бог велел.

Цитата Сообщение от Storm23 Посмотреть сообщение
что железятники - обычно не программисты
Да, у железячников свой, особый взгляд на программирование. Заточенный на железо. В работе десктопных ОС им в большинстве своём разбираться некогда и незачем. Вот и получается то, что получается.
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
07.04.2018, 19:49
Cha1000000, вы все-таки попробуйте для начала просто подход, цикл в 10 итераций с задержкой по 50 мс и проверкой буфера порта при каждой итерации. В принципе, это должно работать как и обычный таймаут в 500 мс для порта.
Типа того что ниже. И потом уже посмотрите, насколько дольше это работает.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected override byte[] GetResponse(byte[] request, int bytesToRead, int requestCount = 3, int milliseconds = 0) {
            //Внешний цикл отправки запроса
            for (int i = 0; i < requestCount; i++) {
                //Очистка буферов порта
                port.DiscardInBuffer();
                port.DiscardOutBuffer();
 
                //Отправка полного блока в порт для записи
                port.Write(request, 0, request.Length);
 
                //Внутренний цикл ожидания данных в буфере порта
                for (int j = 0; j < 10; j++) {
                    Thread.Sleep(70);
                    if (port.BytesToRead == bytesToRead) {
                        byte[] response = new byte[bytesToRead];
                        port.Read(response, 0, bytesToRead);
                        return response;
                    }
                }
            }
            return null;
        }
Добавлено через 5 минут
Цитата Сообщение от Rius Посмотреть сообщение
Вот и получается то, что получается.
Ну да, та программа, кусок кода из которой я показал, в плане работы с железом (мк) просто удивительна. Сделана очень хорошо и со знанием дела (я бы так не смог, нужны хорошие знания работы с мк, коими я не обладаю). А вот в плане интерфейса-это просто тихий ужас. Если без подробностей-разработчики попытались сделать нечто вроде а-ля WPF, но все это на формах, да еще и на 2-м .NET-е. Жесть конечно вышла та еще, косяков куча (с размерами окон, не влезающими надписями и прочим).
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
07.04.2018, 19:50
Цитата Сообщение от Cha1000000 Посмотреть сообщение
Типа у конкурентов аналогичное устройство "за 2 (или 5) минут выгружает базу в 20000 строк" со слов начальника...
Не знаю поможет вам или нет в вашей проблеме, но я когда-то тоже сталкивался с медленной работой COM порта, и выяснилось, что это проблема дотнетовского SerialPort. После этого я всегда использовал другой сериал порт, вот типа такого https://github.com/AnthonyNyst... ommBase.cs
Он работает значительно быстрее (если по ссылке не разберетесь могу скинуть рабочие исходники).
2
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
07.04.2018, 19:57
Цитата Сообщение от Storm23 Посмотреть сообщение
другой сериал порт
Обёртка над тем самым трушным WinAPI.
Жаль лицензия не указана.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
07.04.2018, 19:57

Виртуальный COM-порт на STM32, скорость обмена.
Всем привет. Прошу помощи :) Экспериментирую с USB - CDC-класс, стоит задача передать данные в хост на максимально возможной скорости....

Копирование через буфер обмена из 2х полей формы и вставка данных в другую форму
Всем очень добрый день! Подскажите пожалуйста, можно ли реализовать одновременное копирование данных из 2-х полей формы и вставку этих...

COM-порт, работа с двумя формами и одним буфером обмена
Доброго времени суток. Обращаюсь с вопросом, который повторяли, наверно, сотню и один раз. Но ответа, подходящего под специфическую...

Запретить вставку текста в TEdit из буфера обмена через Ctrl+V или через контекстное меню
Добрый день! Есть такой вопрос: Что нужно сделать, чтобы в TEdit не было возможности вставить текст из буфера обмена при помощи CTRL+V...

Обмена информации через сокеты
Здравствуйте, уважаемые форумчани. Пожалуйста, помоги сделать эту задачу: В среде Visual C++ написать клиентскую и серверную программы...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
сукцессия 30. Фосфорный и азотный замки по "честному" закону лимитирования Либиха
anaschu 16.07.2026
Основные достижения за последние дни 1. Механизм отложенного высвобождения фосфора Добавлен специальный пул для медленного разложения меланизированных гиф ЕСМ Реализована разная скорость. . .
Запрет пометки на удаление и отмены проведения
Maks 16.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "ПутевойЛист" разработанного в КА2. Задача: запретить помечать на удаление и отменять проведения путевого листа при условии, если он сдан. . .
Как надо было делать правильно - вообще не слушать ИИ, его дело - текст.
Hrethgir 15.07.2026
А вообще надо было делать не так, чтобы не исправлять ошибку https:/ / www. cyberforum. ru/ blogs/ 223907/ 10996. html , правильно было : удалил кнопку, а потом добавил её. Всё это стресс конечно. Почему?. . .
Знаете, от чего появляется стресс?
kumehtar 15.07.2026
Стресс появляется оттого, что вы, зная как поступить правильно, делаете наоборот. Ларри Уингет
Нас бьют, а мы крепчаем? Какая чушь!
kumehtar 15.07.2026
Вот это вот бытующее мнение, что человек меняется только под действием проблем, всегда считал вредоносным. Поверь, от проблем у людей появляются не изменения, а нервное расстройство и ПТСР. А. . .
сукцессия 29. Переход от одних деревьев на другие делать более или менее вероятностным?
anaschu 12.07.2026
Насколько смена типов микоризы — исключительное событие в двухвековой сукцессии? Оценка вероятности в пространстве параметров В текущей версии модели успешно реализован ключевой механизм. . .
сукцессия 27. Думаю, как переделывать уже написанную статью с планами на сукцессию.
anaschu 12.07.2026
Анализ соответствия модели требованиям Реализованные компоненты: Механизм закисления почвы через протонную помпу Конкуренция между типами микориз pH как триггер сукцессии C/ P соотношение. . .
Сукцессия 26. Мат модель создана.
anaschu 12.07.2026
Модель смены растительных сукцессий посредством управления грибами работает внутри небольшой ячейки почвы, восстанавливающейся после пожара, где ненадолго бывшее царство хвойных снова захватили. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru