Russian Qt Forum

Qt => Дополнительные компоненты => Тема начата: Kurles от Апрель 09, 2012, 11:02



Название: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: Kurles от Апрель 09, 2012, 11:02
Здравствуйте! Возникла проблема при использовании  связки QSerialDevice2 + linux + tibbo virtual com port. Есть устройство, которое взаимодействует с компом через драйвер tibbo tcp/ip <> serial port. Драйвер порта на конечной машине установлен и функционирует. Открываю порт таким образом:

Код
C++ (Qt)
   serialPort = new SerialPort(this);
   connect(serialPort, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
   serialPort->setPort("/dev/vsps0");
   serialPort->setRate(SerialPort::Rate9600, SerialPort::Input);
   serialPort->setRate(SerialPort::Rate9600, SerialPort::Output);
   serialPort->setDataBits(SerialPort::Data8);
   serialPort->setParity(SerialPort::NoParity);
   serialPort->setFlowControl(SerialPort::NoFlowControl);
   serialPort->setStopBits(SerialPort::OneStop);
   serialPort->setReadBufferSize(1024);
   serialPort->open(SerialPort::ReadWrite);

затем записываю в него управляющую команду:

Код
C++ (Qt)
   array.append((char)0x00);
   array.append((char)0x40);
   array.append((char)0x26);
   array.append((char)0x31);
   array.append((char)0x09);
   array.append((char)0x60);
   serialPort->write(array);
В результате команда до устройства доходит, а его ответ до компа - нет, пробовал форсировать получение ответа не через ReadyRead(),  а по кнопке после посылки команды - толку ноль. В randterm (терминал, написанный на питоне), команды принимаются и отправляются, при чем если сначала отправить данные через QSerialDevice2, закрыть порт, а затем открыть порт через randterm - последний принимает не полученный ответ от устройства. Очень бы хотелось иметь возможность не только посылать данные, но  и получать...

зыЖ писать в ветку разработки  постеснялся :)


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: kuzulis от Апрель 09, 2012, 12:10
Порт сначала надо открыть, а потом конфигурить!

