382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
1

Откуда при чтении из COM-порта берутся 99 байт?

23.12.2014, 20:46. Показов 2270. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Этот отрывок кода взят из рабоче программы, которая работает около 2-х лет и судя по отзывам - успешно. Она написана на С++, я изменил только синтаксис, чтобы было понятно Дельфистам.
Начало я опускаю - там ничего интересног (настройка DCB, установка тайм-аутов, очистка буфера приёма). А вот в этом месте и начинаются "чудеса":
Например, мне надо принять 100 байт. Я устанавливаю nBufPRM равным 100, передаю запрос и получаю свои 100 байт. Код, приведённый ниже, работает таким образом:
Функция WaitCommEvent() устанавливает ожидаемое событие - приём символа.
Функция WaitForSingleObject() переводит объект в несигнальное состояние, из которого переход в сигнальное состояние произойдёт сразу же при получении первого байта данных.
Далее, если всё нормально, функция ClearCommError() возвращает количество принятых байт и это кол-во будет прочитано, т.е мою исходную установку nBufPRM:=100 заменяет на nBufPRM:= comstat.cbInQue.

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
WaitCommEvent(hCom,&maska,&ovr); // Ожидкние события (приёма байта).
signal:= WaitForSingleObject(ovr.hEvent, 125); // Приостановить поток до прихода первого байта.
if signal=WAIT_OBJECT_0 then   // Если получен байта данных.
begin
   if(GetOverlappedResult(hCom,ovr,A,true) txen // Успешно ли завершилась операция ожидания символа.
    begin       
       if (maska and EV_RXCHAR)=EV_RXCHAR then // Если получен символ.
        begin       
            ClearCommError(hCom, A, comstat); // Узнать кол-во принятых байтов.
            nBufPRM:= comstat.cbInQue;
            if nBufPRM then // Если действительно есть байты для чтения.
            begin
                ReadFile(hCom,BufPRM,nBufPRM,A,ovr);// Приём.
            end;
        end;
    end;
end;
Но после приёма первого символа по всей логике в буфере будет только один байт, а почему в результате считывается 100 байт? Каким образом считывается ещё 99 байт? Если бы не строка "nBufPRM:= comstat.cbInQue;", то всё было бы понятно.
Вот исходник: Kod_C++.rar
У меня только единственное объяснение - может не корректно происходит переход в сигнальное состояние и за это время успевают проскочить оставшиеся 99 байт... У кого и какое ещё есть мнение по этому поводу?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.12.2014, 20:46
Ответы с готовыми решениями:

Чтение из COM порта, При чтении из порта зависает read()
Каждому рано или поздно приходится программировать com порт. Вот и мой черед пришол. Я ужу умею:...

Откуда берутся символы при ошибках?
Иногда,когда программа содержит код с ошибками,начинают выскакивать какие-то колдунские...

Откуда берутся пробелы при вводе символов с использованием функции _getch()?
Недавно начал использовать функцию _getch() для того, чтобы вводить нужную строку целиком, но...

Откуда берутся лишние символы при создании массива с помощью оператора new?
Здравствуйте) Наблюдаю странное поведение оператора new. ifstream is;...

16
Пишу на Delphi...иногда
1423 / 1278 / 286
Регистрация: 03.12.2012
Сообщений: 3,914
Записей в блоге: 5
23.12.2014, 21:37 2
Цитата Сообщение от shyub Посмотреть сообщение
Функция WaitForSingleObject() переводит объект в несигнальное состояние, из которого переход в сигнальное состояние произойдёт сразу же при получении первого байта данных
или по прошествии 125 мс после установки несигнального, но дальнейшая обработка произойдет, если перешло в сигнальное состояние - сработало требуемое событие (WaitForSingleObject == WAIT_OBJECT_0), далее ожидание асинхронной процедуры, которое не закончится, пока не будет получен результат (GetOverlappedResult с bWait == true), причем значение переменной A (_Out_ LPDWORD lpNumberOfBytesTransferred) тут, скорее всего, и будет равно 100 байтам, а далее comstat.cbInQue также должен быть равен 100 и т.д. (стоит проверить, но версия такая), если все именно так - как вариант отказаться от асинхронной работы с портом и перейти на синхронную
0
пофигист широкого профиля
4658 / 3093 / 854
Регистрация: 15.07.2013
Сообщений: 17,842
24.12.2014, 02:44 3
Цитата Сообщение от shyub Посмотреть сообщение
Этот отрывок кода взят из рабоче программы, которая работает около 2-х лет и судя по отзывам - успешно. Она написана на С++, я изменил только синтаксис, чтобы было понятно Дельфистам.
А можешь объяснить вот эти строчки "чтобы они были понятны Дельфистам" (ну т.е. существам более низкого уровня).
Delphi
1
2
3
4
            nBufPRM:= comstat.cbInQue;
            if nBufPRM then // Если действительно есть байты для чтения.
            begin
                ReadFile(hCom,BufPRM,nBufPRM,A,ovr);
Добавлено через 2 минуты
С форума Си-шников тебя выгнали поганой метлой?
0
382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
24.12.2014, 09:27  [ТС] 4
Цитата Сообщение от cotseec Посмотреть сообщение
дальнейшая обработка произойдет, если перешло в сигнальное состояние - сработало требуемое событие (WaitForSingleObject == WAIT_OBJECT_0), далее ожидание асинхронной процедуры, которое не закончится, пока не будет получен результат (GetOverlappedResult с bWait == true)
Согласен, но приём первого байта - это тоже результат. Следовательно после приёма первого байта успешно отработает ClearCommError() и перестроит функцию чтения ReadFile() на приём только одного байта nBufPRM:= comstat.cbInQue. В этом и заключается весь парадокс.
Цитата Сообщение от northener Посмотреть сообщение
А можешь объяснить вот эти строчки
Не могу, т.к. изначально задано nBufPRM:=100, а здесь происходит подмена nBufPRM:= comstat.cbInQue;.
Цитата Сообщение от northener Посмотреть сообщение
существам более низкого уровня
...извиняюсь, если Вас это обидело...
Цитата Сообщение от northener Посмотреть сообщение
С форума Си-шников тебя выгнали поганой метлой?
Где-то слышал, что повышенная обидчивость, агрессивность - признаки психического растройства. Вам бы лечиться...
0
Пишу на Delphi...иногда
1423 / 1278 / 286
Регистрация: 03.12.2012
Сообщений: 3,914
Записей в блоге: 5
24.12.2014, 14:04 5
Цитата Сообщение от shyub Посмотреть сообщение
приём первого байта - это тоже результат. Следовательно после приёма первого байта успешно отработает ClearCommError()
не забывайте про GetOverlappedResult, которая не завершится (bWait == true), пока не поступит вся посылка, а затем уже обрабатывается ClearCommError и т.д.
пошлите 1 байт - примите 1 байт, пошлёте 100 байт - примете 100 байт
Цитата Сообщение от shyub Посмотреть сообщение
ClearCommError() возвращает количество принятых байт и это кол-во будет прочитано, т.е мою исходную установку nBufPRM:=100 заменяет на nBufPRM:= comstat.cbInQue.
дабы дальше не гадать на кофейной гуще - посмотрите, какое значение у comstat.cbInQue в момент приема

if nBufPRM then - в Delphi не пройдет, будет синтаксическая ошибка: или явное приведение типов (if BOOL(nBufPRM) then) или логическое выражение (if (nBufPRM > 0) then)
1
382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
24.12.2014, 16:40  [ТС] 6
Цитата Сообщение от cotseec Посмотреть сообщение
не завершится (bWait == true), пока не поступит вся посылка
Спасибо за ответ, но это место что-то до меня не доходит: как она определяет что закончилось сообщение или нет, ведь она "не знает" ни о начальной установке nBufPRM, ни о установках COMMTIMEOUTS. А вдруг был передан только один байт, а дальше идут помехи (например симплексная связь), так получается что переход в сигнальное состояние произойдёт только по тайм-ауту и в буфере приёма будет куча мусора.
Стали бы Вы использовать такую конструкцию? Может лучше nBufPRM:= comstat.cbInQue; вообще выкинуть, пусть ReadFile() отрабатывает по изначально заданным nBufPRM и COMMTIMEOUTS
0
Пишу на Delphi...иногда
1423 / 1278 / 286
Регистрация: 03.12.2012
Сообщений: 3,914
Записей в блоге: 5
24.12.2014, 17:19 7
Цитата Сообщение от shyub Посмотреть сообщение
как она определяет что закончилось сообщение или нет
это определяется на физическом уровне (протокол RS-232), функции действуют на канальном уровне - м.б. с моделью могу ошибаться (с названиями уровней)
грубо говоря - определением того, что пришло - помехи или информационные значения определяется протоколом на одном уровне, программный интерфейс - другой (более высокий уровень) и он работает уже с данными, не "отвлекаясь" на организацию связи между устройствами и определения что пришло: данные, помехи или служебные сигналы

Цитата Сообщение от shyub Посмотреть сообщение
Может лучше nBufPRM:= comstat.cbInQue; вообще выкинуть
можно и выкинуть, но как иначе узнать количество байт, имеющихся в приемном буфере в конкретный момент времени?
0
382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
24.12.2014, 20:55  [ТС] 8
Вопрос снимается.
На канальном уровне контроллер порта осуществляет стробирование с частотой, превышающей скорость передачи, затем осуществляет статистическую обработку, на основании чего принимается решение о получении 0 или 1. Далее после получения стопового сигнала объект в течении какого-то небольшого промежутка времени удерживаетс в несигнальном состоянии, т.е. происходит ожидание очередного старта. Если получен старт, то цикл повторяется. Если старта нет, то объект переходит в сигнальное состояние. К сожалению величину этой задержки найти в литературе не смог.
Мораль: если неизвестен момент, когда придёт пакет с данными, и его размер, то необходимо использовать именно этот алгоритм. Единственное, заранее нет смысла задавать размер ожидаемых данных nBufPRM.

Добавлено через 3 минуты
И ещё, если в пакете будут разрывы (это бывает при использовании сотовой связи), то затем на программном уровне придётся осуществлять сборку, т.к. вместо одного большого пакета может быть получено несколько маленьких.
0
пофигист широкого профиля
4658 / 3093 / 854
Регистрация: 15.07.2013
Сообщений: 17,842
25.12.2014, 03:10 9
Цитата Сообщение от shyub Посмотреть сообщение
Единственное, заранее нет смысла задавать размер ожидаемых данных nBufPRM.
Ну вот и сам понял, что я просил объяснить. Ну хотя бы суть того. То что тот код написан непонятно на каком языке - это уже прошлое.

Цитата Сообщение от shyub Посмотреть сообщение
И ещё, если в пакете будут разрывы (это бывает при использовании сотовой связи), то затем на программном уровне придётся осуществлять сборку, т.к. вместо одного большого пакета может быть получено несколько маленьких.
А вот это уже ноу хау. И почему я всю свою уже весьма немалую жизнь в работе с последовательными портами разного рода был уверен, что "один большой пакет" не приходит никогда, никому, ни за какие деньги? И без "сборки" никакая программа работать нормально просто не сможет.
0
382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
25.12.2014, 22:56  [ТС] 10
Уважаемый northener, я полагаю, что Вы человек далеко не глупый. Несмотря на то, что данный вопрос снимается с форума
Цитата Сообщение от shyub Посмотреть сообщение
Вопрос снимается.
мне всё-таки было бы интересно продолжить с Вами разговор на эту тему. Вы пишете, что
Цитата Сообщение от northener Посмотреть сообщение
я всю свою уже весьма немалую жизнь в работе с последовательными портами разного рода
, т.е. Вы считаете себя профессионалом в вопросе работы с портами. В таком случае, как профессионал, поделитесь своим опытом. Вы могли бы привести отрывки из своих работ и комментарии к ним. Проще всего, конечно, критиковать других, быть такой "жирной жабой",сидящей на ветке и квакать. Ой, не обижайтесь, жаб я тоже люблю и не в коем случае не хочу задеть Ваше самолюбие - вдруг Вы опчять это воспримитеа на свой счёт, что жаб я считаю более низким сословием (а то меня и с форума Delphi прогонят сраной метлой, как Вы пишете).
Так что, принимаете вызов?
А в качестве, так сказать, жеста "доброй воли" прикрепляю к сообщению замечательную (на мой взгляд) статью неизвестного, к большому сожалению, мне автора: COM-порт и TThread.rar
Далее, разумеется, если Вы ответите конструктивно, буду выкладывать свои наработки в этой области (где-то лет так 30 тоже приходится соприкосаться с этим вопросом).
0
382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
25.12.2014, 23:32  [ТС] 11
Ребята, хоть убейте, но пытался сегдня найти это:
Цитата Сообщение от shyub Посмотреть сообщение
после получения стопового сигнала объект в течении какого-то небольшого промежутка времени удерживаетс в несигнальном состоянии
Дизассемблировал всё, что смог, в т.ч. и kernek.dll, но так и не нашол подтверждения...

Добавлено через 12 минут
Извиняюсь, отправил сообщение, но не проверил граматику. Следует читать не "kernek.dll" а "kernel.dll"
0
пофигист широкого профиля
4658 / 3093 / 854
Регистрация: 15.07.2013
Сообщений: 17,842
26.12.2014, 03:16 12
Цитата Сообщение от shyub Посмотреть сообщение
Вы считаете себя профессионалом в вопросе работы с портами.
Считаю.
Цитата Сообщение от shyub Посмотреть сообщение
Вы могли бы привести отрывки из своих работ и комментарии к ним
Могу.Проблема только с комментариями. Комментарии обычно пишутся для того чтобы можно было впоследствие понять очём шла речь. С учётом, что эти комментарии возможно будет читать другой человек, который будет продолжать твою работу. Но при этом имеется в виду, что этот другой человек имеет достаточные базовые знания.
P.S. Насчёт "Ой, не обижайтес" можешь не страдать.
Цитата Сообщение от shyub Посмотреть сообщение
Так что, принимаете вызов?
Принимаю.
Цитата Сообщение от shyub Посмотреть сообщение
А в качестве, так сказать, жеста "доброй воли" прикрепляю к сообщению замечательную (на мой взгляд) статью неизвестного, к большому сожалению, мне автора
Скачал сий опус.
0
382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
05.01.2015, 23:56  [ТС] 13
Вы считаете себя профессионалом -
Цитата Сообщение от northener Посмотреть сообщение
Считаю.
Во первых, хочу Вас поздравит с 2015 годом и пожелать всего самого, самого, самого...!
Второе, как Вы заметили, я - С-ишнк (это я скрывал),однако к большому сожалению, до сих пор нет более менее нормального языка (если не считать Ассемблер) для работы с микроконтроллерами (кроме С), а это - моя и работа, и хобби, и (не хочу преувеличивать) смысл жизни! Не стану Вам рассказывать на форуме о своих личных успехах и проблемах (если Вам интересно, пишите на shyub@mail.ru, буду рад).
Третье, вопрос или, пожалуй, решение. Проверил работоспособность кода в Lazarus 1.3 FPC 2.7.1. Выкладывю:
COM_Port.rar
Если бы не добавил вот это:
Delphi
1
2
3
4
5
6
7
repeat
  nBufPRM:=nPRM; // Принято ранее.
  Sleep(t);
  // Заполнить структуру COMSTAT (узнать кол-во принятых байтов).
  ClearCommError(hCom, err, @MyComstat);
  nPRM:=MyComstat.cbInQue;
until nPRM=nBufPRM;
то вся эта "филькина грамота" накрылась бы одним местомю Если Вы, уважаемый northener можете предложить своё решение, то буду очень рад.
И последнее, дорогой апонент northener, хотел бы Вам привести в пример слова моего Учителя: "Не бойтесь спорить, если считаете себя правым. Истина - состязание личностей, состязание ваших знаний. Нет проигравших в вашем споре. Победа всегда за наукой!" (д.т.н. О.Г.Цебиногин - уже его нет)
0
382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
06.01.2015, 00:40  [ТС] 14
К стати, чтобы не сложилось мнение у всех форумчан, что здесь два "длб...", живущих в районе МКАД о чём-то спорят, то признаюсь, что живу в г. Ташкенте (Республика Узбекистан).
0
пофигист широкого профиля
4658 / 3093 / 854
Регистрация: 15.07.2013
Сообщений: 17,842
06.01.2015, 05:07 15
Цитата Сообщение от shyub Посмотреть сообщение
Вы считаете себя профессионалом -
Цитата Сообщение от northener Посмотреть сообщение
Считаю.
Во первых, хочу Вас поздравит с 2015 годом и пожелать всего самого, самого, самого...!
Спасибо. И тебе того же.
Цитата Сообщение от shyub Посмотреть сообщение
Второе, как Вы заметили, я - С-ишнк (это я скрывал),однако к большому сожалению, до сих пор нет более менее нормального языка (если не считать Ассемблер) для работы с микроконтроллерами (кроме С), а это - моя и работа
И моя тоже. И тоже долгое время.
Цитата Сообщение от shyub Посмотреть сообщение
И последнее, дорогой апонент northener
"апонентом" меня ещё никогда , никто не обзывал. Даже не знаю гордиться или гневаться?

P.S. Ну а где сам вызов?
Ну т.е. вызов меня на дуэль? В том архиве, что ты привел куча мусора.
Как ты эту кучу мусора используешь мне совсем не интересно. (Как я уже не раз сказал, геморрой есть у всех свой).
Но работа с СОМ-портом всегда одна и та же. Ну пока не придумали и не внедрили что-то иное. Хотя вряд ли это кому под силу.

Добавлено через 16 минут
Цитата Сообщение от shyub Посмотреть сообщение
Если Вы, уважаемый northener можете предложить своё решение, то буду очень рад.
Грубо говоря могу, но не "забесплатно". Но и в этом случае я не обещаю, что возьмусь за решение твоей задачи.
0
382 / 181 / 47
Регистрация: 11.07.2013
Сообщений: 993
06.01.2015, 11:29  [ТС] 16
Уклоняетесь. Иного и не ожидал.
0
пофигист широкого профиля
4658 / 3093 / 854
Регистрация: 15.07.2013
Сообщений: 17,842
07.01.2015, 01:43 17
Цитата Сообщение от shyub Посмотреть сообщение
Уклоняетесь. Иного и не ожидал.
Я на подобных "форумах" уже четверть века приблизительно. И на разводы типа "А слабо..." не реагирую.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.01.2015, 01:43
Помогаю со студенческими работами здесь

Формат столбца при выгрузке в Excel - откуда-то берутся шесть лишних нулей
Выгружаю данные из Access через DataTable (c#) в Excel. Столкнулся с косяком. В таблице есть...

Подвисает при чтении COM порта
Доброго времени суток, сделал программу, которая читает данные из COM порта, строка кода которая...

Зависает при чтении com порта
Привет всем, подскажите, пожалуйста, у меня есть прибор, с которого я считываю данные каждую...

«Зависает» при чтении com порта
Здравствуйте! Алгоритм программы следующий: «Читать до конца файла» 1.1 Программный reset...


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

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru