LINUX.ORG.RU

Чтение из COM порта, При чтении из порта зависает read()


0

1

Каждому рано или поздно приходится программировать com порт. Вот и мой черед пришол. Я ужу умею: Откривать,закривать, писать. а читать не получается. програма зависает при read(). Я читал з /dev/tteS0 и /dev/tteS1. я ожидал что read() вернет 0 или чтото в етом роде но не зависнет.


у тебя read блокирует программу пока не считает всё что есть. Так как ничего нету, он ждёт. Читай или про AIO, или про non-blocking fd. В man 2 open и man 2 read всё написано.

anonymous
()
Ответ на: комментарий от Eddy_Em

писать и читать

//Запись в порт int ComPort::WritePort(char *buff, int Size) { qDebug()<<«Write Thread Start!!!»; int writebytes = write(p_Port, buff, Size); qDebug()<<«DATA were writed... (total »<<writebytes<<" bytes)";

return 0; }

//Чтения из порта int ComPort::ReadPort(void* lp, int Size, bool ShowRead) { int readbytes = 0; qDebug(«%s»,«Start Read»); do { //прочитать байты из порта в буфер программы readbytes = read(p_Port, lp, Size); if(readbytes > 0) if(ShowRead) ShowReadData((char*)lp, (int)readbytes); qDebug()<<«Read:»<<readbytes; } while(readbytes > 0);

qDebug()<<«Read good»; return readbytes; }

NOCaut
() автор топика
Ответ на: комментарий от m0rph

откритие порта

int ComPort::OpenPort() { if (PortName == "") return -5;

qDebug(«%s»,PortName.toAscii().data()); //Вiдкриваэмо порт в режим читта i запису. Ставимо в не блокуючий режим p_Port = open(PortName.toAscii().data(), O_RDWR | O_NOCTTY | O_NONBLOCK); if (p_Port < 0) return -1;

//save curent port setting tcgetattr(p_Port,&oldDevice);

if (lockf(p_Port , F_TEST, 0) == -1) { qDebug()<<«Serial Port is locked»; return -2; }

// Настраиваем порт на асинхронную передачу // allow the process to receive SIGIO fcntl(p_Port, F_SETOWN, getpid()); // Make the file descriptor asynchronous (the manual page says only // O_APPEND and O_NONBLOCK, will work with F_SETFL...) fcntl(p_Port, F_SETFL, FASYNC);

// TSubCommandFormat l_MsgHeader; // l_MsgHeader = SubCommandFormat[ASubCommand];

if(!SetupConnection()) return -3;

fConnected = true; try { int reta = connect(&theComPortNotifier, SIGNAL(signalNotify()), this, SLOT(slot()),Qt::DirectConnection); qDebug()<<«ComPortLin: Connect signal=»<<reta; } catch(...) { fConnected = false; return -4; }

//По умолчанию - режим не задан p_SubMode = false;

return 0; } int ComPort::ClosePort() { //Очистка буферов и очередей порта. Берем по максимому // PurgeComm(m_idComDevice, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); //Повертаэмо порту попереднi налаштування tcsetattr(p_Port, TCSANOW, &oldDevice); // Закритие порта if (fConnected) close(p_Port); // Закриваем порт

return 0; }

bool ComPort::SetupConnection() { // заповняэмо структуру // linux.die.net/man/3/termios struct termios newtio; // newtio.c_cflag = B19200 | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_cflag = B19200 | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; // input modes newtio.c_oflag = 0; // output modes newtio.c_lflag = 0; // local modes --ICANON; newtio.c_cc[VMIN] = 1; // VMIN - minimum number of characters for noncanonical read(MIN) newtio.c_cc[VTIME] = TimeOut; // VTIME - inter-character timer unused

// задаэмо нову структуру для порта if(tcsetattr(p_Port,TCSANOW,&newtio)<0) return false;

//очищаэмо входну структуру в якый э данi, якы були отриманы,але не прочитанi tcflush(p_Port, TCIFLUSH);

return true; }

NOCaut
() автор топика
Ответ на: писать и читать от NOCaut

Ты два компьютера через RS232 соединил или у тебя 2 порта и ты воткнул между ними петлю?

// P.S. И открой уже для себя LORCODE! читать невозможно твои портянки!
// P.P.S. И лучше над русским не издевайся: пиши уже по-английски!

Eddy_Em ☆☆☆☆☆
()
Последнее исправление: Eddy_Em (всего исправлений: 3)
Ответ на: комментарий от strangeman

Да я понял: потому и прошу по-английски писать.

// беларус, похоже

Eddy_Em ☆☆☆☆☆
()
Последнее исправление: Eddy_Em (всего исправлений: 1)
Ответ на: комментарий от Tweaker

Так как уже используешь Qt, то не мучайся и пользуйся QextSerialPort.

Это гогно мамонта? :)

Лучше уж http://qt-project.org/wiki/QtSerialPort_Russian

тем более, что начали интеграцию в Qt и в версии 5.1, думаю оно объявится, если не случится ничего экстра-ординарного.

kuzulis ★★
()
Ответ на: комментарий от kuzulis

Вот поражаюсь с этих извращенцев! Да на обычном termios все гораздо прозрачней и короче, чем с этими вашими классами.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Tweaker

Зато работает. А QtSerialPort на оффтопике периодически виснет и отваливается.

Не прокати за балабола (короче - не пи#ди) без доказательств и баг-репортов.

kuzulis ★★
()
Ответ на: комментарий от Eddy_Em

Да на обычном termios все гораздо прозрачней и короче, чем с этими вашими классами.

В принципе я согласен с тобой. Но это верно только тогда, когда ты пишешь на «чистую», что нить масюсенькое без всяких тулкитов и фреймворков. Но если используещь Qt (к примеру), то это уже не будет работать также хорошо в комплексе с Qt (то гуй зависнет то еще что), то придется постоянно поллить, то тред создавать, в общем, гемор еще тот на голову.

А все эти классы (точнее нормально - только QtSerialPort) очень стройненько используют все внутренние системные Qt-шные няшки и очень сильно облегчают жизнь.

А если что-то и не работает - то пишите баг-репорты. :)

kuzulis ★★
()
Ответ на: комментарий от Eddy_Em

Работа с компортом нужна для разного рода снифферов, которыми пользуюсь на работе где везде стоит винда, такие дела.

Tweaker ★★★★☆
()
Ответ на: комментарий от Eddy_Em

А чего не так? Не ethernet снифферы, а разных легких беспроводных протоколов, сами аппратные, выплевывают данные на юзб, а на кьюте парсер\интерфейс.

Tweaker ★★★★☆
()
Последнее исправление: Tweaker (всего исправлений: 1)
Ответ на: комментарий от kuzulis

Там не только один Я разработчик, я автор, но арзрабатывают много людей. Так что, может кто что тоже подскажет. GoGoGo на форум :)

kuzulis ★★
()
Ответ на: комментарий от Tweaker

Ну, не знаю. По-моему, под линуксом все это проще сделать. И с USB работать в т.ч. (я, например, просто взял USB-CDC и получил "виртуальный" последовательный порт, с которым работаю, как с реальным — безо всяких libusb).

Eddy_Em ☆☆☆☆☆
()

Он не виснет, он так и должен работать. Это называется блокирующее чтение.

com порт
пришол

кошмар, какой кошмар.

nanoolinux ★★★★
()
Ответ на: комментарий от Eddy_Em

коменти на украинском; то что нету елементов форматирования - ето недорабортка форума; 1 - ком порт 1 - комп; подключил терминал для считивания скретч карт

NOCaut
() автор топика
Ответ на: комментарий от nanoolinux

и сколька он так будет висеть ожидая байты? ето можна както обойти например если нету ничего секунд 10 знач оборвать и вернуть false;

