example 'meshtastic': refactor connection part

This commit is contained in:
pls.153 2024-04-17 13:31:46 +02:00
parent 679fca2d25
commit 013a75d3f5
22 changed files with 432 additions and 285 deletions

View file

@ -163,14 +163,16 @@ SOURCES += \
!android { !android {
HEADERS += \ HEADERS += \
cpp/ble/ble.h \ cpp/connection/connection.h \
cpp/ble/ble_meshtastic.h \ cpp/connection/ble/ble.h \
cpp/usb/usb_meshtastic.h cpp/connection/ble/ble_meshtastic.h \
cpp/connection/usb/usb_meshtastic.h
SOURCES += \ SOURCES += \
cpp/ble/ble.cpp \ cpp/connection/connection.cpp \
cpp/ble/ble_meshtastic.cpp \ cpp/convention/ble/ble.cpp \
cpp/usb/usb_meshtastic.cpp cpp/convention/ble/ble_meshtastic.cpp \
cpp/convention/usb/usb_meshtastic.cpp
} }
RESOURCES += $$files(qml/*) RESOURCES += $$files(qml/*)

View file

@ -1,5 +1,4 @@
#include "qtandroidservice_ro.h" #include "qtandroidservice_ro.h"
#include "../ble/ble_meshtastic.h"
#if (QT_VERSION < 0x060000) #if (QT_VERSION < 0x060000)
#include <QAndroidService> #include <QAndroidService>
@ -14,7 +13,5 @@ int main(int argc, char* argv[]) {
QtAndroidService qtAndroidService; QtAndroidService qtAndroidService;
srcNode.enableRemoting(&qtAndroidService); srcNode.enableRemoting(&qtAndroidService);
BLE_ME ble(&qtAndroidService);
return app.exec(); return app.exec();
} }

View file

@ -1,13 +1,16 @@
class QtAndroidService { class QtAndroidService {
SLOT(void startDeviceDiscovery(const QString&)); SLOT(void setConnectionType(const QVariant&));
SLOT(void setDeviceFilter(const QString&)); SLOT(void startDeviceDiscovery(const QVariant&));
SLOT(void read()); SLOT(void stopDeviceDiscovery());
SLOT(void write(const QByteArray&)); SLOT(void setDeviceFilter(const QVariant&));
SLOT(void read2());
SLOT(void write2(const QVariant&));
SLOT(void setBackgroundMode(bool)); SLOT(void setBackgroundMode(bool));
SIGNAL(deviceDiscovered(const QString&));
SIGNAL(deviceDiscovered(const QVariant&));
SIGNAL(bleError()); SIGNAL(bleError());
SIGNAL(setReady(bool, const QString&, const QStringList&)); SIGNAL(setReady(const QVariant&));
SIGNAL(receivedFromRadio(const QByteArray&, const QString&)); SIGNAL(receivedFromRadio(const QVariant&));
SIGNAL(receivingDone()); SIGNAL(receivingDone());
SIGNAL(sendSavedPackets(const QVariant&)); SIGNAL(sendSavedPackets(const QVariant&));
} }

View file

@ -1,14 +1,17 @@
#include "rep_qtandroidservice_source.h" #include "rep_qtandroidservice_source.h"
#include "../ble/ble_meshtastic.h" #include "../connection/connection.h"
class QtAndroidService : public QtAndroidServiceSource { class QtAndroidService : public QtAndroidServiceSource {
public: public:
BLE_ME* ble = nullptr; QtAndroidService() { con = new Connection(this); }
Connection* con;
public slots: public slots:
void startDeviceDiscovery(const QString& a1) override { ble->startDeviceDiscovery(a1); } void setConnectionType(const QVariant& a1) override { con->setConnectionType(a1); }
void setDeviceFilter(const QString& a1) override { ble->setDeviceFilter(a1); } void startDeviceDiscovery(const QVariant& a1) override { con->startDeviceDiscovery(a1); }
void read() override { ble->read(); } void stopDeviceDiscovery() override { con->stopDeviceDiscovery(); }
void write(const QByteArray& a1) override { ble->write(a1); } void setDeviceFilter(const QVariant& a1) override { con->setDeviceFilter(a1); }
void setBackgroundMode(bool a1) override { ble->setBackgroundMode(a1); } void read2() override { con->read2(); }
void write2(const QVariant& a1) override { con->write2(a1); }
void setBackgroundMode(bool a1) override { con->setBackgroundMode(a1); }
}; };

View file

@ -1,4 +1,4 @@
QT += core bluetooth remoteobjects QT += core bluetooth serialport remoteobjects
TEMPLATE = lib TEMPLATE = lib
CONFIG += c++17 dll CONFIG += c++17 dll
INCLUDEPATH += $$PWD INCLUDEPATH += $$PWD
@ -15,13 +15,17 @@ lessThan(QT_MAJOR_VERSION, 6) {
} }
HEADERS += \ HEADERS += \
../ble/ble.h \ ../connection/connection.h \
../ble/ble_meshtastic.h \ ../connection/ble/ble.h \
../connection/ble/ble_meshtastic.h \
../connection/usb/usb_meshtastic.h \
qtandroidservice_ro.h qtandroidservice_ro.h
SOURCES += \ SOURCES += \
../ble/ble.cpp \ ../connection/connection.cpp \
../ble/ble_meshtastic.cpp \ ../connection/ble/ble.cpp \
../connection/ble/ble_meshtastic.cpp \
../connection/usb/usb_meshtastic.cpp \
main.cpp main.cpp
REPC_SOURCE += qtandroidservice.rep REPC_SOURCE += qtandroidservice.rep

View file

@ -1,14 +1,9 @@
#include "ble_meshtastic.h" #include "ble_meshtastic.h"
#include "../connection.h"
#include <QMetaEnum> #include <QMetaEnum>
#include <QStandardPaths>
#include <QFile>
#include <QDataStream>
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include "../android_service/qtandroidservice_ro.h" #include "../../android_service/qtandroidservice_ro.h"
#if (QT_VERSION < 0x060000)
#include <QAndroidService>
#endif
#endif #endif
// service // service
@ -20,13 +15,12 @@ const UID BLE_ME::uuid_fromRadio = UID(STR("{2c55e69e-4993-11ed-b878-0242ac12000
const UID BLE_ME::uuid_fromNum = UID(STR("{ed9da18c-a800-4f66-a670-aa7547e34453}")); const UID BLE_ME::uuid_fromNum = UID(STR("{ed9da18c-a800-4f66-a670-aa7547e34453}"));
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
BLE_ME::BLE_ME(QtAndroidService* service) : BLE(uuid_service), emitter(service) { BLE_ME::BLE_ME(QtAndroidService* service, Connection* _con) : BLE(uuid_service), emitter(service), con(_con) {
service->ble = this;
// forward signals defined in class BLE // forward signals defined in class BLE
connect(this, &BLE::deviceDiscovered, emitter, &QtAndroidService::deviceDiscovered); connect(this, &BLE::deviceDiscovered, service, &QtAndroidService::deviceDiscovered);
connect(this, &BLE::bleError, emitter, &QtAndroidService::bleError); connect(this, &BLE::bleError, service, &QtAndroidService::bleError);
#else #else
BLE_ME::BLE_ME() : BLE(uuid_service), emitter(this) { BLE_ME::BLE_ME(Connection* _con) : BLE(uuid_service), emitter(_con), con(_con) {
#endif #endif
connect(this, &BLE::mainServiceReady, this, &BLE_ME::ini); connect(this, &BLE::mainServiceReady, this, &BLE_ME::ini);
connect(this, &BLE::deviceDisconnecting, this, &BLE_ME::disconnecting); connect(this, &BLE::deviceDisconnecting, this, &BLE_ME::disconnecting);
@ -111,8 +105,10 @@ void BLE_ME::searchCharacteristics() {
for (auto device : qAsConst(devices)) { for (auto device : qAsConst(devices)) {
names << device.name().right(4); names << device.name().right(4);
} }
if (!backgroundMode) { if (!con->backgroundMode) {
emitter->setReady(true, currentDevice.name().right(4), names); QVariantList vNames;
for (auto name : qAsConst(names)) { vNames << name; }
emitter->setReady(QVariant(QVariantList() << true << currentDevice.name().right(4) << vNames));
} }
} }
} }
@ -120,10 +116,10 @@ void BLE_ME::searchCharacteristics() {
void BLE_ME::characteristicChanged(const QLowEnergyCharacteristic&, void BLE_ME::characteristicChanged(const QLowEnergyCharacteristic&,
const QByteArray& data) { const QByteArray& data) {
if (!data.isEmpty()) { if (!data.isEmpty()) {
if (backgroundMode) { if (con->backgroundMode) {
read(); read();
} else { } else {
emitter->receivedFromRadio(data, "notified"); emitter->receivedFromRadio(QVariant(QVariantList() << data << QString("notified")));
} }
} }
} }
@ -131,20 +127,20 @@ void BLE_ME::characteristicChanged(const QLowEnergyCharacteristic&,
void BLE_ME::characteristicRead(const QLowEnergyCharacteristic&, void BLE_ME::characteristicRead(const QLowEnergyCharacteristic&,
const QByteArray& data) { const QByteArray& data) {
if (data.isEmpty()) { if (data.isEmpty()) {
if (!backgroundMode) { if (!con->backgroundMode) {
emitter->receivingDone(); emitter->receivingDone();
static bool startup = true; static bool startup = true;
if (startup) { if (startup) {
sendSavedBytes(); // for eventual, saved but not sent packets con->sendSavedBytes(); // for eventual, saved but not sent packets
} else { } else {
startup = false; startup = false;
} }
} }
} else { } else {
if (backgroundMode) { if (con->backgroundMode) {
saveBytes(data); con->saveBytes(data);
} else { } else {
emitter->receivedFromRadio(data, QString()); emitter->receivedFromRadio(QVariant(QVariantList() << data));
} }
read(); read();
} }
@ -188,57 +184,9 @@ void BLE_ME::disconnecting() {
// disable notifications // disable notifications
mainService->writeDescriptor(notifications, QByteArray::fromHex("0000")); mainService->writeDescriptor(notifications, QByteArray::fromHex("0000"));
} }
if (!backgroundMode) { if (!con->backgroundMode) {
emitter->setReady(false, QString(), QStringList()); emitter->setReady(QVariant(QVariantList()));
} }
delete mainService; mainService = nullptr; delete mainService; mainService = nullptr;
} }
// background mode
void BLE_ME::setBackgroundMode(bool background) {
#if (defined Q_OS_ANDROID) || (defined Q_OS_IOS)
backgroundMode = background;
qDebug() << "background mode:" << backgroundMode;
if (!backgroundMode) {
sendSavedBytes();
}
#endif
}
static QString packetsFile() {
// choose already existing directory
QStandardPaths::StandardLocation location = QStandardPaths::AppDataLocation;
#ifdef Q_OS_IOS
location = QStandardPaths::DocumentsLocation;
#endif
return QStandardPaths::writableLocation(location) + QStringLiteral("/meshtastic-packets.bin");
}
void BLE_ME::saveBytes(const QByteArray& packet) {
QFile file(packetsFile());
if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
QDataStream ds(&file);
ds << packet;
file.close();
}
}
void BLE_ME::sendSavedBytes() {
QVariantList packets;
QString fileName(packetsFile());
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
QDataStream ds(&file);
while (!ds.atEnd()) {
QByteArray packet;
ds >> packet;
packets.append(packet);
}
file.close();
if (!packets.isEmpty()) {
emitter->sendSavedPackets(QVariant(packets));
QFile::remove(fileName);
}
}
}

View file

@ -6,8 +6,9 @@
#define STR QStringLiteral #define STR QStringLiteral
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
class QtAndroidService; class QtAndroidService;
#endif #endif
class Connection;
class BLE_ME : public BLE { class BLE_ME : public BLE {
Q_OBJECT Q_OBJECT
@ -16,16 +17,15 @@ class BLE_ME : public BLE {
public: public:
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
BLE_ME(QtAndroidService*); BLE_ME(QtAndroidService*, Connection*);
#else #else
BLE_ME(); BLE_ME(Connection*);
#endif #endif
public Q_SLOTS: public Q_SLOTS:
void setDeviceFilter(const QString& s) { filter = s; } void setDeviceFilter(const QString& s) { filter = s; }
void read(); void read();
void write(const QByteArray&); void write(const QByteArray&);
void setBackgroundMode(bool);
Q_SIGNALS: Q_SIGNALS:
void setReady(bool, const QString&, const QStringList&); void setReady(bool, const QString&, const QStringList&);
@ -48,9 +48,9 @@ public:
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
QtAndroidService* emitter = nullptr; QtAndroidService* emitter = nullptr;
#else #else
BLE_ME* emitter = nullptr; Connection* emitter = nullptr;
#endif #endif
bool backgroundMode = false; Connection* con = nullptr;
QString filter = "meshtastic"; QString filter = "meshtastic";
QLowEnergyDescriptor notifications; QLowEnergyDescriptor notifications;
@ -66,8 +66,4 @@ private Q_SLOTS:
void characteristicWritten(const QLowEnergyCharacteristic&, const QByteArray&); void characteristicWritten(const QLowEnergyCharacteristic&, const QByteArray&);
void serviceError(QLowEnergyService::ServiceError); void serviceError(QLowEnergyService::ServiceError);
void disconnecting(); void disconnecting();
private:
void saveBytes(const QByteArray&);
void sendSavedBytes();
}; };

View file

@ -0,0 +1,122 @@
#include "connection.h"
#include "ble/ble_meshtastic.h"
#include "usb/usb_meshtastic.h"
#include <QStandardPaths>
#include <QFile>
#include <QDataStream>
#ifdef Q_OS_ANDROID
#include "../android_service/qtandroidservice_ro.h"
#if (QT_VERSION < 0x060000)
#include <QAndroidService>
#endif
#endif
#ifdef Q_OS_ANDROID
Connection::Connection(QtAndroidService* service) {
// forward signal
connect(this, &Connection::sendSavedPackets, service, &QtAndroidService::sendSavedPackets);
ble = new BLE_ME(service, service->con);
usb = new USB_ME(service, service->con);
}
#else
Connection::Connection() {
ble = new BLE_ME(this);
usb = new USB_ME(this);
}
#endif
void Connection::setConnectionType(const QVariant& vType) {
QByteArray t = vType.toByteArray();
if (t == "USB") {
type = USB;
} else {
type = BLE;
}
}
void Connection::startDeviceDiscovery(const QVariant& vName) {
switch (type) {
case BLE:
usb->disconnect();
ble->startDeviceDiscovery(vName.toString());
break;
case USB:
ble->disconnect();
usb->connectToRadio();
break;
}
}
void Connection::stopDeviceDiscovery() {
ble->stopDeviceDiscovery();
}
void Connection::setDeviceFilter(const QVariant& vName) {
ble->setDeviceFilter(vName.toString());
}
void Connection::read2() {
ble->read();
}
void Connection::write2(const QVariant& vBytes) {
QByteArray bytes = vBytes.toByteArray();
switch (type) {
case BLE:
ble->write(bytes);
break;
case USB:
usb->write2(bytes);
break;
}
}
// background mode
void Connection::setBackgroundMode(bool background) {
#if (defined Q_OS_ANDROID) || (defined Q_OS_IOS)
backgroundMode = background;
qDebug() << "background mode:" << backgroundMode;
if (!backgroundMode) {
sendSavedBytes();
}
#endif
}
static QString packetsFile() {
// choose already existing directory
QStandardPaths::StandardLocation location = QStandardPaths::AppDataLocation;
#ifdef Q_OS_IOS
location = QStandardPaths::DocumentsLocation;
#endif
return QStandardPaths::writableLocation(location) + QStringLiteral("/meshtastic-packets.bin");
}
void Connection::saveBytes(const QByteArray& packet) {
QFile file(packetsFile());
if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
QDataStream ds(&file);
ds << packet;
file.close();
}
}
void Connection::sendSavedBytes() {
QVariantList packets;
QString fileName(packetsFile());
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
QDataStream ds(&file);
while (!ds.atEnd()) {
QByteArray packet;
ds >> packet;
packets.append(packet);
}
file.close();
if (!packets.isEmpty()) {
Q_EMIT sendSavedPackets(QVariant(packets));
QFile::remove(fileName);
}
}
}

View file

@ -0,0 +1,49 @@
#pragma once
#include <QObject>
#include <QVariant>
class BLE_ME;
class USB_ME;
class QtAndroidService;
class Connection : public QObject {
Q_OBJECT
public:
#ifdef Q_OS_ANDROID
Connection(QtAndroidService*);
#else
Connection();
#endif
enum Type {
BLE, USB
};
Type type = BLE;
BLE_ME* ble = nullptr;
USB_ME* usb = nullptr;
bool backgroundMode = false;
void setConnectionType(const QVariant&);
void startDeviceDiscovery(const QVariant&);
void stopDeviceDiscovery();
void setDeviceFilter(const QVariant&);
void read2();
void write2(const QVariant&);
void setBackgroundMode(bool);
// background mode
void saveBytes(const QByteArray&);
void sendSavedBytes();
Q_SIGNALS:
void deviceDiscovered(const QVariant&);
void bleError();
void setReady(const QVariant&);
void receivedFromRadio(const QVariant&);
void receivingDone();
void sendSavedPackets(const QVariant&);
};

View file

@ -1,10 +1,19 @@
#include "usb_meshtastic.h" #include "usb_meshtastic.h"
#include "../connection.h"
#include <QSerialPortInfo> #include <QSerialPortInfo>
#include <QTimer> #include <QTimer>
#include <QGuiApplication> #include <QGuiApplication>
#include <QtDebug> #include <QtDebug>
USB_ME::USB_ME() { #ifdef Q_OS_ANDROID
#include "../../android_service/qtandroidservice_ro.h"
#endif
#ifdef Q_OS_ANDROID
USB_ME::USB_ME(QtAndroidService* service, Connection* _con) : emitter(service), con(_con) {
#else
USB_ME::USB_ME(Connection* _con) : emitter(_con), con(_con) {
#endif
connect(this, &QSerialPort::readyRead, this, &USB_ME::read2); connect(this, &QSerialPort::readyRead, this, &USB_ME::read2);
connect(this, &QSerialPort::errorOccurred, connect(this, &QSerialPort::errorOccurred,
[](QSerialPort::SerialPortError error) { [](QSerialPort::SerialPortError error) {
@ -16,14 +25,16 @@ USB_ME::USB_ME() {
void USB_ME::connectToRadio() { void USB_ME::connectToRadio() {
if (isOpen()) { if (isOpen()) {
Q_EMIT setReady(portName()); if (!con->backgroundMode) {
emitter->setReady(QVariant(QVariantList() << portName()));
}
qDebug() << "USB already open;" << portName(); qDebug() << "USB already open;" << portName();
return; return;
} }
const auto infos = QSerialPortInfo::availablePorts(); const auto infos = QSerialPortInfo::availablePorts();
const QStringList supported = { "RAK" }; // TODO: currently RAK only const QStringList supported = { "RAK" }; // TODO: currently RAK only
for (const QSerialPortInfo& info : infos) { for (auto info : infos) {
QString name(info.description() + " " + info.manufacturer()); QString name(info.description() + " " + info.manufacturer());
QString port(info.portName()); QString port(info.portName());
if (port.startsWith("tty") && if (port.startsWith("tty") &&
@ -38,13 +49,15 @@ void USB_ME::connectToRadio() {
} }
} }
} }
done:
done:
if (!open(QIODevice::ReadWrite)) { if (!open(QIODevice::ReadWrite)) {
qDebug() << "USB: unable to open port" << portName(); qDebug() << "USB: unable to open port" << portName();
} else { } else {
ready = true; ready = true;
Q_EMIT setReady(portName()); if (!con->backgroundMode) {
emitter->setReady(QVariant(QVariantList() << portName()));
}
qDebug() << "USB open"; qDebug() << "USB open";
} }
} }
@ -72,18 +85,38 @@ void USB_ME::read2() {
int end = 0; int end = 0;
int start = LEN; int start = LEN;
while ((end = data.indexOf(HEADER, start)) != -1) { while ((end = data.indexOf(HEADER, start)) != -1) {
Q_EMIT receivedFromRadio(data.mid(start, end - start)); received(data.mid(start, end - start));
start = end + LEN; start = end + LEN;
} }
Q_EMIT receivedFromRadio(data.mid(start)); received(data.mid(start));
static QTimer* timer = nullptr; static QTimer* timer = nullptr;
if (!timer) { if (timer == nullptr) {
timer = new QTimer; timer = new QTimer;
timer->setSingleShot(true); timer->setSingleShot(true);
connect(timer, &QTimer::timeout, this, &USB_ME::receivingDone); connect(timer, &QTimer::timeout, this, &USB_ME::done);
} }
timer->start(1000); // assume receiving done after pause of 1 sec timer->start(1000); // assume receiving done after pause of 1 sec
} }
} }
void USB_ME::received(const QByteArray& data) {
if (con->backgroundMode) {
con->saveBytes(data);
} else {
emitter->receivedFromRadio(QVariant(QVariantList() << data));
}
}
void USB_ME::done() {
if (!con->backgroundMode) {
emitter->receivingDone();
static bool startup = true;
if (startup) {
con->sendSavedBytes(); // for eventual, saved but not sent packets
} else {
startup = false;
}
}
}

View file

@ -0,0 +1,49 @@
#pragma once
#include <QSerialPort>
#ifdef Q_OS_ANDROID
class QtAndroidService;
#endif
class Connection;
class USB_ME : public QSerialPort {
Q_OBJECT
/*** <INTERFACE> ****************************************/
public:
#ifdef Q_OS_ANDROID
USB_ME(QtAndroidService*, Connection*);
#else
USB_ME(Connection*);
#endif
public Q_SLOTS:
void connectToRadio();
void disconnect();
void read2();
void write2(const QByteArray&);
Q_SIGNALS:
void setReady(const QString&);
void receivedFromRadio(const QByteArray&);
void receivingDone();
/*** </INTERFACE> ***************************************/
public:
#ifdef Q_OS_ANDROID
QtAndroidService* emitter = nullptr;
#else
Connection* emitter = nullptr;
#endif
Connection* con = nullptr;
bool ready = false;
void received(const QByteArray&);
public Q_SLOTS:
void done();
};

View file

@ -21,8 +21,7 @@
#include <QtCore/private/qandroidextras_p.h> #include <QtCore/private/qandroidextras_p.h>
#endif #endif
#else #else
#include "ble/ble_meshtastic.h" #include "connection/connection.h"
#include "usb/usb_meshtastic.h"
#endif #endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -35,92 +34,72 @@ QObject* ini() {
return qt; return qt;
} }
// connection
QT::QT() : QObject() { QT::QT() : QObject() {
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
// remote object for android service // remote object for android service
QRemoteObjectNode* repNode = new QRemoteObjectNode; QRemoteObjectNode* repNode = new QRemoteObjectNode;
repNode->connectToNode(QUrl(QStringLiteral("local:replica"))); repNode->connectToNode(QUrl(QStringLiteral("local:replica")));
QSharedPointer<QtAndroidServiceReplica> rep(repNode->acquire<QtAndroidServiceReplica>()); con = repNode->acquire<QtAndroidServiceReplica>();
bool res = rep->waitForSource(); bool res = con->waitForSource();
Q_ASSERT(res); Q_ASSERT(res);
ble = rep;
#else #else
ble = new BLE_ME; con = new Connection;
#endif #endif
usb = new USB_ME;
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::deviceDiscovered, QObject::connect(con, &QtAndroidServiceReplica::deviceDiscovered,
#else #else
QObject::connect(ble, &BLE::deviceDiscovered, QObject::connect(con, &Connection::deviceDiscovered,
#endif #endif
[](const QString& fullName) { [](const QVariant& vFullName) {
ecl_fun("radios:device-discovered", fullName.right(4)); ecl_fun("radios:device-discovered", vFullName.toString().right(4));
}); });
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::bleError, QObject::connect(con, &QtAndroidServiceReplica::bleError,
#else #else
QObject::connect(ble, &BLE::bleError, QObject::connect(con, &Connection::bleError,
#endif #endif
[]() { []() {
ecl_fun("radios:reset"); ecl_fun("radios:reset");
}); });
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::setReady, QObject::connect(con, &QtAndroidServiceReplica::setReady,
#else #else
QObject::connect(ble, &BLE_ME::setReady, QObject::connect(con, &Connection::setReady,
#endif #endif
[](bool ready, const QString& current, const QStringList& names) { [](const QVariant& vArg) {
QVariantList vNames; // Lisp doesn't know 'QStringList' ecl_fun("lora:set-ready", vArg);
for (auto name : names) {
vNames << name;
}
ecl_fun("lora:set-ready-ble", ready, current, vNames);
});
QObject::connect(usb, &USB_ME::setReady,
[](const QString& port) {
ecl_fun("lora:set-ready-usb", port);
}); });
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::receivedFromRadio, QObject::connect(con, &QtAndroidServiceReplica::receivedFromRadio,
#else #else
QObject::connect(ble, &BLE_ME::receivedFromRadio, QObject::connect(con, &Connection::receivedFromRadio,
#endif #endif
[](const QByteArray& data, const QString& notified) { [](const QVariant& vArg) {
ecl_fun("lora:received-from-radio", data, notified.isEmpty() ? QVariant() : notified); ecl_fun("lora:received-from-radio", vArg);
});
QObject::connect(usb, &USB_ME::receivedFromRadio,
[](const QByteArray& data) {
ecl_fun("lora:received-from-radio", data);
}); });
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::receivingDone, QObject::connect(con, &QtAndroidServiceReplica::receivingDone,
#else #else
QObject::connect(ble, &BLE_ME::receivingDone, QObject::connect(con, &Connection::receivingDone,
#endif #endif
[]() { []() {
ecl_fun("lora:receiving-done"); ecl_fun("lora:receiving-done");
}); });
QObject::connect(usb, &USB_ME::receivingDone,
[]() {
ecl_fun("lora:receiving-done");
});
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::sendSavedPackets, QObject::connect(con, &QtAndroidServiceReplica::sendSavedPackets,
#else #else
QObject::connect(ble, &BLE_ME::sendSavedPackets, QObject::connect(con, &Connection::sendSavedPackets,
#endif #endif
[](const QVariant& packets) { [](const QVariant& vPackets) {
ecl_fun("lora:process-saved-packets", packets); ecl_fun("lora:process-saved-packets", vPackets);
}); });
#if (defined Q_OS_ANDROID) || (defined Q_OS_IOS) #if (defined Q_OS_ANDROID) || (defined Q_OS_IOS)
@ -128,14 +107,14 @@ QT::QT() : QObject() {
QObject::connect(qGuiApp, &QGuiApplication::applicationStateChanged, QObject::connect(qGuiApp, &QGuiApplication::applicationStateChanged,
[&](Qt::ApplicationState state) { [&](Qt::ApplicationState state) {
if (state == Qt::ApplicationInactive) { if (state == Qt::ApplicationInactive) {
ble->setBackgroundMode(true); con->setBackgroundMode(true);
ecl_fun("app:background-mode-changed", true); ecl_fun("app:background-mode-changed", true);
} else if (state == Qt::ApplicationActive) { } else if (state == Qt::ApplicationActive) {
static bool startup = true; static bool startup = true;
if (startup) { if (startup) {
startup = false; startup = false;
} else { } else {
ble->setBackgroundMode(false); con->setBackgroundMode(false);
ecl_fun("app:background-mode-changed", false); ecl_fun("app:background-mode-changed", false);
} }
} }
@ -143,50 +122,33 @@ QT::QT() : QObject() {
#endif #endif
} }
// BLE QVariant QT::setConnectionType(const QVariant& vType) {
con->setConnectionType(vType);
return QVariant();
}
QVariant QT::startDeviceDiscovery(const QVariant& vName) { QVariant QT::startDeviceDiscovery(const QVariant& vName) {
QByteArray connection(ecl_fun("radios:connection").toString().toLatin1()); con->startDeviceDiscovery(vName);
if (connection == "BLE") { return QVariant();
usb->disconnect();
ble->startDeviceDiscovery(vName.toString());
} else if (connection == "USB") {
ble->disconnect();
usb->connectToRadio();
}
return vName;
} }
QVariant QT::stopDeviceDiscovery() { QVariant QT::stopDeviceDiscovery() {
ble->stopDeviceDiscovery(); con->stopDeviceDiscovery();
return QVariant(); return QVariant();
} }
QVariant QT::setDeviceFilter(const QVariant& vName) { QVariant QT::setDeviceFilter(const QVariant& vName) {
ble->setDeviceFilter(vName.toString()); con->setDeviceFilter(vName);
return vName;
}
QVariant QT::readBle() {
ble->read();
return QVariant(); return QVariant();
} }
QVariant QT::writeBle(const QVariant& vBytes) { QVariant QT::read2() {
ble->write(vBytes.toByteArray()); con->read2();
return QVariant(); return QVariant();
} }
QVariant QT::setBackgroundMode(const QVariant& vBackground) { QVariant QT::write2(const QVariant& vBytes) {
// for testing con->write2(vBytes);
ble->setBackgroundMode(vBackground.toBool());
return QVariant();
}
// USB
QVariant QT::writeUsb(const QVariant& vBytes) {
usb->write2(vBytes.toByteArray());
return QVariant(); return QVariant();
} }
@ -312,7 +274,7 @@ QVariant QT::dataPath(const QVariant& prefix) {
} }
QVariant QT::localIp() { QVariant QT::localIp() {
// Returns the local IP string. Private networks may use: // returns the local IP string; private networks may use:
// 10.*.*.* // 10.*.*.*
// 172.16.*.* // 172.16.*.*
// 192.168.*.* // 192.168.*.*

View file

@ -12,8 +12,7 @@
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
class QtAndroidServiceReplica; class QtAndroidServiceReplica;
#else #else
class BLE_ME; class Connection;
class USB_ME;
#endif #endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -24,16 +23,13 @@ class QT : public QObject {
Q_OBJECT Q_OBJECT
public: public:
// BLE // connection
Q_INVOKABLE QVariant setConnectionType(const QVariant&);
Q_INVOKABLE QVariant startDeviceDiscovery(const QVariant&); Q_INVOKABLE QVariant startDeviceDiscovery(const QVariant&);
Q_INVOKABLE QVariant stopDeviceDiscovery(); Q_INVOKABLE QVariant stopDeviceDiscovery();
Q_INVOKABLE QVariant setDeviceFilter(const QVariant&); Q_INVOKABLE QVariant setDeviceFilter(const QVariant&);
Q_INVOKABLE QVariant readBle(); Q_INVOKABLE QVariant read2();
Q_INVOKABLE QVariant writeBle(const QVariant&); Q_INVOKABLE QVariant write2(const QVariant&);
Q_INVOKABLE QVariant setBackgroundMode(const QVariant&);
// USB
Q_INVOKABLE QVariant writeUsb(const QVariant&);
// GPS // GPS
Q_INVOKABLE QVariant iniPositioning(); Q_INVOKABLE QVariant iniPositioning();
@ -54,10 +50,9 @@ public:
QSqlDatabase db; QSqlDatabase db;
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
QSharedPointer<QtAndroidServiceReplica> ble; QtAndroidServiceReplica* con = nullptr;
#else #else
BLE_ME* ble = nullptr; Connection* con = nullptr;
USB_ME* usb = nullptr;
#endif #endif
}; };

View file

@ -10,15 +10,17 @@ OBJECTS_DIR = ./tmp/
MOC_DIR = ./tmp/ MOC_DIR = ./tmp/
HEADERS += \ HEADERS += \
ble/ble.h \ connection/connection.h \
ble/ble_meshtastic.h \ connection/ble/ble.h \
usb/usb_meshtastic.h \ connection/ble/ble_meshtastic.h \
connection/usb/usb_meshtastic.h \
qt.h qt.h
SOURCES += \ SOURCES += \
ble/ble.cpp \ connection/connection.cpp \
ble/ble_meshtastic.cpp \ connection/ble/ble.cpp \
usb/usb_meshtastic.cpp \ connection/ble/ble_meshtastic.cpp \
connection/usb/usb_meshtastic.cpp \
qt.cpp qt.cpp
linux { linux {

View file

@ -1,24 +0,0 @@
#pragma once
#include <QSerialPort>
class USB_ME : public QSerialPort {
Q_OBJECT
public:
USB_ME();
bool ready = false;
public Q_SLOTS:
void connectToRadio();
void disconnect();
void write2(const QByteArray&);
void read2();
Q_SIGNALS:
void setReady(const QString&);
void receivedFromRadio(const QByteArray&);
void receivingDone();
};

View file

@ -68,18 +68,22 @@
(me:make-to-radio :want-config-id *config-id*)) (me:make-to-radio :want-config-id *config-id*))
(q> |playing| ui:*busy* t))) (q> |playing| ui:*busy* t)))
(defun set-ready-ble (&optional ready name ble-names) ; see Qt (defun set-ready (args) ; see Qt
(setf *ready* ready) (case radios:*connection*
(when ready (:ble
(setf *ble-names* ble-names) (destructuring-bind (ready name ble-names)
(app:toast (x:cc (tr "radio") ": " name) 2) args
(get-node-config)) (setf *ready* ready)
(values)) (when ready
(setf *ble-names* ble-names)
(defun set-ready-usb (port) ; see Qt (app:toast (x:cc (tr "radio") ": " name) 2)
(setf *ready* t) (get-node-config))))
(app:toast (x:cc "USB: " port) 2) (:usb
(get-node-config) (destructuring-bind (port)
args
(setf *ready* t)
(app:toast (x:cc "USB: " port) 2)
(get-node-config))))
(values)) (values))
(defun add-line-breaks (text) (defun add-line-breaks (text)
@ -140,7 +144,7 @@
(defun read-radio () (defun read-radio ()
"Triggers a read on the radio. Will call RECEIVED-FROM-RADIO on success." "Triggers a read on the radio. Will call RECEIVED-FROM-RADIO on success."
(qrun* (qt:read-ble qt:*cpp*))) (qrun* (qt:read* qt:*cpp*)))
(defun send-to-radio (to-radio) (defun send-to-radio (to-radio)
"Sends passed TO-RADIO, preceded by a header." "Sends passed TO-RADIO, preceded by a header."
@ -150,27 +154,29 @@
(header (header (length bytes)))) (header (header (length bytes))))
(case radios:*connection* (case radios:*connection*
(:ble (qrun* (:ble (qrun*
(qt:write-ble qt:*cpp* header) (qt:write* qt:*cpp* header)
(qt:write-ble qt:*cpp* bytes))) (qt:write* qt:*cpp* bytes)))
(:usb (qrun* (:usb (qrun*
(qt:write-usb qt:*cpp* (concatenate 'vector header bytes))))))) (qt:write* qt:*cpp* (concatenate 'vector header bytes)))))))
(defun received-from-radio (bytes &optional notified) ; see Qt (defun received-from-radio (args) ; see Qt
(if notified (destructuring-bind (bytes &optional notified)
(progn args
(setf *notify-id* bytes) (if notified
(read-radio)) (progn
(multiple-value-bind (from-radio error) (setf *notify-id* bytes)
(ignore-errors (pr:deserialize-from-bytes 'me:from-radio bytes)) (read-radio))
(setf *reading* t) (multiple-value-bind (from-radio error)
(if from-radio (ignore-errors (pr:deserialize-from-bytes 'me:from-radio bytes))
(progn (setf *reading* t)
(when *print-json* (if from-radio
(pr:print-json from-radio)) (progn
(push from-radio *received*)) (when *print-json*
(progn (pr:print-json from-radio))
(qlog "received faulty bytes: ~A" error) (push from-radio *received*))
(push bytes *received-faulty*))))) (progn
(qlog "received faulty bytes: ~A" error)
(push bytes *received-faulty*))))))
(values)) (values))
(defun receiving-done () ; see Qt (defun receiving-done () ; see Qt

View file

@ -12,12 +12,11 @@
#:local-ip #:local-ip
#:start-device-discovery #:start-device-discovery
#:stop-device-discovery #:stop-device-discovery
#:read-ble #:read*
#:set-background-mode ; for testing #:set-connection-type
#:set-device-filter #:set-device-filter
#:sql-query #:sql-query
#:write-ble #:write*))
#:write-usb))
(in-package :qt) (in-package :qt)

View file

@ -6,6 +6,7 @@
(defun ini () (defun ini ()
(setf *connection* (or (app:setting :connection) (setf *connection* (or (app:setting :connection)
:ble)) :ble))
(set-connection-type)
(q> |checked| (symbol-name *connection*) t) (q> |checked| (symbol-name *connection*) t)
(q> |model| ui:*region* (q> |model| ui:*region*
(cons "-" (mapcar 'symbol-name (rest (lora:keywords :region-code))))) (cons "-" (mapcar 'symbol-name (rest (lora:keywords :region-code)))))
@ -13,17 +14,18 @@
(x:when-it (app:setting :device-filter) (x:when-it (app:setting :device-filter)
(qt:set-device-filter qt:*cpp* x:it))) (qt:set-device-filter qt:*cpp* x:it)))
(defun connection () ; see Qt
(symbol-name *connection*))
(defun connection-changed (name) (defun connection-changed (name)
(when (eql *connection* :ble) (when (eql *connection* :ble)
(qt:stop-device-discovery qt:*cpp*)) (qt:stop-device-discovery qt:*cpp*))
(let ((con (app:kw name))) (let ((con (app:kw name)))
(setf *connection* con) (setf *connection* con)
(app:change-setting :connection con)) (app:change-setting :connection con))
(set-connection-type)
(lora:start-device-discovery)) (lora:start-device-discovery))
(defun set-connection-type ()
(qt:set-connection-type qt:*cpp* (symbol-name *connection*)))
(defun saved-region () (defun saved-region ()
(let ((region (app:setting :region))) (let ((region (app:setting :region)))
(unless (find region '(nil :unset)) (unless (find region '(nil :unset))

View file

@ -80,6 +80,7 @@ Item {
text: "USB" text: "USB"
autoExclusive: true autoExclusive: true
checkable: true checkable: true
enabled: (Qt.platform.os !== "android") && (Qt.platform.os !== "ios")
onTriggered: connection.changed(objectName) onTriggered: connection.changed(objectName)
} }
} }

View file

@ -66,14 +66,12 @@ they are 64 bit and run at least iOS 12.
How to use cl-meshtastic How to use cl-meshtastic
------------------------ ------------------------
If you have your radio connected via USB to your PC, you can choose 'USB' as If you have your radio connected to your PC via USB, you can choose 'USB' as
connection type from the main menu (see 'Radios' icon). This currently only connection type from the main menu (see 'Radios' icon). This only works on
works on Linux and macOS, and only with RAK devices (which don't need any Linux and macOS (Windows not tested), and only with RAK devices (which don't
driver, just permission to e.g. `/dev/ttyACM0` on Linux). need any driver, just permission to e.g. `/dev/ttyACM0` on Linux).
Android is currently WIP. For mobile there is BLE (Bluetooth Low Energy).
The next best option is BLE (Bluetooth Low Energy).
Your radio needs to be turned on and bluetooth needs to be enabled before you Your radio needs to be turned on and bluetooth needs to be enabled before you
start the app. start the app.