LINUX.ORG.RU

[c++] com порт проверка на подключенность

 


0

1

Здравствуйте. В программе испльзуется устройство по com порту, и если его отключить и начать обращаться к устройству, программа зависает. Вот, как бы так сделать чтобы проверка происходила на подключенность устройства к порту. termios перенастраивать нельзя.

ЕМНИП если к компорту подключено устройство, то он одной из ез его ног формируцется логическая единица, говорящая контроллеру о том, что подключено устройство. Проверяй этот бит.

Zhbert ★★★★★
()

… = open(…, … | O_NONBLOCK);

потом контролировать чтение/запись вручную, естественно.

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

а если ноги к порту подключены но устройство выключили по кнопке... сработает проверка этого байта? и как это сделать
гугл ничего не дает

pozitiffcat ★★★
() автор топика

Я юзал для компортов boost.asio и, насколько я помню, при попытке записи/чтения из отрубившегося (либо отсоединенного) девайса прилетал exception. Я его ловил и смело работал дальше, с остальными устройствами. Ничего не зависало

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

>а если ноги к порту подключены но устройство выключили по кнопке... сработает проверка этого байта?

Да, там будет ноль.

и как это сделать


Почитай документацию по ком-порту. Потом почитай про ассемблер. Потом про С. Я не помню, можно ли в С прямо обращаться к железу. Ассемблером можно точно. Вставб подпрограмму на асме, которая будет проверять.

З.Ы. Метод скорее всего ректальный.

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

select не прокатит.. мне нужно например так: нажал по кнопке, получил ответ подключено или нет.. с selectom я не понял может и можно так.. подскажите плиззз..

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

select лично мне не нравится, покажу на примере poll:

struct pollfd pfd;
pfd.fd = serial_fd;
pfd.events = POLLIN;
int n = poll(&pfd, 1, 1000);
if (n > 0 && (pfd.revents & POLLIN)) {
    read(serial_fd, …);
}
arsi ★★★★★
()
Ответ на: комментарий от pozitiffcat

Ну правильно, она на read вешается (Или на write, хотя это странновато будет). Перед read делаешь select({твой_дескриптор, на чтение}, 200 мс). Если твой дескриптор доступен на чтение - read, нет - таймаут, железки нет.

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

select лично мне не нравится, покажу на примере poll:

Ну это уже детали, poll в чем-то красивее, но смысл от этого не меняется :-)

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

Да вы совсем укурились юзать селекты и поллы в _плюсах_ :)

Гм, а ты прав, пожалуй.

ЮЗАЙ ASIO @ НЕ ЗНАЙ ПРОБЛЕМ

Тащить еще asio, при этом автор говорит о кнопках, значит у него уже есть какой-то фреймворк (Qt, GTK или что там еще). В фреймворке уже должны быть механизмы для асинхронной работы, интегрированные с event loop фреймворка. Вот их и стоит использовать, как по мне.

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

>++ головного мозга?

Нет, это просто стремление использовать в языке _родные для него_ методы и идиомы.

А вот у тех, кто тащит в плюсатые проекты селекты, поллы, опен-клоус-рид-райты в неприкрытом виде - тут да, Си головного мозга в терминальной стадии.

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

вот как выкинут си из с++, тогда и поговорим, ок? ;)

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

О каком косяке? Ты используешь блокирующее чтение, и программа блокируется, все как и должно быть. Для Qt есть http://gitorious.org/inbiza-labs/qserialport, я его не смотрел, за ненадобностью, посмотри, может подойдет.

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

Гм, нет. Тогда значит в цикле виснет, смотри strace, там можно увидеть, как именно у тебя виснет, я ж не телепат. А select/poll как раз и придуманы для этой ситуации, использую уже много лет, куча железяк, все работает.

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

Ну у меня нет готового примера, я использую свой фреймворк и пишу на js, поэтому чисто сишного кода сейчас не найду. А на псевдокоде я выше написал.

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

А блин... У тебя ж гуи будет при select блокироваться, точно. Тебе надо это через event loop протащить, либо в отдельной нити запускать. Но тут я мало чем могу помочь, не qt-шник

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

а перед записью зачем?) запись произойдёт успешно, даже если устройство не подключено. разве что там аппаратное контроль передачи данных…

arsi ★★★★★
()
Ответ на: комментарий от arsi
int set_up_tty (int tty_fd)
{
  int speed;
  struct termios tios;

  if (tcgetattr(tty_fd, &tios) < 0) return -1;

  tios.c_cflag     &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
  tios.c_cflag     |= CS8 | CREAD | HUPCL ;

  tios.c_iflag      = IGNBRK | IGNPAR;
  tios.c_oflag      = 0;
  tios.c_lflag      = 0;
  tios.c_cc[VMIN]   = 1;//1
  tios.c_cc[VTIME]  = 0;//0

  tios.c_cflag &= ~CRTSCTS;

  speed = LineSpeedVal[prop->BaudRate];
  if (speed)
    {
      cfsetospeed (&tios, speed);
      cfsetispeed (&tios, speed);
    }

  if (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0) return -1;

  return 1;
}

pozitiffcat ★★★
() автор топика

Я не использую O_NONBLOCK:

void tty_init(){
        if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){
                err("Can't use port %s\n",comdev);
                return;
        }
        ioctl(comfd,TCGETA,&oldtty); // Узнаем текущие параметры порта
        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] = 1;
        ioctl(comfd,TCSETA,&tty);
}
А для проверки, есть ли железка, и отвечает ли она корректно, использую элементарные функции
unsigned char read_tty(){ // считываем 1 байт (с ожиданием сигнала)
        unsigned char rb; // то, что считываем
        if(comfd < 1) return 0;
        tty.c_iflag &= ~PARODD; // принимаем с девятым битом = 0
        ioctl(comfd,TCSETA,&tty);
        if(read(comfd, &rb, 1) < 1) return 0; // ошибка считывания
        return rb;
}

void write_tty_raw(unsigned char wb){
        if(comfd < 1) return;
        if(crc(wb)) // нечетная сумма
                tty.c_cflag |=PARODD; // 9-й бит = 0
        else
                tty.c_cflag &= ~PARODD; // = 1
        ioctl(comfd,TCSETA,&tty); // перенастраиваем порт
        if(write(comfd, &wb, 1) < 0) err("Error! Can't write to port :(\n"); // и пишем в него байт
}
Таким образом, если read не может считать данные из порта, или порт не открыт, read_tty возвращает 0 (ошибка). Если возникает проблема с записью - write_tty_raw сообщает об ошибке. Зависаний никогда не было.

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

вот это еще перед set_up_tty [code=cpp] int opendev(fr_prop *f) { prop = f; if(prop->USB==0) while ((devfile = open(devname(prop->ComPortNumber), O_NONBLOCK | O_RDWR, 0)) < 0); if(prop->USB==1) while ((devfile = open(devUname(prop->ComPortNumber), O_NONBLOCK | O_RDWR, 0)) < 0) if (errno != EINTR) return -1; if ((fdflags = fcntl(devfile, F_GETFL)) == -1 || fcntl(devfile, F_SETFL, fdflags & ~O_NONBLOCK) < 0) return -1; set_up_tty(devfile);

FD_ZERO (&set); FD_SET (devfile, &set); settimeout(prop->Timeout); return 1; } [/code]

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

ой

int opendev(fr_prop *f)
{
  prop = f;
  if(prop->USB==0)
    while ((devfile = open(devname(prop->ComPortNumber), O_NONBLOCK | O_RDWR, 0)) < 0);
  if(prop->USB==1)
    while ((devfile = open(devUname(prop->ComPortNumber), O_NONBLOCK | O_RDWR, 0)) < 0)
  if (errno != EINTR) return -1;
  if ((fdflags = fcntl(devfile, F_GETFL)) == -1 || fcntl(devfile, F_SETFL, fdflags & ~O_NONBLOCK) < 0) return -1;
  set_up_tty(devfile);

  FD_ZERO (&set);
  FD_SET (devfile, &set);
  settimeout(prop->Timeout);
  return 1;
}

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

а перед записью зачем?

У меня фреймворк, я писал выше, этот же write используется и для сокетов и для всего, поэтому я всегда жду writeable, не помешает :-) Хотя может и зря, как-то не задумывался об оптимизации в этом месте.

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

в куте для этого есть QSocketNotifier,

Точно, это оно.

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

Ну почему ж не дало.. Таймера ж есть в Qt? Запускаешь таймер и QSocketNotifier, ждешь ивента, если пришел от таймера раньше - таймаут, если от нотифайера - можно читать, читаешь.

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

Так вам же уже разжевали, как это стандартными средствами сделать.

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

QSocketNotifier - это и есть select/poll, но интегрированный с event loop Qt. Да, асинхронный ввод-вывод никогда и нигде не был простым, но вариантов тут немного - либо select/poll (то есть QSocketNotifier) либо запустить нить, которая будет блокироваться, а гуи останется рабочим. Я предпочитаю первое (но у меня есть coroutines в языке, мне проще, а на C++ это будут коллбеки/ивенты).

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

> tios.c_cflag

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

tios.c_cflag &= ~(CSIZE|CSTOPB|PARENB|PARODD);
tios.c_cflag |=  (CLOCAL|CREAD|CS8);
arsi ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.