mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-15 14:51:14 -08:00
fix/revision of example 'meshtastic'
This commit is contained in:
parent
a5af331a8d
commit
6da7bf8670
5 changed files with 126 additions and 110 deletions
|
|
@ -25,5 +25,13 @@
|
|||
</ul>
|
||||
<p>All parts above combined cost me around 50€.</p>
|
||||
<p>I used a soldering iron, a hot glue gun, a step drill bit, double sided tape.</p>
|
||||
<br>
|
||||
<h3>Antennas</h3>
|
||||
<p>
|
||||
A good antenna is crucial for the radio to function properly. A <a href="https://nanovna.com/" target="_blank">NanoVNA</a> is very helpful to test if an antenna is resonant at the specified frequency (otherwise it's useless). You can find good clones for about 50€/$ (beware of really cheap/bad clones).
|
||||
</p>
|
||||
<p>
|
||||
Antennas listed in the <a href="https://store.rakwireless.com/products/" target="_blank">RAK store</a> are generally of good/industrial quality. Some other mass produced offerings are of such bad quality that I had to throw them away (after measuring them).
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
(/ (* deg pi) 180))
|
||||
|
||||
(defun distance (from to)
|
||||
(qlog :distance from to)
|
||||
;; Haversine formula
|
||||
(destructuring-bind ((lat-1 lon-1) (lat-2 lon-2))
|
||||
(list from to)
|
||||
|
|
|
|||
|
|
@ -191,107 +191,110 @@
|
|||
:alt (me:altitude pos)
|
||||
:time (me:time pos))))))
|
||||
|
||||
(defun process-received ()
|
||||
"Walks *RECEIVED* FROM-RADIOs and saves relevant data."
|
||||
(setf *received* (nreverse *received*))
|
||||
(unless *ble-names*
|
||||
(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))
|
||||
(decoded (me:decoded packet)))
|
||||
(when decoded
|
||||
(let ((payload (me:payload decoded)))
|
||||
(case (me:portnum decoded)
|
||||
;; text-message
|
||||
(:text-message-app
|
||||
(let ((timestamp (get-universal-time))
|
||||
(mid (me:id packet))
|
||||
(text (qfrom-utf8 payload)))
|
||||
(setf msg:*message-id* (max mid msg:*message-id*))
|
||||
(if (x:starts-with ":e" text) ; 'echo'
|
||||
(qsingle-shot 1000 (lambda () (send-message (x:cc "<b>echo:</b>" (subseq text #.(length ":e"))))))
|
||||
(progn
|
||||
(when (x:starts-with "<b>echo:</b>" text)
|
||||
(setf text (msg:echo-message text (me:from packet) (me:rx-snr packet) (me:rx-rssi packet))))
|
||||
(msg:add-message
|
||||
(list :receiver (my-name)
|
||||
:sender (node-to-name (me:from packet))
|
||||
:timestamp timestamp
|
||||
:hour (timestamp-to-hour timestamp)
|
||||
:text (add-line-breaks text)
|
||||
:mid mid))))))
|
||||
;; for :ack-state (acknowledgement state)
|
||||
(:routing-app
|
||||
(let ((state (me:routing.error-reason
|
||||
(pr:deserialize-from-bytes 'me:routing payload))))
|
||||
(msg:change-state (case state
|
||||
(:none
|
||||
:received)
|
||||
(t
|
||||
(qlog "message state changed: ~A" state)
|
||||
:not-received))
|
||||
(me:request-id decoded))))
|
||||
;; GPS location
|
||||
(:position-app
|
||||
(unless (zerop (length payload))
|
||||
(set-gps-position (me:from packet)
|
||||
(pr:deserialize-from-bytes 'me:position payload)))))))))
|
||||
;; my-info
|
||||
((me:from-radio.has-my-info struct)
|
||||
(setf *my-node-info* (me:my-node-num (me:my-info struct))))
|
||||
;; node-info
|
||||
((me:from-radio.has-node-info struct)
|
||||
(let ((info (me:node-info struct)))
|
||||
(if (eql *my-node-info* (me:num info))
|
||||
(setf *my-node-info* info)
|
||||
(setf *node-infos*
|
||||
(nconc *node-infos* (list info))))
|
||||
(x:when-it (me:position info)
|
||||
(set-gps-position (me:num info) x:it))
|
||||
(when *schedule-clear*
|
||||
(radios:clear)
|
||||
(group:clear))
|
||||
(let ((name (me:short-name (me:user info)))
|
||||
(current (= (me:num info)
|
||||
(me:num *my-node-info*)))
|
||||
(metrics (me:device-metrics info)))
|
||||
(unless current
|
||||
(group:add-person
|
||||
(list :radio-name name
|
||||
:custom-name (or (app:setting name :custom-name) "")
|
||||
:node-num (me:num info)
|
||||
:current (equal name (app:setting :latest-receiver)))))
|
||||
(when (find name *ble-names* :test 'string=)
|
||||
(setf radios:*found* t)
|
||||
(radios:add-radio
|
||||
(list :name name
|
||||
:hw-model (symbol-name (me:hw-model (me:user info)))
|
||||
:battery-level (float (if metrics (me:battery-level metrics) 0))
|
||||
:current current))
|
||||
(when current
|
||||
(app:change-setting :device name))))))
|
||||
;; channel
|
||||
((me:from-radio.has-channel struct)
|
||||
(let ((channel (me:channel struct)))
|
||||
(when (eql :primary (me:role channel))
|
||||
(setf *my-channel* channel))
|
||||
(push channel *channels*)))
|
||||
;; config lora
|
||||
((me:from-radio.has-config struct)
|
||||
(let ((config (me:config struct)))
|
||||
(when (me:config.has-lora config)
|
||||
(setf *config-lora* (me:lora config)))))
|
||||
;; config-complete-id
|
||||
((me:from-radio.has-config-complete-id struct)
|
||||
(when (= *config-id* (me:config-complete-id struct))
|
||||
(setf *config-complete* t)
|
||||
(q> |playing| ui:*busy* nil)
|
||||
(qlog "config-complete id: ~A" *config-id*)
|
||||
(unless (string= *my-channel-name*
|
||||
(me:name (me:settings *my-channel*)))
|
||||
(qlater 'config-device))))))
|
||||
(setf *received* nil))
|
||||
(let (echo-text)
|
||||
(defun process-received ()
|
||||
"Walks *RECEIVED* FROM-RADIOs and saves relevant data."
|
||||
(setf *received* (nreverse *received*))
|
||||
(unless *ble-names*
|
||||
(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))
|
||||
(decoded (me:decoded packet)))
|
||||
(when decoded
|
||||
(let ((payload (me:payload decoded)))
|
||||
(case (me:portnum decoded)
|
||||
;; text-message
|
||||
(:text-message-app
|
||||
(let ((timestamp (get-universal-time))
|
||||
(mid (me:id packet))
|
||||
(text (qfrom-utf8 payload)))
|
||||
(setf msg:*message-id* (max mid msg:*message-id*))
|
||||
(if (x:starts-with ":e" text) ; 'echo'
|
||||
(progn
|
||||
(setf echo-text (subseq text #.(length ":e")))
|
||||
(qsingle-shot 1000 (lambda () (send-message (x:cc "<b>echo:</b>" echo-text)))))
|
||||
(progn
|
||||
(when (x:starts-with "<b>echo:</b>" text)
|
||||
(setf text (msg:echo-message text (me:from packet) (me:rx-snr packet) (me:rx-rssi packet))))
|
||||
(msg:add-message
|
||||
(list :receiver (my-name)
|
||||
:sender (node-to-name (me:from packet))
|
||||
:timestamp timestamp
|
||||
:hour (timestamp-to-hour timestamp)
|
||||
:text (add-line-breaks text)
|
||||
:mid mid))))))
|
||||
;; for :ack-state (acknowledgement state)
|
||||
(:routing-app
|
||||
(let ((state (me:routing.error-reason
|
||||
(pr:deserialize-from-bytes 'me:routing payload))))
|
||||
(msg:change-state (case state
|
||||
(:none
|
||||
:received)
|
||||
(t
|
||||
(qlog "message state changed: ~A" state)
|
||||
:not-received))
|
||||
(me:request-id decoded))))
|
||||
;; GPS location
|
||||
(:position-app
|
||||
(unless (zerop (length payload))
|
||||
(set-gps-position (me:from packet)
|
||||
(pr:deserialize-from-bytes 'me:position payload)))))))))
|
||||
;; my-info
|
||||
((me:from-radio.has-my-info struct)
|
||||
(setf *my-node-info* (me:my-node-num (me:my-info struct))))
|
||||
;; node-info
|
||||
((me:from-radio.has-node-info struct)
|
||||
(let ((info (me:node-info struct)))
|
||||
(if (eql *my-node-info* (me:num info))
|
||||
(setf *my-node-info* info)
|
||||
(setf *node-infos*
|
||||
(nconc *node-infos* (list info))))
|
||||
(x:when-it (me:position info)
|
||||
(set-gps-position (me:num info) x:it))
|
||||
(when *schedule-clear*
|
||||
(radios:clear)
|
||||
(group:clear))
|
||||
(let ((name (me:short-name (me:user info)))
|
||||
(current (= (me:num info)
|
||||
(me:num *my-node-info*)))
|
||||
(metrics (me:device-metrics info)))
|
||||
(unless current
|
||||
(group:add-person
|
||||
(list :radio-name name
|
||||
:custom-name (or (app:setting name :custom-name) "")
|
||||
:node-num (me:num info)
|
||||
:current (equal name (app:setting :latest-receiver)))))
|
||||
(when (find name *ble-names* :test 'string=)
|
||||
(setf radios:*found* t)
|
||||
(radios:add-radio
|
||||
(list :name name
|
||||
:hw-model (symbol-name (me:hw-model (me:user info)))
|
||||
:battery-level (float (if metrics (me:battery-level metrics) 0))
|
||||
:current current))
|
||||
(when current
|
||||
(app:change-setting :device name))))))
|
||||
;; channel
|
||||
((me:from-radio.has-channel struct)
|
||||
(let ((channel (me:channel struct)))
|
||||
(when (eql :primary (me:role channel))
|
||||
(setf *my-channel* channel))
|
||||
(push channel *channels*)))
|
||||
;; config lora
|
||||
((me:from-radio.has-config struct)
|
||||
(let ((config (me:config struct)))
|
||||
(when (me:config.has-lora config)
|
||||
(setf *config-lora* (me:lora config)))))
|
||||
;; config-complete-id
|
||||
((me:from-radio.has-config-complete-id struct)
|
||||
(when (= *config-id* (me:config-complete-id struct))
|
||||
(setf *config-complete* t)
|
||||
(q> |playing| ui:*busy* nil)
|
||||
(qlog "config-complete id: ~A" *config-id*)
|
||||
(unless (string= *my-channel-name*
|
||||
(me:name (me:settings *my-channel*)))
|
||||
(qlater 'config-device))))))
|
||||
(setf *received* nil)))
|
||||
|
||||
(defun send-admin (admin-message)
|
||||
(send-to-radio
|
||||
|
|
|
|||
|
|
@ -124,15 +124,19 @@
|
|||
sending an ':e ...' text message, which will be echoed with info about signal
|
||||
strength, position and distance."
|
||||
(let ((from-pos (loc:position* from))
|
||||
(my-pos #+mobile (nbutlast (loc:last-gps-position) 1)
|
||||
(my-pos #+mobile (nbutlast (loc:latest-gps-position) 1)
|
||||
#-mobile nil))
|
||||
(format nil "~A~%~%snr: <b>~F</b> rssi: <b>~D</b>~%lat: ~,5F lon: ~,5F~%distance: <b>~:D m</b>"
|
||||
text snr rssi
|
||||
(if my-pos (first my-pos) "-")
|
||||
(if my-pos (second my-pos) "-")
|
||||
(if (and from-pos my-pos)
|
||||
(loc:distance my-pos from-pos)
|
||||
"-"))))
|
||||
(x:cc (format nil "~A~%~%snr: <b>~F</b> rssi: <b>~D</b>"
|
||||
text snr rssi)
|
||||
(if my-pos
|
||||
(format nil "~%lat: ~,5F lon: ~,5F"
|
||||
(first my-pos)
|
||||
(second my-pos))
|
||||
"")
|
||||
(if (and my-pos from-pos)
|
||||
(format nil "~%distance: <b>~:D m</b>"
|
||||
(loc:distance my-pos from-pos))
|
||||
""))))
|
||||
|
||||
(defun swipe-to-left () ; see QML
|
||||
(q> |currentIndex| ui:*main-view* 0)
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@
|
|||
#:distance
|
||||
#:extract-map-bin
|
||||
#:ini
|
||||
#:last-gps-position
|
||||
#:latest-gps-position
|
||||
#:make-map-bin
|
||||
#:position*
|
||||
#:position-count
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue