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

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

Страниц: 1 2 3 [4] 5   Вниз
  Печать  
Автор Тема: Как разрулить потоки  (Прочитано 26519 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Команды приходят во входной буфер, результат скидывается в выходной. Соответственно серия из команд ограничена только емкость буфера.
Это не протокол. Принципиально может ли устройство ответить с тем же уникальным кодом/ID что и посланная команда. Если да - можно посылать в любом (разумном) порядке.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



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

Команды приходят во входной буфер, результат скидывается в выходной. Соответственно серия из команд ограничена только емкость буфера.
Вы сейчас говорите уже о слое бизнес-логики?
Записан
Sphynx
Гость
« Ответ #47 : Июль 26, 2016, 09:52 »

Я не знаю что такое слой бизнес-логики ) Не надо ничего усложнять все до банальности просто. Устройство читает свой входной буфер, если там что-то есть, то выполняет и результат скидывает в выходной буфер.
Затолкать в буфер можно и одну и 2 и 10 команд, все равно они будут считываться и выполнятся последовательно.
Отслеживать ID запроса в железке теоретически можно, но придется перепиливать софт железки. По моему немного отошли от темы. Все что сейчас мешает это двойной вызов функции mcu->Read(); Я не знаю, может есть какие-то стандартные средства С++ чтобы не допускать такого. Либо раз уж это происходит, почему программа вешается при моем варианте решения. Как вообще правильно делить одну функция между разными потоками.
Записан
Bepec
Гость
« Ответ #48 : Июль 26, 2016, 10:12 »

Ей богу, вам лучше написать тз и заказать программу под ваши нужды.

По идее вам надо начать с протокола, проанализировать, поменять или улучшить, соответственно перепрошить железяку под новый протокол(а мб и не нужно, кто знает), потом взять приведённые в теме коды и на его основе построить логику приема/передачи. А уже под эту логику сделать ui.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



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

Я не знаю что такое слой бизнес-логики ) Не надо ничего усложнять все до банальности просто. Устройство читает свой входной буфер, если там что-то есть, то выполняет и результат скидывает в выходной буфер.
Затолкать в буфер можно и одну и 2 и 10 команд, все равно они будут считываться и выполнятся последовательно.
Отслеживать ID запроса в железке теоретически можно, но придется перепиливать софт железки. По моему немного отошли от темы. Все что сейчас мешает это двойной вызов функции mcu->Read(); Я не знаю, может есть какие-то стандартные средства С++ чтобы не допускать такого. Либо раз уж это происходит, почему программа вешается при моем варианте решения. Как вообще правильно делить одну функция между разными потоками.
Ничего в прошивке менять не нужно.
Покажите, для примера, несколько запросов к устройству с ответами и я покажу как это реализовать.
Например:
Запрос alive - ответ ok;
Запрос mode - ответ число обозначающее режим;
Запрос state - ответ bool (true - можно менять режим)
и т.д.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

От kuzulis тоже не понимаю, запрос идет через слот, а как реализована обратная связь ?
Это самый простой/естественный вариант, неясно чем он не устраивает. Не организуем никаких ожиданий, не вызывает processEvents. Просто по таймеру получаем упр-е и смотрим есть (пришли) ли данные. Нет - уходим в событийный цикл, UI свободно. Пришли - разбираемся с ними. Все

А определить/идентифицировать на что пришел ответ так или иначе придется. Напр истек таймаут - а устройство прислало (запоздалый ответ).

Как посылать - тоже рассказали, самое простое складывать в очередь, а реальную посылку устройству делать когда получен (и обработан) ответ  
Записан
Sphynx
Гость
« Ответ #51 : Июль 26, 2016, 11:39 »

Команды шлются в текстовом виде, в устройстве крутится простейший интерпретатор, например:
ADC 6 IREF 5 3 2 AVCC 7 ; Эту посылку можно рассматривать как 7 команд: запрашивает измерение с канала 6, установка опоры, измерение каналов 5 3 2 установка опоры, измерение канала 7.
Ответ будет последовательность слов каждое из которых оканчивается кодом $0D :
123 OK 234 345 456 OK 567
Соответственно послав строку ADC 6 IREF 5 3 2 AVCC 7 ; необходимо вычитать ровно 7 слов.
В моем случае это будет 7 последовательных вызовов mcu->Read();
Функция нарезает слова из буфера и возвращает признак:
m_OK - пришло сообщение "OK"
m_Num - пришло число
m_Timeout - превышено время ожидания.
и т.д.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


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