NOCaut
() автор топика
Ответ на: комментарий от NOCaut

то что нету елементов форматирования - ето недорабортка форума

Теги [code] вокруг кода libastral не расставит!

подключил терминал для считивания скретч карт

Он точно посылает что-нибудь? Ну и сделай все-таки порт неблокирующим.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

И с USB работать в т.ч. (я, например, просто взял USB-CDC и получил «виртуальный» последовательный порт, с которым работаю, как с реальным — безо всяких libusb).

Нуну, можно подумать, под оффтопиком это не работает... :)

kuzulis ★★
()
Ответ на: комментарий от kuzulis

Я без понятия, как в офтопике termios реализуется.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

<<Теги

 вокруг кода libastral не расставит!
Я имел ввиду кнопки управления для форматирования текста

<<Он точно посылает что-нибудь? 

Я уже не уверен. как опредилить номер порта к которому я подклучил устройство. я пеердаю в /dev/ttyS1. но наверно ето не мое устройство((

<<Ну и сделай все-таки порт неблокирующим.
O_NONBLOCK - у меня етот флаг стоит если етого не достаточно то что ище нужно.

NOCaut
() автор топика
Ответ на: комментарий от NOCaut

Я имел ввиду кнопки управления для форматирования текста

DIY или читай маны.

как опредилить номер порта к которому я подключил устройство

Если это "железные" порты, то /dev/ttyS0 — COM0, /dev/ttyS1 — COM1 и т.д. Если USB'шные разные — по VendorID/ProductID, если одинаковые — никак.

O_NONBLOCK - у меня етот флаг стоит если етого не достаточно то что ище нужно.

Достаточно. Но тогда нужно внимательно анализировать, что read вернет. Лучше таки `select` использовать.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Видимо не достаточно. он у меня стоял при open(); fcntl(p_Port, F_SETFL, O_NONBLOCK); - так помогло спасибо.

<<то /dev/ttyS0 — COM0, /dev/ttyS1 — COM1

я понял, но как опредилить что к нему подключено устройство.. порт откривается и так и так. ето винда не дала б работать с портом.

NOCaut
() автор топика
Ответ на: комментарий от NOCaut

При `open` хватает же! Как-то так:

        int i, flag = 1;
        unsigned char comdev[32];
        snprintf(comdev, 32, "/dev/ttyS%d", ComPort);
        if(comfd){
                ioctl(comfd,TCSETA,&oldtty);
                close(comfd);
        }
        WARN("Открываю порт %s... ", comdev);
        if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){ 
                WARN("Не могу использовать порт %s: %s\nОтключаюсь.", comdev, strerror(errno));
                exit(1);
        }
        WARN(" OK\nПолучаю текущие настройки порта... ");
        if(ioctl(comfd,TCGETA,&oldtty) < 0) flag = 0; // Узнаем текущие параметры порта
        tty = oldtty;
        tty.c_lflag    = 0;
        tty.c_iflag    = BRKINT;
        tty.c_oflag    = 0;
        tty.c_cflag    = B9600|CS8|CREAD|CLOCAL|PARENB;
        tty.c_cflag &= ~PARODD;
        tty.c_cc[VMIN] = 0;
        tty.c_cc[VTIME] = 5;
        if(ioctl(comfd,TCSETA,&tty) < 0) flag = 0;
        if(flag){
                WARN(" OK\n");
        }
        else{
                WARN(" Ошибка настройки порта, отлючаюсь.\n");
                exit(1);
        }

Соответственно, чтение:

        unsigned char rb; // то, что считываем
        fd_set rfds; // набор файловых дескрипторов
        struct timeval tv; // время ожидания
        int retval; // возвращаемое ф-й select значение
        tty.c_iflag &= ~PARODD; // принимаем с девятым битом = 0
        ioctl(comfd,TCSETA,&tty);
        FD_ZERO(&rfds); // очищаем набор
        FD_SET(comfd, &rfds); // теперь это - свойства порта
        tv.tv_sec = 0; tv.tv_usec = 500000; // ждем .5с
        retval = select(comfd + 1, &rfds, NULL, NULL, &tv);
        if (!retval){
                MSG("Контроллер не готов!\n");
                return (-1); // если сигнала нет, возвращаем ноль
        }
        if(FD_ISSET(comfd, &rfds)){
                if(read(comfd, &rb, 1) < 1){
                        MSG("Ошибка считывания\n");
                        return (-1); // ошибка считывания
                }
        } 
        else{
                MSG("Готов, но не COM-порт\n");
                return (-1); // ошибка 
        }
        MSG("считан сигнал: %d\n", rb);
        return (int)rb;

как опредилить что к нему подключено устройство

Пингануть.

Eddy_Em ☆☆☆☆☆
()
Последнее исправление: Eddy_Em (всего исправлений: 1)
Ответ на: комментарий от NOCaut

я не буду его юзать полность. я сравняю со своим и чтото дополню из твоего)

NOCaut
() автор топика
Ответ на: комментарий от Eddy_Em

зачем ти ждеш 5 сек. и будит ли етот код аналогичен твоему.

 unsigned long ComPort::GetTick()
{
    struct timeval tv;
    gettimeofday(&tv,0);
    return (tv.tv_sec*1000+tv.tv_usec/1000);
}
 if((GetTick()-m_SendDataTimer)<5000) {
        return false; // затримка на 5 сек
    }
NOCaut
() автор топика
Ответ на: комментарий от NOCaut

Поки байти не прийдуть, буде чекати, читай man tcsetattr, дивись параметри VMIN та VTIME.

Щоб зробити з таймаутом краще використати select з одним дескриптором. Там є параметр відповідальний за таймаут.

nanoolinux ★★★★
()
Ответ на: комментарий от NOCaut

зачем ти ждеш 5 сек.

Не 5, а 0.5, читай ман внимательней. А жду потому, что все равно паузы нужны были.

будит ли етот код аналогичен твоему

Не совсем. Но подобным образом ты можешь узнавать, подключено ли вообще что-то.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

FD_SET - что он делает. я до етого порт настраивал через termios

tcsetattr();

не собет ли мне ета команда порт или лутше взять uslepp(); поставить зчем все било усложнять?

NOCaut
() автор топика
Ответ на: комментарий от NOCaut

или я без него не смогу select() виполнить

NOCaut
() автор топика
Ответ на: комментарий от NOCaut

FD_SET - что он делает. я до етого порт настраивал через termios tcsetattr(); не собет ли мне ета команда порт или лутше взять uslepp(); поставить зчем все било усложнять?

что мне даст select? FD_ISSET - и ето зачем?

NOCaut
() автор топика
Ответ на: комментарий от kuzulis

Лучше уж

А чем лучше? Когда последний раз смотрел QtSerialDevice он не умел сигнализировать об отключении девайса, зато умел кучу других сомнительных. Ситуация с сигналом отключения изменилась? Не сочтите за нападок, интереса ради спрашиваю.

nand
()
Ответ на: комментарий от nand

А чем лучше?

Да всем, см. реализацию в сорсниках.

Когда последний раз смотрел QtSerialDevice он не умел сигнализировать об отключении девайса,

Эмм... эта «фича» была специально удалена, т.к. невозможно ее имплементировать на всех платформах. Раньше она была в QSerialDevice.

зато умел кучу других сомнительных.

Как раз таки это и есть сомнительная фича.

Ситуация с сигналом отключения изменилась?

Нет, и не будет меняться. Сами реализуйте нотификатор, благо код есть и в QSerialDevice и в QExtSerialPort - скопипастить нет проблем.

Но есть возможность отловить выдергивание USB/Serial конвертера из USB порта если порт до этого был открыт.

kuzulis ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.