diff --git a/examples/wear-os/.gitignore b/examples/wear-os-gps/.gitignore similarity index 100% rename from examples/wear-os/.gitignore rename to examples/wear-os-gps/.gitignore diff --git a/examples/wear-os-gps/app.asd b/examples/wear-os-gps/app.asd new file mode 100644 index 0000000..7597341 --- /dev/null +++ b/examples/wear-os-gps/app.asd @@ -0,0 +1,10 @@ +(defsystem :app + :serial t + :depends-on () + :components ((:file "lisp/package") + (:file "lisp/ui-vars") + (:file "lisp/kalman") + (:file "lisp/distance") + (:file "lisp/speed") + (:file "lisp/qt") + (:file "lisp/main"))) diff --git a/examples/wear-os-gps/app.pro b/examples/wear-os-gps/app.pro new file mode 100644 index 0000000..8d8cced --- /dev/null +++ b/examples/wear-os-gps/app.pro @@ -0,0 +1,84 @@ +CONFIG += 32bit + +LISP_FILES = $$files(lisp/*) app.asd make.lisp + +android { + 32bit { + ECL = $$(ECL_ANDROID_32) + } else { + ECL = $$(ECL_ANDROID) + } + lisp.commands = $$ECL/../ecl-android-host/bin/ecl \ + -norc -shell $$PWD/make.lisp +} else:unix { + lisp.commands = /usr/local/bin/ecl -shell $$PWD/make.lisp +} else:win32 { + lisp.commands = ecl.exe -shell $$PWD/make.lisp +} + +lisp.input = LISP_FILES + +win32: lisp.output = tmp/app.lib +!win32: lisp.output = tmp/libapp.a + +QMAKE_EXTRA_COMPILERS += lisp + +win32: PRE_TARGETDEPS = tmp/app.lib +!win32: PRE_TARGETDEPS = tmp/libapp.a + +QT += quick qml sensors positioning +TEMPLATE = app +CONFIG += c++17 no_keywords release +DEFINES = DESKTOP_APP INI_LISP #INI_ECL_CONTRIB +INCLUDEPATH = /usr/local/include +LIBS = -L/usr/local/lib -lecl +DESTDIR = . +TARGET = app +OBJECTS_DIR = tmp +MOC_DIR = tmp + +linux: LIBS += -L../../../platforms/linux/lib +macx: LIBS += -L../../../platforms/macos/lib +win32: LIBS += -L../../../platforms/windows/lib + +win32 { + include(../../src/windows.pri) +} + +android { + QT += androidextras + #DEFINES += INI_ASDF + DEFINES -= DESKTOP_APP + DEFINES += QT_EXTENSION + INCLUDEPATH = $$ECL/include + LIBS = -L$$ECL/lib -lecl + LIBS += -L../../../platforms/android/lib + HEADERS += cpp/qt.h + SOURCES += cpp/qt.cpp + + ANDROID_EXTRA_LIBS += $$ECL/lib/libecl.so + ANDROID_PACKAGE_SOURCE_DIR = ../platforms/android + + 32bit { + ANDROID_ABIS = "armeabi-v7a" + } else { + ANDROID_ABIS = "arm64-v8a" + } +} + +32bit { + LIBS += -llqml32 -llisp32 +} else { + LIBS += -llqml -llisp +} + +LIBS += -Ltmp -lapp +HEADERS += ../../src/cpp/main.h +SOURCES += ../../src/cpp/main.cpp + +RESOURCES += $$files(qml/*) +RESOURCES += $$files(i18n/*.qm) + +lupdate_only { + SOURCES += i18n/tr.h +} diff --git a/examples/wear-os/build-android/connect.sh b/examples/wear-os-gps/build-android/connect.sh similarity index 100% rename from examples/wear-os/build-android/connect.sh rename to examples/wear-os-gps/build-android/connect.sh diff --git a/examples/wear-os-gps/build-android/install-run.sh b/examples/wear-os-gps/build-android/install-run.sh new file mode 100755 index 0000000..bea69ab --- /dev/null +++ b/examples/wear-os-gps/build-android/install-run.sh @@ -0,0 +1,3 @@ +# install/update (keeps app data) +adb install -r android-build/*.apk +adb shell am start -n org.qtproject.example.gps/org.qtproject.qt5.android.bindings.QtActivity # Qt5 diff --git a/examples/wear-os-gps/cpp/qt.cpp b/examples/wear-os-gps/cpp/qt.cpp new file mode 100644 index 0000000..25ee936 --- /dev/null +++ b/examples/wear-os-gps/cpp/qt.cpp @@ -0,0 +1,25 @@ +#include "qt.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QVariant QT::keepScreenOn() { + QtAndroid::runOnAndroidThread([] { + QAndroidJniObject activity = QtAndroid::androidActivity(); + if (activity.isValid()) { + QAndroidJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;"); + if (window.isValid()) { + const int FLAG_KEEP_SCREEN_ON = 128; + window.callMethod("addFlags", "(I)V", FLAG_KEEP_SCREEN_ON); + } + } + QAndroidJniEnvironment env; + if (env->ExceptionCheck()) { + env->ExceptionClear(); + } + }); + return QVariant(); +} + +QT_END_NAMESPACE diff --git a/examples/wear-os-gps/cpp/qt.h b/examples/wear-os-gps/cpp/qt.h new file mode 100644 index 0000000..1fe8dfa --- /dev/null +++ b/examples/wear-os-gps/cpp/qt.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +QT_BEGIN_NAMESPACE + +extern "C" { QObject* ini(); } + +class QT : public QObject { + Q_OBJECT + +public: + Q_INVOKABLE QVariant keepScreenOn(); +}; + +QT_END_NAMESPACE diff --git a/examples/wear-os-gps/kml/kml.lisp b/examples/wear-os-gps/kml/kml.lisp new file mode 100644 index 0000000..3df3bb6 --- /dev/null +++ b/examples/wear-os-gps/kml/kml.lisp @@ -0,0 +1,89 @@ +;;; usage: ecl -shell kml.lisp + +(in-package :cl-user) + +(defun file-contents (file) + (with-open-file (s file) + (let ((str (make-string (file-length s)))) + (read-sequence str s) + str))) + +(defvar *kml-1* (file-contents "template-1.kml")) +(defvar *kml-2* (file-contents "template-2.kml")) +(defvar *kml-3* (file-contents "template-3.kml")) +(defvar *kml-4* (file-contents "template-4.kml")) +(defvar *kml-5* (file-contents "template-5.kml")) + +(defun cc (&rest strings) + (apply 'concatenate 'string strings)) + +(defun split (str &optional (sep #\,)) + (unless (zerop (length str)) + (let (list) + (do ((e (position sep str) (position sep str :start (1+ e))) + (b 0 (1+ e))) + ((not e) (push (subseq str b) list)) + (push (subseq str b e) list)) + (nreverse list)))) + +(defun generate-kml (file) + (let* ((name (cc "logs/" file ".")) + (csv (cc name "csv")) + (kml (cc name "kml")) + (kmz (cc name "kmz"))) + (unless (probe-file kmz) + (format t "~&generating ~S~%" kmz) + (let* ((point "point.png") + (header "

~A

~%") + (row "~A~A~%") + (lines (with-open-file (s csv) + (loop :for line = (split (read-line s nil nil)) + :while line :collect line))) + (i-timestamp 0) + (i-accuracy 3) + (i-lat 4) + (i-lon 5) + (i-direction 7) + (i-speed 8) + (i-distance 9) + (*print-pretty* nil)) + (dolist (file (list kml kmz)) + (when (probe-file file) + (delete-file file))) + (with-open-file (s kml :direction :output :if-exists :supersede) + (write-string *kml-1* s) + (dolist (line lines) + (format s "~A,~A,0 " + (nth i-lon line) + (nth i-lat line))) + (write-string *kml-2* s) + (let ((c 0)) + (dolist (line lines) + (when (zerop (mod (incf c) 60)) ; a marker every minute + (write-string *kml-3* s) + (format s header (nth i-timestamp line)) + (write-line "" s) + ;; table of log values + (format s row 2 + (nth i-distance line) + "m") + (format s row 2 + (nth i-speed line) + "km/h") + (format s row 1 + (nth i-accuracy line) + "acc") + (format s row 1 + (nth i-direction line) + "°") + ;; position + (format s *kml-4* + (nth i-lon line) + (nth i-lat line))))) + (write-string *kml-5* s)) + (ext:run-program "zip" (list kmz kml point)) + (delete-file kml))))) + +(dolist (file (directory "logs/*.csv")) + (generate-kml (pathname-name file))) + diff --git a/examples/wear-os-gps/kml/point.png b/examples/wear-os-gps/kml/point.png new file mode 100644 index 0000000..a2577b5 Binary files /dev/null and b/examples/wear-os-gps/kml/point.png differ diff --git a/examples/wear-os-gps/kml/template-1.kml b/examples/wear-os-gps/kml/template-1.kml new file mode 100644 index 0000000..86ffb40 --- /dev/null +++ b/examples/wear-os-gps/kml/template-1.kml @@ -0,0 +1,47 @@ + + + +LQML Example GPS.kml + + + + +normal +#point + + +highlight +#point_hl + + + + +#marker + +0 +relativeToGround + diff --git a/examples/wear-os-gps/kml/template-2.kml b/examples/wear-os-gps/kml/template-2.kml new file mode 100644 index 0000000..eefa48f --- /dev/null +++ b/examples/wear-os-gps/kml/template-2.kml @@ -0,0 +1,4 @@ + + + + diff --git a/examples/wear-os-gps/kml/template-3.kml b/examples/wear-os-gps/kml/template-3.kml new file mode 100644 index 0000000..bd79159 --- /dev/null +++ b/examples/wear-os-gps/kml/template-3.kml @@ -0,0 +1,11 @@ + +#marker + +.s1 { font-size: 16px; text-align: right; font-weight: bold; } +.s2 { font-size: 22px; text-align: right; font-weight: bold; } +td { font-size: 10px; } +table { border-collapse: collapse; margin: auto; width: 90%; } +table, th, td { border: 1px solid #d0d0d0; } +h2 { text-align: center; color: blue; } + diff --git a/examples/wear-os-gps/kml/template-4.kml b/examples/wear-os-gps/kml/template-4.kml new file mode 100644 index 0000000..f954677 --- /dev/null +++ b/examples/wear-os-gps/kml/template-4.kml @@ -0,0 +1,6 @@ +
+]]> + +~A,~A,0 + + diff --git a/examples/wear-os-gps/kml/template-5.kml b/examples/wear-os-gps/kml/template-5.kml new file mode 100644 index 0000000..0022a0a --- /dev/null +++ b/examples/wear-os-gps/kml/template-5.kml @@ -0,0 +1,2 @@ + + diff --git a/examples/wear-os-gps/lisp/distance.lisp b/examples/wear-os-gps/lisp/distance.lisp new file mode 100644 index 0000000..91746fa --- /dev/null +++ b/examples/wear-os-gps/lisp/distance.lisp @@ -0,0 +1,69 @@ +(in-package :gps) + +(defconstant +earth-mean-radius+ 6371.0072d0) + +(defun to-rad (deg) + (/ (* deg pi) 180)) + +(defun to-deg (rad) + (/ (* 180 rad) pi)) + +(defun point-distance (from to) + "Coordiante distance according to Haversine formula." + (let ((from-x (car from)) + (from-y (cdr from)) + (to-x (car to)) + (to-y (cdr to))) + (if (and (numberp from-x) + (numberp to-x)) + (let* ((dlat (to-rad (- to-x from-x))) + (dlon (to-rad (- to-y from-y))) + (h-dlat (sin (/ dlat 2))) + (h-dlon (sin (/ dlon 2)))) + (setf h-dlat (expt h-dlat 2) + h-dlon (expt h-dlon 2)) + (let* ((y (+ h-dlat (* (cos (to-rad from-x)) + (cos (to-rad to-x)) + h-dlon))) + (x (* 2 (asin (sqrt y))))) + (* x +earth-mean-radius+ 1000))) + 0))) + +(let ((positions-distance 0) + (distance 0) + position-1 + position-2 + constant-direction) + (defun update-distance () + "Calculate distance of farest points with same direction + (fallback: re-calculate after a certain distance)." + (when (and *direction* + (not constant-direction)) + (setf constant-direction *direction*)) + (let ((pos (cons kal:*lat* kal:*lon*)) + (reset (if constant-direction + (or (>= (abs (- *direction* constant-direction)) + 15) ; not too small (not accurate with low speed) + (>= positions-distance 75)) ; 75 m + (>= positions-distance 25)))) ; 25 m + (if reset + (progn + (setf constant-direction *direction*) + (if position-1 + (progn + (setf position-2 pos) + (incf distance (positions-distance)) + (setf positions-distance 0) + (shiftf position-1 position-2 nil)) + (setf position-1 pos))) + (progn + (if position-1 + (setf position-2 pos) + (setf position-1 pos)) + (setf positions-distance (positions-distance)))))) + (defun positions-distance () + (if position-2 + (point-distance position-1 position-2) + 0)) + (defun distance () + (+ distance positions-distance))) diff --git a/examples/wear-os-gps/lisp/kalman.lisp b/examples/wear-os-gps/lisp/kalman.lisp new file mode 100644 index 0000000..a0e7dc9 --- /dev/null +++ b/examples/wear-os-gps/lisp/kalman.lisp @@ -0,0 +1,37 @@ +(defpackage :kalman + (:use :cl) + (:nicknames :kal) + (:export + #:*lat* + #:*lon* + #:*timestamp* + #:*variance* + #:filter + #:reset)) + +(in-package :kal) + +(defvar *lat* nil) +(defvar *lon* nil) +(defvar *timestamp* nil) +(defvar *variance* nil) + +(defun reset () + (setf *variance* nil)) + +(defun filter (lat lon accuracy speed) + (when (and lat lon accuracy speed) + (setf accuracy (max 1 accuracy)) + (let ((timestamp (get-internal-real-time))) + (if *variance* + (let ((time-inc (- timestamp *timestamp*))) + (incf *variance* (/ (* time-inc (expt speed 2)) 1000)) + (setf *timestamp* timestamp) + (let ((k (/ *variance* (+ *variance* (expt accuracy 2))))) + (incf *lat* (* k (- lat *lat*))) + (incf *lon* (* k (- lon *lon*))) + (setf *variance* (* (- 1 k) *variance*)))) + (setf *lat* lat + *lon* lon + *timestamp* timestamp + *variance* (expt accuracy 2)))))) diff --git a/examples/wear-os-gps/lisp/main.lisp b/examples/wear-os-gps/lisp/main.lisp new file mode 100644 index 0000000..f930028 --- /dev/null +++ b/examples/wear-os-gps/lisp/main.lisp @@ -0,0 +1,59 @@ +(in-package :gps) + +(defvar *start-time* nil) +(defvar *direction* nil) +(defvar *log-stream* nil) + +(defun run () + (qt:ini) + #+android + (progn + (qt:keep-screen-on qt:*cpp*) + (ensure-permissions :access-fine-location))) + +(defun closing () + (close *log-stream*) + (qquit)) + +(defun round* (x &optional (digits 0)) + (when (numberp x) + (let* ((f (expt 10 digits)) + (r (/ (truncate (+ 0.5 (* f x))) + f))) + (if (zerop digits) + r + (float r))))) + +(defun str (x) + (cond ((stringp x) + x) + ((null x) + "") + (t + (princ-to-string x)))) + +(defun position-changed (lat lon accuracy speed direction timestamp) + (unless *start-time* + (setf *start-time* timestamp) + (setf *log-stream* (open (format nil "LOG ~A.csv" (substitute #\. #\: timestamp)) + :direction :output :if-does-not-exist :create))) + (when (and lat lon accuracy) + (when direction + (setf *direction* direction)) + (kal:filter lat lon accuracy speed) + (update-distance) + (update-speed) + (q> |value| ui:*speed* (speed*)) + (q> |text| ui:*distance* (str (round* (distance)))) + (q> |text| ui:*accuracy* (str (round* accuracy 1))) + (when kal:*lat* + (format *log-stream* "~A,~F,~F,~F,~F,~F,~A,~A,~A,~A~%" + timestamp + lat lon (round* accuracy 1) + kal:*lat* kal:*lon* + (str (round* speed 1)) + (str (round* direction)) + (round* (speed*) 1) + (round* (distance)))))) + +(qlater 'run) diff --git a/examples/wear-os-gps/lisp/package.lisp b/examples/wear-os-gps/lisp/package.lisp new file mode 100644 index 0000000..8354c21 --- /dev/null +++ b/examples/wear-os-gps/lisp/package.lisp @@ -0,0 +1,3 @@ +(defpackage :gps + (:use :cl :qml) + (:export)) diff --git a/examples/wear-os-gps/lisp/qt.lisp b/examples/wear-os-gps/lisp/qt.lisp new file mode 100644 index 0000000..dca45a7 --- /dev/null +++ b/examples/wear-os-gps/lisp/qt.lisp @@ -0,0 +1,17 @@ +(defpackage :qt + (:use :cl :qml) + (:export + #:*cpp* + #:ini + #:keep-screen-on)) + +(in-package :qt) + +(defvar *cpp* nil) + +(defun ini () + #+android + (progn + (setf *cpp* (qfind-child nil "QT")) + (let ((*package* (find-package :qt))) + (define-qt-wrappers *cpp*)))) diff --git a/examples/wear-os-gps/lisp/speed.lisp b/examples/wear-os-gps/lisp/speed.lisp new file mode 100644 index 0000000..15fd408 --- /dev/null +++ b/examples/wear-os-gps/lisp/speed.lisp @@ -0,0 +1,20 @@ +(in-package :gps) + +(let ((speed 0.0) + samples) + (defun update-speed () + "After 10 distance samples, calculate average speed and update on every new + distance sample." + (push (cons (distance) + (get-internal-real-time)) + samples) + (when (> (length samples) 10) + (setf samples (butlast samples)) + (let ((b (first samples)) + (a (first (last samples)))) + (setf speed (* 3.6 ; km/h + (/ (- (car b) (car a)) ; m + (/ (- (cdr b) (cdr a)) ; s + 1000.0))))))) + (defun speed* () + speed)) diff --git a/examples/wear-os-gps/lisp/ui-vars.lisp b/examples/wear-os-gps/lisp/ui-vars.lisp new file mode 100644 index 0000000..8d6676e --- /dev/null +++ b/examples/wear-os-gps/lisp/ui-vars.lisp @@ -0,0 +1,12 @@ +(defpackage ui + (:use :cl :qml) + (:export + #:*accuracy* + #:*distance* + #:*speed*)) + +(in-package :ui) + +(defparameter *accuracy* "accuracy") +(defparameter *distance* "distance") +(defparameter *speed* "speed") diff --git a/examples/wear-os-gps/make.lisp b/examples/wear-os-gps/make.lisp new file mode 100644 index 0000000..7bc81a1 --- /dev/null +++ b/examples/wear-os-gps/make.lisp @@ -0,0 +1,60 @@ +;; check target +(let ((arg (first (ext:command-args)))) + (mapc (lambda (name feature) + (when (search name arg) + (pushnew feature *features*))) + (list "/ecl-android/" "/ecl-ios/") + (list :android :ios))) + +#+(or android ios) +(pushnew :mobile *features*) + +(require :asdf) + +(push (merge-pathnames "../") + asdf:*central-registry*) + +(setf *default-pathname-defaults* + (truename (merge-pathnames "../../../"))) ; LQML root + +(defvar *current* + (let ((name (namestring *load-truename*))) + (subseq name + (length (namestring *default-pathname-defaults*)) + (1+ (position #\/ name :from-end t))))) + +(dolist (file (list "package" "x" "ecl-ext" "ini" "qml")) ; load LQML symbols + (load (merge-pathnames file "src/lisp/"))) + +(defun cc (&rest args) + (apply 'concatenate 'string args)) + +#-mobile +(asdf:make-build "app" + :monolithic t + :type :static-library + :move-here (cc *current* "build/tmp/") + :init-name "ini_app") + +#+mobile +(progn + (pushnew :interpreter *features*) + (defvar *asdf-system* "app") + (defvar *ql-libs* (cc *current* "ql-libs.lisp")) + (defvar *init-name* "ini_app") + (defvar *library-path* (format nil "~Abuild-~A/tmp/" + *current* + #+android "android" + #+ios "ios")) + (defvar *require* (list :ecl-curl)) + (load "platforms/shared/make")) + +;; rename lib +(let* ((from #-mobile (cc *current* "build/tmp/app--all-systems.a") + #+mobile (cc *library-path* "app--all-systems.a")) + (to "libapp.a") + (to* #-mobile (cc *current* "build/tmp/" to) + #+mobile (cc *library-path* to))) + (when (probe-file to*) + (delete-file to*)) + (rename-file from to)) diff --git a/examples/wear-os-gps/platforms/android/AndroidManifest.xml b/examples/wear-os-gps/platforms/android/AndroidManifest.xml new file mode 100644 index 0000000..b13e67c --- /dev/null +++ b/examples/wear-os-gps/platforms/android/AndroidManifest.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/wear-os-gps/qml/ext/Gauge.qml b/examples/wear-os-gps/qml/ext/Gauge.qml new file mode 100644 index 0000000..f1b5501 --- /dev/null +++ b/examples/wear-os-gps/qml/ext/Gauge.qml @@ -0,0 +1,92 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Extras 1.4 + +Rectangle { + anchors.fill: parent + color: "black" + + CircularGauge { + id: gauge + objectName: "speed" + anchors.fill: parent + maximumValue: 10 + stepSize: 0.1 + + Behavior on value { + NumberAnimation { + duration: 1000 + easing.type: Easing.InOutCubic + } + } + + style: CircularGaugeStyle { + id: style + labelStepSize: 1 + tickmarkStepSize: 1 + minorTickmarkCount: 5 + minimumValueAngle: -90 + maximumValueAngle: 90 + + property int limit: parent.maximumValue * 8/10 + property string baseColor: "white" + property string limitColor: "orange" + + function toRad(deg) { return deg * (Math.PI / 180) } + + background: Canvas { + onPaint: { + var ctx = getContext("2d") + ctx.reset() + ctx.beginPath() + ctx.strokeStyle = limitColor + ctx.lineWidth = outerRadius * 0.02 + ctx.arc(outerRadius, outerRadius, outerRadius - ctx.lineWidth / 2, + toRad(valueToAngle(limit) - 90), toRad(valueToAngle(gauge.maximumValue) - 90)) + ctx.stroke() + } + } + + tickmark: Rectangle { + implicitWidth: outerRadius * 0.02 + antialiasing: true + implicitHeight: outerRadius * 0.06 + color: styleData.value >= limit ? limitColor : baseColor + } + + minorTickmark: Rectangle { + visible: styleData.value < limit + implicitWidth: outerRadius * 0.01 + antialiasing: true + implicitHeight: outerRadius * 0.03 + color: baseColor + } + + tickmarkLabel: Text { + font.pixelSize: Math.max(6, outerRadius * 0.15) + font.bold: true + text: styleData.value + color: styleData.value >= limit ? limitColor : baseColor + antialiasing: true + } + + needle: Rectangle { + y: outerRadius * 0.15 + implicitWidth: outerRadius * 0.07 + implicitHeight: outerRadius * 0.85 + radius: implicitWidth / 2 + antialiasing: true + color: baseColor + } + + foreground: Rectangle { + width: outerRadius * 0.15 + height: width + radius: width / 2 + color: baseColor + anchors.centerIn: parent + } + } + } +} diff --git a/examples/wear-os-gps/qml/ext/LogText.qml b/examples/wear-os-gps/qml/ext/LogText.qml new file mode 100644 index 0000000..1b00e10 --- /dev/null +++ b/examples/wear-os-gps/qml/ext/LogText.qml @@ -0,0 +1,7 @@ +import QtQuick 2.15 + +Text { + anchors.horizontalCenter: parent.horizontalCenter + color: "white" + font.bold: true +} diff --git a/examples/wear-os-gps/qml/main.qml b/examples/wear-os-gps/qml/main.qml new file mode 100644 index 0000000..d09195a --- /dev/null +++ b/examples/wear-os-gps/qml/main.qml @@ -0,0 +1,48 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtSensors 5.15 +import QtPositioning 5.15 +import "ext/" as Ext + +Rectangle { + width: 210 // for desktop + height: 210 + color: "black" + + PositionSource { + objectName: "position_source" + updateInterval: 1000 + active: true + + onPositionChanged: { + Lisp.call("gps:position-changed", + position.latitudeValid ? position.coordinate.latitude : null, + position.longitudeValid ? position.coordinate.longitude : null, + position.horizontalAccuracyValid ? position.horizontalAccuracy : null, + position.speedValid ? position.speed : null, + position.directionValid ? position.direction : null, + position.timestamp.toLocaleString(Qt.locale(), "yyyy-MM-dd hh:mm:ss")) + } + } + + Ext.Gauge {} + + Column { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 5 + spacing: -5 + + Ext.LogText { objectName: "distance"; font.pixelSize: 48 } + Ext.LogText { objectName: "accuracy"; font.pixelSize: 24 } + } + + // quit + + Keys.onPressed: { + if (event.key === Qt.Key_Back) { + event.accepted = true + Lisp.call("gps:closing") + } + } +} diff --git a/examples/wear-os/readme-build.md b/examples/wear-os-gps/readme-build.md similarity index 99% rename from examples/wear-os/readme-build.md rename to examples/wear-os-gps/readme-build.md index 24b98f0..84c9aa6 100644 --- a/examples/wear-os/readme-build.md +++ b/examples/wear-os-gps/readme-build.md @@ -42,7 +42,6 @@ Log note: for showing only your own messages, see `log.sh`. Important note (Qt bug) ----------------------- - After editing [AndroidManifest.xml](platforms/android/AndroidManifest.xml) in **Qt Creator** you need to add this inside `activity`: ``` diff --git a/examples/wear-os-gps/readme.md b/examples/wear-os-gps/readme.md new file mode 100644 index 0000000..669be56 --- /dev/null +++ b/examples/wear-os-gps/readme.md @@ -0,0 +1,59 @@ + +Prepare +------- + +Please copy the app template files first: +``` +$ cd .. +$ ./copy.sh wear-os-gps +``` + + +Info +---- + +This is a practical example of displaying both the speed and the whole distance +of e.g. a canoe session (only meant for constant altitude values). You probably +need to adapt the maximum speed value (km/h) to your personal needs. + +The data is automatically logged, and can be accessed with e.g. +**Device File Explorer** from Android Studio (see Help / Find Action...). + +The path of the log files is: +``` +/data/data/org.qtproject.example.gps/files/ +``` + +You can then put those log files in directory [kml/logs/](kml/logs/) and run +``` +cd kml + +ecl -shell kml.lisp +``` +This will generate **kmz** files of all log files, which can then be viewed +using **Google Earth** (the free desktop app). + +A simple **Kalman** filter is used for the necessary GPS data smoothing. + +The UI uses a `CircularGauge` for displaying the speed (an average of the +latest 10 seconds). Additionally it shows the whole distance and the GPS +accuracy in meters. + + + +Run (desktop demo) +------------------ +``` +lqml run.lisp +``` +Optionally pass `-slime` to start a Swank server, and connect from Emacs with +`M-x slime-connect`. + +During development you can pass `-auto`, which will releoad all QML files after +you made a change to any of them and saved it. For re-initialization after +reloading, file `lisp/qml-reload/on-reloaded` will be loaded. + +Closing the window quits the app. If you try to kill it with `ctrl-c`, you need +an additional `ctrl-d` to exit from ECL. To quit from Slime, do `(qq)` which is +short for `(qquit)`. + diff --git a/examples/wear-os-heart/.gitignore b/examples/wear-os-heart/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/examples/wear-os-heart/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/examples/wear-os/app.asd b/examples/wear-os-heart/app.asd similarity index 100% rename from examples/wear-os/app.asd rename to examples/wear-os-heart/app.asd diff --git a/examples/wear-os/app.pro b/examples/wear-os-heart/app.pro similarity index 100% rename from examples/wear-os/app.pro rename to examples/wear-os-heart/app.pro diff --git a/examples/wear-os-heart/build-android/connect.sh b/examples/wear-os-heart/build-android/connect.sh new file mode 100755 index 0000000..87626ba --- /dev/null +++ b/examples/wear-os-heart/build-android/connect.sh @@ -0,0 +1,5 @@ +# IP of your watch / run and confirm on the watch + +adb kill-server +adb connect 192.168.1.?:5555 + diff --git a/examples/wear-os/cpp/qt.cpp b/examples/wear-os-heart/cpp/qt.cpp similarity index 100% rename from examples/wear-os/cpp/qt.cpp rename to examples/wear-os-heart/cpp/qt.cpp diff --git a/examples/wear-os/cpp/qt.h b/examples/wear-os-heart/cpp/qt.h similarity index 100% rename from examples/wear-os/cpp/qt.h rename to examples/wear-os-heart/cpp/qt.h diff --git a/examples/wear-os/lisp/main.lisp b/examples/wear-os-heart/lisp/main.lisp similarity index 100% rename from examples/wear-os/lisp/main.lisp rename to examples/wear-os-heart/lisp/main.lisp diff --git a/examples/wear-os/lisp/package.lisp b/examples/wear-os-heart/lisp/package.lisp similarity index 100% rename from examples/wear-os/lisp/package.lisp rename to examples/wear-os-heart/lisp/package.lisp diff --git a/examples/wear-os/lisp/qt.lisp b/examples/wear-os-heart/lisp/qt.lisp similarity index 100% rename from examples/wear-os/lisp/qt.lisp rename to examples/wear-os-heart/lisp/qt.lisp diff --git a/examples/wear-os/lisp/ui-vars.lisp b/examples/wear-os-heart/lisp/ui-vars.lisp similarity index 100% rename from examples/wear-os/lisp/ui-vars.lisp rename to examples/wear-os-heart/lisp/ui-vars.lisp diff --git a/examples/wear-os/platforms/android/AndroidManifest.xml b/examples/wear-os-heart/platforms/android/AndroidManifest.xml similarity index 96% rename from examples/wear-os/platforms/android/AndroidManifest.xml rename to examples/wear-os-heart/platforms/android/AndroidManifest.xml index 2c953da..f2dde42 100644 --- a/examples/wear-os/platforms/android/AndroidManifest.xml +++ b/examples/wear-os-heart/platforms/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + diff --git a/examples/wear-os/qml/ext/HeartRate.qml b/examples/wear-os-heart/qml/ext/HeartRate.qml similarity index 100% rename from examples/wear-os/qml/ext/HeartRate.qml rename to examples/wear-os-heart/qml/ext/HeartRate.qml diff --git a/examples/wear-os/qml/img/heart.png b/examples/wear-os-heart/qml/img/heart.png similarity index 100% rename from examples/wear-os/qml/img/heart.png rename to examples/wear-os-heart/qml/img/heart.png diff --git a/examples/wear-os/qml/main.qml b/examples/wear-os-heart/qml/main.qml similarity index 100% rename from examples/wear-os/qml/main.qml rename to examples/wear-os-heart/qml/main.qml diff --git a/examples/wear-os/qt-sensor-hack/QtActivity.java b/examples/wear-os-heart/qt-sensor-hack/QtActivity.java similarity index 100% rename from examples/wear-os/qt-sensor-hack/QtActivity.java rename to examples/wear-os-heart/qt-sensor-hack/QtActivity.java diff --git a/examples/wear-os/qt-sensor-hack/git.diff b/examples/wear-os-heart/qt-sensor-hack/git.diff similarity index 100% rename from examples/wear-os/qt-sensor-hack/git.diff rename to examples/wear-os-heart/qt-sensor-hack/git.diff diff --git a/examples/wear-os/qt-sensor-hack/path.txt b/examples/wear-os-heart/qt-sensor-hack/path.txt similarity index 100% rename from examples/wear-os/qt-sensor-hack/path.txt rename to examples/wear-os-heart/qt-sensor-hack/path.txt diff --git a/examples/wear-os/qt-sensor-hack/readme.md b/examples/wear-os-heart/qt-sensor-hack/readme.md similarity index 100% rename from examples/wear-os/qt-sensor-hack/readme.md rename to examples/wear-os-heart/qt-sensor-hack/readme.md diff --git a/examples/wear-os-heart/readme-build.md b/examples/wear-os-heart/readme-build.md new file mode 100644 index 0000000..84c9aa6 --- /dev/null +++ b/examples/wear-os-heart/readme-build.md @@ -0,0 +1,52 @@ + +Note +---- + +This will only work with Qt 5.15 (customized AndroidManifest.xml file) and +requires WearOS 2 or later. + +You'll also need an easy to apply hack for the **heart rate sensor**, see +[qt-sensor-hack](qt-sensor-hack/). + +It is assumed that you already enabled the developer settings on your watch. + + + +Build 32bit android APK +----------------------- + +First you need to connect your device through WiFi. Please set your watch IP +address in [build-android/connect.sh](build-android/connect.sh) and run: +``` +$ ./build-android/connect.sh +``` + +You probably want to build a **32bit** version, because most watches are 32bit. + +For this you first need to build a 32bit version of the LQML library, see +[readme-prepare-android.md](../../readme-prepare-android.md). + +Now you can build the app: +``` +$ cd build-android + +$ qmake-android "CONFIG+=32bit" .. +$ make apk + +$ ./install-run.sh +``` +Log note: for showing only your own messages, see `log.sh`. + + + +Important note (Qt bug) +----------------------- + +After editing [AndroidManifest.xml](platforms/android/AndroidManifest.xml) +in **Qt Creator** you need to add this inside `activity`: +``` +android:theme="@android:style/Theme.DeviceDefault" +``` +If you omit the above setting, the app will not start and just show an error +message instead. + diff --git a/examples/wear-os/readme.md b/examples/wear-os-heart/readme.md similarity index 98% rename from examples/wear-os/readme.md rename to examples/wear-os-heart/readme.md index 7698a60..2ec6567 100644 --- a/examples/wear-os/readme.md +++ b/examples/wear-os-heart/readme.md @@ -5,7 +5,7 @@ Prepare Please copy the app template files first: ``` $ cd .. -$ ./copy.sh wear-os +$ ./copy.sh wear-os-heart ``` diff --git a/screenshots/wear-os-gps.png b/screenshots/wear-os-gps.png new file mode 100644 index 0000000..1ac5a24 Binary files /dev/null and b/screenshots/wear-os-gps.png differ diff --git a/screenshots/wear-os.png b/screenshots/wear-os-heart.png similarity index 100% rename from screenshots/wear-os.png rename to screenshots/wear-os-heart.png