Skip to content

Instantly share code, notes, and snippets.

@bign8
Last active November 3, 2020 21:20
Show Gist options
  • Save bign8/206283c1652d1475136a893d375177a6 to your computer and use it in GitHub Desktop.
Save bign8/206283c1652d1475136a893d375177a6 to your computer and use it in GitHub Desktop.
I have an OLD GPS receiver, and need to force it past the last gps 10 bit week rollover
#!/usr/bin/env python3
# /opt/fakegps
"""
TL;DR: I have an OLD GPS receiver, and need to force it past the last gps 10 bit week rollover
TEST OUTPUT SITE: http://freenmea.net/decoder
WHY THIS IS A PROBLEM: https://gpsd.gitlab.io/gpsd/hacking.html#y2k1
INFO: https://github.com/rnorris/gpsd/blob/master/www/gpsd-time-service-howto.txt
MAN PAGE: http://manpages.ubuntu.com/manpages/trusty/man8/gpsd.8.html
PI HINTS: https://www.satsignal.eu/ntp/Raspberry-Pi-NTP.html
PI HINTS: http://www.unixwiz.net/techtips/raspberry-pi3-gps-time.html
NMEA docs: http://aprs.gids.nl/nmea/#refs
HELPFUL COMMANDS:
gpsd -N -F /var/run/gpsd.sock -b -n -S 9999 /tmp/ttyGPS0.fifo
vi /etc/defaults/gpsd
cgps -s -l s <localhost:9999>
systemctl <cmd> gpsd | ntp
ntpq -p
vi /etc/ntp.conf
"""
import datetime
import os
import errno
import time
def modify(fifo, stream):
for line in stream:
if not line.startswith(b'$GPRMC'):
fifo.write(line)
fifo.flush()
continue
parts = line.split(b',')
# Update DATE to account for 10 bit week counter
d = parts[9]
day, mon, yer = int(d[0:2]), int(d[2:4]), int(d[4:6])
n = datetime.datetime(yer+2000, mon, day)
n += datetime.timedelta(days=7*1024)
parts[9] = n.strftime('%d%m%y').encode()
# recompute checksum (xor all bytes between $ and *, print in hex)
line = b','.join(parts)
line = line[1:] # crop off the $
line = line[:line.index(b'*')]
n = 0
for a in line:
n ^= a
chksum = hex(n)[2:].upper().encode() # remove 0x
fifo.write(b'$' + line + b'*' + chksum + b'\n')
fifo.flush()
# Create a fifo file (ignore if it's already created)
path = '/tmp/ttyGPS0.fifo'
try:
os.mkfifo(path)
print('made /vmp/ttyGPS0.fifo')
except OSError as oe:
if oe.errno != errno.EEXIST:
raise
print('/tmp/ttyGPS0.fifo already exists')
# Startup gpsd.
os.system('systemctl start gpsd')
# Continually listen for pipe readers and start transaction
while True:
# spinloop for gpsd status (multiple readers not allowed)
while os.system('pidof gpsd > /dev/null'):
time.sleep(1)
fifo = open(path, 'wb', 0)
print("Connected")
try:
with open('/dev/ttyUSB0', 'rb', 1) as stream:
modify(fifo, stream)
except BrokenPipeError:
print("Disconnected")
fifo.close()
# /etc/default/gpsd
START_DAEMON="true"
USBAUTO="false"
DEVICES="/tmp/ttyGPS0.fifo"
# -n don't wait for client to connect; poll GPS immediately
# -b bluetooth safe (try opening read only)
GPSD_OPTIONS="-n -b"
# /etc/ntp.conf
# ... ommitted defaults ...
# interval of 5 == 32 seconds between updates == hot ARP cache (default is 6, or 64s, ARP cache default is 60s)
pool us.pool.ntp.org iburst minpoll 5 maxpoll 5
# GPS Data
server 127.127.28.0 minpoll 4 maxpoll 4 prefer
fudge 127.127.28.0 time1 -0.220 refid GPS
#!/bin/sh -e
# /etc/rc.local
# Start fakegps (yes, there are more modern ways of doing this)
/opt/fakegps &
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment