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 {
HEADERS += \
cpp/ble/ble.h \
cpp/ble/ble_meshtastic.h \
cpp/usb/usb_meshtastic.h
cpp/connection/connection.h \
cpp/connection/ble/ble.h \
cpp/connection/ble/ble_meshtastic.h \
cpp/connection/usb/usb_meshtastic.h
SOURCES += \
cpp/ble/ble.cpp \
cpp/ble/ble_meshtastic.cpp \
cpp/usb/usb_meshtastic.cpp
cpp/connection/connection.cpp \
cpp/convention/ble/ble.cpp \
cpp/convention/ble/ble_meshtastic.cpp \
cpp/convention/usb/usb_meshtastic.cpp
}
RESOURCES += $$files(qml/*)

View file

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

View file

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

View file

@ -1,14 +1,17 @@
#include "rep_qtandroidservice_source.h"
#include "../ble/ble_meshtastic.h"
#include "../connection/connection.h"
class QtAndroidService : public QtAndroidServiceSource {
public:
BLE_ME* ble = nullptr;
QtAndroidService() { con = new Connection(this); }
Connection* con;
public slots:
void startDeviceDiscovery(const QString& a1) override { ble->startDeviceDiscovery(a1); }
void setDeviceFilter(const QString& a1) override { ble->setDeviceFilter(a1); }
void read() override { ble->read(); }
void write(const QByteArray& a1) override { ble->write(a1); }
void setBackgroundMode(bool a1) override { ble->setBackgroundMode(a1); }
void setConnectionType(const QVariant& a1) override { con->setConnectionType(a1); }
void startDeviceDiscovery(const QVariant& a1) override { con->startDeviceDiscovery(a1); }
void stopDeviceDiscovery() override { con->stopDeviceDiscovery(); }
void setDeviceFilter(const QVariant& a1) override { con->setDeviceFilter(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
CONFIG += c++17 dll
INCLUDEPATH += $$PWD
@ -15,13 +15,17 @@ lessThan(QT_MAJOR_VERSION, 6) {
}
HEADERS += \
../ble/ble.h \
../ble/ble_meshtastic.h \
../connection/connection.h \
../connection/ble/ble.h \
../connection/ble/ble_meshtastic.h \
../connection/usb/usb_meshtastic.h \
qtandroidservice_ro.h
SOURCES += \
../ble/ble.cpp \
../ble/ble_meshtastic.cpp \
../connection/connection.cpp \
../connection/ble/ble.cpp \
../connection/ble/ble_meshtastic.cpp \
../connection/usb/usb_meshtastic.cpp \
main.cpp
REPC_SOURCE += qtandroidservice.rep

View file

@ -1,14 +1,9 @@
#include "ble_meshtastic.h"
#include "../connection.h"
#include <QMetaEnum>
#include <QStandardPaths>
#include <QFile>
#include <QDataStream>
#ifdef Q_OS_ANDROID
#include "../android_service/qtandroidservice_ro.h"
#if (QT_VERSION < 0x060000)
#include <QAndroidService>
#endif
#include "../../android_service/qtandroidservice_ro.h"
#endif
// 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}"));
#ifdef Q_OS_ANDROID
BLE_ME::BLE_ME(QtAndroidService* service) : BLE(uuid_service), emitter(service) {
service->ble = this;
BLE_ME::BLE_ME(QtAndroidService* service, Connection* _con) : BLE(uuid_service), emitter(service), con(_con) {
// forward signals defined in class BLE
connect(this, &BLE::deviceDiscovered, emitter, &QtAndroidService::deviceDiscovered);
connect(this, &BLE::bleError, emitter, &QtAndroidService::bleError);
connect(this, &BLE::deviceDiscovered, service, &QtAndroidService::deviceDiscovered);
connect(this, &BLE::bleError, service, &QtAndroidService::bleError);
#else
BLE_ME::BLE_ME() : BLE(uuid_service), emitter(this) {
BLE_ME::BLE_ME(Connection* _con) : BLE(uuid_service), emitter(_con), con(_con) {
#endif
connect(this, &BLE::mainServiceReady, this, &BLE_ME::ini);
connect(this, &BLE::deviceDisconnecting, this, &BLE_ME::disconnecting);
@ -111,8 +105,10 @@ void BLE_ME::searchCharacteristics() {
for (auto device : qAsConst(devices)) {
names << device.name().right(4);
}
if (!backgroundMode) {
emitter->setReady(true, currentDevice.name().right(4), names);
if (!con->backgroundMode) {
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&,
const QByteArray& data) {
if (!data.isEmpty()) {
if (backgroundMode) {
if (con->backgroundMode) {
read();
} 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&,
const QByteArray& data) {
if (data.isEmpty()) {
if (!backgroundMode) {
if (!con->backgroundMode) {
emitter->receivingDone();
static bool startup = true;
if (startup) {
sendSavedBytes(); // for eventual, saved but not sent packets
con->sendSavedBytes(); // for eventual, saved but not sent packets
} else {
startup = false;
}
}
} else {
if (backgroundMode) {
saveBytes(data);
if (con->backgroundMode) {
con->saveBytes(data);
} else {
emitter->receivedFromRadio(data, QString());
emitter->receivedFromRadio(QVariant(QVariantList() << data));
}
read();
}
@ -188,57 +184,9 @@ void BLE_ME::disconnecting() {
// disable notifications
mainService->writeDescriptor(notifications, QByteArray::fromHex("0000"));
}
if (!backgroundMode) {
emitter->setReady(false, QString(), QStringList());
if (!con->backgroundMode) {
emitter->setReady(QVariant(QVariantList()));
}
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

@ -8,6 +8,7 @@
#ifdef Q_OS_ANDROID
class QtAndroidService;
#endif
class Connection;
class BLE_ME : public BLE {
Q_OBJECT
@ -16,16 +17,15 @@ class BLE_ME : public BLE {
public:
#ifdef Q_OS_ANDROID
BLE_ME(QtAndroidService*);
BLE_ME(QtAndroidService*, Connection*);
#else
BLE_ME();
BLE_ME(Connection*);
#endif
public Q_SLOTS:
void setDeviceFilter(const QString& s) { filter = s; }
void read();
void write(const QByteArray&);
void setBackgroundMode(bool);
Q_SIGNALS:
void setReady(bool, const QString&, const QStringList&);
@ -48,9 +48,9 @@ public:
#ifdef Q_OS_ANDROID
QtAndroidService* emitter = nullptr;
#else
BLE_ME* emitter = nullptr;
Connection* emitter = nullptr;
#endif
bool backgroundMode = false;
Connection* con = nullptr;
QString filter = "meshtastic";
QLowEnergyDescriptor notifications;
@ -66,8 +66,4 @@ private Q_SLOTS:
void characteristicWritten(const QLowEnergyCharacteristic&, const QByteArray&);
void serviceError(QLowEnergyService::ServiceError);
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 "../connection.h"
#include <QSerialPortInfo>
#include <QTimer>
#include <QGuiApplication>
#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::errorOccurred,
[](QSerialPort::SerialPortError error) {
@ -16,14 +25,16 @@ USB_ME::USB_ME() {
void USB_ME::connectToRadio() {
if (isOpen()) {
Q_EMIT setReady(portName());
if (!con->backgroundMode) {
emitter->setReady(QVariant(QVariantList() << portName()));
}
qDebug() << "USB already open;" << portName();
return;
}
const auto infos = QSerialPortInfo::availablePorts();
const QStringList supported = { "RAK" }; // TODO: currently RAK only
for (const QSerialPortInfo& info : infos) {
for (auto info : infos) {
QString name(info.description() + " " + info.manufacturer());
QString port(info.portName());
if (port.startsWith("tty") &&
@ -38,13 +49,15 @@ void USB_ME::connectToRadio() {
}
}
}
done:
done:
if (!open(QIODevice::ReadWrite)) {
qDebug() << "USB: unable to open port" << portName();
} else {
ready = true;
Q_EMIT setReady(portName());
if (!con->backgroundMode) {
emitter->setReady(QVariant(QVariantList() << portName()));
}
qDebug() << "USB open";
}
}
@ -72,18 +85,38 @@ void USB_ME::read2() {
int end = 0;
int start = LEN;
while ((end = data.indexOf(HEADER, start)) != -1) {
Q_EMIT receivedFromRadio(data.mid(start, end - start));
received(data.mid(start, end - start));
start = end + LEN;
}
Q_EMIT receivedFromRadio(data.mid(start));
received(data.mid(start));
static QTimer* timer = nullptr;
if (!timer) {
if (timer == nullptr) {
timer = new QTimer;
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
}
}
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>
#endif
#else
#include "ble/ble_meshtastic.h"
#include "usb/usb_meshtastic.h"
#include "connection/connection.h"
#endif
QT_BEGIN_NAMESPACE
@ -35,92 +34,72 @@ QObject* ini() {
return qt;
}
// connection
QT::QT() : QObject() {
#ifdef Q_OS_ANDROID
// remote object for android service
QRemoteObjectNode* repNode = new QRemoteObjectNode;
repNode->connectToNode(QUrl(QStringLiteral("local:replica")));
QSharedPointer<QtAndroidServiceReplica> rep(repNode->acquire<QtAndroidServiceReplica>());
bool res = rep->waitForSource();
con = repNode->acquire<QtAndroidServiceReplica>();
bool res = con->waitForSource();
Q_ASSERT(res);
ble = rep;
#else
ble = new BLE_ME;
con = new Connection;
#endif
usb = new USB_ME;
#ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::deviceDiscovered,
QObject::connect(con, &QtAndroidServiceReplica::deviceDiscovered,
#else
QObject::connect(ble, &BLE::deviceDiscovered,
QObject::connect(con, &Connection::deviceDiscovered,
#endif
[](const QString& fullName) {
ecl_fun("radios:device-discovered", fullName.right(4));
[](const QVariant& vFullName) {
ecl_fun("radios:device-discovered", vFullName.toString().right(4));
});
#ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::bleError,
QObject::connect(con, &QtAndroidServiceReplica::bleError,
#else
QObject::connect(ble, &BLE::bleError,
QObject::connect(con, &Connection::bleError,
#endif
[]() {
ecl_fun("radios:reset");
});
#ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::setReady,
QObject::connect(con, &QtAndroidServiceReplica::setReady,
#else
QObject::connect(ble, &BLE_ME::setReady,
QObject::connect(con, &Connection::setReady,
#endif
[](bool ready, const QString& current, const QStringList& names) {
QVariantList vNames; // Lisp doesn't know 'QStringList'
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);
[](const QVariant& vArg) {
ecl_fun("lora:set-ready", vArg);
});
#ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::receivedFromRadio,
QObject::connect(con, &QtAndroidServiceReplica::receivedFromRadio,
#else
QObject::connect(ble, &BLE_ME::receivedFromRadio,
QObject::connect(con, &Connection::receivedFromRadio,
#endif
[](const QByteArray& data, const QString& notified) {
ecl_fun("lora:received-from-radio", data, notified.isEmpty() ? QVariant() : notified);
});
QObject::connect(usb, &USB_ME::receivedFromRadio,
[](const QByteArray& data) {
ecl_fun("lora:received-from-radio", data);
[](const QVariant& vArg) {
ecl_fun("lora:received-from-radio", vArg);
});
#ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::receivingDone,
QObject::connect(con, &QtAndroidServiceReplica::receivingDone,
#else
QObject::connect(ble, &BLE_ME::receivingDone,
QObject::connect(con, &Connection::receivingDone,
#endif
[]() {
ecl_fun("lora:receiving-done");
});
QObject::connect(usb, &USB_ME::receivingDone,
[]() {
ecl_fun("lora:receiving-done");
});
#ifdef Q_OS_ANDROID
QObject::connect(ble.data(), &QtAndroidServiceReplica::sendSavedPackets,
QObject::connect(con, &QtAndroidServiceReplica::sendSavedPackets,
#else
QObject::connect(ble, &BLE_ME::sendSavedPackets,
QObject::connect(con, &Connection::sendSavedPackets,
#endif
[](const QVariant& packets) {
ecl_fun("lora:process-saved-packets", packets);
[](const QVariant& vPackets) {
ecl_fun("lora:process-saved-packets", vPackets);
});
#if (defined Q_OS_ANDROID) || (defined Q_OS_IOS)
@ -128,14 +107,14 @@ QT::QT() : QObject() {
QObject::connect(qGuiApp, &QGuiApplication::applicationStateChanged,
[&](Qt::ApplicationState state) {
if (state == Qt::ApplicationInactive) {
ble->setBackgroundMode(true);
con->setBackgroundMode(true);
ecl_fun("app:background-mode-changed", true);
} else if (state == Qt::ApplicationActive) {
static bool startup = true;
if (startup) {
startup = false;
} else {
ble->setBackgroundMode(false);
con->setBackgroundMode(false);
ecl_fun("app:background-mode-changed", false);
}
}
@ -143,50 +122,33 @@ QT::QT() : QObject() {
#endif
}
// BLE
QVariant QT::setConnectionType(const QVariant& vType) {
con->setConnectionType(vType);
return QVariant();
}
QVariant QT::startDeviceDiscovery(const QVariant& vName) {
QByteArray connection(ecl_fun("radios:connection").toString().toLatin1());
if (connection == "BLE") {
usb->disconnect();
ble->startDeviceDiscovery(vName.toString());
} else if (connection == "USB") {
ble->disconnect();
usb->connectToRadio();
}
return vName;
con->startDeviceDiscovery(vName);
return QVariant();
}
QVariant QT::stopDeviceDiscovery() {
ble->stopDeviceDiscovery();
con->stopDeviceDiscovery();
return QVariant();
}
QVariant QT::setDeviceFilter(const QVariant& vName) {
ble->setDeviceFilter(vName.toString());
return vName;
}
QVariant QT::readBle() {
ble->read();
con->setDeviceFilter(vName);
return QVariant();
}
QVariant QT::writeBle(const QVariant& vBytes) {
ble->write(vBytes.toByteArray());
QVariant QT::read2() {
con->read2();
return QVariant();
}
QVariant QT::setBackgroundMode(const QVariant& vBackground) {
// for testing
ble->setBackgroundMode(vBackground.toBool());
return QVariant();
}
// USB
QVariant QT::writeUsb(const QVariant& vBytes) {
usb->write2(vBytes.toByteArray());
QVariant QT::write2(const QVariant& vBytes) {
con->write2(vBytes);
return QVariant();
}
@ -312,7 +274,7 @@ QVariant QT::dataPath(const QVariant& prefix) {
}
QVariant QT::localIp() {
// Returns the local IP string. Private networks may use:
// returns the local IP string; private networks may use:
// 10.*.*.*
// 172.16.*.*
// 192.168.*.*

View file

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

View file

@ -10,15 +10,17 @@ OBJECTS_DIR = ./tmp/
MOC_DIR = ./tmp/
HEADERS += \
ble/ble.h \
ble/ble_meshtastic.h \
usb/usb_meshtastic.h \
connection/connection.h \
connection/ble/ble.h \
connection/ble/ble_meshtastic.h \
connection/usb/usb_meshtastic.h \
qt.h
SOURCES += \
ble/ble.cpp \
ble/ble_meshtastic.cpp \
usb/usb_meshtastic.cpp \
connection/connection.cpp \
connection/ble/ble.cpp \
connection/ble/ble_meshtastic.cpp \
connection/usb/usb_meshtastic.cpp \
qt.cpp
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*))
(q> |playing| ui:*busy* t)))
(defun set-ready-ble (&optional ready name ble-names) ; see Qt
(defun set-ready (args) ; see Qt
(case radios:*connection*
(:ble
(destructuring-bind (ready name ble-names)
args
(setf *ready* ready)
(when ready
(setf *ble-names* ble-names)
(app:toast (x:cc (tr "radio") ": " name) 2)
(get-node-config))
(values))
(defun set-ready-usb (port) ; see Qt
(get-node-config))))
(:usb
(destructuring-bind (port)
args
(setf *ready* t)
(app:toast (x:cc "USB: " port) 2)
(get-node-config)
(get-node-config))))
(values))
(defun add-line-breaks (text)
@ -140,7 +144,7 @@
(defun read-radio ()
"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)
"Sends passed TO-RADIO, preceded by a header."
@ -150,12 +154,14 @@
(header (header (length bytes))))
(case radios:*connection*
(:ble (qrun*
(qt:write-ble qt:*cpp* header)
(qt:write-ble qt:*cpp* bytes)))
(qt:write* qt:*cpp* header)
(qt:write* qt:*cpp* bytes)))
(: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
(destructuring-bind (bytes &optional notified)
args
(if notified
(progn
(setf *notify-id* bytes)
@ -170,7 +176,7 @@
(push from-radio *received*))
(progn
(qlog "received faulty bytes: ~A" error)
(push bytes *received-faulty*)))))
(push bytes *received-faulty*))))))
(values))
(defun receiving-done () ; see Qt

View file

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

View file

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

View file

@ -80,6 +80,7 @@ Item {
text: "USB"
autoExclusive: true
checkable: true
enabled: (Qt.platform.os !== "android") && (Qt.platform.os !== "ios")
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
------------------------
If you have your radio connected via USB to your PC, you can choose 'USB' as
connection type from the main menu (see 'Radios' icon). This currently only
works on Linux and macOS, and only with RAK devices (which don't need any
driver, just permission to e.g. `/dev/ttyACM0` on Linux).
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 only works on
Linux and macOS (Windows not tested), and only with RAK devices (which don't
need any driver, just permission to e.g. `/dev/ttyACM0` on Linux).
Android is currently WIP.
The next best option is BLE (Bluetooth Low Energy).
For mobile there is BLE (Bluetooth Low Energy).
Your radio needs to be turned on and bluetooth needs to be enabled before you
start the app.