Merge branch 'master' of github.com:nzkarit/ADSB-out-private into csv

This commit is contained in:
nzkarit 2017-09-12 23:18:36 +12:00
commit b1743151f9
5 changed files with 135 additions and 46 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
*.iq8s
*.pyc
*.log
*.log*

View File

@ -10,6 +10,7 @@ import configparser
import logging
import logging.config
import os
import csv
###############################################################
@ -35,9 +36,16 @@ import os
def auto_int(x):
"""Parses HEX into for argParser"""
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:
raise argparse.ArgumentTypeError('Boolean value expected.')
def argParser():
#TODO add some contraint checking
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 loggin 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. Default: %(default)s')
@ -49,11 +57,84 @@ def argParser():
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 ADSB messages. More info would be appreciate). 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 ADSB messages. More info would be appreciate). Default: %(default)s')
parser.add_argument('--time', action='store', type=int, dest='time', default=cfg.getint('plane', 'time'), help='The time. (Think this is always 0 from ADSB messages. More info would be appreciate). Default: %(default)s')
parser.add_argument('-s', '--surface', action='store', default=cfg.getboolean('plane', 'surface'), type=bool, dest='surface', help='If the plane is on the ground or not. 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')
# TODO Make it so it can do a static checksum
# TODO Get pause between messages
# TODO Get pause between repeats
# TODO Do a pause function
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()
for i in range(0, arguments.repeats):
modes = ModeS()
(df17_even, df17_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)
ppm = PPM()
df17_array = ppm.frame_1090es_ppm_modulate(df17_even, df17_odd)
hackrf = HackRF()
samples_array = hackrf.hackrf_raw_IQ_format(df17_array)
samples = samples+samples_array
return samples
def manyPlanes(arguments):
logger.info('Processing CSV file')
logger.info('Repeating the message %s times' % (arguments.repeats))
samples = bytearray()
print(arguments.repeats)
for i in range(0, arguments.repeats):
with open(arguments.csvfile, newline='') as csvfile:
reader = csv.DictReader(csvfile, delimiter=',')
for row in reader:
if not 'icao' in row.keys():
row['icao'] = arguments.icao
row['icao'] = int(row['icao'], 0)
if not 'latitude' in row.keys():
row['latitude'] = arguments.latitude
if not 'longitude' in row.keys():
row['longitude'] = arguments.longitude
if not 'altitude' in row.keys():
row['altitude'] = arguments.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
logger.debug('Row from CSV: %s' % (row))
print(row)
modes = ModeS()
(df17_even, df17_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'])
ppm = PPM()
df17_array = ppm.frame_1090es_ppm_modulate(df17_even, df17_odd)
hackrf = HackRF()
samples_array = hackrf.hackrf_raw_IQ_format(df17_array)
samples = samples+samples_array
return samples
def writeOutputFile(filename, data):
SamplesFile = open('tmp.iq8s', 'wb')
SamplesFile.write(data)
SamplesFile.close()
os.system('sync')
os.system('rm %s' % (filename))
os.system("dd if=tmp.iq8s of=%s bs=4k seek=63" % (filename)) # TODO redirect output to /dev/null
os.system('sync')
os.system('rm tmp.iq8s')
if __name__ == "__main__":
global cfg
@ -67,24 +148,12 @@ if __name__ == "__main__":
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('Repeating the message %s times' % (arguments.repeats))
SamplesFile = open('tmp.iq8s', 'wb')
for i in range(0, arguments.repeats):
modes = ModeS()
(df17_even, df17_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)
ppm = PPM()
df17_array = ppm.frame_1090es_ppm_modulate(df17_even, df17_odd)
hackrf = HackRF()
samples_array = hackrf.hackrf_raw_IQ_format(df17_array)
SamplesFile.write(samples_array)
SamplesFile.close()
os.system('sync')
os.system("dd if=tmp.iq8s of=%s bs=4k seek=63" % (arguments.outputfilename)) # TODO redirect output to /dev/null
os.system('sync')
os.system('rm tmp.iq8s')

View File

@ -1,3 +1,5 @@
Firstly if you use this code or are doing anything with ADS-B broadcast, I would be interested in hearing what you are up to. Get in touch on @nzkarit on twitter or adsb (AT) karit [dot] nz
# "ADS-B Out" add-on for SoftRF-Emu, Stratux, etc...
This repository contains "ADS-B Out" encoder for Tx-capable SDR hardware.
@ -11,59 +13,73 @@ The source code is published for academic purpose only.
## Instructions
1. Execute *ADSB_Encoder.py* all the options have defaults so none are needed to generate with defaults. Running help will show you the optiosn you can change:
```
$ ADSB_Encoder.py
$ ./ADSB_Encoder.py
$ ADSB_Encoder.py -h
Usage: ADSB_Encoder.py [options]
$ ./ADSB_Encoder.py -h
usage: ADSB_Encoder.py [-h] [-i ICAO] [--lat LATITUDE] [--lon LONGITUDE]
[-a ALTITUDE] [--ca CAPABILITY] [--tc TYPECODE]
[--ss SURVEILLANCESTATUS] [--nicsb NICSUPPLEMENTB]
[--time TIME] [-s SURFACE] [-o OUTPUTFILENAME]
[-r REPEATS] [--csv CSVFILE]
Options:
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 loggin config changed in
logging.cfg.
optional arguments:
-h, --help show this help message and exit
-i ICAO, --icao=ICAO The ICAO number for the plane in hex. Ensure the ICAO
-i ICAO, --icao ICAO The ICAO number for the plane in hex. Ensure the ICAO
is prefixed with '0x' to ensure this is parsed as a
hex number. Default: 0xABCDEF
--lat=LATITUDE, --latitude=LATITUDE
--lat LATITUDE, --latitude LATITUDE
Latitude for the plane in decminal degrees. Default:
12.34
--lon=LONGITUDE, --long=LONGITUDE, --longitude=LONGITUDE
--lon LONGITUDE, --long LONGITUDE, --longitude LONGITUDE
Longitude for the place in decminal degrees. Default:
56.78
-a ALTITUDE, --alt=ALTITUDE, --altitude=ALTITUDE
-a ALTITUDE, --alt ALTITUDE, --altitude ALTITUDE
Altitude in decminal feet. Default: 9876.5
--ca=CAPABILITY, --capability=CAPABILITY
--ca CAPABILITY, --capability CAPABILITY
The capability. (Think this is always 5 from ADSB
messages. More info would be appreciate). Default: 5
--tc=TYPECODE, --typecode=TYPECODE
messages. More info would be appreciate). Default: 5
--tc TYPECODE, --typecode TYPECODE
The type for the ADSB messsage. See https://adsb-
decode-guide.readthedocs.io/en/latest/content/introduc
tion.html#ads-b-message-types for more information.
Default: 11
--ss=SURVEILLANCESTATUS, --surveillancestatus=SURVEILLANCESTATUS
--ss SURVEILLANCESTATUS, --surveillancestatus SURVEILLANCESTATUS
The surveillance status. (Think this is always 0 from
ADSB messages. More info would be appreciate).
Default: 0
--nicsb=NICSUPPLEMENTB, --nicsupplementb=NICSUPPLEMENTB
The NIC supplement-B.(Think this is always 0 from
ADSB messages. More info would be appreciate).
Default: 0
--time=TIME The time. (Think this is always 0 from ADSB messages.
More info would be appreciate). Default: 0
-s SURFACE, --surface=SURFACE
--nicsb NICSUPPLEMENTB, --nicsupplementb NICSUPPLEMENTB
The NIC supplement-B.(Think this is always 0 from ADSB
messages. More info would be appreciate). Default: 0
--time TIME The time. (Think this is always 0 from ADSB messages.
More info would be appreciate). Default: 0
-s SURFACE, --surface SURFACE
If the plane is on the ground or not. Default: False
-o OUTPUTFILENAME, --out=OUTPUTFILENAME, --output=OUTPUTFILENAME
-o OUTPUTFILENAME, --out OUTPUTFILENAME, --output OUTPUTFILENAME
The iq8s output filename. This is the file which you
will feed into the hackRF. Default: Samples_256K.iq8s
-r REPEATS, --repeats REPEATS
How many repeats of the data to perform. Default: 1
--csv CSVFILE, --csvfile CSVFILE, --in CSVFILE, --input CSVFILE
Import a CSV file with the plane data in it. Default:
```
2. Transmit the signal into air:
```
$ hackrf_transfer -t Samples_256K.iq8s -f 868000000 -s 2000000 -x 10
$ hackrf_transfer -t Samples_256K.iq8s -f 915000000 -s 2000000 -x 10
call hackrf_sample_rate_set(2000000 Hz/2.000 MHz)
call hackrf_baseband_filter_bandwidth_set(1750000 Hz/1.750 MHz)
call hackrf_set_freq(868000000 Hz/868.000 MHz)
call hackrf_set_freq(915000000 Hz/915.000 MHz)
Stop with Ctrl-C
3.9 MiB / 1.000 sec = 3.9 MiB/second
0.5 MiB / 1.000 sec = 0.5 MiB/second
User cancel, exiting...
Total time: 1.00038 s
Total time: 2.00039 s
hackrf_stop_tx() done
hackrf_close() done
hackrf_exit() done
@ -77,7 +93,7 @@ $
* -x is the gain
## Validation
```
$ sudo dump1090 --net --freq 868000000
$ sudo ./dump1090 --net --freq 915000000
...
```
![](https://github.com/lyusupov/ADSB-Out/raw/master/documents/images/dump1090.JPG)

View File

@ -1,6 +1,7 @@
[general]
outputfilename = Samples_256K.iq8s
repeats = 1
csvfile =
[plane]
icao = 0xABCDEF

3
example.csv Normal file
View File

@ -0,0 +1,3 @@
icao,altitude
0x123456,50000
0xABCDEF,1000
1 icao altitude
2 0x123456 50000
3 0xABCDEF 1000