From db5be52a4e66eecc34015048889caffc8151c655 Mon Sep 17 00:00:00 2001 From: Florian Maurer Date: Thu, 25 Jul 2024 23:05:55 +0200 Subject: [PATCH 1/6] ffac-update-location-gp: initial package version * use bind and unbind to support coldplug * restart micrond after adding service at runtime --- ffac-update-location-gps/Makefile | 22 ++++++ ffac-update-location-gps/README.md | 22 ++++++ .../files/etc/config/update-location-gps | 2 + .../etc/hotplug.d/usb/10-update-location-gps | 26 +++++++ .../luasrc/usr/bin/update-location-gps | 78 +++++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 ffac-update-location-gps/Makefile create mode 100644 ffac-update-location-gps/README.md create mode 100644 ffac-update-location-gps/files/etc/config/update-location-gps create mode 100644 ffac-update-location-gps/files/etc/hotplug.d/usb/10-update-location-gps create mode 100755 ffac-update-location-gps/luasrc/usr/bin/update-location-gps diff --git a/ffac-update-location-gps/Makefile b/ffac-update-location-gps/Makefile new file mode 100644 index 00000000..19bd9262 --- /dev/null +++ b/ffac-update-location-gps/Makefile @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2024 Florian Maurer, xelo +# SPDX-License-Identifier: MIT +include $(TOPDIR)/rules.mk + +PKG_NAME:=ffac-update-location-gps +PKG_VERSION:=1.0 +PKG_RELEASE:=1 + +PKG_LICENSE:=MIT + +include $(TOPDIR)/../package/gluon.mk + +define Package/$(PKG_NAME) + TITLE:=Use attached GPS controller to update location from it + DEPENDS:=+kmod-usb-core +kmod-usb-ohci +kmod-usb2 +kmod-usb-acm +kmod-usb-serial-pl2303 +micrond +endef + +define Package/$(PKG_NAME)/description + If enabled, this package updates the gluon-node-info location based on the NMEA output of an attached GPS device. +endef + +$(eval $(call BuildPackageGluon,$(PKG_NAME))) diff --git a/ffac-update-location-gps/README.md b/ffac-update-location-gps/README.md new file mode 100644 index 00000000..46955c80 --- /dev/null +++ b/ffac-update-location-gps/README.md @@ -0,0 +1,22 @@ +# ffac-update-location-gps + +This package configures gluon to update the location based on tty output of an attached GPS device. + +When a USB device which provides a tty is attached, it updates the location based on the output of it. +This is done using a lua rewrite of the script from the original forum posting. +It seems to work without coreutils-stty installed, which did fail the installation when selected as package dependency. + +The location is only updated in memory - and only if a valid GPS fix is available. +After a reboot, the old location from the config is set. + +## hotplug limitation + +After a sysupgrade/autoupdate - the USB dongle has to be unplugged and plugged in once for the detection to work again. +For reboots, this works fine as is. + +## further information + +Further information can be found here: + +* https://github.com/dmth/gluon-gps-locationupdate +* https://forum.freifunk.net/t/freifunk-location-update-via-gps/1493 \ No newline at end of file diff --git a/ffac-update-location-gps/files/etc/config/update-location-gps b/ffac-update-location-gps/files/etc/config/update-location-gps new file mode 100644 index 00000000..cfc510dd --- /dev/null +++ b/ffac-update-location-gps/files/etc/config/update-location-gps @@ -0,0 +1,2 @@ +config settings 'settings' + option enabled '0' \ No newline at end of file diff --git a/ffac-update-location-gps/files/etc/hotplug.d/usb/10-update-location-gps b/ffac-update-location-gps/files/etc/hotplug.d/usb/10-update-location-gps new file mode 100644 index 00000000..109e4315 --- /dev/null +++ b/ffac-update-location-gps/files/etc/hotplug.d/usb/10-update-location-gps @@ -0,0 +1,26 @@ +#!/bin/sh +TTYPATH="/sys${DEVPATH}/tty" +LOCKPATH="/tmp/update-location-gps" + +ENABLED=$(uci get update-location-gps.settings.enabled) + +if [ "${ACTION}" = "bind" ]; then + [ "${ENABLED}" != "1" ] && exit 0 + test -e "${LOCKPATH}" && exit 0 + if test -e "${TTYPATH}"; then + TTY_NAME=$(find "${TTYPATH}" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed -n 's|.*/tty/||p') + logger -t hotplug "USB GPS device was plugged in" + echo "${DEVPATH}" > "${LOCKPATH}" + echo "*/5 * * * * /usr/bin/update-location-gps /dev/${TTY_NAME} | logger -t update-location-gps" > "/usr/lib/micron.d/update-location-gps" + /etc/init.d/micrond restart + fi +fi + +if [ "${ACTION}" = "unbind" ]; then + if [ "${DEVPATH}" = "$(cat ${LOCKPATH})" ]; then + logger -t hotplug "USB GPS device was removed" + rm -f "/usr/lib/micron.d/update-location-gps" + /etc/init.d/micrond restart + rm "${LOCKPATH}" + fi +fi \ No newline at end of file diff --git a/ffac-update-location-gps/luasrc/usr/bin/update-location-gps b/ffac-update-location-gps/luasrc/usr/bin/update-location-gps new file mode 100755 index 00000000..d60f5d86 --- /dev/null +++ b/ffac-update-location-gps/luasrc/usr/bin/update-location-gps @@ -0,0 +1,78 @@ +#!/usr/bin/lua + +if not arg[1] then + print("Error: No /dev/tty* path specified. Please provide a TTY device path as the first argument.") + os.exit(1) +end + +-- Get GPS device tty +local TTY_DEVICE = arg[1] + +local uci = require('simple-uci').cursor() + +-- Use GPS as Stream +local file = io.open(TTY_DEVICE, "r") + +while true do + local this_line = file:read("*line") + if not this_line then break end -- Exit loop if no more lines + + local nc = this_line:match("^([^,]+)") + + if nc == '$GPRMC' then + local fields = {} + for field in this_line:gmatch("([^,]+)") do + table.insert(fields, field) + end + + local valid = fields[3] + + if valid == "A" then + -- First: Retrieve coordinate + local lat = fields[4] + local lon = fields[6] + + -- Second: Determine if coordinate is oriented North/South or East/West + local latdir = fields[5] + local londir = fields[7] + + -- Split DEGREES from coordinate + local latdeg = tonumber(lat:sub(1, 2)) + local londeg = tonumber(lon:sub(1, 3)) + + -- Split MINUTES.SECONDS from coordinate + local latmin = tonumber(lat:sub(3)) + local lonmin = tonumber(lon:sub(4)) + + -- Convert from Degree-Minutes to Decimal-Minutes + local latdec = latmin / 60 + local londec = lonmin / 60 + + -- Use negative notation instead of North/South or East/West + if latdir == 'S' then + latdeg = -latdeg + end + if londir == 'W' then + londeg = -londeg + end + lat = string.format("%f", latdeg + latdec) + lon = string.format("%f", londeg + londec) + + print("GPS position is valid Lat/Lon:", lat, lon) + -- set temp location in gluon-node-info + uci:set('gluon-node-info', '@location[0]', 'share_location', '1') + uci:set('gluon-node-info', '@location[0]', 'latitude', lat) + uci:set('gluon-node-info', '@location[0]', 'longitude', lon) + uci:save('gluon-node-info') + -- Link to Phip's comment: https://forum.freifunk.net/t/freifunk-location-update-via-gps/1493/2 + -- Committing here would wear out the nvram very fast, so it should not be done. + break + else + print("GPS position is Invalid...", valid) + break + end + end +end + +file:close() +os.exit(0) From c4bbc978ce99ecfab515234fd3a40b6e5a3a4bfe Mon Sep 17 00:00:00 2001 From: Florian Maurer Date: Wed, 7 Aug 2024 21:38:16 +0200 Subject: [PATCH 2/6] Add check if TTY_DEVICE actually exists Co-authored-by: Grische <2787581+grische@users.noreply.github.com> --- ffac-update-location-gps/luasrc/usr/bin/update-location-gps | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ffac-update-location-gps/luasrc/usr/bin/update-location-gps b/ffac-update-location-gps/luasrc/usr/bin/update-location-gps index d60f5d86..cd1ecf0a 100755 --- a/ffac-update-location-gps/luasrc/usr/bin/update-location-gps +++ b/ffac-update-location-gps/luasrc/usr/bin/update-location-gps @@ -12,6 +12,10 @@ local uci = require('simple-uci').cursor() -- Use GPS as Stream local file = io.open(TTY_DEVICE, "r") +if not file then + print("Error: Unable to open " .. TTY_DEVICE) + os.exit(2) +end while true do local this_line = file:read("*line") From 983ed32728ced09f6957c24da3c12f56bfc4bbd1 Mon Sep 17 00:00:00 2001 From: Florian Maurer Date: Thu, 8 Aug 2024 10:57:52 +0200 Subject: [PATCH 3/6] add lock to update-location-gps lua - improve loop handling --- .../etc/hotplug.d/tty/10-update-location-gps | 24 +++++++++++ .../etc/hotplug.d/usb/10-update-location-gps | 26 ------------ .../luasrc/usr/bin/update-location-gps | 41 ++++++++++++++++--- 3 files changed, 59 insertions(+), 32 deletions(-) create mode 100644 ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps delete mode 100644 ffac-update-location-gps/files/etc/hotplug.d/usb/10-update-location-gps diff --git a/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps b/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps new file mode 100644 index 00000000..3fd3c086 --- /dev/null +++ b/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps @@ -0,0 +1,24 @@ +#!/bin/sh +TTYPATH="/sys${DEVPATH}/tty" +lockpath="/var/lock/update-location-gps_${DEVNAME}.lock" + +if [ "${ACTION}" = "add" ]; then + enabled=$(uci get update-location-gps.settings.enabled) + [ "${enabled}" != "1" ] && exit 0 + test -e "${lockpath}" && exit 0 + if test -e "${TTYPATH}"; then + echo "hotplug-update-location-gps: TTY device ${DEVNAME} was plugged in" > /dev/kmsg + echo "${DEVPATH}" > "${lockpath}" + echo "*/5 * * * * /usr/bin/update-location-gps /dev/${DEVNAME} | logger -t update-location-gps" > "/usr/lib/micron.d/update-location-gps_${DEVNAME}" + /etc/init.d/micrond restart + fi +fi + +if [ "${ACTION}" = "remove" ]; then + if [ "${DEVPATH}" = "$(cat "${lockpath}")" ]; then + echo "hotplug-update-location-gps: TTY device ${DEVNAME} was removed" > /dev/kmsg + rm -f "/usr/lib/micron.d/update-location-gps_${DEVNAME}" + /etc/init.d/micrond restart + rm "${lockpath}" + fi +fi diff --git a/ffac-update-location-gps/files/etc/hotplug.d/usb/10-update-location-gps b/ffac-update-location-gps/files/etc/hotplug.d/usb/10-update-location-gps deleted file mode 100644 index 109e4315..00000000 --- a/ffac-update-location-gps/files/etc/hotplug.d/usb/10-update-location-gps +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -TTYPATH="/sys${DEVPATH}/tty" -LOCKPATH="/tmp/update-location-gps" - -ENABLED=$(uci get update-location-gps.settings.enabled) - -if [ "${ACTION}" = "bind" ]; then - [ "${ENABLED}" != "1" ] && exit 0 - test -e "${LOCKPATH}" && exit 0 - if test -e "${TTYPATH}"; then - TTY_NAME=$(find "${TTYPATH}" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed -n 's|.*/tty/||p') - logger -t hotplug "USB GPS device was plugged in" - echo "${DEVPATH}" > "${LOCKPATH}" - echo "*/5 * * * * /usr/bin/update-location-gps /dev/${TTY_NAME} | logger -t update-location-gps" > "/usr/lib/micron.d/update-location-gps" - /etc/init.d/micrond restart - fi -fi - -if [ "${ACTION}" = "unbind" ]; then - if [ "${DEVPATH}" = "$(cat ${LOCKPATH})" ]; then - logger -t hotplug "USB GPS device was removed" - rm -f "/usr/lib/micron.d/update-location-gps" - /etc/init.d/micrond restart - rm "${LOCKPATH}" - fi -fi \ No newline at end of file diff --git a/ffac-update-location-gps/luasrc/usr/bin/update-location-gps b/ffac-update-location-gps/luasrc/usr/bin/update-location-gps index cd1ecf0a..03c2f987 100755 --- a/ffac-update-location-gps/luasrc/usr/bin/update-location-gps +++ b/ffac-update-location-gps/luasrc/usr/bin/update-location-gps @@ -5,22 +5,51 @@ if not arg[1] then os.exit(1) end --- Get GPS device tty -local TTY_DEVICE = arg[1] - local uci = require('simple-uci').cursor() +local bit = require 'bit' +local fcntl = require 'posix.fcntl' +local unistd = require 'posix.unistd' + +-- Get GPS device tty +local tty_device = arg[1] -- Use GPS as Stream -local file = io.open(TTY_DEVICE, "r") +local file = io.open(tty_device, "r") if not file then - print("Error: Unable to open " .. TTY_DEVICE) + print("Error: Unable to open " .. tty_device) os.exit(2) end -while true do +local lockfilename = "/var/lock/update-location-gps_" .. string.gsub(tty_device, "/", "_") + +local lockfd, err = fcntl.open(lockfilename, bit.bor(fcntl.O_WRONLY, fcntl.O_CREAT), 384) -- mode 0600 +if not lockfd then + print('err', err) + local err_verbose = string.format("Unable to get file descriptor for lock file %s .", lockfilename) + print('err', err_verbose) + os.exit(1) +end + +local ok, _ = fcntl.fcntl(lockfd, fcntl.F_SETLK, { + l_start = 0, + l_len = 0, + l_type = fcntl.F_WRLCK, + l_whence = unistd.SEEK_SET, +}) +if not ok then + -- silent as this is run in cron + os.exit(1) +end + +local line_count = 0 +local max_lines = 50 + +while line_count < max_lines do local this_line = file:read("*line") if not this_line then break end -- Exit loop if no more lines + line_count = line_count + 1 -- Increment the line counter + local nc = this_line:match("^([^,]+)") if nc == '$GPRMC' then From 61af535f10afe15df37b43a86ad092fa1a5472aa Mon Sep 17 00:00:00 2001 From: Florian Maurer Date: Tue, 13 Aug 2024 20:51:27 +0200 Subject: [PATCH 4/6] do not change share_location setting --- ffac-update-location-gps/luasrc/usr/bin/update-location-gps | 1 - 1 file changed, 1 deletion(-) diff --git a/ffac-update-location-gps/luasrc/usr/bin/update-location-gps b/ffac-update-location-gps/luasrc/usr/bin/update-location-gps index 03c2f987..30ba92de 100755 --- a/ffac-update-location-gps/luasrc/usr/bin/update-location-gps +++ b/ffac-update-location-gps/luasrc/usr/bin/update-location-gps @@ -93,7 +93,6 @@ while line_count < max_lines do print("GPS position is valid Lat/Lon:", lat, lon) -- set temp location in gluon-node-info - uci:set('gluon-node-info', '@location[0]', 'share_location', '1') uci:set('gluon-node-info', '@location[0]', 'latitude', lat) uci:set('gluon-node-info', '@location[0]', 'longitude', lon) uci:save('gluon-node-info') From b7ba830e65d4b63a972d5e3e042902a148e8fb6a Mon Sep 17 00:00:00 2001 From: Florian Maurer Date: Fri, 23 Aug 2024 16:53:40 +0100 Subject: [PATCH 5/6] improve readme, rename lockfile --- ffac-update-location-gps/README.md | 10 +++++++--- .../files/etc/hotplug.d/tty/10-update-location-gps | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ffac-update-location-gps/README.md b/ffac-update-location-gps/README.md index 46955c80..b19eb81d 100644 --- a/ffac-update-location-gps/README.md +++ b/ffac-update-location-gps/README.md @@ -9,10 +9,14 @@ It seems to work without coreutils-stty installed, which did fail the installati The location is only updated in memory - and only if a valid GPS fix is available. After a reboot, the old location from the config is set. -## hotplug limitation +## behvario and lockfiles + +This creates a lockfile `/var/lock/hotplug-update-location-gps_$DEVNAME.lock` per found TTY device and sets up a cron job which runs every 5 minutes to check if coordinates are available from the stream. +If the TTY is not in use, the open stream waits for the first line to be read (never) and is stuck. +A lockfile `/var/lock/update-location-gps_$TTYDEVICE` is used to check if the cron is already running/stuck and does not start another reading terminal in that case. + +On creation and removal of the micron.d job, the micron.d service is restarted -After a sysupgrade/autoupdate - the USB dongle has to be unplugged and plugged in once for the detection to work again. -For reboots, this works fine as is. ## further information diff --git a/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps b/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps index 3fd3c086..6ce23938 100644 --- a/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps +++ b/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps @@ -1,6 +1,6 @@ #!/bin/sh TTYPATH="/sys${DEVPATH}/tty" -lockpath="/var/lock/update-location-gps_${DEVNAME}.lock" +lockpath="/var/lock/hotplug-update-location-gps_${DEVNAME}.lock" if [ "${ACTION}" = "add" ]; then enabled=$(uci get update-location-gps.settings.enabled) From 03b0bba17cf848f91ee02cb27372cf15cb9b8c6f Mon Sep 17 00:00:00 2001 From: Florian Maurer Date: Thu, 29 Aug 2024 09:31:27 +0200 Subject: [PATCH 6/6] in hotplug.d/tty we already know it is a TTY device, so we do not need this check anymore --- .../files/etc/hotplug.d/tty/10-update-location-gps | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps b/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps index 6ce23938..0cf0dc2c 100644 --- a/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps +++ b/ffac-update-location-gps/files/etc/hotplug.d/tty/10-update-location-gps @@ -1,17 +1,14 @@ #!/bin/sh -TTYPATH="/sys${DEVPATH}/tty" lockpath="/var/lock/hotplug-update-location-gps_${DEVNAME}.lock" if [ "${ACTION}" = "add" ]; then enabled=$(uci get update-location-gps.settings.enabled) [ "${enabled}" != "1" ] && exit 0 test -e "${lockpath}" && exit 0 - if test -e "${TTYPATH}"; then - echo "hotplug-update-location-gps: TTY device ${DEVNAME} was plugged in" > /dev/kmsg - echo "${DEVPATH}" > "${lockpath}" - echo "*/5 * * * * /usr/bin/update-location-gps /dev/${DEVNAME} | logger -t update-location-gps" > "/usr/lib/micron.d/update-location-gps_${DEVNAME}" - /etc/init.d/micrond restart - fi + echo "hotplug-update-location-gps: TTY device ${DEVNAME} was plugged in" > /dev/kmsg + echo "${DEVPATH}" > "${lockpath}" + echo "*/5 * * * * /usr/bin/update-location-gps /dev/${DEVNAME} | logger -t update-location-gps" > "/usr/lib/micron.d/update-location-gps_${DEVNAME}" + /etc/init.d/micrond restart fi if [ "${ACTION}" = "remove" ]; then