biscuit/pkgs/maps/main.fnl

202 lines
5.4 KiB
Plaintext
Raw Normal View History

2024-07-22 21:25:25 +00:00
; (local { : view } (require :fennel))
2025-05-16 21:15:38 +00:00
(local { : fdopen } (require :posix.stdio))
2025-05-17 23:23:32 +00:00
(local nmea (require :nmea))
2024-07-22 21:25:25 +00:00
2025-05-18 18:23:27 +00:00
(import-macros { : define-tests : expect : expect= } :assert)
2024-07-22 21:25:25 +00:00
(local {
: Gtk
: OsmGpsMap
: Gdk
2025-05-16 21:15:38 +00:00
: Gio
: GLib
2024-07-22 21:25:25 +00:00
}
(require :lgi))
(local CSS "
label.readout {
font: 48px \"Noto Sans\";
margin: 10px;
padding: 5px;
background-color: rgba(0, 0, 0, 0.2);
}
")
2025-05-18 18:23:27 +00:00
(local utc-offset
(let [now (os.time)
localt (os.date "*t" now)
utct (os.date "!*t" now)]
(tset localt :isdst false)
(os.difftime (os.time localt) (os.time utct))))
2024-07-22 21:25:25 +00:00
(fn styles []
(let [style_provider (Gtk.CssProvider)]
(Gtk.StyleContext.add_provider_for_screen
(Gdk.Screen.get_default)
style_provider
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
(style_provider:load_from_data CSS)))
(local window (Gtk.Window {
:title "Map"
:name "toplevel"
:default_width 720
:default_height 800
:on_destroy Gtk.main_quit
}))
2025-05-18 18:23:27 +00:00
(local state-widgets { })
2024-07-22 21:25:25 +00:00
(fn osm-widget []
2025-05-18 18:23:27 +00:00
(let [w
(doto (OsmGpsMap.Map {})
(tset :map-source OsmGpsMap.MapSource_t.OPENSTREETMAP)
(: :set_center_and_zoom 52.595 -0.1 17)
(: :layer_add (OsmGpsMap.MapOsd {
:show_copyright true
; :show_coordinates true
:show_scale true
}))
)]
(tset state-widgets :osm w)
w))
(fn readout [name text]
(let [w
(doto (Gtk.Label {:label text : name})
(-> (: :get_style_context)
(: :add_class :readout)))]
(tset state-widgets name w)
w))
(local knot-in-m-s
(/ 1852 ; metres in nautical mile
3600 ; seconds in an hour
))
(fn hhmmss [seconds-since-midnight]
(let [s (% seconds-since-midnight 60)
m (% (// (- seconds-since-midnight s) 60) 60)
h (// (- seconds-since-midnight (* m 60) s) 3600)]
(string.format "%d:%02d:%02d" h m s)))
(expect= (hhmmss (+ 45 (* 60 12) (* 60 60 3))) "3:12:45")
(local
app-state {
:time-of-day 0
:elapsed-time 0
:speed 14
:lat 49
:lon 0
:course 22
}
)
(fn merge [table1 table2]
(collect [k v (pairs table2) &into table1]
k v))
(fn update-app-state [new-vals]
(merge app-state new-vals)
(each [name widget (pairs state-widgets)]
(case name
:speed (widget:set_label
(string.format "%.1f km/h" (* app-state.speed 3.6)))
:osm (widget:set_center app-state.lat app-state.lon)
:time (widget:set_label
(hhmmss (+ utc-offset app-state.time-of-day)))
)))
2024-07-22 21:25:25 +00:00
(fn readouts []
(doto (Gtk.Box
{
:orientation Gtk.Orientation.VERTICAL
:halign Gtk.Align.END
})
(-> (: :get_style_context) (: :add_class :readouts))
2025-05-18 18:23:27 +00:00
(: :add (readout :time ""))
(: :add (readout :elapsed-time ""))
(: :add (readout :speed "0"))))
2025-05-18 23:18:15 +00:00
(fn arrow []
(let [height 40
w (Gtk.Label {
:halign Gtk.Align.CENTER
:valign Gtk.Align.CENTER
:width height :height height
:on_draw
(fn [self g]
(g:set_source_rgb 0.4 0.0 0.1)
(g:translate (// height 2) (// height 2))
(g:rotate (/ (* -2 app-state.course math.pi) 360) )
(g:translate (// height -2) (// height -2))
(g:set_line_width 4)
(g:move_to 10 height)
(g:line_to (// height 2) 0)
(g:line_to (- height 10) height)
(g:fill)
true)
})]
w))
(local socket-path (or (. arg 1) "/var/run/gnss-share.sock"))
2024-07-22 21:25:25 +00:00
2025-05-16 21:15:38 +00:00
(local gnss-socket
(let [addr (Gio.UnixSocketAddress {
:path socket-path
2025-05-16 21:15:38 +00:00
})]
(: (Gio.SocketClient) :connect addr nil)))
(fn read-gnss [socket]
(each [l #(socket:read "l")]
2025-05-17 23:23:32 +00:00
; (print "gnss" l)
(if (not (= l ""))
2025-05-18 18:23:27 +00:00
(let [message (nmea.parse l)]
(case message
{ : lat : lon : utc}
(update-app-state
{
: lat : lon
:time-of-day
(let [(h m s) (string.match utc "(..)(..)(..)")]
(+ s (* m 60) (* h 60 60)))
}
)
{ : speed-knots }
2025-05-18 23:18:15 +00:00
(update-app-state { :speed (* speed-knots knot-in-m-s) }))
(if message.bearing-true
(update-app-state { :course message.bearing-true }))
)))
2025-05-16 21:15:38 +00:00
true)
(let [sock (gnss-socket:get_socket)
fd (sock:get_fd)
events [ GLib.IOCondition.IN GLib.IOCondition.HUP]
channel (GLib.IOChannel.unix_new fd)
handle (fdopen fd :r)]
(GLib.io_add_watch channel 0 events #(read-gnss handle)))
2024-07-22 21:25:25 +00:00
(window:add
(doto (Gtk.Overlay {})
(: :add (osm-widget))
(: :add_overlay (readouts))
2025-05-18 23:18:15 +00:00
(: :add_overlay (arrow))
2024-07-22 21:25:25 +00:00
))
(window:show_all)
(styles)
(Gtk:main)