Add route.py, Update ADSB-Encoder.py

This commit is contained in:
pynstrom 2020-02-13 21:27:26 -05:00
parent 0c21a41dde
commit 2bd07f7e3b
3 changed files with 342 additions and 242 deletions

16
.gitignore vendored
View File

@ -1,16 +0,0 @@
*.iq8s
*.pyc
*.log*
*.csv
# Keep the example CSV
!example.csv
# Don't include the generated CSV related files
generated/
allICAO.py
hackRFAllICAO.sh
allLat.py
hackRFAllLat.sh
allAlt.py
hackRFAllAlt.sh

View File

@ -1,84 +1,49 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
#
from HackRF import HackRF from HackRF import HackRF
from PPM import PPM from PPM import PPM
from ModeS import ModeS from ModeS import ModeS
from sys import argv, exit from getopt import getopt, GetoptError
import argparse import os,csv,sys
import configparser
import logging
import logging.config
import os
import csv
############################################################### class ADSB_Encoder:
def _set_vars(self,alt,lat,lon,capability,imgap,nicsup,rp,gnd,sstat,tc,icao,callsign,time,filename,speed,vspeed,heading):
# Copyright (C) 2017 Linar Yusupov self.altitude = float(alt)
self.callsign = callsign
# This program is free software: you can redistribute it and/or modify self.capability = capability
# it under the terms of the GNU General Public License as published by self.icao = int(icao,16)
# the Free Software Foundation, either version 3 of the License, or self.intermessagegap = imgap
# (at your option) any later version. self.latitude = float(lat)
self.longitude = float(lon)
# This program is distributed in the hope that it will be useful, self.nicsupplementb = nicsup
# but WITHOUT ANY WARRANTY; without even the implied warranty of self.outputfilename = filename
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the self.repeats = rp
# GNU General Public License for more details. self.surface = gnd
self.surveillancestatus = sstat
# You should have received a copy of the GNU General Public License self.time = time
# along with this program. If not, see <http://www.gnu.org/licenses/>. self.typecode = tc
self.speed = float(speed)*0.53996
############################################################### self.vspeed = float(vspeed)
# Further work on fork while heading < 0:heading = heading + 360
# Copyright (C) 2017 David Robinson if 0 <= float(heading) <= 89:self.heading = float(heading) + 180
elif 90 <= float(heading) <= 179:self.heading = float(heading)
def auto_int(x): elif 180 <= float(heading) <= 269:self.heading = float(heading) - 180
"""Parses HEX into for argParser""" elif 270 <= float(heading) <= 359:self.heading = float(heading)
return int(x, 0)
def auto_bool(x):
if x.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif x.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else: else:
raise argparse.ArgumentTypeError('Boolean value expected.') if __name__ == "__main__":usage("Invalid bearing.")
def argParser(): def encode(self):
description = 'This tool will generate ADS-B data in a form that a hackRF can broadcast. In addition to providing the information at the command the defaults can be changed in the config.cfg file and the the logging config changed in logging.cfg.'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('-i', '--icao', action='store', type=auto_int, dest='icao', default=cfg.get('plane', 'icao'), help='The ICAO number for the plane in hex. Ensure the ICAO is prefixed with \'0x\' to ensure this is parsed as a hex number. This is 24 bits long. Default: %(default)s')
parser.add_argument('--lat', '--latitude', action='store', type=float, dest='latitude', default=cfg.getfloat('plane', 'latitude'), help='Latitude for the plane in decimal degrees. Default: %(default)s')
parser.add_argument('--lon', '--long', '--longitude', action='store', type=float, dest='longitude', default=cfg.getfloat('plane', 'longitude'), help='Longitude for the place in decimal degrees. Default: %(default)s')
parser.add_argument('-a', '--alt', '--altitude', action='store', type=float, dest='altitude', default=cfg.getfloat('plane', 'altitude'), help='Altitude in decimal feet. 12 bits. Default: %(default)s')
parser.add_argument('--ca', '--capability', action='store', type=int, dest='capability', default=cfg.getint('plane', 'capability'), help='The capability. (Think this is always 5 from ADS-B messages. More info would be appreciated). 5 indicates that the responder is capable of Communication A and B, and the plane is not on the ground. 3 bits. Default: %(default)s')
parser.add_argument('--tc', '--typecode', action='store', type=int, dest='typecode', default=cfg.getint('plane', 'typecode'), help='The type for the ADS-B message. 11 is an air position message. See https://adsb-decode-guide.readthedocs.io/en/latest/content/introduction.html#ads-b-message-types for more information. 5 bits. Default: %(default)s')
parser.add_argument('--ss', '--surveillancestatus', action='store', type=int, dest='surveillancestatus', default=cfg.getint('plane', 'surveillancestatus'), help='The surveillance status. (Think this is always 0 from ADS-B messages. More info would be appreciated). Default: %(default)s')
parser.add_argument('--nicsb', '--nicsupplementb', action='store', type=int, dest='nicsupplementb', default=cfg.getint('plane', 'nicsupplementb'), help='The NIC supplement-B.(Think this is always 0 from ADS-B messages. More info would be appreciated). Default: %(default)s')
parser.add_argument('--time', action='store', type=int, dest='time', default=cfg.getint('plane', 'time'), help='0 indicates the time is not synchronous with UTC. Default: %(default)s')
parser.add_argument('-s', '--surface', action='store', default=cfg.getboolean('plane', 'surface'), type=auto_bool, dest='surface', help='If the plane is on the ground or not. Default: %(default)s')
parser.add_argument('-o', '--out', '--output', action='store', type=str, default=cfg.get('general', 'outputfilename'), dest='outputfilename', help='The iq8s output filename. This is the file which you will feed into the hackRF. Default: %(default)s')
parser.add_argument('-r', '--repeats', action='store', dest='repeats', type=int, default=cfg.getint('general', 'repeats'), help='How many repeats of the data to perform. Default: %(default)s')
parser.add_argument('--csv', '--csvfile', '--in', '--input', action='store', type=str, default=cfg.get('general', 'csvfile'), dest='csvfile', help='Import a CSV file with the plane data in it. Default: %(default)s')
parser.add_argument('--intermessagegap', action='store', type=int, default=cfg.get('general', 'intermessagegap'), dest='intermessagegap', help='When repeating or reading a CSV the number of microseconds between messages. Default: %(default)s')
parser.add_argument('--realtime', action='store', default=cfg.getboolean('general', 'realtime'), type=auto_bool, dest='realtime', help='When running a CSV which has a timestamp column whether to run in realtime following the timestamp or if just follow intermessagegap. If realtime is set it will override intermessagegap. Default: %(default)s')
parser.add_argument('--callsign', action='store', default=cfg.get('plane', 'callsign'), type=str, dest='callsign', help='The callsign of the aircraft. Is a max of 8 characters. Default: %(default)s')
# TODO Make it so it can do a static checksum or one/two bit error
# TODO Velocity, Heading and vertical speed as argument
return parser.parse_args()
def singlePlane(arguments):
logger.info('Processing default and command line options for a single plane')
logger.info('Repeating the message %s times' % (arguments.repeats))
samples = bytearray() samples = bytearray()
for i in range(0, arguments.repeats): for i in range(0, self.repeats):
modes = ModeS() modes = ModeS()
(df17_pos_even, df17_pos_odd) = modes.df17_pos_rep_encode(arguments.capability, arguments.icao, arguments.typecode, arguments.surveillancestatus, arguments.nicsupplementb, arguments.altitude, arguments.time, arguments.latitude, arguments.longitude, arguments.surface)
df17_velocity = modes.vel_heading_encode(arguments.capability, arguments.icao, 450, 200, -1000) (df17_pos_even, df17_pos_odd) = modes.df17_pos_rep_encode(self.capability, self.icao, self.typecode, \
self.surveillancestatus, self.nicsupplementb, self.altitude, self.time, self.latitude, \
self.longitude, self.surface)
df17_callsign = modes.callsign_encode(arguments.capability, arguments.icao, arguments.callsign) df17_velocity = modes.vel_heading_encode(self.capability, self.icao, self.speed, self.heading, self.vspeed)
df17_callsign = modes.callsign_encode(self.capability, self.icao, self.callsign)
ppm = PPM() ppm = PPM()
df17_array_position = ppm.frame_1090es_ppm_modulate(df17_pos_even, df17_pos_odd) df17_array_position = ppm.frame_1090es_ppm_modulate(df17_pos_even, df17_pos_odd)
@ -89,157 +54,104 @@ def singlePlane(arguments):
#Position #Position
samples_array = hackrf.hackrf_raw_IQ_format(df17_array_position) samples_array = hackrf.hackrf_raw_IQ_format(df17_array_position)
samples = samples+samples_array samples = samples+samples_array
gap_array = ppm.addGap(arguments.intermessagegap) gap_array = ppm.addGap(self.intermessagegap)
samples_array = hackrf.hackrf_raw_IQ_format(gap_array) samples_array = hackrf.hackrf_raw_IQ_format(gap_array)
samples = samples+samples_array samples = samples+samples_array
#Velocity #Velocity
samples_array = hackrf.hackrf_raw_IQ_format(df17_array_velocity) samples_array = hackrf.hackrf_raw_IQ_format(df17_array_velocity)
samples = samples+samples_array samples = samples+samples_array
gap_array = ppm.addGap(arguments.intermessagegap) gap_array = ppm.addGap(self.intermessagegap)
samples_array = hackrf.hackrf_raw_IQ_format(gap_array) samples_array = hackrf.hackrf_raw_IQ_format(gap_array)
samples = samples+samples_array samples = samples+samples_array
#Callsign #Callsign
samples_array = hackrf.hackrf_raw_IQ_format(df17_array_callsign) samples_array = hackrf.hackrf_raw_IQ_format(df17_array_callsign)
samples = samples+samples_array samples = samples+samples_array
gap_array = ppm.addGap(arguments.intermessagegap) gap_array = ppm.addGap(self.intermessagegap)
samples_array = hackrf.hackrf_raw_IQ_format(gap_array) samples_array = hackrf.hackrf_raw_IQ_format(gap_array)
samples = samples+samples_array samples = samples+samples_array
return samples return samples
def manyPlanes(arguments): def writeOutputFile(self, data):
logger.info('Processing CSV file: %s' % (arguments.csvfile)) tmpfile = '%s.tmp'%(self.outputfilename)
samples = bytearray()
logger.info('Repeating the message %s times' % (arguments.repeats))
prevtimestamp = 0
#TODO Callsign, speed, heading, vert speed in CSV
for i in range(0, arguments.repeats):
with open(arguments.csvfile, newline='') as csvfile:
reader = csv.DictReader(csvfile, delimiter=',')
for row in reader:
gap = arguments.intermessagegap
if not 'icao' in row.keys():
row['icao'] = arguments.icao
else:
row['icao'] = int(row['icao'], 0)
if not 'latitude' in row.keys():
row['latitude'] = arguments.latitude
else:
row['latitude'] = float(row['latitude'])
if not 'longitude' in row.keys():
row['longitude'] = arguments.longitude
else:
row['longitude'] = float(row['longitude'])
if not 'altitude' in row.keys():
row['altitude'] = arguments.altitude
else:
row['altitude'] = float(row['altitude'])
if not 'capability' in row.keys():
row['capability'] = arguments.capability
if not 'typecode' in row.keys():
row['typecode'] = arguments.typecode
if not 'surveillancestatus' in row.keys():
row['surveillancestatus'] = arguments.surveillancestatus
if not 'nicsupplementb' in row.keys():
row['nicsupplementb'] = arguments.nicsupplementb
if not 'time' in row.keys():
row['time'] = arguments.time
if not 'surface' in row.keys():
row['surface'] = arguments.surface
if 'timestamp' in row.keys():
if arguments.realtime:
gap = int(row['timestamp']) - prevtimestamp
gap = gap * 100000
prevtimestamp = int(row['timestamp'])
if not 'callsign' in row.keys():
row['callsign'] = arguments.callsign
logger.debug('Row from CSV: %s' % (row))
modes = ModeS()
(df17_pos_even, df17_pos_odd) = modes.df17_pos_rep_encode(row['capability'], row['icao'], row['typecode'], row['surveillancestatus'], row['nicsupplementb'], row['altitude'], row['time'], row['latitude'], row['longitude'], row['surface'])
df17_velocity = modes.vel_heading_encode(row['capability'], row['icao'], 450, 200, -1000)
df17_callsign = modes.callsign_encode(row['capability'], row['icao'], row['callsign'])
ppm = PPM()
df17_array_position = ppm.frame_1090es_ppm_modulate(df17_pos_even, df17_pos_odd)
df17_array_velocity = ppm.frame_1090es_ppm_modulate(df17_velocity, df17_velocity)
df17_array_callsign = ppm.frame_1090es_ppm_modulate(df17_callsign, df17_callsign)
hackrf = HackRF()
#Position
samples_array = hackrf.hackrf_raw_IQ_format(df17_array_position)
samples = samples+samples_array
gap_array = ppm.addGap(arguments.intermessagegap)
samples_array = hackrf.hackrf_raw_IQ_format(gap_array)
samples = samples+samples_array
#Velocity
samples_array = hackrf.hackrf_raw_IQ_format(df17_array_velocity)
samples = samples+samples_array
gap_array = ppm.addGap(arguments.intermessagegap)
samples_array = hackrf.hackrf_raw_IQ_format(gap_array)
samples = samples+samples_array
#Callsign
samples_array = hackrf.hackrf_raw_IQ_format(df17_array_callsign)
samples = samples+samples_array
gap_array = ppm.addGap(arguments.intermessagegap)
samples_array = hackrf.hackrf_raw_IQ_format(gap_array)
samples = samples+samples_array
return samples
def writeOutputFile(filename, data):
tmpfile = '%s.tmp'%(filename)
logger.info('Writing %s file'%(tmpfile))
SamplesFile = open(tmpfile, 'wb') SamplesFile = open(tmpfile, 'wb')
SamplesFile.write(data) SamplesFile.write(data)
SamplesFile.close() SamplesFile.close()
os.system('sync') os.system('sync')
os.system('rm %s' % (filename)) os.system('rm -rf %s' % (self.outputfilename))
logger.info('dd for file: %s' % (filename)) os.system("dd if=%s of=%s bs=4k seek=63 > /dev/null 2>&1" % (tmpfile, self.outputfilename))
os.system("dd if=%s of=%s bs=4k seek=63 > /dev/null 2>&1" % (tmpfile, filename))
os.system('sync') os.system('sync')
os.system('rm %s'%(tmpfile)) os.system('rm %s'%(tmpfile))
def usage(msg=False):
if msg:print(msg)
print("Usage: %s [options]\n" % sys.argv[0])
print("-h | --help Display help message.")
print("-i | --icao <opt> Callsign in hex, Default:0x75008F")
print("--lat <opt> Latitude for the plane in decimal degrees..")
print("--long <opt> Longitude for the place in decimal degrees.")
print("-a | --altitude <opt> Altitude in decimal feet, Default:27000.0")
print("-s | --speed <opt> Airspeed in decimal kph, Default:300")
print("-v | --vspeed <opt> Vertical speed, Default:0")
print("-b | --bearing <opt> Bearing in decimal degrees. Default:0")
print("-c | --callsign <opt> Callsign (8 chars max), Default:pynny")
print("-t | --time <opt> 0 indicates time not synchronous with UTC, Default:0")
print("-r | --repeats <opt> Number of tx repeats, Default:1")
print("-o | --output <opt> iq8s output filename. Default:Samples_256K.iq8s")
print("--capability <opt> Capability, Default:5")
print("--typecode <opt> ADS-B message type, Default:11")
print("--sstatus <opt> Surveillance status, Default:0")
print("--nicsupplementb <opt> NIC supplement-B, Default:0")
print("--intermessagegap <opt> Delay between csv output(microSec), Default:99564")
print("--surface Aircraft located on ground, Default:False")
print("")
sys.exit(2)
def main(): def main():
global cfg alt,lat,lon,capability,imgap,nicsup,rp,gnd,sstat,tc,icao,callsign,time,filename,speed,vspeed,heading = \
cfg = configparser.ConfigParser() 27000,38.919909,-75.5884171,5,99564,0,1,False,0,11,'0x75008F','pynny',0,'Samples_256K.iq8s',300,0,0
cfg.read('config.cfg') try:
(opts, args) = getopt(sys.argv[1:], 'hi:a:s:v:b:c:t:r:o:', \
['help','icao=','lat=','long=','altitude=','speed=','vspeed=','bearing=','callsign=',
'time=','repeats=','output=','surface','capability=','typecode=','sstatus=',
'nicsupplementb=','intermessagegap='])
except GetoptError as err:
usage("%s\n" % err)
if len(opts) != 0:
for (opt, arg) in opts:
if opt in ('-h', '--help'):usage()
elif opt in ('-a', '--altitude'):alt = arg
elif opt in ('--lat'):lat = arg
elif opt in ('--long'):lon = arg
elif opt in ('-i', '--icao'):icao = arg
elif opt in ('-s', '--speed'):speed = arg
elif opt in ('-v', '--vspeed'):vspeed = arg
elif opt in ('-b', '--bearing'):heading = arg
elif opt in ('-c', '--callsign'):callsign = arg
elif opt in ('-t', '--time'):time = arg
elif opt in ('-r', '--repeats'):repeats = arg
elif opt in ('-o', '--output'):filename = arg
elif opt in ('--capability'):capability = arg
elif opt in ('--typecode'):tc = arg
elif opt in ('--sstatus'):sstat = arg
elif opt in ('--nicsupplementb'):nicsup = arg
elif opt in ('--intermessagegap'):imgap = arg
elif opt in ('--surface'):gnd = True
else:usage("Unknown option %s\n" % opt)
arguments = argParser() encoder = ADSB_Encoder()
encoder._set_vars(alt,lat,lon,capability,imgap,nicsup,rp,gnd,sstat,tc,icao,callsign,time,filename,speed,vspeed,heading)
global logger #attrs = vars(encoder)
logging.config.fileConfig('logging.cfg') #print(', '.join("%s: %s" % item for item in attrs.items()))
logger = logging.getLogger(__name__)
logger.info('Starting ADSB Encoder')
logger.debug('The arguments: %s' % (arguments))
data = None
if arguments.csvfile == '':
data = singlePlane(arguments)
else:
data = manyPlanes(arguments)
writeOutputFile(arguments.outputfilename, data)
logger.info('Complete')
def threadingCSV(csv): data = encoder.encode()
global cfg encoder.writeOutputFile(data)
cfg = configparser.ConfigParser()
cfg.read('config.cfg')
arguments = argParser()
arguments.csvfile = csv['csv']
arguments.outputfilename = csv['out']
global logger
logging.config.fileConfig('logging.cfg')
logger = logging.getLogger(__name__)
logger.info('Starting ADSB Encoder threadingCSV entry point')
logger.debug('Being called with the following CSV file: %s' % (arguments.csvfile))
logger.debug('The arguments: %s' % (arguments))
data = None
if arguments.csvfile == '':
data = singlePlane(arguments)
else:
data = manyPlanes(arguments)
writeOutputFile(arguments.outputfilename, data)
logger.info('Complete')
if __name__ == "__main__": if __name__ == "__main__":
main() main()

204
route.py Executable file
View File

@ -0,0 +1,204 @@
#!/usr/bin/env python3
import sys, os
from getopt import getopt, GetoptError
from math import radians, sin, cos, sqrt, atan2, degrees, floor
from ADSB_Encoder import ADSB_Encoder
from HackRF import HackRF
from PPM import PPM
from ModeS import ModeS
def usage(msg=False):
if msg:print(msg)
print("Usage: %s [options]\n" % sys.argv[0])
print("-h | --help Display help message.")
print("-v | --verbose Show output messages.")
print("-s | --start Starting point (lat,long).")
print("-e | --end Finish point (lat,long).")
print("-i | --icao callsign in hex, Default:0x75008F")
print("-a | --altitude Starting altitude, Default:27000")
print("-f | --final_alt Final altitude, Default:altitude")
print("-p | --speed Airspeed in kph, Default:300")
print("-r | --resolution km(s) between transmissions, Default: 1")
print("-n | --name Unique name for file creation, Default:myRoute")
print("-c | --callsign Callsign, Default: pynny")
print("")
sys.exit(2)
def verify_coordinate(point):
if len(point) != 2:
usage("Point %s is incorrect length!" % str(point))
lat, lon = float(point[0]), float(point[1])
if -90 <= lat <= 90 and -180 <= lon <= 180:
return (lat,lon)
elif -90 <= lon <= 90 and -180 <= lat <= 180:
usage("Point %s is probably reversed!" % str(point))
else:
usage("Point %s Cannot be interpreted!" % str(point))
def get_distance(start_point, end_point, R=6371.0088):
lat1, lon1 = start_point
lat2, lon2 = end_point
dlat = radians(lat2-lat1)
dlon = radians(lon2-lon1)
a = sin(dlat/2) * sin(dlat/2) + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2) * sin(dlon/2)
c = 2 * atan2(sqrt(a), sqrt(1-a))
return R * c
def intermediate_point(p1, p2, f=0.5):
R = 6371008.8
lat1, lon1 = radians(p1[0]), radians(p1[1])
lat2, lon2 = radians(p2[0]), radians(p2[1])
d = get_distance(p1, p2) / R
a = sin((1 - f) * d) / sin(d)
b = sin(f * d) / sin(d)
x = a * cos(lat1) * cos(lon1) + b * cos(lat2) * cos(lon2)
y = a * cos(lat1) * sin(lon1) + b * cos(lat2) * sin(lon2)
z = a * sin(lat1) + b * sin(lat2)
lat3 = degrees(atan2(z, sqrt(x * x + y * y)))
lon3 = degrees(atan2(y, x))
return (lat3, lon3)
def init_bearing(p1, p2):
lat1, lon1 = radians(p1[0]), radians(p1[1])
lat2, lon2 = radians(p2[0]), radians(p2[1])
x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1)
y = sin(lon2 - lon1) * cos(lat2)
course = atan2(y, x)
return degrees(course)
def final_bearing(p1, p2):
return (init_bearing(p2, p1) + 180) % 360
def main(argv=None):
start,end,icao,alt,speed,name,resolution,falt,callsign,verbose = False,False,False,False,False,False,False,False,False,False
try:
(opts, args) = getopt(sys.argv[1:], 'hvs:e:i:a:p:n:r:f:c:', \
['help','verbose','start=','end=','icao=','altitude=','speed=','name=','resolution=','final_alt=','callsign='])
except GetoptError as err:
usage("%s\n" % err)
if len(opts) != 0:
for (opt, arg) in opts:
if opt in ('-h', '--help'):
usage()
elif opt in ('-v', '--verbose'):
verbose = True
elif opt in ('-s', '--start'):
start = arg
elif opt in ('-e', '--end'):
end = arg
elif opt in ('-i', '--icao'):
icao = arg
elif opt in ('-a', '--altitude'):
alt = float(arg)
elif opt in ('-f', '--final_alt'):
falt = float(arg)
elif opt in ('-p', '--speed'):
speed = arg
elif opt in ('-n', '--name'):
name = arg
elif opt in ('-c', '--callsign'):
callsign = arg
elif opt in ('-r', '--resolution'):
resolution = float(arg)
else:
usage("Unknown option %s\n" % opt)
else:
usage()
if not name:name = 'myRoute'
if not icao:icao = '0x75008F'
if not alt:alt = 27000
if not start:usage("Starting point required.")
if not end:usage("Finish point required.")
if not resolution:resolution = 1
if not falt:falt = alt
if not callsign:callsign = 'pynny'
if not speed:speed = 300
sCrd = verify_coordinate((start.split(',')[0],start.split(',')[1]))
eCrd = verify_coordinate((end.split(',')[0],end.split(',')[1]))
distance = get_distance(sCrd,eCrd)
div = 1 / floor(distance/resolution)
if os.path.isdir(name):usage("Route directory '%s' already exists" % name)
os.mkdir(name)
file = open("%s/tx_samples.py"%name,"w+")
baseCmd1,baseCmd2 = "hackrf_transfer -t "," -f 1090000000 -s 2000000 -x 20"
file.write("#!/usr/bin/env python3\n\r")
file.write("from os import system\n\r")
file.write("import threading, time\n\n\r")
i, mark = 0, floor(distance/resolution)
interval = floor(((distance / mark) * 3600000) / float(speed))
file.write("tx_interval = %s\n\n\r"%interval)
file.write("def txCmd(name):\n\r")
file.write("\tsystem(\"%s\"+name+\"%s\")\n\r"%(baseCmd1,baseCmd2))
file.write("\t#print(\"%s\"+name+\"%s\")\n\n\r"%(baseCmd1,baseCmd2))
file.write("smpFiles = (")
coords = []
while i < mark:
curLocation = intermediate_point(sCrd,eCrd,((1 / mark) * i))
curAltitude = int(alt + ((falt - alt) * ((1 / mark) * i)))
filename = "%s_sample_%s.iq8s" % (name, i)
command = "ADSB_Encoder.py --lat %s --lon %s -a %s -r 2 --callsign %s -i %s -o %s/%s" % \
(curLocation[0],curLocation[1],curAltitude,callsign,icao,name,filename)
coords.append([curLocation[0],curLocation[1],curAltitude,filename])
file.write("'%s'"%filename)
i+=1
if i < mark:file.write(",")
file.write(")\n\n\r")
file.write("ticker = threading.Event()\n\r")
file.write("cur = 1\n\r")
file.write("txCmd(smpFiles[0])\n\r")
file.write("while not ticker.wait(float(tx_interval/1000)):\n\r")
file.write("\ttxCmd(smpFiles[cur])\n\r")
file.write("\tcur +=1\n\r")
file.write("\tif cur == len(smpFiles):break\n\n\r")
file.close()
os.chmod("%s/tx_samples.py"%name,0o755)
print("Transmit script written %s/tx_samples.py"%name)
encoder = ADSB_Encoder()
for i,coord in enumerate(coords):
if i == (len(coords) - 1):coords[i].append(round(final_bearing((coords[i-1][0],coords[i-1][1]),(coord[0],coord[1]))))
else:coords[i].append(round(init_bearing((coord[0],coord[1]),(coords[i+1][0],coords[i+1][1]))))
curName = "%s/%s" % (name,coord[3])
encoder._set_vars(coord[2],coord[0],coord[1],5,99564,0,2,False,0,11,icao,callsign,0,curName,speed,0,coord[4])
print("Encoding %s of %s" % (i+1, len(coords)))
data = encoder.encode()
print("Writing %s/%s" % (name,coord[3]))
encoder.writeOutputFile(data)
if __name__ == "__main__":
main()