Тут опять про события и про несколько клиентов, подписанных на одно и тоже событие.
Для примера возьму такой девайс, как энкодер. Энкодер это такая штука

С одной стороны 3 ноги (они то мне и нужны), со второй стороны это пины кнопки, которая так же включена в энкодер. Есть девайсы без кнопки, есть с 2 позициями кнопки, например. Но не важно.
И так есть 3 пина...Смысл работы довольно прост. На средний пин подается (+). Путь пины будут именоваться A, P, B. Если на девайс смотреть сверху, то, по часовой стрелке, сначала идет А, потом P, потом B.
При повороте по часовой стрелке сначала срабатывает соединение
A-P затем
P-B, затем
A-P отключается и последним отключается
P-B. Итого имеем, как и в случае светофора, 4 состояния с 2 пинами.
0, 0 - начальная стадия
1, 0 - начало поворота
1,1 - поворот
0, 1 - завершение поворота.
Реализация: Сделаю простое окошко с картинкой компасного табло (выложил сюда
https://github.com/newenclave/ferro-rem ... compas.png), которое будет поворачиваться на определенный угол, когда я буду вращать энкодер.
Забегая вперед; вот так выглядит окошко с результатом:

Табло крутится, spinbox показывает на сколько градусов повернуть табло при одном щелчке девайса. кнопка сбрасывает позицию на 0.
QMLОписывать создание и подключение клиента не буду. Отмечу только, что он имеет
id remoteClient, как и во всех остальных примерах
Опишу сразу компонент Encoder. Который будет содержать счетчик уменьшая или увеличивая его при повороте ручки.
В qml это будет отдельный
Item. Что это такое и какие у него есть свойства можно почитать тут
http://doc.qt.io/qt-5/qml-qtquick-item.htmСвойством элемента будет одно поле - счетчик.
- Код: Выделить всё
Item {
id: encoder
property int count: 0
....
}
Сам девайс у меня подключен ногой A в 5 GPIO, и ногой B в GPIO4. Направление обоих пинов стоит в IN, edge в both. Плюс у каждого есть булевый флаг
up, который показывает поднят ли текущий пин. Итого:
- Код: Выделить всё
Item {
id: encoder
property int count: 0
FrClientGpio {
property bool up: false
client: remoteClient
index: 5
direction: FrClientGpio.DirectIn
edge: FrClientGpio.EdgeBoth
id: pinA
events: true
}
FrClientGpio {
property bool up: false
client: remoteClient
index: 4
direction: FrClientGpio.DirectIn
edge: FrClientGpio.EdgeBoth
id: pinB
events: true
}
}
Далее логика проста:
Подписываемся на события обоих пинов и когда оно приходит, устанавливаем флаг up, если значение в событии 1 и сбрасываем, если 0.
Если флаг поднялся, то посмотрим на другой флаг и если он тоже поднят, то можно сделать вывод, что мы находимся в процессе поворота ручки. В зависимости от того, в каком мы находимся обработчике, уменьшаем или увеличиваем значение на счетчика.
Код:
- Код: Выделить всё
Item {
id: encoder
property int count: 0
FrClientGpio {
property bool up: false
client: remoteClient
index: 5
direction: FrClientGpio.DirectIn
edge: FrClientGpio.EdgeBoth
id: pinA
events: true
}
FrClientGpio {
property bool up: false
client: remoteClient
index: 4
direction: FrClientGpio.DirectIn
edge: FrClientGpio.EdgeBoth
id: pinB
events: true
}
Connections {
target: pinB
onChangeEvent: {
pinB.up = (value != 0);
if( pinB.up && pinA.up ) { /// вторым сработал пин B, значит ручка крутится по часовой стрелке
encoder.count = encoder.count + 1; /// увеличим значение
}
}
}
Connections {
target: pinA
onChangeEvent: {
pinA.up = (value != 0);
if( pinB.up && pinA.up ) { /// вторым сработал пин A, значит ручка крутится против часовой стрелки
encoder.count = encoder.count - 1; // минус 1 к счетчику
}
}
}
Компонент готов. Теперь можно добавить картинку на окошко и привязать его свойство
rotation к свойству
count энкодера.
- Код: Выделить всё
Image {
id: compas
source: "compas.png"
rotation: encoder.count
Component.onCompleted: {
parent.height = compas.height
parent.width = compas.width
}
}
+ картинка (а точнее компонент Image) сделает так, чтоб родительское окно приняло нужные размер по размеру картинки.
Дальше я просто добавлю кнопку, которая будет сбрасывать счетчик, и SpinBox, который будет устанавливать шаг в градусах.
- Код: Выделить всё
SpinBox {
id: step
minimumValue: -359
maximumValue: 359
value: 1 // по-умолчанию 1
anchors { // слева вниpe
left: parent.left
bottom: parent.bottom
}
}
Button {
id: clear
text: "Drop"
anchors { /// справа внизу
right: parent.right
bottom: parent.bottom
}
}
И теперь вместо строк
encoder.count = encoder.count - 1; и
encoder.count = encoder.count + 1; можно задать
encoder.count = encoder.count - step.value; и
encoder.count = encoder.count + step.value;в элемент encoder же добавлю подписку на кнопку
- Код: Выделить всё
Item {
id: encoder
property int count: 0
.....
Connections {
target: clear
onClicked: {
encoder.count = 0
}
}
}
С кодом все. Весь код можно увидеть
>>> ТУТ <<<.
PS:
Клиентов одновременно можно запустить несколько. По понятным причинам, чем больше клиентов, тем больше будет заметно отставание реакции клиента от реального поворота ручки енкодера. Но все клиенты получат одни и те же события, а значит будут реагировать одинаково. И при одинаковых условиях клиенты будут одинаковых состояниях.
Далее я снял 4 видео:
Первое это запуск и работа 1 клиента на виртуалбоксе, образ которого описан в 1 топике.
https://www.youtube.com/watch?v=XnhfxSyHIHA Второе запуск 6 клиентов на этом виртуал боксе. + установка разных шагов каждому клиенту.
https://www.youtube.com/watch?v=xdBe3yXHJyIТретье - запуск на рабочем ноуте 1 клиента. Девайс между 2 картонками, чтоб держать удобнее было.
https://www.youtube.com/watch?v=2Zi9XgNpcVAЧетверное - запуск 10 клиентов на рабочем ноуте.
можно смотреть с 30 секунды.
https://youtu.be/9tKPsecC_5Y?t=30s