ЗЫ: Ну сколько уже можно то а? А проверить возвращаемые значения от setRate(), setDataBits() и т.п. не судьба?


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: Kurles от Апрель 09, 2012, 12:40
Порт сначала надо открыть, а потом конфигурить!
Да, тут я невнимательно поступил. Собственно есть уже работающий проект, использующий первую (нулевую?) версию Вашей библиотеки, там все в нужном порядке конфигурируется, и под Windows все прекрасно работает,  понадобилось перевести этот проект под linux - скомпилировалось все с первого раза, приложение данные посылает, а принимать отказывается. Вот и решил попробовать v2.0, и в результате такой же результат :(
ЗЫ: Ну сколько уже можно то а? А проверить возвращаемые значения от setRate(), setDataBits() и т.п. не судьба?
Теперь проверяю, конфигурирую в нужном порядке (setPort, open, setDataBits, setRate, etc...), все так же отказывается принимать данные :( ЧЯДН? Под виндой работает. Грешил бы на драйвер, но ведь из других терминалов (собственно проверял только на randterm, так как он позволяет посылать пакеты в hex формате) работает. Так что приходится грешить на свои кривые руки :(


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: kuzulis от Апрель 09, 2012, 13:21
Хм... интересно.... Значит readyRead() не излучается?

А у тебя есть исходники драйвера tibbo tcp/ip ?
Может быть, там select не реализован?

Попробуй собрать отладочную версию и поставить брекпойнт
в src/serialportengine_p_unix.cpp в методе

Код
C++ (Qt)
bool UnixSerialPortEngine::eventFilter(QObject *obj, QEvent *e)
{
 
   if (e->type() == QEvent::SockAct) {
 
       if (obj == m_readNotifier) {
 
           m_parent->canReadNotification();
 
           return true;
 
       }
 
       if (obj == m_writeNotifier) {
 
           m_parent->canWriteNotification();
 
           return true;
 
       }
 
       if (obj == m_exceptionNotifier) {
 
           m_parent->canErrorNotification();
 
           return true;
 
       }
 
   }
 
   return QObject::eventFilter(obj, e);
}
 

т.е.

1. брекпойнт на сам этот метод или qDebug() для проверки
того, а вызывается ли вообще этот метод?
2. брекпойнт или qDebug() в секцию
Код
C++ (Qt)
       if (obj == m_readNotifier) {
 
           m_parent->canReadNotification();
 
           return true;
 
       }
 

для проверки того, а ловит ли m_readNotifier вообще
эвент о приходе данных?


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: kuzulis от Апрель 09, 2012, 13:59
Цитировать
Может быть, там select не реализован?
Хотя, бегло глянув в исходники древней версии vspd-1.12-linux.tar.gz
видно, что оно вроде было реализовано:

Код
C
...
static unsigned int vsp_poll( struct VSP_ROOT *_root, int _num, poll_table *_pt, struct file *_file) {
unsigned int mask = 0;
struct VSP_DEV *dev_read, *dev_write;
if ( _num >= _root->maxdev) return( -ENODEV);
/* if write to file ==> dev = file (F->F) 0->1 */
/* if write to port ==> dev = port (S->S) 1->0 */
dev_read = &( _root->devices_S[ _num]);
dev_write = &( _root->devices_D[ _num]);
poll_wait( _file, &( dev_read->wqr), _pt);
poll_wait( _file, &( dev_write->wqw), _pt);
if ( dev_read->buff_len > 0) mask |= POLLIN | POLLRDNORM; /* readable */
if ( dev_write->buff_len < VSP_MAXBUF - 1) mask |= POLLOUT | POLLWRNORM; /* writable */
if ( debug > 2) KLOG( "[%s] poll/select returns %i for R%s W%s to %s(%d)\n", VSP_MOD_NAME, mask, dev_read->name, dev_write->name, VSP_PCOMM, VSP_PID);
return( mask);  }
 
static unsigned int vspd_poll( struct tty_struct *_tty, struct file *_file, poll_table *_pt) {
return( vsp_poll( &rootdev, VSP_MNUMF( _file), _pt, _file));  }
static unsigned int vsps_poll( struct tty_struct *_tty, struct file *_file, poll_table *_pt) {
return( vsp_poll( &rootdev, VSP_MNUMF( _file), _pt, _file));  }
 
static void vspd_setldisc( struct tty_struct *_tty) {
_tty->ldisc.read = vspd_read;
_tty->ldisc.write = vspd_l_write;
_tty->ldisc.poll = vspd_poll;
return;  }
static void vsps_setldisc( struct tty_struct *_tty) {
_tty->ldisc.read = vsps_read;
_tty->ldisc.write = vsps_l_write;
_tty->ldisc.poll = vsps_poll;
return;  }
...
 


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: Kurles от Апрель 09, 2012, 14:06
Добавил QDebug() в оба места.
До обоих выводов доходит, секция
Код
C++ (Qt)
       if (obj == m_readNotifier) {
 
           m_parent->canReadNotification();
 
           return true;
 
       }
постоянно (более  100 вызовов в секунду) вызывается до закрытия приложения. Какие-то исходники к драйверу прилагаются, только я не уверен, что это то, что нужно. На всякий случай во вложении архив с драйвером.


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: kuzulis от Апрель 09, 2012, 14:12
Хм.. странно... Если вызвается - то должно быть все OK.

Если сам сигнал readyRead() излучается, то убери вообще
Код
C++ (Qt)
...
   serialPort->setReadBufferSize(1024);
...
 


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: Kurles от Апрель 09, 2012, 14:34
собственно в функции bool SerialPortPrivate::canReadNotification()

Код
C++ (Qt)
       // If reading from the serial fails after getting a read
       // notification, close the serial.
       newBytes = m_readBuffer.size();
 
       if (!readFromPort()) {
           m_readSerialNotifierCalled = false;
           return false;
       }

вылетает на этом. Если убрать вызов

Код
C++ (Qt)
   serialPort->setReadBufferSize(1024);
Код
C++ (Qt)
qDebug() << "readBuffer" <<  serialPort->readBufferSize();
возвращает 0.



Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: kuzulis от Апрель 09, 2012, 14:50
Ну а залезь в readFromPort() и пройди шаг за шагом до UnixSerialPortEngine::read().
Что возвращает нативная функция read()?

Цитировать
Если убрать вызов

Код

C++ (Qt)
    serialPort->setReadBufferSize(1024);

Код

C++ (Qt)
qDebug() << "readBuffer" <<  serialPort->readBufferSize();

возвращает 0.

Не используй setReadBufferSize() вообще, без него пробуй


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: Kurles от Апрель 09, 2012, 14:57
Он считает, что ему считывать нечего.

Код
C++ (Qt)
 qint64 bytesToRead = (m_policy == SerialPort::IgnorePolicy) ?
               bytesAvailable() : 1;
 
   if (bytesToRead <= 0)
       return false;
bytesToRead = 0. Повторюсь, сторонняя терминальная программа, подключаясь к данному порту считывает из буфера данные, не полученные QSerialDevice.


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: kuzulis от Апрель 09, 2012, 15:25
По ходу в драйвере что-то накосячено с обработкой ioctl(..., FIONREAD, ...) т.е.
bytesAvailable() возвращает хренотень (ноль).
Код
C
static int vsp_ioctl_S( struct VSP_ROOT *_root, int _num, unsigned int _cmd, unsigned long _arg, struct tty_struct *_tty, struct file *_file)
{
...
unsigned short tmp_short = 0;
...
...
 
  case FIONREAD:
    if ( debug & DEBUG_IOCTL_S) KLOG( "[%s] %s FIONREAD\n", VSP_MOD_NAME, __FUNCTION__);
    if ( VSP_ACCESS_OK( VERIFY_WRITE, ( void *)_arg, sizeof( unsigned short)) == 0) return( -EFAULT);
// FIXME : write buffer space to tmp_short
    KTU( ( void *)_arg, &tmp_short, sizeof( unsigned short));
    break;
...
...
}
 

Поэтому замени bytesAvailable() тупо на любое число, например на 256
Код
C++ (Qt)
 qint64 bytesToRead = (m_policy == SerialPort::IgnorePolicy) ?
               256 : 1;
 
   if (bytesToRead <= 0)
       return false;
 

Цитировать
Повторюсь, сторонняя терминальная программа, подключаясь к данному порту считывает из буфера данные, не полученные QSerialDevice.
Я посмотрел исходники этой питоновской терминальной программки - она читает потому,
что у нее в отдельном потоке крутится постоянно read()   :o

Так что вот так.


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: Kurles от Апрель 09, 2012, 15:45
Спасибо! Заработало. Буду писать тиббовцам :)


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: kuzulis от Апрель 09, 2012, 15:51
Ок.

Тогда я тоже самое фикшу в QtSerialPort  (http://qt-project.org/wiki/QtSerialPort_Russian)(избавляюсь от bytesAvailable)
раз с дровишками бывают такие проблемы...


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: b-s-a от Апрель 09, 2012, 22:04
Я бы на твоем месте сделал бы некий workaround. т.е. если данные через read поступают, а через ioctl(..., FIONREAD, ...) нет, то тогда включать обход (два флага: тест уже пройден/еще не пройден и ioctl работает/не работает). В противном случае не включать.


Название: Re: QSerialDevice2 + linux + tibbo virtual com port
Отправлено: kuzulis от Апрель 10, 2012, 09:45
Нет, в этом нет необходимости, тут (в этом коде)  FIONREAD вообще не нужен,
он только мешает.

Я давно хотел его отсюда убрать (т.е. убрать bytesAvailable() ) и заменить на чтение чанками,
т.к. раз canReadyRead() был вызван - значит что-то пришло в порт и это нужно вычитать.

А сколько там пришло данных - не важно, нет необходимости вызывать bytesAvailable() для
определения их кол-ва.

Достаточно читать тупо кусками. Для увеличения производительности,
можно читать кусками не по 256 байт, а по 100500 - чтобы за один проход все...

Так что, не нужно тут ничего городить.