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

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

Страниц: 1 2 [3] 4 5   Вниз
  Печать  
Автор Тема: Как разрулить потоки  (Прочитано 25230 раз)
Sphynx
Гость
« Ответ #30 : Июль 25, 2016, 21:33 »

Я даже и не спорю, я действительно не понимаю механики. Можете привести пример ?
Сейчас общение с устройством происходит так, хоть по таймеру хоть по кнопке:
Код
C++ (Qt)
mcu->Send("Команда");
if(mcu->Read()=m_Ok);//Получаем ответ
{
   //Команда прошла успешно
}
 
Как будет происходить общение в вашем случае ? Подробностей не надо, просто хотя-бы структуру вместо моей текущей.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #31 : Июль 25, 2016, 22:17 »

Код
C++ (Qt)
#ifndef MCU_H
#define MCU_H
 
#include <QObject>
 
class QSerialPort;
class QTimer;
 
class MCU : public QObject
{
Q_OBJECT
public:
explicit MCU( QObject *parent = nullptr );
 
void addRequest( int val );
 
private slots:
void nextRequest();
void readyData();
void timeout();
 
private:
QSerialPort *m_port;
QTimer *m_timer;
 
using RequestQueue = QList<int>;
RequestQueue m_requests;
};
 
#endif // MCU_H
 

Код
C++ (Qt)
#include "mcu.h"
#include <QSerialPort>
#include <QTimer>
 
MCU::MCU( QObject *parent ) :
QObject( parent ),
m_port( new QSerialPort( this ) ),
m_timer( new QTimer( this ) )
{
// Настраиваем порт
connect( m_port, SIGNAL(readyRead()), SLOT(readyData()) );
 
// Настраиваем таймер
connect( m_timer, SIGNAL(timeout()), SLOT(timeout()) );
m_timer->setSingleShot( true );
m_timer->setInterval( 250 );
}
 
void MCU::addRequest( int val )
{
// Добавляем запрос в очередь
m_requests.append( val );
nextRequest();
}
 
void MCU::nextRequest()
{
if( m_requests.isEmpty() )
return;
 
// Получаем запрос но оставляем его в очереди
int request = m_requests.first();
 
QByteArray data;
m_port->write( data ); // Отправили запрос
m_timer->start(); // Запустили таймер ожидания ответа
// Теперь сработает один из сигналов: пришли данные (readyRead)
// или сработал таймер (timeout)
}
 
void MCU::readyData()
{
// Пришли данные от устройства
 
// Останавливем таймер
m_timer->stop();
 
// Читаем ответ из порта
QByteArray result = m_port->readAll();
 
// В очереди есть запрос
if( m_requests.isEmpty() )
{
// Получаем запрос на который пришел ответ и удаляем его из очереди
int request = m_requests.takeFirst();
 
// Обрабатываем ответ
// ...
 
// Переходим к следующему запросу
nextRequest();
}
}
 
void MCU::timeout()
{
// Ответ не пришел во время
 
// В очереди есть запрос
if( m_requests.isEmpty() )
{
// Получаем запрос на который пришел ответ и удаляем его из очереди
int request = m_requests.takeFirst();
 
// Обрабатываем ошибку по таймауту
// ...
 
// Переходим к следующему запросу
nextRequest();
}
}
 
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #32 : Июль 25, 2016, 22:26 »

Код
C++ (Qt)
 
class Foo : public QObject
{
public:
   Foo() {
       // конфигурим сторожа
       watchdog->setSingleShot(true);
       watchdog->setInterval(100);
       connect(watchdog, &QTimer::timeout, [this]() {
           if (serial->bytesAvailable() == 0) {
               // это ошибка по таймауту, у-во вообще ничо не ответило
           } else {
               // извлекаем весь ответ, т.к. он будет полным
               const QByteArray response = serial->readAll();
 
               // что-то делаем с ответом, парсим его и пр.
          }
 
           sendNextRequest(); // шлем следующий запрос из очереди
       });
 
       // шлем запросы по таймеру
       connect(timer, &QTimer::timeout, [this]() {
           const QByteArray request1 = ....;
           appendRequest(request1);
       });
 
       // шлем запросы по кнопке 1
       connect(button1, &QPushButton::clicked, [this]() {
           const QByteArray request2 = ....;
           appendRequest(request2);
       });
 
       // шлем запросы по кнопке N
       connect(buttonN, &QPushButton::clicked, [this]() {
           const QByteArray requestN = ....;
           appendRequest(request3);
       });
 
      // перезапускаем сторожа чтобы он не срабатывал, т.к. когда он сработает это будет
      // означать или таймаут или весь пакет принят
      connect(serial, &QSerialPort::readyRead, [this]() {
          watchdog->start();
      }
 
private:
   void appendRequest(const QByteArray &request) {
       pendingRequests << request;
 
       sendNextRequest();
   }
 
   void sendNextRequest() {
       if (watchdog->isActive() || pendingRequests.isEmpty())
           return;
 
       const QByteArray request = pendingRequests.takeFirst();
       serial->write(request);
       watchdog->start();
   }
 
   QList<QByteArray> pendingRequests;
   QSerialPort *serial;
   QTimer *watchdog;
}
 
 

ооо.. я опоздал  Улыбающийся

но у меня чуть по-другому  Подмигивающий
« Последнее редактирование: Июль 25, 2016, 22:27 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Sphynx
Гость
« Ответ #33 : Июль 26, 2016, 05:11 »

Спасибо, попробую разобраться. Только уже не понятно как будет происходить запрос-ответ, допустим по нажатию кнопки. В примере от Old по нажатию на кнопку я вызываю MCU::addRequest(), но обработка ответа происходит внутри MCU::readyData(), мне не ясно как "кнопка" узнает прошла команда или нет. От kuzulis тоже не понимаю, запрос идет через слот, а как реализована обратная связь ?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #34 : Июль 26, 2016, 05:19 »

Спасибо, попробую разобраться. Только уже не понятно как будет происходить запрос-ответ, допустим по нажатию кнопки. В примере от Old по нажатию на кнопку я вызываю MCU::addRequest(), но обработка ответа происходит внутри MCU::readyData(), мне не ясно как "кнопка" узнает прошла команда или нет. От kuzulis тоже не понимаю, запрос идет через слот, а как реализована обратная связь ?
Вы можете в класс MCU добавить свои сигналы и имитеть их при получении ответа или срабатывании таймаута, тогда вызывающая сторона сможет узнать, что происходит.
Записан
Sphynx
Гость
« Ответ #35 : Июль 26, 2016, 05:30 »

Вот допустим по нажатию на кнопку1 я отправляю запрос, устройство возвращает мне число которое я отображаю на лебеле1. По нажатию кнопки2 на лабеле2, и т.д. Неужели внутри независимого класса придется создавать кучу слотов под конкретную задачу ?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #36 : Июль 26, 2016, 05:36 »

Вот допустим по нажатию на кнопку1 я отправляю запрос, устройство возвращает мне число которое я отображаю на лебеле1. По нажатию кнопки2 на лабеле2, и т.д. Неужели внутри независимого класса придется создавать кучу слотов под конкретную задачу ?
Слот может быть один, а в нем вы можете решать в каком label отображать результат.
Записан
Sphynx
Гость
« Ответ #37 : Июль 26, 2016, 05:43 »

Каждая кнопка при нажатии должна перецеплять слот к своему обработчику ?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #38 : Июль 26, 2016, 06:10 »

Каждая кнопка при нажатии должна перецеплять слот к своему обработчику ?
Есть такая штука, как QSignalMapper.
Записан
Sphynx
Гость
« Ответ #39 : Июль 26, 2016, 06:31 »

Ладно, сработал таймер, отправил запрос и подключил слот к себе. Тут, так случилось, что в этот же момент нажимается кнопка, отправляется запрос, и слот переподключается на кнопку. Ответ для таймера забирает кнопка, таймер остается вообще без ответа. Проблема та-же, но с другой стороны )
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #40 : Июль 26, 2016, 06:45 »

Ладно, сработал таймер, отправил запрос и подключил слот к себе. Тут, так случилось, что в этот же момент нажимается кнопка, отправляется запрос, и слот переподключается на кнопку. Ответ для таймера забирает кнопка, таймер остается вообще без ответа. Проблема та-же, но с другой стороны )
Не надо ничего переподключать. Вы в самом запросе можете сохранять для кого предназначается ответ (таймеру или кнопке), а в слоте по этому флагу решать, что делать с ответом. Слот для получения результата, что для кнопки, что для таймера, будет один.
Записан
Sphynx
Гость
« Ответ #41 : Июль 26, 2016, 07:12 »

Да, получается что если отправлять данные с неким ид, например mcu->Send("Команда",1); того кто отправляет запрос тогда в обработчике слота проверять:
if(id=1){кнопка1}
if(id=2){кнопка2}
....
Тогда функции mcu->Read(); вообще не будет, а останется только слот с сигналом что получено некое сообщение.
Так наверно будет работать, пока подвохов не вижу )
Записан
Sphynx
Гость
« Ответ #42 : Июль 26, 2016, 07:47 »

Хотя нет, появляется другая не очень приятная вещь.
Так например по нажатию на кнопку может выполнятся некая последовательность действий:

Отправляем команду1;
Если команда прошла успешно,то:
    Отправляем команду2;
    Отправляем команду3;
    Ждем пока команды обработаются;
    Читаем результат команды2;
    Читаем результат команды3;

Во первых этими id придется завалиться и на каждый запрос придумывать свой, даже внутри одной кнопки. Либо выстраивать дополнительные флаги.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #43 : Июль 26, 2016, 08:08 »

Хотя нет, появляется другая не очень приятная вещь.
Так например по нажатию на кнопку может выполнятся некая последовательность действий:

Отправляем команду1;
Если команда прошла успешно,то:
    Отправляем команду2;
    Отправляем команду3;
    Ждем пока команды обработаются;
    Читаем результат команды2;
    Читаем результат команды3;

Во первых этими id придется завалиться и на каждый запрос придумывать свой, даже внутри одной кнопки. Либо выстраивать дополнительные флаги.
Судя по вашим постам ваше устройство не умеет получать серию запросов, выполнять их, а потом возвращать несколько результатов.
Вы определитесь с протоколом обмена.
Записан
Sphynx
Гость
« Ответ #44 : Июль 26, 2016, 08:22 »

Команды приходят во входной буфер, результат скидывается в выходной. Соответственно серия из команд ограничена только емкость буфера.
Записан
Страниц: 1 2 [3] 4 5   Вверх
  Печать  
 
Перейти в:  


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