mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-06 02:30:38 -08:00
example 'meshtastic': refactor connection part
This commit is contained in:
parent
679fca2d25
commit
013a75d3f5
22 changed files with 432 additions and 285 deletions
|
|
@ -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/*)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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&));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
};
|
||||
122
examples/meshtastic/cpp/connection/connection.cpp
Normal file
122
examples/meshtastic/cpp/connection/connection.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
49
examples/meshtastic/cpp/connection/connection.h
Normal file
49
examples/meshtastic/cpp/connection/connection.h
Normal 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&);
|
||||
};
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
49
examples/meshtastic/cpp/connection/usb/usb_meshtastic.h
Normal file
49
examples/meshtastic/cpp/connection/usb/usb_meshtastic.h
Normal 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();
|
||||
};
|
||||
|
||||
|
|
@ -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.*.*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ Item {
|
|||
text: "USB"
|
||||
autoExclusive: true
|
||||
checkable: true
|
||||
enabled: (Qt.platform.os !== "android") && (Qt.platform.os !== "ios")
|
||||
onTriggered: connection.changed(objectName)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue