#!/usr/bin/env python3 import os import random import argparse import datetime as dt import subprocess as sp from typing import Tuple from laika.downloader import download_nav from laika.gps_time import GPSTime from laika.helpers import ConstellationId cache_dir = '/tmp/gpstest/' def download_rinex(): # TODO: check if there is a better way to get the full brdc file for LimeGPS gps_time = GPSTime.from_datetime(dt.datetime.utcnow()) utc_time = dt.datetime.utcnow()# - dt.timedelta(1) gps_time = GPSTime.from_datetime(dt.datetime(utc_time.year, utc_time.month, utc_time.day)) return download_nav(gps_time, cache_dir, ConstellationId.GPS) def get_coords(lat, lon, s1, s2, o1=0, o2=0) -> Tuple[int, int]: lat_add = random.random()*s1 + o1 lon_add = random.random()*s2 + o2 lat = ((lat + lat_add + 90) % 180) - 90 lon = ((lon + lon_add + 180) % 360) - 180 return round(lat, 5), round(lon, 5) def get_continuous_coords(lat, lon) -> Tuple[int, int]: # continuously move around the world return get_coords(lat, lon, 0.01, 0.01) def get_random_coords(lat, lon) -> Tuple[int, int]: # jump around the world return get_coords(lat, lon, 20, 20, 10, 20) def run_limeSDR_loop(lat, lon, alt, contin_sim, rinex_file, timeout): while True: try: # TODO: add starttime setting and altitude # -t 2023/01/15,00:00:00 -T 2023/01/15,00:00:00 # this needs to match the date of the navigation file print(f"starting LimeGPS, Location: {lat} {lon} {alt}") cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", f"{lat},{lon},{alt}"] print(f"CMD: {cmd}") sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) except KeyboardInterrupt: print("stopping LimeGPS") return except sp.TimeoutExpired: print("LimeGPS timeout reached!") except Exception as e: out_stderr = e.stderr.decode('utf-8')# pylint:disable=no-member if "Device is busy." in out_stderr: print("GPS simulation is already running, Device is busy!") return print(f"LimeGPS crashed: {str(e)}") print(f"stderr:\n{e.stderr.decode('utf-8')}")# pylint:disable=no-member return if contin_sim: lat, lon = get_continuous_coords(lat, lon) else: lat, lon = get_random_coords(lat, lon) def run_hackRF_loop(lat, lon, rinex_file, timeout): if timeout is not None: print("no jump mode for hackrf!") return try: print(f"starting gps-sdr-sim, Location: {lat},{lon}") # create 30second file and replay with hackrf endless cmd = ["gps-sdr-sim/gps-sdr-sim", "-e", rinex_file, "-l", f"{lat},{lon},-200", "-d", "30"] sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) # created in current working directory except Exception: print("Failed to generate gpssim.bin") try: print("starting hackrf_transfer") # create 30second file and replay with hackrf endless cmd = ["hackrf/host/hackrf-tools/src/hackrf_transfer", "-t", "gpssim.bin", "-f", "1575420000", "-s", "2600000", "-a", "1", "-R"] sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) except KeyboardInterrupt: print("stopping hackrf_transfer") return except Exception as e: print(f"hackrf_transfer crashed:{str(e)}") def main(lat, lon, alt, jump_sim, contin_sim, hackrf_mode): if hackrf_mode: if not os.path.exists('hackrf'): print("hackrf not found run 'setup_hackrf.sh' first") return if not os.path.exists('gps-sdr-sim'): print("gps-sdr-sim not found run 'setup_hackrf.sh' first") return output = sp.check_output(["hackrf/host/hackrf-tools/src/hackrf_info"]) if output.strip() == b"" or b"No HackRF boards found." in output: print("No HackRF boards found!") return else: if not os.path.exists('LimeGPS'): print("LimeGPS not found run 'setup.sh' first") return if not os.path.exists('LimeSuite'): print("LimeSuite not found run 'setup.sh' first") return output = sp.check_output(["LimeSuite/builddir/LimeUtil/LimeUtil", "--find"]) if output.strip() == b"": print("No LimeSDR device found!") return print(f"Device: {output.strip().decode('utf-8')}") if lat == 0 and lon == 0: lat, lon = get_random_coords(47.2020, 15.7403) rinex_file = download_rinex() timeout = None if jump_sim: timeout = 30 if hackrf_mode: run_hackRF_loop(lat, lon, rinex_file, timeout) else: run_limeSDR_loop(lat, lon, alt, contin_sim, rinex_file, timeout) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Simulate static [or random jumping] GPS signal.") parser.add_argument("lat", type=float, nargs='?', default=0) parser.add_argument("lon", type=float, nargs='?', default=0) parser.add_argument("alt", type=float, nargs='?', default=0) parser.add_argument("--jump", action="store_true", help="signal that jumps around the world") parser.add_argument("--contin", action="store_true", help="continuously/slowly moving around the world") parser.add_argument("--hackrf", action="store_true", help="hackrf mode (DEFAULT: LimeSDR)") args = parser.parse_args() main(args.lat, args.lon, args.alt, args.jump, args.contin, args.hackrf)