Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Программирование COM под Windows
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Интерфейсы
paskal
Проверяю UART некоторого устройства через компьютер. Программа написана на C++ билдере под ХР. Прием - передача в принципе работает. Компьютер посылает блок данных, устройство в ответ шлет свой блок, комп его принимает. Программа при этом работает исключительно в синхронном режиме: пошлет пакет, ожидает ответного пакета.

Но есть еще отдельный режим, когда устройство посылает поток байт, а компьютер ничего с ними не делает. После этого программа перестает работать. Выяснил что это происходит из за переполнения приемного буфера, но вылечить это не могу. Не помогает ни вызов ClearCommError, ни закрытие-открытие порта. Да и не может помочь, т.к. в пошаговой отладке выяснилось что переменная в которой хранился дескриптор порта (полученный вызовом CreateFile) - затирается. Т.е. я в принципе не могу работать с портом. Пробовал устранить переполнение присвоением false в переменной dcb->fAbortOnError - не помогло.
Что еще посоветуете?
Xenia
Посоветую увеличить размер буфера (можно входного и выходного сразу).

Делается это фукцией API:
SetupComm(COMhandle, InBufSize, OutBufSize);
Только, чур, нечетных размеров не задавать, и длиннее, чем 65634 тоже поостеречься (нет у меня уверенности, что третий байт не откусит).
paskal
Цитата(Xenia @ Nov 19 2012, 19:17) *
Посоветую увеличить размер буфера (можно входного и выходного сразу).

Нет, не годится. Количество мусора, который может прийти неограничено. Буфер любого размера все равно когда то переполнится.
Xenia
Цитата(paskal @ Nov 19 2012, 20:42) *
Нет, не годится. Количество мусора, который может прийти неограничено. Буфер любого размера все равно когда то переполнится.


Буфер (тот, который по SetupComm заводится) самоочищается на столько байт, сколько вы читаете из COM-порта.

Ну, а если вы открыли COM-порт, как файл, и погнали в него с внешнего устройства информацию, а средства оперативного чтения (хотя бы раз в секунду) не предусмотрели, то вы сами себе злобный Буратино sm.gif.

Обычно на таймер (ПК-шный) нагружают процедуру, которая периодически с каким-то постоянным периодом читает из СОМ-порта и хотя бы на диск эти данные пишет, если сама не знает, что с ними делать. Буфер не хранилка данных, а лишь средство, чтобы продержаться (не потерять данные) между их поступлением в ПК и чтением их из программы.
paskal
Таймер там не нужен потому что алгоритм работы предельно простой: программа послала блок и тут же приняла ответный блок уже известной длины.
Ввести таймер можно, но это мне кажется слишком тяжеловесным решением. Надо еще следить чтоб таймер не вмешался в прием нужных данных.
Можно между посылками закрывать порт и открывать когда нужно послать очередной раз. Но это тоже много лишних действий - после очередного открытия надо настраивать таймауты, режимы через dcb. Вот если бы можно было переводить порт как бы в спячку, чтоб он временно ничего не принимал. Но как это сделать я не знаю.
И еще я не понимаю почему простое переполнение приводит к таким последствиям что забиваются переменные. Может это тоже можно как то устранить?
zombi
1. Попробуйте всегда перед началом работы с портом выполнить PurgeComm.
2. Не думаю что виндовский буфер может что то затирать кроме себя. biggrin.gif Неужели Вы думаете что винда может не контролировать переполнение буфера и что то там затирать? biggrin.gif
Xenia
Цитата(paskal @ Nov 19 2012, 21:16) *
Можно между посылками закрывать порт и открывать когда нужно послать очередной раз. Но это тоже много лишних действий - после очередного открытия надо настраивать таймауты, режимы через dcb. Вот если бы можно было переводить порт как бы в спячку, чтоб он временно ничего не принимал. Но как это сделать я не знаю.
И еще я не понимаю почему простое переполнение приводит к таким последствиям что забиваются переменные. Может это тоже можно как то устранить?

Мне не понятно ваше возражение о том, что "Буфер любого размера все равно когда-то переполнится". С чего бы ему вдруг переполняться, если вы посылки регулярно забираете? Этот буфер FIFO, и переполниться он может только если посылки будут приходить, а получать вы их не будете. Если вы наотрез отказываетесь использовать SetComm для установки размера буфера, то буфер все равно будет, только по умолчанию в 16 байт. Влезает в них ваша посылка?

На ваш вопрос я уже ответила (или попыталась ответить) советом увеличить размер буфера. Если вы знаете размер посылки, то сделайте размер приемного буфера раз в 10 больше, чем этот размер. А еще лучше, поставьте 30000 и проверьте, пропал ваш синдром или нет.


Цитата(zombi @ Nov 19 2012, 22:18) *
Неужели Вы думаете что винда может не контролировать переполнение буфера и что то там затирать? biggrin.gif

Винда не обязана заполнять всю свою память или писать на диск всю ту муру, что приходит на СОМ-порт. Она складирует "неполученные отправления" до тех пор, пока не кончится место в заказанном программой (которая тот СОМ-порт открыла) буфере. Эти данные уже не пропадут, но попадут те, которые пришли вслед за ними, и которым места в буфере нехватило.
zombi
Цитата(Xenia @ Nov 19 2012, 22:20) *
... Эти данные уже не пропадут, но попадут те, которые пришли вслед за ними, и которым места в буфере нехватило.

Это Вы к чему???
Я с Вами полностью согласен.
Но ТС пишет :
Цитата(paskal @ Nov 19 2012, 21:16) *
И еще я не понимаю почему простое переполнение приводит к таким последствиям что забиваются переменные. Может это тоже можно как то устранить?

Т.е. ТС считает что в программе что то "забивается", "затирается" именно из за переполнения буфера.
paskal
Цитата(zombi @ Nov 19 2012, 21:18) *
1. Попробуйте всегда перед началом работы с портом выполнить PurgeComm.

Не получится. После переполения теряется дескриптор, а он нужен в том числе и для PurgeComm.
Цитата(zombi @ Nov 19 2012, 21:18) *
2. Не думаю что виндовский буфер может что то затирать кроме себя. biggrin.gif Неужели Вы думаете что винда может не контролировать переполнение буфера и что то там затирать? biggrin.gif

Честно - совсем так не думал. Но это происходит и я не могу понять почему.


Цитата(Xenia @ Nov 19 2012, 21:20) *
Мне не понятно ваше возражение о том, что "Буфер любого размера все равно когда-то переполнится". С чего бы ему вдруг переполняться, если вы посылки регулярно забираете? Этот буфер FIFO, и переполниться он может только если посылки будут приходить, а получать вы их не будете.

Забираю я из буфера не регулярно. А ненужные посылки идут непрерывно.
Ситуация такая. Есть посылки которые шлет компьютер по нажатию мышкой, и получает тут же ответ. Это все работает. А можно переключить пульт в автономный режим. И в этом режиме в компьютер непрерывно шлется мусор. Компьютер в это время ничего не делает, но буфер его наполняется мусором. И количество мусора ничем не ограничено.

Цитата(Xenia @ Nov 19 2012, 21:20) *
На ваш вопрос я уже ответила (или попыталась ответить) советом увеличить размер буфера. Если вы знаете размер посылки, то сделайте размер приемного буфера раз в 10 больше,

Да хоть в 1000 раз, все равно он теоретически может переполниться, я уже сказал что такой вариант мне не подходит.
zombi
Цитата(paskal @ Nov 19 2012, 21:55) *
После переполения теряется дескриптор

НЕ ВЕРЮ. Как такое возможно!!! Не должно такого быть!!!
Сергей Борщ
QUOTE (paskal @ Nov 19 2012, 20:55) *
Не получится. После переполения теряется дескриптор,
Но подумайте, что вы такое пишете? Дескриптор в винде - это указатель, которая винда дает вам при открытии прота. Вы его храните у себя, как он может потеряться? Разве что ваша программа неловким движением что-то пишет в ту ячейку, куда вы положили этот указатель.
paskal
Цитата(Сергей Борщ @ Nov 19 2012, 22:10) *
Но подумайте, что вы такое пишете? Дескриптор в винде - это указатель, которая винда дает вам при открытии прота. Вы его храните у себя, как он может потеряться? Разве что ваша программа неловким движением что-то пишет в ту ячейку, куда вы положили этот указатель.

Ну не знаю, просто говорю что вижу в отладчике. А я этот дескриптор не трогаю. Да и происходит это во время когда моя программа ничего не делает, но в порт летит мусор. Завтра еще перепроверю.
Ну а как бы временно приостановить прием есть варианты?
paskal
дубль. сорри.
XVR
Цитата(paskal @ Nov 19 2012, 23:39) *
Ну а как бы временно приостановить прием есть варианты?
Прием останавливается сам, как раз при переполнении буфера (при этом порт переходит в состояние ошибки). Затираться ничего нигде не должно.
Цитата
Ну не знаю, просто говорю что вижу в отладчике. А я этот дескриптор не трогаю. Да и происходит это во время когда моя программа ничего не делает, но в порт летит мусор.
Ищите ошибку у себя в программе. Скорее всего вы не обрабатываете ошибки, которые функции работы с портом будут возвращать после переполнения буфера.
MrYuran
Цитата(zombi @ Nov 19 2012, 22:18) *
2. Не думаю что виндовский буфер может что то затирать кроме себя. biggrin.gif Неужели Вы думаете что винда может не контролировать переполнение буфера и что то там затирать? biggrin.gif

Открыли порт - на куче появился дескриптор. Задали буфер - он лег рядом. Пошли писать - вышли за пределы и затерли соседние данные.
Никто за вас не обязан отслеживать границы массивов.

Цитата(Сергей Борщ @ Nov 19 2012, 23:10) *
Дескриптор в винде - это указатель, которая винда дает вам при открытии прота. Вы его храните у себя, как он может потеряться?

У себя - это где?
А буфер где?
dac
ТС походу объявил в проге массив, и считывает в него то что приходит с порта. и не проверяет размер, соответсвенно если пришло больше чем размер массива - пишет дальше sm.gif
ARV
я конечно извиняюсь... но нафига вообще открывать порт, если из него не берутся данные? перешла программа в "автономный" режим - закрывать порт, и точка. все, что туда придет, будет сброшено аппаратно, ничего нигде затираться не будет. потребуется снова войти в режим "связи" - заново открывается порт, очищается его буфер (было сказано, как) и работа начинается снова...

что не так в моем рассказе?
vvs157
Цитата(paskal @ Nov 19 2012, 20:10) *
что переменная в которой хранился дескриптор порта (полученный вызовом CreateFile) - затирается.
Не затирается, а Вы его затираете некорректной работой с памятью, указателями итп. В С и даже в С++ система особенно не отслеживает выходы за границы массивов, выделенной области памяти для объектов, адресуемых указателями итп. Ищите у себя где Вы затираете переменную.

Цитата(ARV @ Nov 20 2012, 15:19) *
что не так в моем рассказе?
Если устройство использует аппаратные сигналы DTR и/или RTS для разрешения работы, то при закрывании порта эти сигналы сбросятся и устройство ничего выдавать не будет. Так, кстати поступают телефонные модемы по умолчанию.
zombi
Цитата(MrYuran @ Nov 20 2012, 12:39) *
Открыли порт - на куче появился дескриптор. Задали буфер - он лег рядом. Пошли писать - вышли за пределы и затерли соседние данные.
Никто за вас не обязан отслеживать границы массивов.

Я в шоке.
Где TC пишет о своём буфере???
Речь идёт о стандарном виндовском.


Цитата(dac @ Nov 20 2012, 13:36) *
ТС походу объявил в проге массив, и считывает в него то что приходит с порта. и не проверяет размер, соответсвенно если пришло больше чем размер массива - пишет дальше sm.gif

Цитата(paskal @ Nov 19 2012, 19:10) *
... Но есть еще отдельный режим, когда устройство посылает поток байт, а компьютер ничего с ними не делает...

Xenia
Цитата(ARV @ Nov 20 2012, 15:19) *
я конечно извиняюсь... но нафига вообще открывать порт, если из него не берутся данные? перешла программа в "автономный" режим - закрывать порт, и точка. все, что туда придет, будет сброшено аппаратно, ничего нигде затираться не будет. потребуется снова войти в режим "связи" - заново открывается порт, очищается его буфер (было сказано, как) и работа начинается снова...

что не так в моем рассказе?


А вот что не так sm.gif. Бывают конструкции внешних устройств, которые питаются за счет сигнальных линий СОМ-порта (т.к., в отличие от USB, питание на этот разъем не подается). К такому решению располагает уменьшение энергопотребления большинства МК (им такой мощности для питания достаточно), но отвращает, что СОМ-порт постепенно выходит из моды, исчезая из стандартных устройств ПК.

Часто потупают так - отказываются от хэндшейкинга, а освободившиеся линии DTR и RTS используют для питания. При этом напряжение на них уставливают в "противофазе", чтобы получить побольше разность потенциалов, и тогда из нее можно получить стабилизированное 5 вольт.

Закрытие СОМ-порта приведет к тому, что выставленные уровни DTR и RTS изменятся, т.к. закрытый СОМ-порт не держит своих прежних установок. А питание внешнего устройства по многим причинам прекращать бывает нежелательно. Особенно в тех случаях, когда оно работает в ждущем режиме - не постоянно посылки гонит, а лишь в случае наступления того или иного события. Вот и было бы заманчиво установить такой режим (перепрограммирование СОМ-порта без его закрытия), чтобы (временно) отказаться от приема сообщений, но сам СОМ-порт не закрывать, чтобы сохранить уровни DTR и RTS.

Всевозможные идеи (а таких можно выдвинуть много) о том, как можно организовать альтернативное питание, не взирая на полярность DTR и RTS, можете оставить при себе. Сейчас же интересует только одна вещь - возможно это сделать программным путем или невозможно. И выяснить этот вопрос хотелось бы раньше, чем брать в руки паяльник и курочить внешнее устройство.
ARV
Цитата(Xenia @ Nov 20 2012, 16:20) *
А вот что не так sm.gif . Бывают конструкции ...
Xenia, бывает, что и корова летает... при себе можно вообще оставить все попытки подсказать топикстартеру методы решения его проблемы, ограничившись просто советом найти и исправить ошибку в программе - ведь это очевидно все, не так ли? кстати, топикстартер и просил "временно приостановить прием" - что может быть лучшепроще закрытия порта для этого?!
vvs157
Цитата(ARV @ Nov 20 2012, 16:32) *
что может быть лучшепроще закрытия порта для этого?!
Как показывает опыт работы по RS232 с различными устройствами неосознанное манипулирование с DTR и RTS очень часто приводит к полному разочарованию. И далеко не все устройства имеют 3-проводный RS232. Поэтому простое с точки зрения программиста решение - дезактивирование порта при нежелании что-либо принимать - не может быть универсальным решением. На самом деле самое простое - игнорировать и очищать буфер приема. Если это не получается - читать документацию и/или искать ошибку в собтвенном коде. Это так же как пользоваться вместо выключателя выдергиванием и вставлением вилки в розетку особенно при 1 кВт мощности.
Xenia
Цитата(ARV @ Nov 20 2012, 16:32) *
Xenia, бывает, что и корова летает... при себе можно вообще оставить все попытки подсказать топикстартеру методы решения его проблемы, ограничившись просто советом найти и исправить ошибку в программе - ведь это очевидно все, не так ли? кстати, топикстартер и просил "временно приостановить прием" - что может быть лучшепроще закрытия порта для этого?!


Вы невнимательно читали его просьбу, а потому так неадекватно реагируете. Топикстартер САМ наотрез отказался закрывать СОМ-порт, вот так обосновав свой отказ:
Цитата(paskal @ Nov 19 2012, 21:16) *
Можно между посылками закрывать порт и открывать когда нужно послать очередной раз. Но это тоже много лишних действий - после очередного открытия надо настраивать таймауты, режимы через dcb. Вот если бы можно было переводить порт как бы в спячку, чтоб он временно ничего не принимал. Но как это сделать я не знаю.

Т.е. изначально поставил задачу так, чтобы решение не содержало закрытия порта.
paskal
Цитата(Сергей Борщ @ Nov 19 2012, 22:10) *
Но подумайте, что вы такое пишете? Дескриптор в винде - это указатель, которая винда дает вам при открытии прота. Вы его храните у себя, как он может потеряться? Разве что ваша программа неловким движением что-то пишет в ту ячейку, куда вы положили этот указатель.

Ваша правда, это я накосячил. Сегодня потрассировал внимательнее. Оказалось что я очищал буфер путем определения количества байт в нем ф-ей ClearCommError, потом читал всю эту длину одним махом в свой буфер. А когда мусора было слишком много, больше моего буфера, то соответственно терлись соседние данные. Вылечил заменой на PurgeComm.
Всем спасибо, ваши советы подтолкнули где искать ошибку.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.