Skip to content

Instantly share code, notes, and snippets.

@alastair-dm
Last active November 22, 2024 03:12
Show Gist options
  • Save alastair-dm/263209b54d01209be28828e555fa6628 to your computer and use it in GitHub Desktop.
Save alastair-dm/263209b54d01209be28828e555fa6628 to your computer and use it in GitHub Desktop.
Proof of concept AGPS data loading for PinePhone
#!/usr/bin/python3
#
# load_agps_data
#
# proof of concept loading of agps data to quectel modem via AT commands
from datetime import datetime, timezone
import requests
import serial
at_port = '/dev/ttyUSB2' # ttyUSB2 is the command port on mobian - think they renamed via udev on PmOS
agps_url = 'http://xtrapath1.izatcloud.net/xtra.bin'
agps_file = 'RAM:xtra.bin'
def sendCmd(cmdstring):
print(cmdstring)
ser.write(f"{cmdstring}\r\n".encode('ascii'))
res = []
while True:
line = ser.readline()
if (line == b''):
break
else:
res.append(line)
print(res)
return res
def setTime():
now = datetime.utcnow().replace(tzinfo=timezone.utc).strftime('%Y/%m/%d,%H:%M:%S')
return sendCmd(f"AT+QGPSXTRATIME=0,\"{now}\"")
# is ModemManager running? Won't work if it's already got the port
print('open serial port')
ser = serial.Serial(at_port, timeout=1)
print('Check modem will talk to us')
res = sendCmd('AT')
# FIXME - expect response OK - really ought to check this and other responses
## is GPS turned on? If so the later stuff won't work so we'll have to turn it off
print('Is GPS turned on?')
res = sendCmd('AT+QGPS?')
print('Turn off GPS')
res = sendCmd('AT+QGPSEND') # this ought to be sent only if the gps was on...
print('Is AGPS enabled?')
res = sendCmd('AT+QGPSXTRA?')
print('Precautionary enabling of AGPS')
res = sendCmd('AT+QGPSXTRA=1')
print('Is valid AGPS data already loaded?')
res = sendCmd('AT+QGPSXTRADATA?')
# FIXME: check the returned stuff
# actually this check seems unnecessary as the returned value is alway the same
# so doesn't help (and doesn't match the docs)
# fetch http://xtrapath[1-3].izatcloud.net/xtra(2).bin and upload
r = requests.get(agps_url)
#FIXME: check r.status_code before doing anything with the data
print('download status: ', r.status_code)
# precautionary delete of the target file - upload will fail if file name in use
print('delete previous AGPS data file')
res = sendCmd(f"AT+QFDEL=\"{agps_file}\"")
print('upload new AGPS data')
res = sendCmd(f"AT+QFUPL=\"{agps_file}\",{len(r.content)}")
# FIXME: check res == CONNECT and don't send if it's not
ser.write(r.content)
res = []
while True:
line = ser.readline()
if (line == b''):
break
else:
res.append(line)
print(res)
#FIXME: calculate agps file checksum and check that it matches the response
# we'll assume here that local system time is kept accurate either by NTP or
# phone network time, so we don't need to fetch SNTP time
print('set current UTC time using local system time')
res = setTime()
print('set AGPS data to file we uploaded')
res = sendCmd(f"AT+QGPSXTRADATA=\"{agps_file}\"")
print('what does it day about data validity now?')
res = sendCmd('AT+QGPSXTRADATA?')
print('NOTE: it\'s given us the same response as before, despite having new data uploaded')
print('enable gps')
res = sendCmd('AT+QGPS=1')
print('close serial port')
if ser.is_open:
ser.close()
@beckmi
Copy link

beckmi commented Feb 19, 2021

  1. Simply trial and error.
  2. Yes – I know. It was just a little surprising for me to see that the battery was discharged within a day of testing, instead of five days ...

I think there still is a lot to do. The device even sometimes changes state to unavailable for no apparent reason.
Nevertheless nice thing to play with :)

Copy link

ghost commented Aug 13, 2021

I get an error in line 34:
Traceback (most recent call last): File "/home/diederick/load_agps_data.py", line 34, in <module> ser = serial.Serial(at_port, timeout=1) AttributeError: module 'serial' has no attribute 'Serial'

@FalcoGer
Copy link

I get an error in line 34: Traceback (most recent call last): File "/home/diederick/load_agps_data.py", line 34, in <module> ser = serial.Serial(at_port, timeout=1) AttributeError: module 'serial' has no attribute 'Serial'

I had the same issue because I installed "serial" with pip. You need to install "pyserial" (after uninstalling serial)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment