Russian Qt Forum
Апрель 29, 2024, 09:50 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QSerialDevice2 + linux + tibbo virtual com port  (Прочитано 9847 раз)
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« : Апрель 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 - последний принимает не полученный ответ от устройства. Очень бы хотелось иметь возможность не только посылать данные, но  и получать...

зыЖ писать в ветку разработки  постеснялся Улыбающийся
Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #1 : Апрель 09, 2012, 12:10 »

Порт сначала надо открыть, а потом конфигурить!

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

ArchLinux x86_64 / Win10 64 bit
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #2 : Апрель 09, 2012, 12:40 »

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

Код
C++ (Qt)
while(!asleep()) sheep++;
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #3 : Апрель 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 вообще
эвент о приходе данных?
Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #4 : Апрель 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;  }
...
 
Записан

ArchLinux x86_64 / Win10 64 bit
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #5 : Апрель 09, 2012, 14:06 »

Добавил QDebug() в оба места.
До обоих выводов доходит, секция
Код
C++ (Qt)
       if (obj == m_readNotifier) {
 
           m_parent->canReadNotification();
 
           return true;
 
       }
постоянно (более  100 вызовов в секунду) вызывается до закрытия приложения. Какие-то исходники к драйверу прилагаются, только я не уверен, что это то, что нужно. На всякий случай во вложении архив с драйвером.
Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #6 : Апрель 09, 2012, 14:12 »

Хм.. странно... Если вызвается - то должно быть все OK.

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

ArchLinux x86_64 / Win10 64 bit
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #7 : Апрель 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.

Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #8 : Апрель 09, 2012, 14:50 »

Ну а залезь в readFromPort() и пройди шаг за шагом до UnixSerialPortEngine::read().
Что возвращает нативная функция read()?

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

Код

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

Код

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

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

Не используй setReadBufferSize() вообще, без него пробуй
« Последнее редактирование: Апрель 09, 2012, 14:54 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #9 : Апрель 09, 2012, 14:57 »

Он считает, что ему считывать нечего.

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

Код
C++ (Qt)
while(!asleep()) sheep++;
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #10 : Апрель 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()   Шокированный

Так что вот так.
« Последнее редактирование: Апрель 09, 2012, 15:33 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #11 : Апрель 09, 2012, 15:45 »

Спасибо! Заработало. Буду писать тиббовцам Улыбающийся
Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #12 : Апрель 09, 2012, 15:51 »

Ок.

Тогда я тоже самое фикшу в QtSerialPort (избавляюсь от bytesAvailable)
раз с дровишками бывают такие проблемы...
Записан

ArchLinux x86_64 / Win10 64 bit
b-s-a
Гость
« Ответ #13 : Апрель 09, 2012, 22:04 »

Я бы на твоем месте сделал бы некий workaround. т.е. если данные через read поступают, а через ioctl(..., FIONREAD, ...) нет, то тогда включать обход (два флага: тест уже пройден/еще не пройден и ioctl работает/не работает). В противном случае не включать.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #14 : Апрель 10, 2012, 09:45 »

Нет, в этом нет необходимости, тут (в этом коде)  FIONREAD вообще не нужен,
он только мешает.

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

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

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

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

ArchLinux x86_64 / Win10 64 bit
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.263 секунд. Запросов: 22.