diff --git a/examples/meshtastic/cpp/android_service/qtandroidservice.rep b/examples/meshtastic/cpp/android_service/qtandroidservice.rep index e3d76f9..2dd4bab 100644 --- a/examples/meshtastic/cpp/android_service/qtandroidservice.rep +++ b/examples/meshtastic/cpp/android_service/qtandroidservice.rep @@ -3,9 +3,11 @@ class QtAndroidService { SLOT(void setDeviceFilter(const QString&)); SLOT(void read()); SLOT(void write(const QByteArray&)); + SLOT(void setBackgroundMode(bool)); SIGNAL(deviceDiscovered(const QString&)); SIGNAL(bleError()); SIGNAL(setReady(bool, const QString&, const QStringList&)); SIGNAL(receivedFromRadio(const QByteArray&, const QString&)); SIGNAL(receivingDone()); + SIGNAL(sendSavedPackets(const QVariant&)); } diff --git a/examples/meshtastic/cpp/android_service/qtandroidservice_ro.h b/examples/meshtastic/cpp/android_service/qtandroidservice_ro.h index 3dddd37..ad832d1 100644 --- a/examples/meshtastic/cpp/android_service/qtandroidservice_ro.h +++ b/examples/meshtastic/cpp/android_service/qtandroidservice_ro.h @@ -10,4 +10,5 @@ public slots: 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); } }; diff --git a/examples/meshtastic/cpp/android_service/rep_qtandroidservice_source.h b/examples/meshtastic/cpp/android_service/rep_qtandroidservice_source.h deleted file mode 100644 index 7794304..0000000 --- a/examples/meshtastic/cpp/android_service/rep_qtandroidservice_source.h +++ /dev/null @@ -1,216 +0,0 @@ -#ifndef REP_QTANDROIDSERVICE_SOURCE_H -#define REP_QTANDROIDSERVICE_SOURCE_H - -// This is an autogenerated file. -// Do not edit this file, any changes made will be lost the next time it is generated. - -#include -#include -#include -#include - -#include -#include - - -class QtAndroidServiceSource : public QObject -{ - Q_OBJECT - Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "QtAndroidService") - Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, "5239a8ec9c5c20228d0b3b90f08230011762e23c") - -public: - explicit QtAndroidServiceSource(QObject *parent = nullptr) : QObject(parent) - { - } - -public: - ~QtAndroidServiceSource() override = default; - - -Q_SIGNALS: - void deviceDiscovered(const QString & __repc_variable_1); - void bleError(); - void setReady(bool __repc_variable_1, const QString & __repc_variable_2, const QStringList & __repc_variable_3); - void receivedFromRadio(const QByteArray & __repc_variable_1, const QString & __repc_variable_2); - void receivingDone(); - -public Q_SLOTS: - virtual void startDeviceDiscovery(const QString & __repc_variable_1) = 0; - virtual void setDeviceFilter(const QString & __repc_variable_1) = 0; - virtual void read() = 0; - virtual void write(const QByteArray & __repc_variable_1) = 0; - -private: - friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode); -}; - - -class QtAndroidServiceSimpleSource : public QtAndroidServiceSource -{ - Q_OBJECT - -public: - explicit QtAndroidServiceSimpleSource(QObject *parent = nullptr) : QtAndroidServiceSource(parent) - { - } - -public: - ~QtAndroidServiceSimpleSource() override = default; - - -private: -}; - - -template -struct QtAndroidServiceSourceAPI : public SourceApiMap -{ - QtAndroidServiceSourceAPI(ObjectType *object, const QString &name = QLatin1String("QtAndroidService")) - : SourceApiMap(), m_name(name) - { - Q_UNUSED(object); - m_enums[0] = 0; - m_properties[0] = 0; - m_signals[0] = 5; - m_signals[1] = QtPrivate::qtro_signal_index(&ObjectType::deviceDiscovered, static_cast(0),m_signalArgCount+0,&m_signalArgTypes[0]); - m_signals[2] = QtPrivate::qtro_signal_index(&ObjectType::bleError, static_cast(0),m_signalArgCount+1,&m_signalArgTypes[1]); - m_signals[3] = QtPrivate::qtro_signal_index(&ObjectType::setReady, static_cast(0),m_signalArgCount+2,&m_signalArgTypes[2]); - m_signals[4] = QtPrivate::qtro_signal_index(&ObjectType::receivedFromRadio, static_cast(0),m_signalArgCount+3,&m_signalArgTypes[3]); - m_signals[5] = QtPrivate::qtro_signal_index(&ObjectType::receivingDone, static_cast(0),m_signalArgCount+4,&m_signalArgTypes[4]); - m_methods[0] = 4; - m_methods[1] = QtPrivate::qtro_method_index(&ObjectType::startDeviceDiscovery, static_cast(0),"startDeviceDiscovery(QString)",m_methodArgCount+0,&m_methodArgTypes[0]); - m_methods[2] = QtPrivate::qtro_method_index(&ObjectType::setDeviceFilter, static_cast(0),"setDeviceFilter(QString)",m_methodArgCount+1,&m_methodArgTypes[1]); - m_methods[3] = QtPrivate::qtro_method_index(&ObjectType::read, static_cast(0),"read()",m_methodArgCount+2,&m_methodArgTypes[2]); - m_methods[4] = QtPrivate::qtro_method_index(&ObjectType::write, static_cast(0),"write(QByteArray)",m_methodArgCount+3,&m_methodArgTypes[3]); - } - - QString name() const override { return m_name; } - QString typeName() const override { return QStringLiteral("QtAndroidService"); } - int enumCount() const override { return m_enums[0]; } - int propertyCount() const override { return m_properties[0]; } - int signalCount() const override { return m_signals[0]; } - int methodCount() const override { return m_methods[0]; } - int sourceEnumIndex(int index) const override - { - if (index < 0 || index >= m_enums[0]) - return -1; - return m_enums[index+1]; - } - int sourcePropertyIndex(int index) const override - { - if (index < 0 || index >= m_properties[0]) - return -1; - return m_properties[index+1]; - } - int sourceSignalIndex(int index) const override - { - if (index < 0 || index >= m_signals[0]) - return -1; - return m_signals[index+1]; - } - int sourceMethodIndex(int index) const override - { - if (index < 0 || index >= m_methods[0]) - return -1; - return m_methods[index+1]; - } - int signalParameterCount(int index) const override - { - if (index < 0 || index >= m_signals[0]) - return -1; - return m_signalArgCount[index]; - } - int signalParameterType(int sigIndex, int paramIndex) const override - { - if (sigIndex < 0 || sigIndex >= m_signals[0] || paramIndex < 0 || paramIndex >= m_signalArgCount[sigIndex]) - return -1; - return m_signalArgTypes[sigIndex][paramIndex]; - } - int methodParameterCount(int index) const override - { - if (index < 0 || index >= m_methods[0]) - return -1; - return m_methodArgCount[index]; - } - int methodParameterType(int methodIndex, int paramIndex) const override - { - if (methodIndex < 0 || methodIndex >= m_methods[0] || paramIndex < 0 || paramIndex >= m_methodArgCount[methodIndex]) - return -1; - return m_methodArgTypes[methodIndex][paramIndex]; - } - int propertyIndexFromSignal(int index) const override - { - Q_UNUSED(index); - return -1; - } - int propertyRawIndexFromSignal(int index) const override - { - Q_UNUSED(index); - return -1; - } - const QByteArray signalSignature(int index) const override - { - switch (index) { - case 0: return QByteArrayLiteral("deviceDiscovered(QString)"); - case 1: return QByteArrayLiteral("bleError()"); - case 2: return QByteArrayLiteral("setReady(bool,QString,QStringList)"); - case 3: return QByteArrayLiteral("receivedFromRadio(QByteArray,QString)"); - case 4: return QByteArrayLiteral("receivingDone()"); - } - return QByteArrayLiteral(""); - } - QList signalParameterNames(int index) const override - { - if (index < 0 || index >= m_signals[0]) - return QList(); - return ObjectType::staticMetaObject.method(m_signals[index + 1]).parameterNames(); - } - const QByteArray methodSignature(int index) const override - { - switch (index) { - case 0: return QByteArrayLiteral("startDeviceDiscovery(QString)"); - case 1: return QByteArrayLiteral("setDeviceFilter(QString)"); - case 2: return QByteArrayLiteral("read()"); - case 3: return QByteArrayLiteral("write(QByteArray)"); - } - return QByteArrayLiteral(""); - } - QMetaMethod::MethodType methodType(int) const override - { - return QMetaMethod::Slot; - } - QList methodParameterNames(int index) const override - { - if (index < 0 || index >= m_methods[0]) - return QList(); - return ObjectType::staticMetaObject.method(m_methods[index + 1]).parameterNames(); - } - const QByteArray typeName(int index) const override - { - switch (index) { - case 0: return QByteArrayLiteral("void"); - case 1: return QByteArrayLiteral("void"); - case 2: return QByteArrayLiteral("void"); - case 3: return QByteArrayLiteral("void"); - } - return QByteArrayLiteral(""); - } - QByteArray objectSignature() const override { return QByteArray{"5239a8ec9c5c20228d0b3b90f08230011762e23c"}; } - - int m_enums[1]; - int m_properties[1]; - int m_signals[6]; - int m_methods[5]; - const QString m_name; - int m_signalArgCount[5]; - const int* m_signalArgTypes[5]; - int m_methodArgCount[4]; - const int* m_methodArgTypes[4]; -}; - -QT_BEGIN_NAMESPACE -QT_END_NAMESPACE - - -#endif // REP_QTANDROIDSERVICE_SOURCE_H diff --git a/examples/meshtastic/cpp/ble/ble.cpp b/examples/meshtastic/cpp/ble/ble.cpp index 5ad906f..1502e66 100644 --- a/examples/meshtastic/cpp/ble/ble.cpp +++ b/examples/meshtastic/cpp/ble/ble.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include BLE::BLE(const QBluetoothUuid& uuid) : mainServiceUuid(uuid) { @@ -50,11 +49,11 @@ void BLE::deviceScanFinished() { if (devices.isEmpty()) { qDebug() << "no BLE devices found"; discoveryAgent->setLowEnergyDiscoveryTimeout(3000); - QTimer::singleShot(0, this, [&]() { startDeviceDiscovery(); }); + startDeviceDiscovery(); } else { qDebug() << "device scan done"; discoveryAgent->setLowEnergyDiscoveryTimeout(1000); // reset to default - QTimer::singleShot(0, this, &BLE::scanServices); + scanServices(); } } @@ -152,7 +151,7 @@ void BLE::deviceConnected() { void BLE::retryScan() { if (connected && !scanned) { - QTimer::singleShot(0, this, &BLE::scanServices); + scanServices(); } } @@ -184,4 +183,3 @@ void BLE::deviceScanError(QBluetoothDeviceDiscoveryAgent::Error error) { qDebug() << "error: " + QLatin1String(qme.valueToKey(error)); } } - diff --git a/examples/meshtastic/cpp/ble/ble_meshtastic.cpp b/examples/meshtastic/cpp/ble/ble_meshtastic.cpp index 224ccca..1b35193 100644 --- a/examples/meshtastic/cpp/ble/ble_meshtastic.cpp +++ b/examples/meshtastic/cpp/ble/ble_meshtastic.cpp @@ -1,6 +1,8 @@ #include "ble_meshtastic.h" #include -#include +#include +#include +#include #ifdef Q_OS_ANDROID #include "../android_service/qtandroidservice_ro.h" @@ -96,30 +98,42 @@ void BLE_ME::searchCharacteristics() { for (auto device : qAsConst(devices)) { names << device.name().right(4); } - emitter->setReady(true, currentDevice.name().right(4), names); + if (!backgroundMode) { + emitter->setReady(true, currentDevice.name().right(4), names); + } } } void BLE_ME::characteristicChanged(const QLowEnergyCharacteristic&, const QByteArray& data) { if (!data.isEmpty()) { - emitter->receivedFromRadio(data, "notified"); + if (backgroundMode) { + read(); + } else { + emitter->receivedFromRadio(data, "notified"); + } } } void BLE_ME::characteristicRead(const QLowEnergyCharacteristic&, const QByteArray& data) { if (data.isEmpty()) { - emitter->receivingDone(); + if (!backgroundMode) { + emitter->receivingDone(); + } } else { - emitter->receivedFromRadio(data, QString()); - QTimer::singleShot(0, this, &BLE_ME::read); + if (backgroundMode) { + saveBytes(data); + } else { + emitter->receivedFromRadio(data, QString()); + } + read(); } } void BLE_ME::characteristicWritten(const QLowEnergyCharacteristic&, const QByteArray&) { - QTimer::singleShot(0, this, &BLE_ME::read); + read(); } void BLE_ME::serviceError(QLowEnergyService::ServiceError error) { @@ -155,7 +169,51 @@ void BLE_ME::disconnecting() { // disable notifications mainService->writeDescriptor(notifications, QByteArray::fromHex("0000")); } - emitter->setReady(false, QString(), QStringList()); + if (!backgroundMode) { + emitter->setReady(false, QString(), QStringList()); + } 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() { + return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/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; + QFile file(packetsFile()); + 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(packetsFile()); + } + } +} diff --git a/examples/meshtastic/cpp/ble/ble_meshtastic.h b/examples/meshtastic/cpp/ble/ble_meshtastic.h index ab1e5f0..6dd9827 100644 --- a/examples/meshtastic/cpp/ble/ble_meshtastic.h +++ b/examples/meshtastic/cpp/ble/ble_meshtastic.h @@ -25,11 +25,13 @@ 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&); void receivedFromRadio(const QByteArray&, const QString&); void receivingDone(); + void sendSavedPackets(const QVariant&); /*** ***************************************/ @@ -48,6 +50,7 @@ public: #else BLE_ME* emitter = nullptr; #endif + bool backgroundMode = false; QString filter = "meshtastic"; QLowEnergyDescriptor notifications; @@ -63,4 +66,8 @@ private Q_SLOTS: void characteristicWritten(const QLowEnergyCharacteristic&, const QByteArray&); void serviceError(QLowEnergyService::ServiceError); void disconnecting(); + +private: + void saveBytes(const QByteArray&); + void sendSavedBytes(); }; diff --git a/examples/meshtastic/cpp/qt.cpp b/examples/meshtastic/cpp/qt.cpp index f7a7d86..4571364 100644 --- a/examples/meshtastic/cpp/qt.cpp +++ b/examples/meshtastic/cpp/qt.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #ifdef PLUGIN @@ -105,6 +106,27 @@ QT::QT() : QObject() { []() { ecl_fun("lora:receiving-done"); }); + +#ifdef Q_OS_ANDROID + QObject::connect(ble.data(), &QtAndroidServiceReplica::sendSavedPackets, +#else + QObject::connect(ble, &BLE_ME::sendSavedPackets, +#endif + [](const QVariant& packets) { + ecl_fun("lora:process-saved-packets", packets); + }); + +#if (defined Q_OS_ANDROID) || (defined Q_OS_IOS) + // background mode + QObject::connect(qGuiApp, &QGuiApplication::applicationStateChanged, + [&](Qt::ApplicationState state) { + if (state == Qt::ApplicationInactive) { + ble->setBackgroundMode(true); + } else if (state == Qt::ApplicationActive) { + ble->setBackgroundMode(false); + } + }); +#endif } // BLE @@ -129,6 +151,11 @@ QVariant QT::write2(const QVariant& bytes) { return QVariant(); } +QVariant QT::setBackgroundMode(const QVariant& vBackground) { + // for testing + ble->setBackgroundMode(vBackground.toBool()); +} + // GPS #ifdef Q_OS_ANDROID diff --git a/examples/meshtastic/cpp/qt.h b/examples/meshtastic/cpp/qt.h index c95dabb..ad5444e 100644 --- a/examples/meshtastic/cpp/qt.h +++ b/examples/meshtastic/cpp/qt.h @@ -28,6 +28,7 @@ public: Q_INVOKABLE QVariant setDeviceFilter(const QVariant&); Q_INVOKABLE QVariant read2(); Q_INVOKABLE QVariant write2(const QVariant&); + Q_INVOKABLE QVariant setBackgroundMode(const QVariant&); // GPS Q_INVOKABLE QVariant iniPositioning(); diff --git a/examples/meshtastic/lisp/lora.lisp b/examples/meshtastic/lisp/lora.lisp index 8f0c82a..24892ca 100644 --- a/examples/meshtastic/lisp/lora.lisp +++ b/examples/meshtastic/lisp/lora.lisp @@ -169,6 +169,13 @@ (process-received) (values)) +(defun process-saved-packets (packets) ; see Qt + "Called when app changes from background to foreground (mobile only)." + (dolist (packet packets) + (received-from-radio packet)) + (receiving-done) + (values)) + (defun node-to-name (num) (if (= +broadcast-id+ num) *broadcast-name* diff --git a/examples/meshtastic/lisp/messages.lisp b/examples/meshtastic/lisp/messages.lisp index 10b9387..387671f 100644 --- a/examples/meshtastic/lisp/messages.lisp +++ b/examples/meshtastic/lisp/messages.lisp @@ -1,8 +1,7 @@ (in-package :msg) -(defvar *states* '(:not-received :sending :received)) -(defvar *message-id* 0) -(defvar *message-ids* nil "associate (temporary) QML :mid to (unique) DB 'mid'") +(defvar *states* '(:not-received :sending :received)) +(defvar *message-id* 0) (defun ini () (q> |fontSize| ui:*message-view* @@ -11,8 +10,12 @@ (defun new-message-id () (mod (incf *message-id*) #.(expt 2 32))) -(defun db-mid (mid) - (cdr (assoc mid *message-ids*))) +(let (message-ids) + ;; associate (temporary) QML :mid to (unique) DB 'mid' + (defun add-message-id (ids) + (push ids message-ids)) + (defun db-mid (mid) + (cdr (assoc mid message-ids)))) (defun show-message-p (message) (let ((user (app:setting :latest-receiver))) @@ -31,8 +34,8 @@ (unless loading (let ((db-mid (db:save-message (parse-integer x:it :radix 16) ; uid (prin1-to-string message)))) - (push (cons (getf message :mid) db-mid) - *message-ids*))) + (add-message-id (cons (getf message :mid) + db-mid)))) (if (or loading (show-message-p message)) (qjs |addMessage| ui:*messages* message) (let* ((sender (getf message :sender)) diff --git a/examples/meshtastic/lisp/package.lisp b/examples/meshtastic/lisp/package.lisp index 5e971b0..01749d3 100644 --- a/examples/meshtastic/lisp/package.lisp +++ b/examples/meshtastic/lisp/package.lisp @@ -57,6 +57,7 @@ #:keywords #:my-name #:my-num + #:process-saved-packets #:send-position #:start-device-discovery #:read-radio diff --git a/examples/meshtastic/lisp/qt.lisp b/examples/meshtastic/lisp/qt.lisp index c3a82c0..6aca86e 100644 --- a/examples/meshtastic/lisp/qt.lisp +++ b/examples/meshtastic/lisp/qt.lisp @@ -12,6 +12,7 @@ #:local-ip #:start-device-discovery #:read* + #:set-background-mode ; for testing #:set-device-filter #:sql-query #:write*)) diff --git a/examples/meshtastic/platforms/android/AndroidManifest.xml b/examples/meshtastic/platforms/android/AndroidManifest.xml index 94e43bc..faa5315 100644 --- a/examples/meshtastic/platforms/android/AndroidManifest.xml +++ b/examples/meshtastic/platforms/android/AndroidManifest.xml @@ -79,7 +79,7 @@ - +