Страниц: [1]
  Печать  
Автор Тема: parity check - как правильно?  (Прочитано 8711 раз)
SMihalych
Участник
*
Offline Offline

Сообщений: 11


Просмотр профиля
« : Января 26, 2005, 07:17:50 pm »

В наличии почти полное отсутствие какого-либо опыта программирования СОМ-портов. Поэтому вопрос может оказаться идиотским (сорри сильно не пинать)...
В реализации modbus-а нужно соорудить проверку четности.
А как это сделать правильно? Прямым inport() регистра LCR при получении байта по read() или использовать devctl() c командой DCMD_CHR_GETOBAND (оно кстати как-то не очень понятно описано)?
Старательно сейчас штудирую все, что удается найти в сети, но иногда на конкретные вопросы ответа не находится
Записан
bob
Участник
*
Offline Offline

Сообщений: 0


Просмотр профиля WWW
« Ответ #1 : Января 27, 2005, 01:51:43 pm »

Драйвер com-порта сам умеет контролировать четность. Реакцией на ошибки можно управлять (IGNPAR, PARMRK и т.п.) То есть ошибочные байты могут удаляться, помечаться и др. После вызова read() либо байт будет помечен, либо Вы его не получите. Подробнее, например в описании stty. Или в любой книге по Unix (Терминальный интерфейс/атрибуты терминала)
Записан
bessonov
Участник
*
Offline Offline

Сообщений: 0


Просмотр профиля
« Ответ #2 : Января 27, 2005, 04:17:29 pm »

use stty

http://linuxland.itam.nsc.ru/misc/other19/index.html#CONTENTS

http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap11.html#tag_11

http://easysw.com/~mike/serial/serial.html

+ поиск в форуме
Записан
SMihalych
Участник
*
Offline Offline

Сообщений: 11


Просмотр профиля
« Ответ #3 : Января 27, 2005, 07:46:24 pm »

Блин... Может, я туп до невозможности

"If IGNPAR is set, a byte with a framing or parity error (other than break) shall be ignored."

Это понятно...
А это как?

"If PARMRK is set, and IGNPAR is not set, a byte with a framing or parity error (other than break) shall be given to the application as the three-byte sequence 0xff 0x00 X, where 0xff 0x00 is a two-byte flag preceding each sequence and X is the data of the byte received in error. To avoid ambiguity in this case, if ISTRIP is not set, a valid byte of 0xff is given to the application as 0xff 0xff. If neither PARMRK nor IGNPAR is set, a framing or parity error (other than break) shall be given to the application as a single byte 0x00."

Ну не понимаю я ... Если я читаю N-ое количество байт из порта в буфер:
nbytes=read(port_fd, buf_ptr, buf_size);
то чего и где и как будет "помечено"Huh?
Это значит, что вместо одного байта драйвер на каждый байт будет передавать 3? Один  - собственно данные, а перед ним 0xff и 0х00 (т.е. маркер неправильного байта)
А в случае правильного байта?
Т.е. надо читать по одному байту чтобы отловить по маркерам, что байт ошибочный?
nbytes=read(port_fd, buf_ptr, 1);
Т.е. читаем так 3 раза подряд анализируя маркеры и сам байт данных?

If neither PARMRK nor IGNPAR is set, a framing or parity error (other than break) shall be given to the application as a single byte 0x00.
А если из порта вычитывается подряд 0x00 0x00 0x00 0x00 как это понимать?

Только не отсылайте, бога ради к литературе и поиску.
Это первое, что я сделал, само собой...
Если можете - дайте конкретный совет (покажите) - как сделать.
Все ссылки, приведенные bessonov  (спасибо ему в любом случае) я уже до этого читал - а результат - вот такой идиотский вопрос
Записан
bessonov
Участник
*
Offline Offline

Сообщений: 0


Просмотр профиля
« Ответ #4 : Января 27, 2005, 08:50:16 pm »

Если я правильно понимаю из доки, драйвер положит в свой буфер только те байты которые соответсвуют одному из флагов который стоит для данного СОМ порта - EVEN, ODD, NONE parity. Эти флаги устанавливаются структуре типа termios. tcgetattr(), tcsetattr().


Это имеет отношению к вашему вопросу?
http://linuxland.itam.nsc.ru/misc/other19/index.html#CONTENTS

Опция IGNPAR несколько опасна, поскольку указывает драйверу последовательного порта игнорировать ошибки четности и передавать принятые данные как буд-то ошибок не было. Это может быть полезно при тестировании качества коммуникационной связи, но, в основном, не используется по практическим соображениям.

Опция PARMRK указывает 'маркировать' ошибки четности во входном потоке используя специальный символ. Если установлено IGNPAR, то вашей программе будет посылаться символ NUL (восьмеричное 000) перед каждым символом который получен с ошибкой четности. Иначе будут посылаться символы DEL (восьмеричное 177) и NUL вместе с ошибочно принятым символом.


