- PVSM.RU - https://www.pvsm.ru -

Привет, читатель! Графики — это удобно. Нередко при разработке они нужны мне для визуализации процесса или демонстрации критичных событий. А еще их можно использовать, чтобы отобразить изменения погоды в течение дня, колебания курса валюты или диаграмму нагрузки и доступности сервера [1]. В большинстве случаев для построения графиков есть готовые инструменты в самой операционной системе, но если вы это читаете, то в «Авроре» я ничего такого не нашел. Как я решал проблему и с какими подводными камнями столкнулся, рассказываю под катом.
Используйте навигацию, если не хотите читать текст полностью:
→ Введение [2]
→ Фронтенд [3]
→ Бэкенд [4]
→ Модули, объединяйтесь! [5]
→ Заключение [6]
В ходе разработки некоторых устройств нередко необходимо проверить работу, полностью «отвязавшись» от внешних источников питания. При этом важно просматривать различную отладочную информацию или вводить команды в консоли. Иногда необходимо просто сделать мобильное устройство на базе телефона. Для реализации этого есть различные модули и шилды, которые позволяют сделать прибор «беспроводным». Однако проще подцепиться кабелем к смартфону и выводить на его экран необходимую графику. В рамках реализации НИОКР и рефакторинга некоторых решений подготовил небольшое pet-приложение на ОС «Аврора» для реализации этих кейсов.
В первую очередь необходимо определиться, что требуется от приложения. Это лог сообщений в виде текста, поле ввода команд и отображение в виде графика — иногда полезно посмотреть на форму сигнала и заметить аномалии.
В вузе долгое время для этих целей использовал LabVIEW и собирал .exe пакет для планшета на Windows. Подход не самый стабильный, тяжелый, но позволял быстро накидать решение и разные дополнительные функции, например спектральный анализ. Дополнительно в качестве эксперимента использовал SiminTech и его модуль связки с Arduino [7].
Очевидно, что подобных «лабораторных» сред под мобильные устройства нет. Под каждый кейс либо разрабатывается полноценное отдельное приложение, либо, если оно уже есть, в него добавляется функциональный модуль.
Для «Авроры» существует несколько основных инструментов разработки. Сейчас популярность активно набирает Flutter — относительно новый фреймворк с открытым исходным кодом. Используя этот инструмент для разработки, легко оперативно получить готовое приложение. В нем есть необходимые графические библиотеки. Однако при погружении в эту тему я не нашел решения по подключению ко внешним устройствам. Так я вернулся к работе с привычным Qt.
Если хотите начать работать с фреймворком flutter под «Авророй», то есть отличная статья для старта [8], а также цикл статей на gitlab pages [9] и примеры [10] от ОМП.
Qt предлагает IDE, адаптированный под «Аврору». Следовательно, отличным, простым и правильным решением кажется использовать QtCharts. Однако с этой библиотекой есть две небольшие проблемы:
Отсутствие библиотеки стало только стимулом собрать ее из исходников. К сожалению, попытка не увенчалась успехом: библиотека собирается, подключается к проекту, но не работает (на версии ОС 4.0.203). А еще выдает следующую ошибку: «Cбой отображения сегмента из разделяемого объекта».
Я пробовал несколько вариантов и меня порадовала работа техподдержки ОМП: сотрудники действительно стараются помочь и предложить решение. Так, на одной из ошибок мне прислали сообщение с указанием вариантов подключения библиотек и модулей.


В поисках решения обратился к Google и Telegram-сообществу. В свободном распространении нашлась пара занимательных библиотек. Они мне не подошли, но оставлю здесь — возможно, кого-то они заинтересуют.

Источник [14].
В чате разработчиков мне указали, что в QML можно использовать JavaScript, а также есть успешные примеры применения библиотеки D3.js [15] для отображения информации. Что ж, пойдем этим путем.

Про использование D3 в QML есть статья на Хабре [16]. Также применение этой библиотеки нашел в портированом Денисом Богомоловым приложении Plotter, исходный код на Git Flic [17]. Взяв эту информацию за основу, доработал QML-страницу приложения, которое можно скопировать в свой проект с GitHub [18].
Для подключения графика в проект достаточно выполнить несколько простых шагов:
Версии D3 не имеют обратной совместимости, поэтому для работы проекта используется версия 4 [19].
Дерево файлов директории QML должно выглядеть примерно следующим образом:
qml
├── cover
│ ├── DefaultCoverPage.qml
├── js
│ ├── d3.v4.js
├── js_test.qml
└── pages
├── AboutPage.qml
├── MainPage.qml
├── Plot.qml
└── Settings.qml
Также не забывайте подключить дополнительные файлы в RPM, чтобы после установки приложения оно могло импортировать необходимые ресурсы:
DISTFILES +=
qml/js/*.js
qml/*
rpm/ru.auroraos.js_test.spec
Далее в файле страницы, на которой будет отображаться график (в рамках этого примера — MainPage), подключаем заголовочный файл d3 и добавляем компонент plot:
import "../js/d3.v4.js" as D3
…
Plot {
id: plot
anchors.margins: Theme.horizontalPageMargin
width: parent.width
height: parent.height
function drawPlot(line) {
var arr = [];
for (var i=0;i<exampleSin.length;i++){
arr.push([i,exampleSin[i]])
}
line(arr);
}
…
Минимальная реализация готова! В функции drawPlot происходит конвертация массива исходных данных (exampleSin) в двумерный массив arr для функции построения графиков. drawPlot вызывается каждый раз при перерисовке графика. После запуска на телефоне отображается заранее описанный синус, подобный тому, как на КДПВ.
Реализация бэкенда приложения не сильно сложная: микроконтроллер собирает данные, обрабатывает и передает в телефон через конвертер интерфейсов UART-USB. На стороне микроконтроллера для эксперимента использую максимально простой код: по сигналу прерывания, настроенному на 10 миллисекунд, производится считывание и отправка в UART значения из АЦП.
В основе взаимодействия лежит библиотека CDCConnect, которая позволяет подключиться к необходимым микросхемам. Для работы реализовал небольшой класс-прослойку. Во время инициализации, после того как найдено подходящее оборудование, выполняется инициализация таймера, который каждые несколько миллисекунд опрашивает интерфейс на наличие данных. Это реализовано следующим образом:
void initTimer(){
QThread* thread = new QThread(this);
thread->start();
QTimer *timer = new QTimer(0);
timer->setInterval(timerUptime);
timer->moveToThread(thread);
connect(timer, SIGNAL(timeout()), this, SLOT(slotTimerAlarm()), Qt::DirectConnection);
connect(thread, SIGNAL(started()), timer, SLOT(start()));
}
Срабатывание тайма вызывает функцию slotTimerAlarm, которая выполняет чтение строки данных, их преобразование в текстовую строку для отладки и вывода в консоль. Дополнительно эта же функция делает попытку конвертации каждого значения к типу double и записи в буфер для дальнейшей отрисовки на графике.
int error = 0;
unsigned char buf[65];
QString readed = "";
error = dev.readBytes(buf, 64, timerUptime); ///< Чтение ответного сообщения из UART
if (error > 0)
{
readed = toQrealArray(buf, error);
emit messageAvailable( readed);
qreal val =0;
for (QString row: readed.split("n")){
val = rowreplace("r","").toDouble();
//qDebug() << val;
m_arr[buffPosition]=val;
buffPosition++;
if (buffPosition>=(bufferSize)) buffPosition=0;
}
emit digitsComplete(buffPosition);
}<
return 0;
Для передачи информационных переменных и массива данных в QML объявлены соответствующие свойства:
Q_PROPERTY (QString name READ getName);
Q_PROPERTY (QString description READ getDesc);
Q_PROPERTY (QString vidXpid READ vidXpid);
Q_PROPERTY (int bSize READ getBuffSize);
Q_PROPERTY (QVariantList arr READ getarr);
Инструментарий QT позволяет быстро и нативно связывать объекты друг с другом. Для передачи данных из C++ на фронтенд QML я предпочитаю использовать свойства контекста [20]. При таком варианте сначала создается экземпляр объекта, который передается фронтенду следующим образом:
…
QtCDC device;
…
QScopedPointer<QQuickView> view(Aurora::Application::createView());
view->rootContext()->setContextProperty("deviceCdc", &device);
view->setSource(Aurora::Application::pathTo(QStringLiteral("qml/js_test.qml")));
view->show();
device.init();
return application->exec();
…
Чтобы обновить данные и перестроить график, подключаюсь к сигналу digitsComplete. Также в функции drawPlot внес корректировку — вместо exampleSin используется deviceCdc.arr:
Connections {
target: deviceCdc
onDigitsComplete: {
plot.requestPaint();
}
}
Забавный факт: для подключения к CDC через libusb требуется добавить разрешение на работу с интернетом в файле *.desktop проекта:
[X-Application] Permissions=Internet
Полученное приложение позволяет использовать подключенный микроконтроллер в качестве мобильного аналога осциллоскопа или в качестве Arduino-консоли и плоттера. Периодически применяю его для отладки компонентов в стартапе, для просмотра и сохранения логов работы устройства.
В планах на следующий год — выполнить подключение к приборам с существующими открытыми исходными кодами для ПК, например Hantek365, и выпустить приложение в RuStore.
Автор: VRyabchevsky
Источник [21]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/gadzhety/404624
Ссылки в тексте:
[1] сервера: https://selectel.ru/services/cloud/servers/?utm_source=habr.com&utm_medium=referral&utm_campaign=cloud_article_qtgraphics_091224_content
[2] Введение: #1
[3] Фронтенд: #2
[4] Бэкенд: #3
[5] Модули, объединяйтесь!: #4
[6] Заключение: #5
[7] связки с Arduino: https://help.simintech.ru/index.html%2310_bibliotekblokov/Arduino/I2C/arduino2c_priem_dannyx_po_i2c.html
[8] статья для старта: https://habr.com/ru/companies/friflex/articles/854928/
[9] gitlab pages: https://omprussia.gitlab.io/flutter/flutter/examples/build/
[10] примеры: https://gitlab.com/omprussia/flutter
[11] QCustomPlot: https://www.qcustomplot.com/index.php/introduction
[12] QWT: https://qwt.sourceforge.io/%23downloads
[13] интересные инструменты ввода и индикации: https://qwt.sourceforge.io/controlscreenshots.html
[14] Источник: http://qwt.sourceforge.io
[15] D3.js: https://d3js.org/
[16] статья на Хабре: https://habr.com/ru/articles/339930/
[17] на Git Flic: https://gitflic.ru/project/mrdenis/aurora-plotter
[18] с GitHub: https://gist.github.com/VORyabchevsky/a737211cc1a7e6023918950d5752aa55
[19] версия 4: https://github.com/d3/d3/releases?page=9
[20] свойства контекста: https://metanit.com/cpp/qt/5.1.php
[21] Источник: https://habr.com/ru/companies/selectel/articles/864966/?utm_campaign=864966&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.