Удаленное управление. QML.
- 
И всем снова привет. Тут вспомнил еще про один проект, который построен на базе ferro_remote клиента. Это QML клиент. Тем, кто не знает, что это такое можно прочитать тут + много русскоязычных источников. QML это простой язык описания визуального интерфейса со встроенным JS. Была когда-то идея купить себе Jolla, интерфейс, которой построен именно на QML. Проект, который входит в дерево ferro_remote. Пока я его подзабросил, потому как телефон Jolla я так и не купил. Вот про этот клиент я и напишу сейчас. gui_client, а именно так называется этот клиент (с названиями у меня туго, да) представляет собой обычный бинарник, который принимает в командную строку путь к QML файлу, экспортирует в машину некоторые интерфейсы клиента и исполняет файл. Все просто. Все очень похоже на работу lua_client, который я тут описывал не так давно. Есть, однако, пара моментов. Клиентов в одном экземпляре QML может быть несколько, каждый может быть соединен со своим агентом 
 Соединяться нужно из скрипта, то есть вызывать методы клиента и реагировать на его события (сигналы)
 Тут еще стоит отметить, что собранного бинарника для той же винды у меня нет, потому как под рукой нет самой винды с QtCreator.И так. Запуск приложения выглядит вот так $ ./gui_client test.qmlгде test.qml это как раз само окно приложения со всем, что необходимо. Самый простой пример: import QtQuick 2.0 Rectangle { id: mainWindow }Теперь, если это запустить, мы получим просто белое окошко, которое можно свернуть, развернуть, или закрыть Но нужно ж соединиться с малиной, например. Добавим. import QtQuick 2.0 import Fr.Client 1.0 /// импорт клиента и некоторых интерфейсов Rectangle { id: mainWindow FrClient { // клиент id: generalClient Component.onCompleted: connect( "192.168.3.1:12345" ) // соединимся с малиной } }Все. Вызов: (Далее просто можно закрыть) $ ./gui_client test.qmlВ логах агента на стороне малины будет: 2000-Jan-11 02:38:19.472011 [INF] [listener] New connection: ep: tcp://0.0.0.0:12345 client: tcp://192.168.3.10:52849 total: 1 2000-Jan-11 02:38:26.854824 [INF] [listener] tcp://0.0.0.0:12345 Close connection: tcp://192.168.3.10:52849; count: 0Этот код можно немного причесать и получить что-то типа такого  Сам QML файл лежит тут. Он соединяется, разъединяется, показывает ошибку, если возникла. Можно сделать что-то поинтереснее. Например валяется у меня Grove LCD RGB. Как известно из даташита на это устройство, устройства в этой железке 2. Первое отвечает за текст, второе за цвет экранчика. Оба рулятся по i2c. Все должно быть просто. Кстати сам экранчик выглядит вот так  Это он подключен не к малинке, если что. Просто такой же девайсик с линуксом на борту и агентом ferro_remote. Для того, чтоб уметь работать с устройством, добавлю 2 компонента FrClientI2C: Rectangle { // это будет общий компонент-девайс, который мы сможет потом, 
 // например, вынести в отдельный файл
 id: lcdDevice
 width: 0
 height: 0
 FrClientI2c {
 id: txtDev // этот для текста
 client: generalClient // использовать клиента с id generalClient
 busId: 1 // шина 1
 slaveAddress: 0x3E // адрес
 }FrClientI2c { id: rgbDev // этот для цвета client: generalClient busId: 1 slaveAddress: 0x62 }} Что тут происходит: Компоненты будут готовы к работе, как только клиент будет соединен с агентом. У каждого компонента (если я нигде не забыл это воткнуть), есть свойство ready и соответственно сигнал "onReadyChanged", в которой передается значение ready (true or false). Поэтому прям в компонент lcdDevice можно добавить свойство, которое принесет с собой и сигналы, на которые можно реагировать: Rectangle { id: lcdDevice width: 0 height: 0 property bool ready: txtDev.ready && rgbDev.ready // привяжем состояние 2 устройств к 1 значению........ 
 onReadyChanged: { // устройства изменили состояния
 if( ready ) {
 ..... // оба устройства готовы.
 }
 }
 }
 Добавим в код пару функций. Первая будет менять цвет, вторая очищать экран.Rectangle { id: lcdDevice ...... function set_color( r, g, b ) { // установка цвета. за это отвечают 3 регистра. rgbDev.writeBytes( { 0x04: r, 0x03: g, 0x02: b } ) } function clear( ) { // очистка экрана - установка регистра 0x80 в 1 txtDev.writeBytes( { 0x80: 0x01 } ) } }и теперь можно при готовности устройств очистить их и сбросить цвет на 0 onReadyChanged: { if( ready ) { clear( ) set_color( 0, 0, 0 ) } }Так при подключении программка будет убирать текст с экрана и устанавливать цвет в 0x000000 то есть он будет выключен. Добавлю функцию для установки текста. Я сделаю функцию с 2 параметрами, так как строк у экранчика 2. /// собственно функция формирует массив из объектов, которые выглядят так: {registry: value} /// после этого все это пишется в устройство. /// тут, при использовании массива будет гарантия того, /// что значение регистров будет установлено ровно в той последовательности, /// в какой они поступят в массив. /// 0x40 - регистр, который пишет свое значение в следующее знакоместо. function set_text( txt, txt2 ) { /// сначала очистка экрана и установка курсора с положение 1:1 txtDev.writeBytes( [{ 0x80: 0x01 }, { 0x80: 0x08 | 0x4 }, { 0x80: 0x28 }] ) var txt_value = [] /// значение регистров для записи текстаfor( var i = 0; i < txt.length; i++ ) { txt_value = txt_value.concat( [{ 0x40: txt.charCodeAt(i) }] ) } txt_value = txt_value.concat({ 0x80: 0xC0 }) /// переход на 2 строку. for( i = 0; i < txt2.length; i++ ) { txt_value = txt_value.concat( [{ 0x40: txt2.charCodeAt(i) }] ) } txtDev.writeBytes(txt_value) /// Пишем. }Если все правильно, то после вызова функции мы увидим на экранчике текст, переданный в параметрах. onReadyChanged: { if( ready ) { //clear( ) set_color( 100, 100, 100 ) set_text( "Hola,", "raspberrypi.ru" ) } }Запустив и подключив, мы увидим светлый экран и надпись на нем "Hola,\nraspberrypi.ru" Дальше - больше.  Я добавил ColorDialog из "QtQuick.Dialogs 1.0" и повесил событие смены текущего цвета на смену цвета экрана. Скрипт можно взять тут. Скрипты немного корявенькие, потому как это вообще первый мой проект, как с QML, так и с Qt вообще. PS: есть еще примеры работы с удаленным исполнением консольной команды, с листингом директории.  - Есть работа с пинами GPIO и, недавно начал прикручивать, SPI.
 Так же при помощи QML можно легко и непринужденно смотреть видео с железки Rectangle { width: 600 height: 200 Video { anchors.fill: parent source: "rtsp://192.168.3.1:554/video" enabled: true visible: true focus: true autoPlay: true } }Пока все. Спасибо за внимание  