Цитировать
ADC 6 IREF 5 3 2 AVCC 7 ... как 7 команд

Моя парсилка видит только три:

* запрос ADC 6 -> ответ 123 OK (+CR)
* запрос  IREF 5 3 2 -> ответ 234 345 456 OK (+CR)
* запрос  AVCC 7 -> ответ 567 (ОК?) (+CR)

И в чем проблема?

1) суем в очередь три запроса
2) берем первый запрос ADC 6 из очереди и отсылаем его
3) приходит ответ 123 OK
4) мы определяем, соответствует ли данный ответ текущему запросу (запрос у нас еще в очереди)
5) если соответствует, то удаляем из очереди первый запрос, а ответ парсим и выводим в нужные контролы в UI
6) берем следующий запрос  IREF 5 3 2 из очереди и отсылаем его
7) приходит ответ 234 345 456 OK
8 ) мы определяем, соответствует ли данный ответ текущему запросу (запрос у нас еще в очереди)
9) если соответствует, то удаляем из очереди первый запрос, а ответ парсим и выводим в нужные контролы в UI

и т.п.

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

Цитировать
оканчивается кодом $0D :

Это же ЕМНИП, CR, тогда вообще нет проблем с парсингом ответа: просто используем serial->canReadLine() && serial->readLine(),
все еще проще становится.

ЗЫ: Ну и в чем сложность то?
« Последнее редактирование: Июль 26, 2016, 12:31 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Bepec
Гость
« Ответ #53 : Июль 26, 2016, 13:49 »

У него почти отсутствует протокол, в том и проблема.
ADC 6 IREF 5 3 2 AVCC 7
Разбор на мой взгляд
ADC [номер канала] - запрос измерения с 6 канала (ответ цифра)
IREF - установка опоры (ответ OK/noOK)
(5 3 2 7 )[\d] - запрос данных с канала (ответ цифра)
AVCC - установка опоры (ответ OK/noOK)

Т.е. тут даже не пахнет нормальным протоколом, потому и возникают проблемы с логикой.
По хорошему на мой взгляд надо сделать стандартный кадр.
Что то типо
[признак начала кадра][команда][параметры команды]

Хотя и в таком виде можно спокойно написать свой менеджер.
PS и ещё 1 сообщение будет ниже. Для разделения мух и котлет.
Записан
Bepec
Гость
« Ответ #54 : Июль 26, 2016, 14:10 »

Вам нужен менеджер с ожиданием ответа.
Пихаем в менеджер команды
ADC 6
IREF
5
3
2
AVCC 7

Он шлёт устройству, ждёт ответа.
Приходит ответ 123 OK 234 345 456 OK 567
Менеджер его парсит соответственно
123
OK
234
345
456
OK
567

И по кончанию парсинга испускает 7 (семь) сигналов о получении данных аля
Запрос   Ответ
ADC 6     123
IREF       OK
5            234
3            345
2            456
AVCC      OK
7            567

В результате вам и думать не надо о том, что где то чёто вызывать, менеджер сам разрулит всё, вам нужно будет лишь их обработать.
Записан
Sphynx
Гость
« Ответ #55 : Июль 26, 2016, 16:18 »

С разбором ответа проблем никаких и не возникает. Проблема возникает когда от от таймера ушла команда например ADC 0 1 2 ; и вызывается mcu->Read() для получения первого результата. И в этот момент от другого потока по нажатию на кнопку отправляется например PORT $55 ; и снова вызывается mcu->Read() для получения ответа.
Вариант с менеджером мы тут уже разобрали. Менеджер испустит 7 сигналов, только кому ? Запросы могут идти от различных кнопок.
Допустим получит менеджер число 123 и что ему с ним делать ? Кому его отправлять ?
Синтаксис запросов подразумевает что все что между ADC и ; принадлежит к группе команд измерений.
ADC 6 IREF 5 3 2 AVCC 7 ; эквивалентно ADC 6 ; ADC IREF ; ADC 5 ; ADC 3 ; ADC 2 ; ADC AVCC ; ADC 7 ;
Поэтому если на запрос 3 пришел ответ 345, это абсолютно ни о чем не говорит.
Мне надо как-то заблокировать mcu->Read() для другого потока, пока первый поток не считает все данные.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


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

Блин, все же уже разжевали.  Злой

И опять-25, какие-то потоки, какие-то кнопки и пр. причем здесь кнопки, потоки вообще... каша-в-голове.

Ты понимаешь что такое очередь? Например, за колбасой:

1. Человеки в очереди - это таски/реквесты
2. Продавец - удаленный девайс
3. Первый чел протягивает 100р и грит: "Дайте краковской 100 гр" (это эквивалент запроса)
4. Продавец дает ему (это ответ)..
5. Чел покидает очередь
6. След чел дает 1рубь.. дайте московской 10 кг...
7. У продавца ступор и когнитивный диссонанс (это таймаут)
8. Продавец отвечает: "да пшел ты с рублем" - это ошибка.
9. Чел или уходит из очереди или пытается состав 1000р повторить попытку..

Я умываю руки.
« Последнее редактирование: Июль 26, 2016, 16:42 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Bepec
Гость
« Ответ #57 : Июль 26, 2016, 16:35 »

Вы опять не догоняете.
Выбросьте из головы своей свою mcu->read. Забудьте о вызове этого метода, его нет, не будет и никогда не было.

У вас 1(один) объект порта. У вас 1(один) менеджер. У вас 2(два) получателя/просителя/работника/потока.

3 сущности:
Поток 1
Поток 2
Менеджер

Поток 1 пишет в менеджер  ADC 0 1 2.
Список запросов менеджера:
0 Поток 1 запросил "ADC 0 1 2"

Поток 2 пишет в менеджер PORT $55.
Список запросов менеджера:
0 Поток 1 запросил "ADC 0 1 2"
1 Поток 2 запросил "PORT $55"

Менеджер начинает работу. Посылает устройству запрос 0 и запускает таймер на ответ
Если пришли данные - вынимает из запрос 0 отправителя и шлёт ему отвёт "122 155 166"
Если данных нет и таймер вышел, то - вынимает из запрос0 отправителя и шлёт ему ошибку "Запрос ADC 0 1 2 нет ответа"
В результате удаляет первый элемент списка запросов.

Список запросов менеджера:
0 Поток 2 запросил "PORT $55"
Дальше аналогично.

У вас в результате оба потока получили данные(или ошибку). Мало того, потоков может быть неограниченное число, менеджеру без разницы сколько их.

PS я конечно опустил многие детали вроде разделение данных и ошибок, вроде парсинга структур и проверки данных на соответствие, добавлении, удаления запросов, обработку ошибок порта и прочее. Но это уже несущественно.

PPS на правах рекламы - за энную сумму могу вам написать программу, проконсультировать, разъяснить.
« Последнее редактирование: Июль 26, 2016, 16:36 от Bepec » Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


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

Млин, да не нужны тут потоки.. ну вообще не нужны!
Записан

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

Не обижайтесь, я правда не понимаю что вы мне пытаетесь разжевать.
Можно конкретней, пусть будут 3 кнопки A B C. По нажатию на кнопки необходимо выполнять определенный сценарий из команд.
Опишите пожалуйста не нижние функции обработчика парсера менеджера и тд. а верхние.
То есть прям конкретно пусть по нажатии кнопки А необходимо:
Установить порт PORT DDR $FF 0 ;
Измерить канал ADC 5 ;
если значение меньше 100 то установить порт PORT $FF ;
Как будет выглядеть эта процедура прям вот конкретно внутри MainWindow::on_pushButton_clicked() 
Записан
Страниц: 1 2 3 [4] 5   Вверх
  Печать  
 
Перейти в:  


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