mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-06 02:30:38 -08:00
example 'meshtastic', add iOS version, background ini, startup animation
This commit is contained in:
parent
1f72af5440
commit
0446628830
25 changed files with 181 additions and 111 deletions
2
examples/meshtastic/.gitignore
vendored
Normal file
2
examples/meshtastic/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
||||||
|
|
@ -30,7 +30,7 @@ win32: PRE_TARGETDEPS = tmp/app.lib
|
||||||
QT += quick qml bluetooth
|
QT += quick qml bluetooth
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
CONFIG += c++17 no_keywords release
|
CONFIG += c++17 no_keywords release
|
||||||
DEFINES += DESKTOP_APP INI_LISP INI_ECL_CONTRIB QT_EXTENSION
|
DEFINES += DESKTOP_APP BACKGROUND_INI_LISP INI_ECL_CONTRIB QT_EXTENSION
|
||||||
INCLUDEPATH = /usr/local/include
|
INCLUDEPATH = /usr/local/include
|
||||||
ECL_VERSION = $$lower($$system(ecl -v))
|
ECL_VERSION = $$lower($$system(ecl -v))
|
||||||
ECL_VERSION = $$replace(ECL_VERSION, " ", "-")
|
ECL_VERSION = $$replace(ECL_VERSION, " ", "-")
|
||||||
|
|
@ -87,10 +87,10 @@ ios {
|
||||||
LIBS += -L../../../platforms/ios/lib
|
LIBS += -L../../../platforms/ios/lib
|
||||||
|
|
||||||
QMAKE_INFO_PLIST = platforms/ios/Info.plist
|
QMAKE_INFO_PLIST = platforms/ios/Info.plist
|
||||||
QMAKE_ASSET_CATALOGS += platforms/ios/Assets.xcassets
|
#QMAKE_ASSET_CATALOGS += platforms/ios/Assets.xcassets
|
||||||
|
|
||||||
launch.files = platforms/ios/designable.storyboard platforms/img/logo.png
|
#launch.files = platforms/ios/designable.storyboard platforms/img/logo.png
|
||||||
QMAKE_BUNDLE_DATA += launch
|
#QMAKE_BUNDLE_DATA += launch
|
||||||
}
|
}
|
||||||
|
|
||||||
32bit {
|
32bit {
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@ BLE::BLE(const QBluetoothUuid& uuid) : mainServiceUuid(uuid) {
|
||||||
connect(discoveryAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
|
connect(discoveryAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
|
||||||
this, &BLE::deviceScanError);
|
this, &BLE::deviceScanError);
|
||||||
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BLE::deviceScanFinished);
|
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BLE::deviceScanFinished);
|
||||||
|
|
||||||
QTimer::singleShot(0, this, &BLE::startDeviceDiscovery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BLE::startDeviceDiscovery() {
|
void BLE::startDeviceDiscovery() {
|
||||||
|
|
@ -60,8 +58,7 @@ void BLE::scanServices() {
|
||||||
if (controller && (previousAddress != currentDevice.address())) {
|
if (controller && (previousAddress != currentDevice.address())) {
|
||||||
Q_EMIT deviceDisconnecting();
|
Q_EMIT deviceDisconnecting();
|
||||||
controller->disconnectFromDevice();
|
controller->disconnectFromDevice();
|
||||||
delete controller;
|
delete controller; controller = nullptr;
|
||||||
controller = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,11 @@ Q_SIGNALS:
|
||||||
void mainServiceReady();
|
void mainServiceReady();
|
||||||
void deviceDisconnecting();
|
void deviceDisconnecting();
|
||||||
|
|
||||||
/*** </INTERFACE> *********************************************************/
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void startDeviceDiscovery();
|
void startDeviceDiscovery();
|
||||||
|
|
||||||
|
/*** </INTERFACE> *********************************************************/
|
||||||
|
|
||||||
void scanServices();
|
void scanServices();
|
||||||
void connectToService(const QString&);
|
void connectToService(const QString&);
|
||||||
void disconnectFromDevice();
|
void disconnectFromDevice();
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ QT::QT() : QObject() {
|
||||||
ble = new BLE_ME;
|
ble = new BLE_ME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant QT::startDeviceDiscovery() {
|
||||||
|
ble->startDeviceDiscovery();
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
QVariant QT::read2() {
|
QVariant QT::read2() {
|
||||||
ble->read();
|
ble->read();
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ class QT : public QObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// BLE_ME
|
// BLE_ME
|
||||||
|
Q_INVOKABLE QVariant startDeviceDiscovery();
|
||||||
Q_INVOKABLE QVariant read2();
|
Q_INVOKABLE QVariant read2();
|
||||||
Q_INVOKABLE QVariant write2(const QVariant&);
|
Q_INVOKABLE QVariant write2(const QVariant&);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
(defun ini ()
|
(defun ini ()
|
||||||
(qt:ini)
|
(qt:ini)
|
||||||
|
(qt:start-device-discovery qt:*ble*)
|
||||||
(msg:load-messages)
|
(msg:load-messages)
|
||||||
(q> |visible| ui:*hour-glass* nil) ; shown during Lisp startup
|
(q> |playing| ui:*loading* nil) ; shown during Lisp startup
|
||||||
(q> |playing| ui:*busy* t)) ; shown during BLE setup
|
(q> |playing| ui:*busy* t)) ; shown during BLE setup
|
||||||
|
|
||||||
(qlater 'ini)
|
(qlater 'ini)
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,19 @@
|
||||||
(defun add-message (message &optional loading)
|
(defun add-message (message &optional loading)
|
||||||
"Adds passed MESSAGE (a PLIST) to both the QML item model and *MESSAGES*.
|
"Adds passed MESSAGE (a PLIST) to both the QML item model and *MESSAGES*.
|
||||||
The model keys are:
|
The model keys are:
|
||||||
:m-text :m-sender :m-timestamp :m-id :m-ack-state"
|
:text :sender :me :timestamp :mid :ack-state"
|
||||||
(qjs |addMessage| ui:*messages* message)
|
(qjs |addMessage| ui:*messages* message)
|
||||||
(unless loading
|
(unless loading
|
||||||
(push message *messages*)
|
(push message *messages*)
|
||||||
(qlater 'save-messages)))
|
(qlater 'save-messages)))
|
||||||
|
|
||||||
(defun change-state (state id)
|
(defun change-state (state mid)
|
||||||
(let ((i-state (position state *states*)))
|
(let ((i-state (position state *states*)))
|
||||||
(qjs |changeState| ui:*messages*
|
(qjs |changeState| ui:*messages*
|
||||||
i-state id)
|
i-state mid)
|
||||||
(dolist (msg *messages*)
|
(dolist (msg *messages*)
|
||||||
(when (eql (getf msg :m-id) id) ; EQL: might be NIL
|
(when (eql (getf msg :mid) mid) ; EQL: might be NIL
|
||||||
(setf (getf msg :m-ack-state) i-state)
|
(setf (getf msg :ack-state) i-state)
|
||||||
(return))))
|
(return))))
|
||||||
(qlater 'save-messages))
|
(qlater 'save-messages))
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
(with-open-file (s *file*)
|
(with-open-file (s *file*)
|
||||||
(setf *messages* (read s)))
|
(setf *messages* (read s)))
|
||||||
(dolist (msg (reverse *messages*))
|
(dolist (msg (reverse *messages*))
|
||||||
(setf *message-id* (max (or (getf msg :m-id) 0)
|
(setf *message-id* (max (or (getf msg :mid) 0)
|
||||||
*message-id*))
|
*message-id*))
|
||||||
(add-message msg t))))
|
(add-message msg t))))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
(:export
|
(:export
|
||||||
#:*ble*
|
#:*ble*
|
||||||
#:ini
|
#:ini
|
||||||
|
#:start-device-discovery
|
||||||
#:read*
|
#:read*
|
||||||
#:write*))
|
#:write*))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,6 @@
|
||||||
(values))
|
(values))
|
||||||
|
|
||||||
(defun start-config ()
|
(defun start-config ()
|
||||||
#+android
|
|
||||||
(ensure-permissions :access-coarse-location) ; needed for BLE
|
|
||||||
(when *ready*
|
(when *ready*
|
||||||
(incf *config-id*)
|
(incf *config-id*)
|
||||||
(send-to-radio
|
(send-to-radio
|
||||||
|
|
@ -60,11 +58,12 @@
|
||||||
:portnum :text-message-app
|
:portnum :text-message-app
|
||||||
:payload (babel:string-to-octets text)))))
|
:payload (babel:string-to-octets text)))))
|
||||||
(msg:add-message
|
(msg:add-message
|
||||||
(list :m-text text
|
(list :text text
|
||||||
:m-sender (me:short-name (me:user *my-node-info*))
|
:sender (me:short-name (me:user *my-node-info*))
|
||||||
:m-timestamp (timestamp-to-string)
|
:me t
|
||||||
:m-id msg:*message-id*
|
:timestamp (timestamp-to-string)
|
||||||
:m-ack-state (position :not-received msg:*states*))))
|
:mid msg:*message-id*
|
||||||
|
:ack-state (position :not-received msg:*states*))))
|
||||||
|
|
||||||
(defun read-radio ()
|
(defun read-radio ()
|
||||||
"Triggers a read on the radio. Will call RECEIVED-FROM-RADIO on success."
|
"Triggers a read on the radio. Will call RECEIVED-FROM-RADIO on success."
|
||||||
|
|
@ -89,9 +88,10 @@
|
||||||
(push from-radio *received*)))
|
(push from-radio *received*)))
|
||||||
(values))
|
(values))
|
||||||
|
|
||||||
(defun receiving-done ()
|
(defun receiving-done () ; called from Qt
|
||||||
(setf *reading* nil)
|
(setf *reading* nil)
|
||||||
(process-received))
|
(process-received)
|
||||||
|
(values))
|
||||||
|
|
||||||
(defun node-to-name (num)
|
(defun node-to-name (num)
|
||||||
(dolist (info *node-infos*)
|
(dolist (info *node-infos*)
|
||||||
|
|
@ -115,10 +115,10 @@
|
||||||
;; text-message
|
;; text-message
|
||||||
(:text-message-app
|
(:text-message-app
|
||||||
(msg:add-message
|
(msg:add-message
|
||||||
(list :m-text (babel:octets-to-string payload)
|
(list :text (babel:octets-to-string payload)
|
||||||
:m-sender (node-to-name (me:from packet))
|
:sender (node-to-name (me:from packet))
|
||||||
:m-timestamp (timestamp-to-string))))
|
:timestamp (timestamp-to-string))))
|
||||||
;; for :m-ack-state (acknowledgement state)
|
;; for :ack-state (acknowledgement state)
|
||||||
(:routing-app
|
(:routing-app
|
||||||
(msg:change-state (case (me:routing.error-reason
|
(msg:change-state (case (me:routing.error-reason
|
||||||
(pr:deserialize-from-bytes 'me:routing payload))
|
(pr:deserialize-from-bytes 'me:routing payload))
|
||||||
|
|
@ -148,8 +148,6 @@
|
||||||
((me:from-radio.has-config-complete-id struct)
|
((me:from-radio.has-config-complete-id struct)
|
||||||
(when (= *config-id* (me:config-complete-id struct))
|
(when (= *config-id* (me:config-complete-id struct))
|
||||||
(qlater 'config-device)
|
(qlater 'config-device)
|
||||||
(q> |myName| ui:*view*
|
|
||||||
(me:short-name (me:user *my-node-info*)))
|
|
||||||
(q> |playing| ui:*busy* nil)
|
(q> |playing| ui:*busy* nil)
|
||||||
(qlog :config-complete *config-id*)))))
|
(qlog :config-complete *config-id*)))))
|
||||||
(setf *received* nil))
|
(setf *received* nil))
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@
|
||||||
(:use :cl)
|
(:use :cl)
|
||||||
(:export
|
(:export
|
||||||
#:*busy*
|
#:*busy*
|
||||||
#:*hour-glass*
|
#:*loading*
|
||||||
#:*messages*
|
#:*messages*
|
||||||
#:*view*))
|
#:*view*))
|
||||||
|
|
||||||
(in-package :ui)
|
(in-package :ui)
|
||||||
|
|
||||||
(defparameter *busy* "busy")
|
(defparameter *busy* "busy")
|
||||||
(defparameter *hour-glass* "hour_glass")
|
(defparameter *loading* "loading")
|
||||||
(defparameter *messages* "messages")
|
(defparameter *messages* "messages")
|
||||||
(defparameter *view* "view")
|
(defparameter *view* "view")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,35 +91,3 @@
|
||||||
(delete-file to*))
|
(delete-file to*))
|
||||||
(rename-file from to))
|
(rename-file from to))
|
||||||
|
|
||||||
;;; build 'cl-protobufs.fas' (slow on mobile, will be loaded in background)
|
|
||||||
|
|
||||||
#|
|
|
||||||
#-mobile
|
|
||||||
(asdf:make-build "my-cl-protobufs"
|
|
||||||
:monolithic t
|
|
||||||
:type :fasl
|
|
||||||
:move-here (cc *current* "build/tmp/"))
|
|
||||||
|
|
||||||
#+mobile
|
|
||||||
(progn
|
|
||||||
(pushnew :interpreter *features*)
|
|
||||||
(defvar *asdf-system* "my-cl-protobufs")
|
|
||||||
(defvar *ql-libs* (cc *current* "ql-libs.lisp"))
|
|
||||||
(defvar *build-type* :fasl)
|
|
||||||
(defvar *library-path* (format nil "~Abuild-~A/tmp/"
|
|
||||||
*current*
|
|
||||||
#+android "android"
|
|
||||||
#+ios "ios"))
|
|
||||||
(load "platforms/shared/make"))
|
|
||||||
|
|
||||||
;;; rename lib
|
|
||||||
|
|
||||||
(let* ((from #-mobile (cc *current* "build/tmp/my-cl-protobufs--all-systems.fasb")
|
|
||||||
#+mobile (cc *library-path* "my-cl-protobufs--all-systems.fasb"))
|
|
||||||
(to "cl-protobufs.fas")
|
|
||||||
(to* #-mobile (cc *current* "build/tmp/" to)
|
|
||||||
#+mobile (cc *library-path* to)))
|
|
||||||
(when (probe-file to*)
|
|
||||||
(delete-file to*))
|
|
||||||
(rename-file from to))
|
|
||||||
|#
|
|
||||||
|
|
|
||||||
41
examples/meshtastic/platforms/ios/Info.plist
Normal file
41
examples/meshtastic/platforms/ios/Info.plist
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${QMAKE_SHORT_VERSION}</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>${QMAKE_PKGINFO_TYPEINFO}</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>${QMAKE_FULL_VERSION}</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>MinimumOSVersion</key>
|
||||||
|
<string>${IPHONEOS_DEPLOYMENT_TARGET}</string>
|
||||||
|
<key>NOTE</key>
|
||||||
|
<string>This file was generated by Qt/QMake.</string>
|
||||||
|
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||||
|
<string>For connecting to meshtastic radio devices.</string>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB |
BIN
examples/meshtastic/qml/img/busy.webp
Normal file
BIN
examples/meshtastic/qml/img/busy.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 126 KiB |
|
|
@ -16,7 +16,7 @@ Item {
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "#e5d8bd"
|
color: loading.visible ? "#1974d3" : "#e5d8bd"
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
|
|
@ -28,27 +28,32 @@ Item {
|
||||||
spacing: 3
|
spacing: 3
|
||||||
delegate: messageDelegate
|
delegate: messageDelegate
|
||||||
model: messages
|
model: messages
|
||||||
|
|
||||||
property string myName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: messages
|
id: messages
|
||||||
objectName: "messages"
|
objectName: "messages"
|
||||||
|
|
||||||
|
// hack to define all model key _types_
|
||||||
|
ListElement {
|
||||||
|
text: ""; sender: ""; me: true; timestamp: ""; mid: 0; ackState: 0
|
||||||
|
}
|
||||||
|
|
||||||
function addMessage(message) {
|
function addMessage(message) {
|
||||||
append(message)
|
append(message)
|
||||||
view.positionViewAtEnd()
|
view.positionViewAtEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeState(state, id) {
|
function changeState(state, mid) {
|
||||||
for (var i = count - 1; i >= 0; i--) {
|
for (var i = count - 1; i >= 0; i--) {
|
||||||
if (get(i).mId === id) {
|
if (get(i).mid === mid) {
|
||||||
setProperty(i, "mAckState", state)
|
setProperty(i, "ackState", state)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: remove(0) // see hack above
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
|
@ -61,7 +66,7 @@ Item {
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: (mSender === view.myName) ? "#f2f2f2" : "#ffffcc"
|
color: model.me ? "#f2f2f2" : "#ffffcc"
|
||||||
radius: 12
|
radius: 12
|
||||||
border.width: 0
|
border.width: 0
|
||||||
border.color: "#dc1128"
|
border.color: "#dc1128"
|
||||||
|
|
@ -78,8 +83,8 @@ Item {
|
||||||
width: 8
|
width: 8
|
||||||
height: width
|
height: width
|
||||||
source: "img/semaphore.gif"
|
source: "img/semaphore.gif"
|
||||||
currentFrame: mAckState
|
currentFrame: model.ackState
|
||||||
visible: (sender.text === view.myName)
|
visible: model.me
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -88,7 +93,7 @@ Item {
|
||||||
font.bold: true
|
font.bold: true
|
||||||
font.family: fontMono.name
|
font.family: fontMono.name
|
||||||
color: "#8B0000"
|
color: "#8B0000"
|
||||||
text: mSender
|
text: model.sender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,7 +104,7 @@ Item {
|
||||||
font.pixelSize: 10
|
font.pixelSize: 10
|
||||||
font.family: fontText.name
|
font.family: fontText.name
|
||||||
color: "#505050"
|
color: "#505050"
|
||||||
text: mTimestamp
|
text: model.timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -111,7 +116,7 @@ Item {
|
||||||
font.pixelSize: 18
|
font.pixelSize: 18
|
||||||
font.family: fontText.name
|
font.family: fontText.name
|
||||||
color: "#303030"
|
color: "#303030"
|
||||||
text: mText
|
text: model.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -159,28 +164,37 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// busy image / animation
|
// shown while loading app (may take a while)
|
||||||
|
Item {
|
||||||
Item { // shown while loading app (slow...)
|
visible: loading.visible
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
objectName: "hour_glass"
|
|
||||||
|
|
||||||
Image {
|
AnimatedImage {
|
||||||
|
id: loading
|
||||||
|
objectName: "loading"
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
source: "img/busy.png"
|
source: "img/busy.webp"
|
||||||
|
visible: playing
|
||||||
|
playing: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
width: parent.width
|
id: iniCount
|
||||||
anchors.bottom: parent.bottom
|
anchors.centerIn: parent
|
||||||
anchors.bottomMargin: main.height / 4
|
color: "white"
|
||||||
horizontalAlignment: Text.AlignHCenter
|
font.family: fontText.name
|
||||||
font.pixelSize: 20
|
font.pixelSize: 22
|
||||||
text: qsTr("Loading app...\n(make take a while)")
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
running: loading.playing
|
||||||
|
interval: 4500
|
||||||
|
repeat: true
|
||||||
|
onTriggered: iniCount.text = Number(iniCount.text) + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedImage { // shown during config
|
AnimatedImage {
|
||||||
objectName: "busy"
|
objectName: "busy"
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: 42
|
width: 42
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
Info
|
Info
|
||||||
----
|
----
|
||||||
|
|
||||||
Please note: this is **WIP!**. It's only a 'proof-of-concept' version.
|
Please note: this is **WIP!** It's only a 'proof-of-concept' version.
|
||||||
|
|
||||||
Eventually it will (hopefully) catch up with the official app versions.
|
Eventually it will (hopefully) catch up with the official app versions.
|
||||||
|
|
||||||
|
|
@ -22,10 +22,15 @@ some small adaptions and included all generated proto Lisp files in order to be
|
||||||
independent.
|
independent.
|
||||||
|
|
||||||
Unfortunately cl-protobufs loads very slowly on mobile (and conses hugely
|
Unfortunately cl-protobufs loads very slowly on mobile (and conses hugely
|
||||||
during startup). On an older phone and a cold startup this may take up to 30
|
during startup). On an older phone and a cold startup this may take more than
|
||||||
seconds. On newer phones and warm startup it should 'only' take around 10
|
20 seconds. On newer phones and warm startup it should 'only' take around 10
|
||||||
seconds (which seems acceptable).
|
seconds (which seems acceptable).
|
||||||
|
|
||||||
|
For the above reason, an animation is shown while loading the app, together
|
||||||
|
with a counter. For this to work, the app is loaded in the background (that is,
|
||||||
|
in a separate thread). You'll need to rebuild the lqml library for this to
|
||||||
|
work.
|
||||||
|
|
||||||
You will see a json output of all data sent/received. It simply uses the
|
You will see a json output of all data sent/received. It simply uses the
|
||||||
`print-json` convenience function from cl-protobufs.
|
`print-json` convenience function from cl-protobufs.
|
||||||
|
|
||||||
|
|
@ -34,24 +39,29 @@ You will see a json output of all data sent/received. It simply uses the
|
||||||
Tested
|
Tested
|
||||||
------
|
------
|
||||||
|
|
||||||
Currently tested on Linux, macOS, android. The macOS version shows an exception
|
Tested on Linux, macOS, android, iOS. The macOS version shows an ECL exception
|
||||||
during BLE ini, but works nevertheless.
|
during BLE ini, but works nevertheless.
|
||||||
|
|
||||||
The iOS version doesn't currently work yet (WIP).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
How to use cl-meshtastic
|
How to use cl-meshtastic
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
You currently need 2 meshtastic radio devices, both should be running before
|
You currently need exactly 2 meshtastic radio devices, both should be running
|
||||||
you start the app. Both bluetooth and location needs to be enabled (coarse
|
before you start the app. Both bluetooth and location needs to be enabled
|
||||||
location permission is required on android for BLE to work).
|
(coarse location permission is required on android for BLE to work).
|
||||||
|
|
||||||
Pairing might sometimes require some playing around. If it asks for a PIN and
|
Pairing might sometimes require some playing around. If it asks for a PIN and
|
||||||
your device doesn't have a display (like the RAK starter kit), just use
|
your device doesn't have a display (like the RAK starter kit), just use
|
||||||
`123456`.
|
`123456`.
|
||||||
|
|
||||||
|
On iOS pairing is not needed beforehand, because it will ask for pairing and
|
||||||
|
PIN during BLE ini.
|
||||||
|
|
||||||
|
If your android phone says "no BLE devices found" (see logcat output), you
|
||||||
|
might need to uninstall an eventual app which used the LoRa radio before, and
|
||||||
|
restart the phone.
|
||||||
|
|
||||||
On Linux you might need to restart the bluetooth service if you want to pair
|
On Linux you might need to restart the bluetooth service if you want to pair
|
||||||
a different device (after already pairing a first one).
|
a different device (after already pairing a first one).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ Qt Creator.
|
||||||
TODO
|
TODO
|
||||||
----
|
----
|
||||||
|
|
||||||
* add (very simple) [meshtastic](https://meshtastic.org) app example
|
|
||||||
* port to CMake (?)
|
* port to CMake (?)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
BIN
screenshots/meshtastic.jpg
Normal file
BIN
screenshots/meshtastic.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 216 KiB |
|
|
@ -23,11 +23,11 @@
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
void iniCLFunctions() {
|
void iniCLFunctions() {
|
||||||
cl_object qml(STRING("QML"));
|
cl_object l_qml(STRING("QML"));
|
||||||
if (cl_find_package(qml) == ECL_NIL) {
|
if (cl_find_package(l_qml) == ECL_NIL) {
|
||||||
cl_make_package(1, qml);
|
cl_make_package(1, l_qml);
|
||||||
}
|
}
|
||||||
si_select_package(qml);
|
si_select_package(l_qml);
|
||||||
DEFUN ("clipboard-text", clipboard_text, 0)
|
DEFUN ("clipboard-text", clipboard_text, 0)
|
||||||
DEFUN ("%disable-clipboard-menu", disable_clipboard_menu2, 1)
|
DEFUN ("%disable-clipboard-menu", disable_clipboard_menu2, 1)
|
||||||
DEFUN ("%ensure-permissions", ensure_permissions2, 1)
|
DEFUN ("%ensure-permissions", ensure_permissions2, 1)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include <QQuickView>
|
#include <QQuickView>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
const char LQML::version[] = "23.5.2"; // May 2023
|
const char LQML::version[] = "23.6.1"; // June 2023
|
||||||
|
|
||||||
extern "C" void ini_LQML(cl_object);
|
extern "C" void ini_LQML(cl_object);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#define ADD_MACOS_BUNDLE_IMPORT_PATH
|
#define ADD_MACOS_BUNDLE_IMPORT_PATH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef INI_LISP
|
#if (defined INI_LISP) || (defined BACKGROUND_INI_LISP)
|
||||||
extern "C" void ini_app(cl_object);
|
extern "C" void ini_app(cl_object);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -54,6 +54,13 @@ int catch_all_qexec() {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cl_object do_ini_app() {
|
||||||
|
#ifdef BACKGROUND_INI_LISP
|
||||||
|
ecl_init_module(NULL, ini_app);
|
||||||
|
#endif
|
||||||
|
return Cnil;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
#if QT_VERSION < 0x060000
|
#if QT_VERSION < 0x060000
|
||||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
|
@ -93,6 +100,10 @@ int main(int argc, char* argv[]) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cl_object l_qml(STRING("QML"));
|
||||||
|
si_select_package(l_qml);
|
||||||
|
DEFUN ("do-ini-app", do_ini_app, 0)
|
||||||
|
|
||||||
QTranslator translator;
|
QTranslator translator;
|
||||||
if ((QFile::exists("i18n") && translator.load(QLocale(), QString(), QString(), "i18n"))
|
if ((QFile::exists("i18n") && translator.load(QLocale(), QString(), QString(), "i18n"))
|
||||||
|| translator.load(QLocale(), QString(), QString(), ":/i18n")) {
|
|| translator.load(QLocale(), QString(), QString(), ":/i18n")) {
|
||||||
|
|
@ -165,6 +176,10 @@ int main(int argc, char* argv[]) {
|
||||||
ecl_init_module(NULL, ini_app);
|
ecl_init_module(NULL, ini_app);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BACKGROUND_INI_LISP
|
||||||
|
LQML::eval("(qml::background-ini)", true); // see 'ini.liso'
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef NO_QT_RESTART
|
#ifdef NO_QT_RESTART
|
||||||
bool qtRestart = false;
|
bool qtRestart = false;
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,21 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#undef SLOT
|
||||||
|
|
||||||
|
#include <ecl/ecl.h>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QInputMethodEvent>
|
#include <QInputMethodEvent>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#define STRING(s) ecl_make_constant_base_string(s, -1)
|
||||||
|
|
||||||
|
#define DEFUN(name, c_name, num_args) \
|
||||||
|
ecl_def_c_function(ecl_read_from_cstring(name), (cl_objectfn_fixed)c_name, num_args);
|
||||||
|
|
||||||
|
cl_object do_ini_app (); // for background ini
|
||||||
|
|
||||||
class Engine : public QQmlEngine {
|
class Engine : public QQmlEngine {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -338,6 +338,12 @@
|
||||||
#-mobile
|
#-mobile
|
||||||
:mobile-only)
|
:mobile-only)
|
||||||
|
|
||||||
|
;;; background ini for big apps, so we can show animation during ini
|
||||||
|
|
||||||
|
(defun background-ini ()
|
||||||
|
;; DO-INI-APP is defined in main.cpp
|
||||||
|
(mp:process-run-function :app-ini 'do-ini-app))
|
||||||
|
|
||||||
;;; alias
|
;;; alias
|
||||||
|
|
||||||
(defmacro alias (s1 s2)
|
(defmacro alias (s1 s2)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#:*engine*
|
#:*engine*
|
||||||
#:*root-item*
|
#:*root-item*
|
||||||
#:*caller*
|
#:*caller*
|
||||||
|
#:background-ini
|
||||||
#:clipboard-text
|
#:clipboard-text
|
||||||
#:copy-all-asset-files
|
#:copy-all-asset-files
|
||||||
#:define-qt-wrappers
|
#:define-qt-wrappers
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue