mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-06 02:30:38 -08:00
example 'meshtastic': make it work on android again (sqlite)
This commit is contained in:
parent
e15e58daaa
commit
f3c80bbce4
13 changed files with 94 additions and 48 deletions
|
|
@ -2,7 +2,6 @@
|
|||
:serial t
|
||||
:depends-on (#-depends-loaded :uiop
|
||||
#-depends-loaded :cl-base64
|
||||
#-depends-loaded :sqlite
|
||||
#-depends-loaded :my-cl-protobufs
|
||||
#-depends-loaded :trivial-package-local-nicknames)
|
||||
:components ((:file "lisp/package")
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ QMAKE_EXTRA_COMPILERS += lisp
|
|||
win32: PRE_TARGETDEPS = tmp/app.lib
|
||||
!win32: PRE_TARGETDEPS = tmp/libapp.a
|
||||
|
||||
QT += quick qml bluetooth
|
||||
QT += quick qml bluetooth sql
|
||||
TEMPLATE = app
|
||||
CONFIG += c++17 no_keywords release
|
||||
DEFINES += DESKTOP_APP BACKGROUND_INI_LISP INI_ECL_CONTRIB QT_EXTENSION
|
||||
DEFINES += DESKTOP_APP INI_ECL_CONTRIB QT_EXTENSION BACKGROUND_INI_LISP
|
||||
INCLUDEPATH = /usr/local/include
|
||||
ECL_VERSION = $$lower($$system(ecl -v))
|
||||
ECL_VERSION = $$replace(ECL_VERSION, " ", "-")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "qt.h"
|
||||
#include "ble_meshtastic.h"
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlError>
|
||||
#include <QtDebug>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
@ -16,6 +18,8 @@ QT::QT() : QObject() {
|
|||
ble = new BLE_ME;
|
||||
}
|
||||
|
||||
// BLE_ME
|
||||
|
||||
QVariant QT::startDeviceDiscovery(const QVariant& vName) {
|
||||
auto name = vName.toString();
|
||||
if (!name.isNull()) {
|
||||
|
|
@ -43,4 +47,41 @@ QVariant QT::write2(const QVariant& bytes) {
|
|||
return QVariant();
|
||||
}
|
||||
|
||||
// SQLite
|
||||
|
||||
QVariant QT::iniDb(const QVariant& name) {
|
||||
db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db.setDatabaseName(name.toString());
|
||||
return name;
|
||||
}
|
||||
|
||||
QVariant QT::sqlQuery(const QVariant& vQuery, const QVariant& vValues) {
|
||||
// very simple, we don't need more
|
||||
QVariantList results;
|
||||
QSqlQuery query(db);
|
||||
if (db.open()) {
|
||||
query.prepare(vQuery.toString());
|
||||
const QVariantList values = vValues.value<QVariantList>();
|
||||
for (auto value : values) {
|
||||
query.addBindValue(value);
|
||||
}
|
||||
if (query.exec()) {
|
||||
while (query.next()) {
|
||||
results << query.value(0);
|
||||
}
|
||||
db.close();
|
||||
return results;
|
||||
}
|
||||
db.close();
|
||||
}
|
||||
QString text;
|
||||
if (query.lastError().isValid()) {
|
||||
text = query.lastError().text();
|
||||
} else {
|
||||
text = db.lastError().text();
|
||||
}
|
||||
qDebug() << "SQL error:" << text;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#ifdef Q_CC_MSVC
|
||||
#define LIB_EXPORT __declspec(dllexport)
|
||||
|
|
@ -24,9 +25,14 @@ public:
|
|||
Q_INVOKABLE QVariant read2();
|
||||
Q_INVOKABLE QVariant write2(const QVariant&);
|
||||
|
||||
// SQLite
|
||||
Q_INVOKABLE QVariant iniDb(const QVariant&);
|
||||
Q_INVOKABLE QVariant sqlQuery(const QVariant&, const QVariant&);
|
||||
|
||||
QT();
|
||||
|
||||
BLE_ME* ble;
|
||||
QSqlDatabase db;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
QT += bluetooth
|
||||
QT += bluetooth sql
|
||||
TEMPLATE = lib
|
||||
CONFIG += c++17 plugin release no_keywords
|
||||
DEFINES += PLUGIN
|
||||
|
|
|
|||
|
|
@ -2,33 +2,31 @@
|
|||
|
||||
(defvar *file* (merge-pathnames "data/db"))
|
||||
|
||||
(defun query (query &rest values)
|
||||
(qt:sql-query qt:*cpp* query values))
|
||||
|
||||
(defun ini ()
|
||||
(with-open-database (db *file*)
|
||||
(execute-non-query
|
||||
db "create table if not exists messages (mid integer primary key, uid integer, message text)")))
|
||||
(ensure-directories-exist *file*)
|
||||
(qt:ini-db qt:*cpp* (namestring *file*))
|
||||
(query "create table if not exists messages (mid integer primary key, uid integer, message text)"))
|
||||
|
||||
(defun save-message (mid uid message)
|
||||
(with-open-database (db *file*)
|
||||
(execute-non-query
|
||||
db "insert into messages (mid, uid, message) values (?, ?, ?)" mid uid message)))
|
||||
(query "insert into messages (mid, uid, message) values (?, ?, ?)"
|
||||
mid uid message))
|
||||
|
||||
(defun load-message (mid)
|
||||
(with-open-database (db *file*)
|
||||
(execute-single
|
||||
db "select message from messages where mid = ?" mid)))
|
||||
(first (query "select message from messages where mid = ?"
|
||||
mid)))
|
||||
|
||||
(defun update-message (mid message)
|
||||
(with-open-database (db *file*)
|
||||
(execute-non-query
|
||||
db "update messages set message = ? where mid = ?" message mid)))
|
||||
(query "update messages set message = ? where mid = ?"
|
||||
message mid))
|
||||
|
||||
(defun load-messages (uid)
|
||||
(with-open-database (db *file*)
|
||||
(execute-to-list
|
||||
db "select message from messages where uid = ? order by mid" uid)))
|
||||
(query "select message from messages where uid = ? order by mid"
|
||||
uid))
|
||||
|
||||
(defun max-message-id ()
|
||||
(or (with-open-database (db *file*)
|
||||
(execute-single db "select max(mid) from messages"))
|
||||
0))
|
||||
(let ((val (first (query "select max(mid) from messages"))))
|
||||
(if (numberp val) val 0)))
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
(defun start-device-discovery (&optional (name ""))
|
||||
(setf radios:*schedule-clear* t)
|
||||
(setf *ble-names* nil)
|
||||
(qt:start-device-discovery qt:*ble* name)
|
||||
(qt:start-device-discovery qt:*cpp* name)
|
||||
(q> |playing| ui:*busy* t))
|
||||
|
||||
(defun start-config ()
|
||||
|
|
@ -56,6 +56,8 @@
|
|||
(defun send-message (text)
|
||||
"Sends TEXT to radio and adds it to QML item model."
|
||||
(incf msg:*message-id*)
|
||||
(when (stringp *receiver*)
|
||||
(setf *receiver* (name-to-node *receiver*)))
|
||||
(send-to-radio
|
||||
(me:make-to-radio
|
||||
:packet (me:make-mesh-packet
|
||||
|
|
@ -78,15 +80,15 @@
|
|||
|
||||
(defun read-radio ()
|
||||
"Triggers a read on the radio. Will call RECEIVED-FROM-RADIO on success."
|
||||
(qrun* (qt:read* qt:*ble*)))
|
||||
(qrun* (qt:read* qt:*cpp*)))
|
||||
|
||||
(defun send-to-radio (to-radio)
|
||||
"Sends passed TO-RADIO, preceded by a header."
|
||||
(pr:print-json to-radio)
|
||||
(let ((bytes (pr:serialize-to-bytes to-radio)))
|
||||
(qrun*
|
||||
(qt:write* qt:*ble* (header (length bytes)))
|
||||
(qt:write* qt:*ble* bytes))))
|
||||
(qt:write* qt:*cpp* (header (length bytes)))
|
||||
(qt:write* qt:*cpp* bytes))))
|
||||
|
||||
(defun received-from-radio (bytes &optional notified) ; called from Qt
|
||||
(if notified
|
||||
|
|
@ -109,6 +111,11 @@
|
|||
(when (= num (me:num info))
|
||||
(return (me:short-name (me:user info))))))
|
||||
|
||||
(defun name-to-node (name)
|
||||
(dolist (info *node-infos*)
|
||||
(when (string= name (me:short-name (me:user info)))
|
||||
(return (me:num info)))))
|
||||
|
||||
(defun my-name ()
|
||||
(me:short-name (me:user *my-node-info*)))
|
||||
|
||||
|
|
@ -121,7 +128,7 @@
|
|||
"Walks *RECEIVED* FROM-RADIOs and saves relevant data."
|
||||
(setf *received* (nreverse *received*))
|
||||
(unless *ble-names*
|
||||
(setf *ble-names* (qt:short-names qt:*ble*)))
|
||||
(setf *ble-names* (qt:short-names qt:*cpp*)))
|
||||
(dolist (struct *received*)
|
||||
(cond ((me:from-radio.has-packet struct)
|
||||
(let* ((packet (me:from-radio.packet struct))
|
||||
|
|
@ -201,10 +208,7 @@
|
|||
(qlog "config-complete id: ~A" *config-id*)
|
||||
(unless (find (my-name) (app:setting :configured) :test 'string=)
|
||||
(app:change-setting :configured (my-name) :cons t)
|
||||
(qlater 'config-device))))
|
||||
;; rebooted
|
||||
((me:from-radio.has-rebooted struct)
|
||||
(qlog "rebooted: ~A" (me:from-radio.rebooted)))))
|
||||
(qlater 'config-device))))))
|
||||
(setf *received* nil))
|
||||
|
||||
(defun send-admin (admin-message)
|
||||
|
|
@ -249,7 +253,7 @@
|
|||
(values))
|
||||
|
||||
(defun change-modem-preset (modem-preset) ; called from QML
|
||||
(app:change-setting :modem-reset (app:kw modem-preset))
|
||||
(app:change-setting :modem-preset (app:kw modem-preset))
|
||||
(qlater 'change-lora-config)
|
||||
(values))
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
(x:when-it (app:setting (getf message :sender) :custom-name)
|
||||
(setf (getf message :sender-name) x:it)))
|
||||
(unless loading
|
||||
(db:save-message (getf message :mid)
|
||||
(db:save-message (parse-integer (getf message :mid))
|
||||
(parse-integer (getf message (if (getf message :me) :receiver :sender))
|
||||
:radix 16)
|
||||
(prin1-to-string message)))
|
||||
|
|
@ -43,8 +43,8 @@
|
|||
(defun show-messages ()
|
||||
(x:when-it (app:setting :latest-receiver)
|
||||
(q! |clear| ui:*messages*)
|
||||
(dolist (row (db:load-messages (parse-integer x:it :radix 16)))
|
||||
(add-message (read-from-string (first row)) t))
|
||||
(dolist (message (db:load-messages (parse-integer x:it :radix 16)))
|
||||
(add-message (read-from-string message) t))
|
||||
(q! |positionViewAtEnd| ui:*message-view*)))
|
||||
|
||||
(defun receiver-changed ()
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
#:set-unread))
|
||||
|
||||
(defpackage :db
|
||||
(:use :cl :sqlite)
|
||||
(:use :cl)
|
||||
(:export
|
||||
#:ini
|
||||
#:load-message
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
(defpackage :qt
|
||||
(:use :cl :qml)
|
||||
(:export
|
||||
#:*ble*
|
||||
#:*cpp*
|
||||
#:ini
|
||||
#:ini-db
|
||||
#:start-device-discovery
|
||||
#:read*
|
||||
#:short-names
|
||||
#:sql-query
|
||||
#:write*))
|
||||
|
||||
(in-package :qt)
|
||||
|
||||
(defvar *ble* nil)
|
||||
(defvar *cpp* nil)
|
||||
|
||||
(defun ini ()
|
||||
(setf *ble*
|
||||
(setf *cpp*
|
||||
#+qt-plugin (qload-c++ "cpp/qt")
|
||||
#-qt-plugin (qfind-child nil "QT"))
|
||||
(let ((*package* (find-package :qt)))
|
||||
(define-qt-wrappers *ble*)))
|
||||
(define-qt-wrappers *cpp*)))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
Rectangle {
|
||||
color: "#ccebc5"
|
||||
}
|
||||
|
|
@ -36,7 +36,10 @@ You will see a json output of all data sent/received. It simply uses the
|
|||
`print-json` convenience function from cl-protobufs.
|
||||
|
||||
The message db uses **sqlite**, but in a lispy manner, storing basically just a
|
||||
plist for every message.
|
||||
plist for every message. The reason I chose Qt instead of cl-sqlite is mobile:
|
||||
Qt comes with its own version, which is pulled in automatially, so one doesn't
|
||||
need to care about the OS limitations or indirect requirements. Additionally,
|
||||
cffi (dependency of cl-sqlite) currently needs a small hack to work on mobile.
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@
|
|||
(push (merge-pathnames "./")
|
||||
asdf:*central-registry*)
|
||||
|
||||
(asdf:load-system :uiop)
|
||||
(asdf:load-system :cl-base64)
|
||||
(asdf:load-system :sqlite)
|
||||
(asdf:load-system :trivial-package-local-nicknames)
|
||||
|
||||
;; may take very long on mobile devices
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue