From 516d6fb2db10854369a8b21c81caf89c95e765ff Mon Sep 17 00:00:00 2001 From: Richard Fuller <156370932+richard-at-semtech@users.noreply.github.com> Date: Wed, 1 Oct 2025 14:50:16 -0700 Subject: [PATCH] Create traxmate_full_almanac.py This calls Traxmate full almanac update as opposed to the retired LoRa Cloud link --- .../traxmate_full_almanac.py | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 lbm_applications/3_geolocation_on_lora_edge/main_full_almanac_update/traxmate_full_almanac.py diff --git a/lbm_applications/3_geolocation_on_lora_edge/main_full_almanac_update/traxmate_full_almanac.py b/lbm_applications/3_geolocation_on_lora_edge/main_full_almanac_update/traxmate_full_almanac.py new file mode 100644 index 0000000..c54c878 --- /dev/null +++ b/lbm_applications/3_geolocation_on_lora_edge/main_full_almanac_update/traxmate_full_almanac.py @@ -0,0 +1,117 @@ + +""" +The Clear BSD License +Copyright Semtech Corporation 2021. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted (subject to the limitations in the disclaimer +below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY +THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +""" + +import base64 +import requests + +import sys +from argparse import ArgumentParser + + +def main(): + + # The optional GPS timestamp for specific almanac date. The following website + # can convert an UTC time to a GPS timestamp: https://www.gw-openscience.org/gps/ + toa_default = "" + + # The file in which the almanac will be written to + filename_default = "almanac.h" + + parser = ArgumentParser( + description="Companion software that generates almanac header file to be compiled for LR1110/LR1120 embedded full almanac update." + ) + parser.add_argument( + "token", help="Cloud service token to use to fetch the almanac" + ) + parser.add_argument( + "-f", + "--output_file", + help="file that will contain the results", + default=filename_default, + ) + parser.add_argument( + "-g", + "--gpstime", + help="GPS time reference to be used for generating the almanac header (can be omitted to get latest almanac)", + default=toa_default, + ) + args = parser.parse_args() + + token = args.token + filename = args.output_file + toa = args.gpstime + + # Build request URL +# if not toa: +# url = "https://mgs.loracloud.com/api/v1/almanac/full" +# print("Requesting latest full almanac image available...") +# else: +# url = "https://mgs.loracloud.com/api/v1/almanac/full?toa=" + toa +# print("Requesting full almanac image for GPS time " + toa + "...") + if not toa: + url = "https://lw.traxmate.io/api/v1/almanac/full" + print("Requesting latest full almanac image available...") + else: + url = "https://lw.traxmate.io/api/v1/almanac/full?toa=" + toa + print("Requesting full almanac image for GPS time " + toa + "...") + # HTTP request to MGS + my_header = {"Authorization": token} + res = requests.get(url, headers=my_header) + + if res.status_code != 200: + print("ERROR: failed to get almanac - " + str(res)) + sys.exit(2) + else: + print("Almanac download success") + + raw_bytes = bytes(base64.b64decode(res.json()["result"]["almanac_image"])) + + # Build the byte array containing the almanac to be written to LR11xx + my_almanac_in_hex = "static const uint8_t full_almanac[( LR11XX_GNSS_FULL_UPDATE_N_ALMANACS * LR11XX_GNSS_SINGLE_ALMANAC_WRITE_SIZE ) + 20] = { " + my_almanac_in_hex += ", ".join("0x{:02X}".format(byt) for byt in raw_bytes) + my_almanac_in_hex += " };" + + # Write C file to be included to the full_almanac_update application for writting to LR11xx + file_header = ( + "/* This file has been auto-generated by the get_full_almanac.py script */\n\n" + ) + file_header += '#include "lr11xx_gnss.h"\n\n' + if toa: + file_header += "/* Almanac image for GPS time " + toa + " */\n" + with open(filename, "w") as f: + f.write(file_header + my_almanac_in_hex + "\n") + + print("Almanac image written to " + filename + " file") + + +if __name__ == "__main__": + main() +