Только я не понимаю, зачем в modbus делать проверку чётности? Драйвер делает её сам и этого вполне достаточно

Дело программера - набирать байти от драйвера СОМ порта пока не соёдтся CRC, либо пока количество байт не будет больше 255.

Абосолютно не вижу смысла делать проверку чётности в modbus.
Записан
SMihalych
Участник
*
Offline Offline

Сообщений: 11


Просмотр профиля
« Ответ #5 : Января 27, 2005, 09:05:32 pm »

Я только что правил свой топик выше, похоже одновременно с приходом Вашего ответа.
С маркировкой как раз и непонятно. Что конкретно с этим делает драйвер если в настройках стоит контроль четности? Просто их "вырезает"?
А по поводу модбаса в его спецификации - EVEN mast be (required) ... ODD and NONE may be (recommended)...
Блин, а может я вообще чего-то совсем не правильно понял?Huh?
Записан
ed1k
QOR.Moderator
*****
Offline Offline

Сообщений: 739


Просмотр профиля WWW
« Ответ #6 : Января 28, 2005, 05:29:03 am »

SMihalych
А если из порта вычитывается подряд 0x00 0x00 0x00 0x00 как это понимать?


Все что вам требуется это не устанавливать IGNPAR. В этом случае, будут "битые" байты выкинуты или помечены, не имеет никакой разницы. modbus пакет завершается CRC, и CRC у вас не совпадет c очень большой вероятностью. Если ваше устройство slave, то оно должно игнорировать такой запрос, а не выяснять какой байт был "битый"; если мастер получил "битый" ответ или никакого, то он повторно посылает запрос, опять же, абсолютно не выясняя какая ошибка и с каким байтом произошла.
Все устройства на одном сегменте должны работать с последовательными портами настроеными одинаково. (Очевидная вещь). Рекомендуется even parity, но для совместимости (если какой-то уродец в сегменте не поддерживает такую настройку) рекомендуется поддерживать также no parity и odd parity (чтобы можно было быстро перестроить весь сегмент под уродца). Требования эти продиктованы в основном только теми соображениями, что далеко не все modbus устройства столь универсальны, как персоналка, где вы можете крутить настройки порта как вам нравится.

Читать из порта вам надо не по одному байту, так как в этом случае вас никто умным не назовет, и кроме того, признаком конца пакета является отсутствие передачи длительностью не меньше времени, требуемого на передачу 3.5 байт, а не какой-то конкретный байт-маркер.

Не нужно вам знать какой байт в пакете пришел с ошибкой четности. Если вы уверены в обратном, покажите мне ссылку на документ или сам документ, где это подтверждается.
Записан
bessonov
Участник
*
Offline Offline

Сообщений: 0


Просмотр профиля
« Ответ #7 : Января 28, 2005, 11:59:14 am »

Иногда таймаут желательно делать не 3.5 байт, а регулируемым. Если планируется передавать типы данных размером более 16 бит, например 32 бита тип float или long, то желательно сделать доп опции swap bytes и swap words. При управлении 485 некоторые делают регулируемую задержку сигнала RTS (в некоторых реализацих управляющая лини DTR).
Записан
SMihalych
Участник
*
Offline Offline

Сообщений: 11


Просмотр профиля
« Ответ #8 : Января 28, 2005, 04:11:12 pm »

to ed1k
"...Не нужно вам знать какой байт в пакете пришел с ошибкой четности. Если вы уверены в обратном, покажите мне ссылку на документ или сам документ, где это подтверждается..."

Нигде не подтверждается. Просто была мысль - зачем читать всю посылку до конца, считать CRC и т.д., если уже 1-ый или 2-3-ий байты пришли с ошибкой четности?

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

Да, с фреймами в RTU режиме мне все было ясно с с амого начала. И если читать именно по 1 байту, то мне понятно, как с помощью select() отследить этот самый 3.5 символьный frame-timeout между двумя байтами и закончить прием ответа тут же делая вывод о том, все получено, что хотелось, или произошла ошибка.
А если запросить read() с известным размером буфера ответа, а ответ где-нибудь в середине будет с таким таймаутом, тогда как? Опять ловить все, и потом уже смотреть, что получилось по CRC? В принципе можно и так, но не эффективно это как-то. Или это тоже как-то отслеживается?
Опыта, опыта работы с СОМ-портами маловато. Точнее совсем нету
Записан
ed1k
QOR.Moderator
*****
Offline Offline

Сообщений: 739


Просмотр профиля WWW
« Ответ #9 : Января 29, 2005, 06:11:08 am »

SMihalych
Нигде не подтверждается. Просто была мысль - зачем читать всю посылку до конца, считать CRC и т.д., если уже 1-ый или 2-3-ий байты пришли с ошибкой четности?

Ну хотя бы для того, чтобы убрать из приемного буфера весь последующий мусор. Что даст эта дополнительная ветвь? Ничего, кроме головной боли, вдруг flush буфера сделаете слишком рано и пр. Кстати, ошибки четности должны быть достаточно редким явлением, если байты "бьются" в дороге надо заниматься аппаратной частью - кабелем и экранами.
SMihalych
Да, с фреймами в RTU режиме мне все было ясно с самого начала. И если читать именно по 1 байту, то мне понятно, как с помощью select() отследить этот самый 3.5 символьный frame-timeout между двумя байтами и закончить прием ответа тут же делая вывод о том, все получено, что хотелось, или произошла ошибка.

Вообще-то, для подобных вещей задумавались MIN и TIME элементы в массиве cc_t структуры termios. Но POSIX определяет TIME как целое выражающее время в 0.1с, что не очень подходит для реализации того, что написано в стандарте.
[offtopic]
На практике паузы в модбасе существенно больше. Мне не попадался еще ни один мастер, который бы долбил сегмент как дятел запросами не дав слейву разобраться, что наступила пауза (например, даже и 0.1с) и подготовить ответ. Но это мое личное мнение. Наверно лучше стремится к совершенству, т.е. стандарту
[/offtopic]
Если следовать букве стандарта, то именно select()-ом и собирать пакет в буфер, потому как временный интервалы уж очень маленькие. Только зачем же по одному байту? Если дескриптор готов для чтения, то там может быть и несколько байт Если же выход из select() по таймауту, то конец пакета. Считать CRC требуется в любом случае, ошибки четности на линии случаются редко, поэтому опять не вижу смысла ветвится. Разве что слейв может и не считать CRC, если адрес не его. А в остальном, это должна быть "дур-машина" без излишних ветвлений и состояний.
SMihalych
А если запросить read() с известным размером буфера ответа,

А вот этого не надо. Нету в модбасе фиксированой длины пакета. Modbus RTU frame может быть до 256 байт, включая адрес, функцию и CRC. Конец пакета это пауза в 3.5 байта. End of story.
SMihalych
Опыта, опыта работы с СОМ-портами маловато. Точнее совсем нету

Дык на www.modbus.org есть куча ссылок на готовые проекты. Почитайте исходники. Иногда полезно посмотреть как это уже люди делали до того, как самому начинать лепить.
Записан
SMihalych
Участник
*
Offline Offline

Сообщений: 11


Просмотр профиля
« Ответ #10 : Января 29, 2005, 08:02:00 am »

to ed1k
"...А вот этого не надо. Нету в модбасе фиксированой длины пакета. Modbus RTU frame может быть до 256 байт, включая адрес, функцию и CRC. Конец пакета это пауза в 3.5 байта. End of story. .."

Ну да, фикированного по длинне пакета теоритически нет. А фиксированная длинна ответа (может я и не прав) д.б. известна всегда. Когда строится модбас-запрос, всегда точно можно посчитать что в ответ должно придти. Или ответ с данными определенного размера, или 5 байт exception.

По поводу исходников - тут вообще интересно. Сколько проектов - столько и реализаций, что вполне и понятно. Кстати в некоторых я встретил именно чтение по 1 байту за раз.
Записан
ed1k
QOR.Moderator
*****
Offline Offline

Сообщений: 739


Просмотр профиля WWW
« Ответ #11 : Января 30, 2005, 06:07:17 am »

SMihalych
Или ответ с данными определенного размера, или 5 байт exception.

Как по мне так этого или-или достаточно тем более, я не отфильтровал, что вы мастера под конкретного слэйва делаете.
SMihalych
Кстати в некоторых я встретил именно чтение по 1 байту за раз.

Ну в этом нет криминала Просто я бы так, скорее всего, не делал. Мне это кажется не эффективным, на каждый байт вызывать select(). Особенно, если мой процесс(поток) занимающийся модбасом не самый приоритетный (а ему, вроде бы, незачем быть самым приоритетным), то пока я стану анализировать выход из select() в порт еще байтов привалит.
Гораздо более порочная практика делать write() по одному байту в порт. Не делайте так, бо нету смысла не положить пакет целиком в буфер драйвера, и очень легко можно выскочить за модбасовский максимальный интербайтный интервал, который равен времени передачи 1.5 байтов.
Записан
SMihalych
Участник
*
Offline Offline

Сообщений: 11


Просмотр профиля
« Ответ #12 : Января 30, 2005, 05:12:16 pm »

Спасибо всем, принявшим участие за помощь. Оно уже работает!
Правда пришлось слегка наступить на горло максималистскому и идеалистическому желанию как можно ближе приблизиться к стандарту и создать мастера на все возможные случаи слэйвов.
Хотя и так получилось не плохо, работает с тремя разными слэйвами .
Записан
Страниц: [1]
  Печать  
 
Перейти в: