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))
|
|
|
|
|
|
|
|
|
2025-05-18 18:00:06 +00:00
|
|
|
(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 {
|
2025-05-18 18:00:06 +00:00
|
|
|
: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)
|