mirror of
https://github.com/30hours/blah2.git
synced 2024-11-18 12:33:58 +00:00
Making some changes v1
This commit is contained in:
commit
3738f78eee
29 changed files with 2506 additions and 1789 deletions
|
@ -3,39 +3,40 @@
|
||||||
# ubuntu-22.04 by default
|
# ubuntu-22.04 by default
|
||||||
ARG VARIANT="jammy"
|
ARG VARIANT="jammy"
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT}
|
FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT}
|
||||||
|
LABEL maintainer="30hours <nathan@30hours.dev>"
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
# Feel like this shouldn't be needed but it drops me in / during build
|
|
||||||
WORKDIR /workspace
|
|
||||||
|
|
||||||
RUN apt-get update \
|
WORKDIR /blah2
|
||||||
#
|
ADD lib lib
|
||||||
# Install dev tools and package dependencies
|
RUN apt-get update && apt-get install -y software-properties-common \
|
||||||
&& apt-get install -y clang-tidy clang-format doxygen graphviz gfortran \
|
&& apt-add-repository ppa:ettusresearch/uhd \
|
||||||
libfftw3-dev liblapack-dev libopenblas-dev libudev-dev libusb-1.0.0-dev \
|
&& apt-get update \
|
||||||
#
|
&& DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install -y \
|
||||||
# Clean up
|
g++ make cmake git curl zip unzip doxygen graphviz \
|
||||||
|
libfftw3-dev pkg-config gfortran \
|
||||||
|
libuhd-dev=4.6.0.0-0ubuntu1~jammy1 \
|
||||||
|
uhd-host=4.6.0.0-0ubuntu1~jammy1 \
|
||||||
&& apt-get autoremove -y \
|
&& apt-get autoremove -y \
|
||||||
&& apt-get clean -y \
|
&& apt-get clean -y \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Install dependencies from vcpkg
|
# install dependencies from vcpkg
|
||||||
RUN vcpkg integrate install \
|
RUN git clone https://github.com/microsoft/vcpkg /opt/vcpkg \
|
||||||
&& vcpkg install catch2 \
|
&& /opt/vcpkg/bootstrap-vcpkg.sh
|
||||||
&& vcpkg install rapidjson \
|
ENV PATH="/opt/vcpkg:${PATH}" VCPKG_ROOT=/opt/vcpkg
|
||||||
&& vcpkg install asio \
|
RUN cd /blah2/lib && vcpkg integrate install \
|
||||||
&& vcpkg install cpp-httplib \
|
&& vcpkg install --clean-after-build
|
||||||
&& vcpkg install armadillo \
|
|
||||||
&& vcpkg install ryml
|
|
||||||
|
|
||||||
COPY lib/sdrplay-3.0.7/SDRplay_RSP_API-Linux-3.07.1.run /workspace/
|
# install SDRplay API
|
||||||
|
RUN chmod +x /blah2/lib/sdrplay-3.14.0/SDRplay_RSP_API-Linux-3.14.0.run \
|
||||||
# Install shitty sdrplay API
|
&& /blah2/lib/sdrplay-3.14.0/SDRplay_RSP_API-Linux-3.14.0.run --tar -xvf -C /blah2/lib/sdrplay-3.14.0 \
|
||||||
RUN chmod +x /workspace/SDRplay_RSP_API-Linux-3.07.1.run \
|
&& cp /blah2/lib/sdrplay-3.14.0/x86_64/libsdrplay_api.so.3.14 /usr/local/lib/libsdrplay_api.so \
|
||||||
&& /workspace/SDRplay_RSP_API-Linux-3.07.1.run --tar -xf \
|
&& cp /blah2/lib/sdrplay-3.14.0/x86_64/libsdrplay_api.so.3.14 /usr/local/lib/libsdrplay_api.so.3.14 \
|
||||||
&& cp x86_64/libsdrplay_api.so.3.07 /usr/local/lib/libsdrplay_api.so \
|
&& cp /blah2/lib/sdrplay-3.14.0/inc/* /usr/local/include \
|
||||||
&& ln -s /usr/local/lib/libsdrplay_api.so /usr/local/lib/libsdrplay_api.so.3.07 \
|
&& chmod 644 /usr/local/lib/libsdrplay_api.so /usr/local/lib/libsdrplay_api.so.3.14 \
|
||||||
&& cp inc/* /usr/local/include \
|
|
||||||
&& chmod 644 /usr/local/lib/libsdrplay_api.so /usr/local/lib/libsdrplay_api.so.3.07 \
|
|
||||||
&& ldconfig
|
&& ldconfig
|
||||||
|
|
||||||
|
# install UHD API
|
||||||
|
RUN uhd_images_downloader
|
||||||
|
|
||||||
|
|
|
@ -1 +1,23 @@
|
||||||
# todo: write readme on using devcontainer with dev-release
|
# todo: currently not working
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Install a recent `nodejs` using [nvm](https://github.com/nvm-sh/nvm).
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
|
||||||
|
nvm install node 21.6.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Install the latest [devcontainer CLI](https://code.visualstudio.com/docs/devcontainers/devcontainer-cli).
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install -g @devcontainers/cli
|
||||||
|
devcontainer --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the devcontainer.
|
||||||
|
|
||||||
|
```
|
||||||
|
devcontainer up --workspace-folder .
|
||||||
|
```
|
|
@ -1,5 +1,7 @@
|
||||||
version: "3.2"
|
version: "3.2"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
blah2-dev:
|
blah2-dev:
|
||||||
user: vscode
|
user: vscode
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -35,7 +35,7 @@ include_directories(src ${UHD_INCLUDE_DIRS})
|
||||||
# TODO: create FindSdrplay.cmake for this
|
# TODO: create FindSdrplay.cmake for this
|
||||||
add_library(sdrplay /usr/local/include/sdrplay_api.h)
|
add_library(sdrplay /usr/local/include/sdrplay_api.h)
|
||||||
set_target_properties(sdrplay PROPERTIES LINKER_LANGUAGE C)
|
set_target_properties(sdrplay PROPERTIES LINKER_LANGUAGE C)
|
||||||
target_link_libraries(sdrplay PUBLIC /usr/local/lib/libsdrplay_api.so.3.12)
|
target_link_libraries(sdrplay PUBLIC /usr/local/lib/libsdrplay_api.so.3.14)
|
||||||
|
|
||||||
add_executable(blah2
|
add_executable(blah2
|
||||||
src/blah2.cpp
|
src/blah2.cpp
|
||||||
|
|
13
Dockerfile
13
Dockerfile
|
@ -1,5 +1,6 @@
|
||||||
FROM ubuntu:22.04 as blah2_env
|
FROM ubuntu:22.04 as blah2_env
|
||||||
LABEL maintainer="30hours <nathan@30hours.dev>"
|
LABEL maintainer="30hours <nathan@30hours.dev>"
|
||||||
|
LABEL org.opencontainers.image.source https://github.com/30hours/blah2
|
||||||
|
|
||||||
WORKDIR /blah2
|
WORKDIR /blah2
|
||||||
ADD lib lib
|
ADD lib lib
|
||||||
|
@ -23,12 +24,12 @@ RUN cd /blah2/lib && vcpkg integrate install \
|
||||||
&& vcpkg install --clean-after-build
|
&& vcpkg install --clean-after-build
|
||||||
|
|
||||||
# install SDRplay API
|
# install SDRplay API
|
||||||
RUN chmod +x /blah2/lib/sdrplay-3.12.1/SDRplay_RSP_API-Linux-3.12.1.run \
|
RUN chmod +x /blah2/lib/sdrplay-3.14.0/SDRplay_RSP_API-Linux-3.14.0.run \
|
||||||
&& /blah2/lib/sdrplay-3.12.1/SDRplay_RSP_API-Linux-3.12.1.run --tar -xvf -C /blah2/lib/sdrplay-3.12.1 \
|
&& /blah2/lib/sdrplay-3.14.0/SDRplay_RSP_API-Linux-3.14.0.run --tar -xvf -C /blah2/lib/sdrplay-3.14.0 \
|
||||||
&& cp /blah2/lib/sdrplay-3.12.1/x86_64/libsdrplay_api.so.3.12 /usr/local/lib/libsdrplay_api.so \
|
&& cp /blah2/lib/sdrplay-3.14.0/x86_64/libsdrplay_api.so.3.14 /usr/local/lib/libsdrplay_api.so \
|
||||||
&& cp /blah2/lib/sdrplay-3.12.1/x86_64/libsdrplay_api.so.3.12 /usr/local/lib/libsdrplay_api.so.3.12 \
|
&& cp /blah2/lib/sdrplay-3.14.0/x86_64/libsdrplay_api.so.3.14 /usr/local/lib/libsdrplay_api.so.3.14 \
|
||||||
&& cp /blah2/lib/sdrplay-3.12.1/inc/* /usr/local/include \
|
&& cp /blah2/lib/sdrplay-3.14.0/inc/* /usr/local/include \
|
||||||
&& chmod 644 /usr/local/lib/libsdrplay_api.so /usr/local/lib/libsdrplay_api.so.3.12 \
|
&& chmod 644 /usr/local/lib/libsdrplay_api.so /usr/local/lib/libsdrplay_api.so.3.14 \
|
||||||
&& ldconfig
|
&& ldconfig
|
||||||
|
|
||||||
# install UHD API
|
# install UHD API
|
||||||
|
|
40
Jenkinsfile
vendored
Normal file
40
Jenkinsfile
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
environment {
|
||||||
|
GHCR_REGISTRY = "ghcr.io"
|
||||||
|
GHCR_TOKEN = credentials('ghcr-login')
|
||||||
|
BLAH2_NAME = "30hours/blah2"
|
||||||
|
BLAH2_API_NAME = "30hours/blah2_api"
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
echo 'Building the project'
|
||||||
|
sh 'docker build -t $BLAH2_NAME .'
|
||||||
|
sh 'docker build -t $BLAH2_API_NAME --file ./api/Dockerfile ./api'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Test') {
|
||||||
|
steps {
|
||||||
|
echo 'Running tests'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Push') {
|
||||||
|
steps {
|
||||||
|
sh 'echo $GHCR_TOKEN_PSW | docker login ghcr.io -u $GHCR_TOKEN_USR --password-stdin'
|
||||||
|
sh 'docker tag $BLAH2_NAME ghcr.io/$BLAH2_NAME'
|
||||||
|
sh 'docker tag $BLAH2_API_NAME ghcr.io/$BLAH2_API_NAME'
|
||||||
|
sh 'docker push ghcr.io/$BLAH2_NAME'
|
||||||
|
sh 'docker push ghcr.io/$BLAH2_API_NAME'
|
||||||
|
sh 'docker logout'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,8 +33,8 @@ The build environment consists of a docker-compose.yml file running the followin
|
||||||
sudo git clone http://github.com/30hours/blah2 /opt/blah2
|
sudo git clone http://github.com/30hours/blah2 /opt/blah2
|
||||||
cd /opt/blah2
|
cd /opt/blah2
|
||||||
vim config/config.yml
|
vim config/config.yml
|
||||||
./lib/sdrplay-3.12.1/SDRplay_RSP_API-Linux-3.12.1.run --tar -xvf -C ./lib/sdrplay-3.12.1
|
./lib/sdrplay-3.14.0/SDRplay_RSP_API-Linux-3.14.0.run --tar -xvf -C ./lib/sdrplay-3.14.0
|
||||||
./lib/sdrplay-3.12.1/install_lib.sh
|
./lib/sdrplay-3.14.0/install_lib.sh
|
||||||
sudo docker network create blah2
|
sudo docker network create blah2
|
||||||
sudo systemctl enable docker
|
sudo systemctl enable docker
|
||||||
sudo docker compose up -d
|
sudo docker compose up -d
|
||||||
|
@ -61,6 +61,8 @@ The radar processing output is available on [http://localhost:49152](http://loca
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
Join the [Discord](https://discord.gg/ewNQbeK5Zn) chat for sharing results and support.
|
||||||
|
|
||||||
Pull requests are welcome - especially for adding support for a new SDR.
|
Pull requests are welcome - especially for adding support for a new SDR.
|
||||||
|
|
||||||
- Currently have an issue where the USRP B210 is timing out after 5-10 mins and crashes the code. Convinced it's an issue with my usage of the API - email me for more info.
|
- Currently have an issue where the USRP B210 is timing out after 5-10 mins and crashes the code. Convinced it's an issue with my usage of the API - email me for more info.
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
FROM node:16
|
FROM node:16
|
||||||
|
|
||||||
|
LABEL maintainer="30hours <nathan@30hours.dev>"
|
||||||
|
LABEL org.opencontainers.image.source https://github.com/30hours/blah2
|
||||||
|
|
||||||
# Create app directory
|
# Create app directory
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"start": "node server.js"
|
"start": "node server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.16.1"
|
"express": "^4.16.1",
|
||||||
|
"js-yaml": "^4.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const dgram = require('dgram');
|
|
||||||
const net = require("net");
|
const net = require("net");
|
||||||
|
const fs = require('fs');
|
||||||
|
const yaml = require('js-yaml');
|
||||||
|
const dns = require('dns');
|
||||||
|
|
||||||
|
// parse config file
|
||||||
|
var config;
|
||||||
|
try {
|
||||||
|
const file = process.argv[2];
|
||||||
|
config = yaml.load(fs.readFileSync(file, 'utf8'));
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error reading or parsing the YAML file:', e);
|
||||||
|
}
|
||||||
|
|
||||||
var stash_map = require('./stash/maxhold.js');
|
var stash_map = require('./stash/maxhold.js');
|
||||||
var stash_detection = require('./stash/detection.js');
|
var stash_detection = require('./stash/detection.js');
|
||||||
|
@ -9,8 +20,8 @@ var stash_timing = require('./stash/timing.js');
|
||||||
var stash_falsetargets = require('./stash/falsetargets.js');
|
var stash_falsetargets = require('./stash/falsetargets.js');
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
const PORT = 3000;
|
const PORT = config.network.ports.api;
|
||||||
const HOST = '0.0.0.0';
|
const HOST = config.network.ip;
|
||||||
var map = '';
|
var map = '';
|
||||||
var detection = '';
|
var detection = '';
|
||||||
var track = '';
|
var track = '';
|
||||||
|
@ -18,7 +29,6 @@ var timestamp = '';
|
||||||
var timing = '';
|
var timing = '';
|
||||||
var iqdata = '';
|
var iqdata = '';
|
||||||
var falsetargets = '';
|
var falsetargets = '';
|
||||||
var data = '';
|
|
||||||
var data_map;
|
var data_map;
|
||||||
var data_detection;
|
var data_detection;
|
||||||
var data_tracker;
|
var data_tracker;
|
||||||
|
@ -59,9 +69,34 @@ app.get('/api/timing', (req, res) => {
|
||||||
app.get('/api/iqdata', (req, res) => {
|
app.get('/api/iqdata', (req, res) => {
|
||||||
res.send(iqdata);
|
res.send(iqdata);
|
||||||
});
|
});
|
||||||
|
app.get('/api/adsb2dd', (req, res) => {
|
||||||
|
if (config.truth.adsb.enabled == true) {
|
||||||
|
const api_url = "https://adsb2dd.30hours.dev/api/dd";
|
||||||
|
const api_query =
|
||||||
|
api_url +
|
||||||
|
"?rx=" + config.location.rx.latitude + "," +
|
||||||
|
config.location.rx.longitude + "," +
|
||||||
|
config.location.rx.altitude +
|
||||||
|
"&tx=" + config.location.tx.latitude + "," +
|
||||||
|
config.location.tx.longitude + "," +
|
||||||
|
config.location.tx.altitude +
|
||||||
|
"&fc=" + (config.capture.fc / 1000000) +
|
||||||
|
"&server=" + "http://" + config.truth.adsb.ip;
|
||||||
|
const jsonResponse = {
|
||||||
|
url: api_query
|
||||||
|
};
|
||||||
|
res.json(jsonResponse);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.status(400).end();
|
||||||
|
}
|
||||||
|
});
|
||||||
app.get('/api/falsetargets', (req, res) => {
|
app.get('/api/falsetargets', (req, res) => {
|
||||||
res.send(falsetargets);
|
res.send(falsetargets);
|
||||||
});
|
});
|
||||||
|
app.get('/api/config', (req, res) => {
|
||||||
|
res.send(config);
|
||||||
|
});
|
||||||
|
|
||||||
// stash API
|
// stash API
|
||||||
app.get('/stash/map', (req, res) => {
|
app.get('/stash/map', (req, res) => {
|
||||||
|
@ -95,10 +130,10 @@ app.listen(PORT, HOST, () => {
|
||||||
|
|
||||||
// tcp listener map
|
// tcp listener map
|
||||||
const server_map = net.createServer((socket)=>{
|
const server_map = net.createServer((socket)=>{
|
||||||
socket.write("Hello From Server!")
|
|
||||||
socket.on("data",(msg)=>{
|
socket.on("data",(msg)=>{
|
||||||
data_map = data_map + msg.toString();
|
data_map = data_map + msg.toString();
|
||||||
if (data_map.slice(-1) === "}") {
|
if (data_map.slice(-1) === "}")
|
||||||
|
{
|
||||||
map = data_map;
|
map = data_map;
|
||||||
data_map = '';
|
data_map = '';
|
||||||
}
|
}
|
||||||
|
@ -107,14 +142,14 @@ const server_map = net.createServer((socket) => {
|
||||||
console.log("Connection closed.");
|
console.log("Connection closed.");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
server_map.listen(3001);
|
server_map.listen(config.network.ports.map);
|
||||||
|
|
||||||
// tcp listener detection
|
// tcp listener detection
|
||||||
const server_detection = net.createServer((socket)=>{
|
const server_detection = net.createServer((socket)=>{
|
||||||
socket.write("Hello From Server!")
|
|
||||||
socket.on("data",(msg)=>{
|
socket.on("data",(msg)=>{
|
||||||
data_detection = data_detection + msg.toString();
|
data_detection = data_detection + msg.toString();
|
||||||
if (data_detection.slice(-1) === "}") {
|
if (data_detection.slice(-1) === "}")
|
||||||
|
{
|
||||||
detection = data_detection;
|
detection = data_detection;
|
||||||
data_detection = '';
|
data_detection = '';
|
||||||
}
|
}
|
||||||
|
@ -123,14 +158,14 @@ const server_detection = net.createServer((socket) => {
|
||||||
console.log("Connection closed.");
|
console.log("Connection closed.");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
server_detection.listen(3002);
|
server_detection.listen(config.network.ports.detection);
|
||||||
|
|
||||||
// tcp listener tracker
|
// tcp listener tracker
|
||||||
const server_tracker = net.createServer((socket)=>{
|
const server_tracker = net.createServer((socket)=>{
|
||||||
socket.write("Hello From Server!")
|
|
||||||
socket.on("data",(msg)=>{
|
socket.on("data",(msg)=>{
|
||||||
data_tracker = data_tracker + msg.toString();
|
data_tracker = data_tracker + msg.toString();
|
||||||
if (data_tracker.slice(-1) === "}") {
|
if (data_tracker.slice(-1) === "}")
|
||||||
|
{
|
||||||
track = data_tracker;
|
track = data_tracker;
|
||||||
data_tracker = '';
|
data_tracker = '';
|
||||||
}
|
}
|
||||||
|
@ -139,11 +174,10 @@ const server_tracker = net.createServer((socket) => {
|
||||||
console.log("Connection closed.");
|
console.log("Connection closed.");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
server_tracker.listen(3003);
|
server_tracker.listen(config.network.ports.track);
|
||||||
|
|
||||||
// tcp listener timestamp
|
// tcp listener timestamp
|
||||||
const server_timestamp = net.createServer((socket)=>{
|
const server_timestamp = net.createServer((socket)=>{
|
||||||
socket.write("Hello From Server!")
|
|
||||||
socket.on("data",(msg)=>{
|
socket.on("data",(msg)=>{
|
||||||
data_timestamp = data_timestamp + msg.toString();
|
data_timestamp = data_timestamp + msg.toString();
|
||||||
timestamp = data_timestamp;
|
timestamp = data_timestamp;
|
||||||
|
@ -153,11 +187,10 @@ const server_timestamp = net.createServer((socket) => {
|
||||||
console.log("Connection closed.");
|
console.log("Connection closed.");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
server_timestamp.listen(4000);
|
server_timestamp.listen(config.network.ports.timestamp);
|
||||||
|
|
||||||
// tcp listener timing
|
// tcp listener timing
|
||||||
const server_timing = net.createServer((socket)=>{
|
const server_timing = net.createServer((socket)=>{
|
||||||
socket.write("Hello From Server!")
|
|
||||||
socket.on("data",(msg)=>{
|
socket.on("data",(msg)=>{
|
||||||
data_timing = data_timing + msg.toString();
|
data_timing = data_timing + msg.toString();
|
||||||
if (data_timing.slice(-1) === "}") {
|
if (data_timing.slice(-1) === "}") {
|
||||||
|
@ -169,11 +202,10 @@ const server_timing = net.createServer((socket) => {
|
||||||
console.log("Connection closed.");
|
console.log("Connection closed.");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
server_timing.listen(4001);
|
server_timing.listen(config.network.ports.timing);
|
||||||
|
|
||||||
// tcp listener iqdata metadata
|
// tcp listener iqdata metadata
|
||||||
const server_iqdata = net.createServer((socket)=>{
|
const server_iqdata = net.createServer((socket)=>{
|
||||||
socket.write("Hello From Server!")
|
|
||||||
socket.on("data",(msg)=>{
|
socket.on("data",(msg)=>{
|
||||||
data_iqdata = data_iqdata + msg.toString();
|
data_iqdata = data_iqdata + msg.toString();
|
||||||
if (data_iqdata.slice(-1) === "}") {
|
if (data_iqdata.slice(-1) === "}") {
|
||||||
|
@ -185,7 +217,8 @@ const server_iqdata = net.createServer((socket) => {
|
||||||
console.log("Connection closed.");
|
console.log("Connection closed.");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
server_iqdata.listen(4002);
|
server_iqdata.listen(config.network.ports.iqdata);
|
||||||
|
|
||||||
|
|
||||||
// tcp listener falsetargets
|
// tcp listener falsetargets
|
||||||
const server_falsetargets = net.createServer((socket) => {
|
const server_falsetargets = net.createServer((socket) => {
|
||||||
|
@ -201,4 +234,4 @@ const server_falsetargets = net.createServer((socket) => {
|
||||||
console.log("Connection closed.");
|
console.log("Connection closed.");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
server_falsetargets.listen(4003);
|
server_falsetargets.listen(4004);
|
||||||
|
|
|
@ -14,13 +14,15 @@ process:
|
||||||
buffer: 1.5
|
buffer: 1.5
|
||||||
overlap: 0
|
overlap: 0
|
||||||
ambiguity:
|
ambiguity:
|
||||||
delayMin: -10 # bins
|
# delay in bins
|
||||||
delayMax: 400 # bins
|
delayMin: -10
|
||||||
dopplerMin: -200 # Hz
|
delayMax: 400
|
||||||
dopplerMax: 200 # Hz
|
# Doppler in Hz
|
||||||
|
dopplerMin: -200
|
||||||
|
dopplerMax: 200
|
||||||
clutter:
|
clutter:
|
||||||
delayMin: -10 # bins
|
delayMin: -10
|
||||||
delayMax: 400 # bins
|
delayMax: 400
|
||||||
detection:
|
detection:
|
||||||
pfa: 0.00001
|
pfa: 0.00001
|
||||||
nGuard: 2
|
nGuard: 2
|
||||||
|
@ -46,18 +48,31 @@ network:
|
||||||
timestamp: 4000
|
timestamp: 4000
|
||||||
timing: 4001
|
timing: 4001
|
||||||
iqdata: 4002
|
iqdata: 4002
|
||||||
falsetargets: 4003
|
config: 4003
|
||||||
|
falsetargets: 4004
|
||||||
|
|
||||||
truth:
|
truth:
|
||||||
asdb:
|
adsb:
|
||||||
enabled: false
|
enabled: false
|
||||||
ip: 0.0.0.0
|
ip: 'adsb.30hours.dev'
|
||||||
port: 30000
|
port: 80
|
||||||
ais:
|
ais:
|
||||||
enabled: false
|
enabled: false
|
||||||
ip: 0.0.0.0
|
ip: 0.0.0.0
|
||||||
port: 30001
|
port: 30001
|
||||||
|
|
||||||
|
location:
|
||||||
|
rx:
|
||||||
|
latitude: -34.9286
|
||||||
|
longitude: 138.5999
|
||||||
|
altitude: 50
|
||||||
|
name: "Adelaide"
|
||||||
|
tx:
|
||||||
|
latitude: -34.9810
|
||||||
|
longitude: 138.7081
|
||||||
|
altitude: 750
|
||||||
|
name: "Mount Lofty"
|
||||||
|
|
||||||
save:
|
save:
|
||||||
iq: false
|
iq: false
|
||||||
map: false
|
map: false
|
||||||
|
|
|
@ -50,17 +50,30 @@ network:
|
||||||
timestamp: 4000
|
timestamp: 4000
|
||||||
timing: 4001
|
timing: 4001
|
||||||
iqdata: 4002
|
iqdata: 4002
|
||||||
|
config: 4003
|
||||||
|
|
||||||
truth:
|
truth:
|
||||||
asdb:
|
adsb:
|
||||||
enabled: false
|
enabled: false
|
||||||
ip: 0.0.0.0
|
ip: 'adsb.30hours.dev'
|
||||||
port: 30000
|
port: 80
|
||||||
ais:
|
ais:
|
||||||
enabled: false
|
enabled: false
|
||||||
ip: 0.0.0.0
|
ip: 0.0.0.0
|
||||||
port: 30001
|
port: 30001
|
||||||
|
|
||||||
|
location:
|
||||||
|
rx:
|
||||||
|
latitude: -34.9286
|
||||||
|
longitude: 138.5999
|
||||||
|
altitude: 50
|
||||||
|
name: "Adelaide"
|
||||||
|
tx:
|
||||||
|
latitude: -34.9810
|
||||||
|
longitude: 138.7081
|
||||||
|
altitude: 750
|
||||||
|
name: "Mount Lofty"
|
||||||
|
|
||||||
save:
|
save:
|
||||||
iq: true
|
iq: true
|
||||||
map: false
|
map: false
|
||||||
|
|
|
@ -46,17 +46,30 @@ network:
|
||||||
timestamp: 4000
|
timestamp: 4000
|
||||||
timing: 4001
|
timing: 4001
|
||||||
iqdata: 4002
|
iqdata: 4002
|
||||||
|
config: 4003
|
||||||
|
|
||||||
truth:
|
truth:
|
||||||
asdb:
|
adsb:
|
||||||
enabled: false
|
enabled: false
|
||||||
ip: 0.0.0.0
|
ip: 'adsb.30hours.dev'
|
||||||
port: 30000
|
port: 80
|
||||||
ais:
|
ais:
|
||||||
enabled: false
|
enabled: false
|
||||||
ip: 0.0.0.0
|
ip: 0.0.0.0
|
||||||
port: 30001
|
port: 30001
|
||||||
|
|
||||||
|
location:
|
||||||
|
rx:
|
||||||
|
latitude: -34.9286
|
||||||
|
longitude: 138.5999
|
||||||
|
altitude: 50
|
||||||
|
name: "Adelaide"
|
||||||
|
tx:
|
||||||
|
latitude: -34.9810
|
||||||
|
longitude: 138.7081
|
||||||
|
altitude: 750
|
||||||
|
name: "Mount Lofty"
|
||||||
|
|
||||||
save:
|
save:
|
||||||
iq: true
|
iq: true
|
||||||
map: false
|
map: false
|
||||||
|
|
|
@ -17,7 +17,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./config:/blah2/config
|
- ./config:/blah2/config
|
||||||
- /opt/blah2/save:/blah2/save
|
- /opt/blah2/save:/blah2/save
|
||||||
- /dev/shm:/dev/shm
|
- /dev/shm:/dev/shm:z
|
||||||
- /dev/usb:/dev/usb
|
- /dev/usb:/dev/usb
|
||||||
network_mode: host
|
network_mode: host
|
||||||
privileged: true
|
privileged: true
|
||||||
|
@ -25,7 +25,7 @@ services:
|
||||||
sh -c "/blah2/bin/blah2 -c config/config.yml"
|
sh -c "/blah2/bin/blah2 -c config/config.yml"
|
||||||
container_name: blah2
|
container_name: blah2
|
||||||
|
|
||||||
blah2_frontend:
|
blah2_web:
|
||||||
restart: always
|
restart: always
|
||||||
image: httpd:2.4
|
image: httpd:2.4
|
||||||
ports:
|
ports:
|
||||||
|
@ -40,7 +40,9 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
build: ./api
|
build: ./api
|
||||||
image: blah2_api
|
image: blah2_api
|
||||||
ports:
|
volumes:
|
||||||
- 3000:8080
|
- ./config:/usr/src/app/config
|
||||||
network_mode: host
|
network_mode: host
|
||||||
|
command: >
|
||||||
|
sh -c "node server.js /usr/src/app/config/config.yml"
|
||||||
container_name: blah2-api
|
container_name: blah2-api
|
||||||
|
|
19
host/README.md
Normal file
19
host/README.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# blah2 Host
|
||||||
|
|
||||||
|
A reverse proxy to host blah2 on the internet.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This can be used to forward the radar to the internet. The radar front-end is at `localhost:49152`, and the API is located at `localhost:3000/api/<data>`. This reverse proxy forwards `localhost:49152` to a port of your choosing, and forwards `localhost:3000` to the same port at `/api/`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
**docker-compose.yml**
|
||||||
|
|
||||||
|
- Change the output port from `8080` as desired in `docker-compose.yml`.
|
||||||
|
- The environment variable `VIRTUAL_HOST=domain.tld` is only applicable if also using [jwilder/nginx](https://github.com/nginx-proxy/nginx-proxy).
|
||||||
|
- If using [jwilder/nginx](https://github.com/nginx-proxy/nginx-proxy), ensure both containers are on the same network with `sudo docker network create <name>`. Otherwise the network configuration can be deleted.
|
||||||
|
|
||||||
|
**nginx.conf**
|
||||||
|
|
||||||
|
- Edit the `backend_ip` and `domain_name` variables in `nginx.conf`.
|
20
host/docker-compose.yml
Normal file
20
host/docker-compose.yml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
networks:
|
||||||
|
nginx-web:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
services:
|
||||||
|
httpd:
|
||||||
|
restart: always
|
||||||
|
image: nginx:1.25.2-alpine
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
- ./html:/usr/local/apache2/htdocs
|
||||||
|
environment:
|
||||||
|
- VIRTUAL_HOST=domain.tld
|
||||||
|
networks:
|
||||||
|
- nginx-web
|
||||||
|
container_name: blah2
|
1
host/html/error.html
Normal file
1
host/html/error.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
radar/down
|
58
host/nginx.conf
Normal file
58
host/nginx.conf
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
user nginx;
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
default_type application/octet-stream;
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
include /etc/nginx/conf.d/*.conf;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
|
||||||
|
set $backend_ip localhost;
|
||||||
|
set $domain_name localhost;
|
||||||
|
|
||||||
|
proxy_pass_header Content-Type;
|
||||||
|
proxy_set_header X-Real-IP $domain_name;
|
||||||
|
proxy_set_header X-Forwarded-For $domain_name;
|
||||||
|
proxy_set_header Host $domain_name;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Connection "";
|
||||||
|
proxy_connect_timeout 1;
|
||||||
|
proxy_next_upstream error timeout http_500 http_502 http_503 http_504 http_404;
|
||||||
|
proxy_intercept_errors on;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://$backend_ip:49152;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(maxhold|api|stash)/(.*) {
|
||||||
|
proxy_pass http://$backend_ip:3000/$1/$2;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 501 502 503 504 =200 /error.html;
|
||||||
|
location = /error.html {
|
||||||
|
root /usr/local/apache2/htdocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,9 @@ var range_y = [];
|
||||||
// setup API
|
// setup API
|
||||||
var urlTimestamp;
|
var urlTimestamp;
|
||||||
var urlDetection;
|
var urlDetection;
|
||||||
|
var urlAdsb;
|
||||||
|
var urlAdsbLink;
|
||||||
|
var urlConfig;
|
||||||
if (isLocalHost) {
|
if (isLocalHost) {
|
||||||
urlTimestamp = '//' + host + ':3000/api/timestamp';
|
urlTimestamp = '//' + host + ':3000/api/timestamp';
|
||||||
} else {
|
} else {
|
||||||
|
@ -23,10 +26,33 @@ if (isLocalHost) {
|
||||||
} else {
|
} else {
|
||||||
urlMap = '//' + host + urlMap;
|
urlMap = '//' + host + urlMap;
|
||||||
}
|
}
|
||||||
|
if (isLocalHost) {
|
||||||
|
urlAdsbLink = '//' + host + ':3000/api/adsb2dd';
|
||||||
|
} else {
|
||||||
|
urlAdsbLink = '//' + host + '/api/adsb2dd';
|
||||||
|
}
|
||||||
|
if (isLocalHost) {
|
||||||
|
urlConfig = '//' + host + ':3000/api/config';
|
||||||
|
} else {
|
||||||
|
urlConfig = '//' + host + '/api/config';
|
||||||
|
}
|
||||||
urlTimestamp = urlTimestamp + '?timestamp=' + Date.now();
|
urlTimestamp = urlTimestamp + '?timestamp=' + Date.now();
|
||||||
urlDetection = urlDetection + '?timestamp=' + Date.now();
|
urlDetection = urlDetection + '?timestamp=' + Date.now();
|
||||||
urlMap = urlMap + '?timestamp=' + Date.now();
|
urlMap = urlMap + '?timestamp=' + Date.now();
|
||||||
|
|
||||||
|
// get truth flag
|
||||||
|
var isTruth = false;
|
||||||
|
var configData = $.getJSON(urlConfig, function () { })
|
||||||
|
.done(function (data_config) {
|
||||||
|
if (data_config.truth.adsb.enabled === true) {
|
||||||
|
isTruth = true;
|
||||||
|
var adsbLinkData = $.getJSON(urlAdsbLink, function () { })
|
||||||
|
.done(function (data) {
|
||||||
|
urlAdsb = data.url;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// setup plotly
|
// setup plotly
|
||||||
var layout = {
|
var layout = {
|
||||||
autosize: true,
|
autosize: true,
|
||||||
|
@ -65,7 +91,8 @@ var layout = {
|
||||||
ticksuffix: ' ',
|
ticksuffix: ' ',
|
||||||
autosize: false,
|
autosize: false,
|
||||||
categoryorder: "total descending"
|
categoryorder: "total descending"
|
||||||
}
|
},
|
||||||
|
showlegend: false
|
||||||
};
|
};
|
||||||
var config = {
|
var config = {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
|
@ -82,6 +109,7 @@ var data = [
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
var detection = [];
|
var detection = [];
|
||||||
|
var adsb = {};
|
||||||
|
|
||||||
Plotly.newPlot('data', data, layout, config);
|
Plotly.newPlot('data', data, layout, config);
|
||||||
|
|
||||||
|
@ -101,6 +129,23 @@ var intervalId = window.setInterval(function () {
|
||||||
detection = data_detection;
|
detection = data_detection;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// get ADS-B data if enabled in config
|
||||||
|
if (isTruth) {
|
||||||
|
var adsbData = $.getJSON(urlAdsb, function () { })
|
||||||
|
.done(function (data_adsb) {
|
||||||
|
adsb['delay'] = [];
|
||||||
|
adsb['doppler'] = [];
|
||||||
|
adsb['flight'] = [];
|
||||||
|
for (const aircraft in data_adsb) {
|
||||||
|
if ('doppler' in data_adsb[aircraft]) {
|
||||||
|
adsb['delay'].push(data_adsb[aircraft]['delay'])
|
||||||
|
adsb['doppler'].push(data_adsb[aircraft]['doppler'])
|
||||||
|
adsb['flight'].push(data_adsb[aircraft]['flight'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// get new map data
|
// get new map data
|
||||||
var apiData = $.getJSON(urlMap, function () { })
|
var apiData = $.getJSON(urlMap, function () { })
|
||||||
.done(function (data) {
|
.done(function (data) {
|
||||||
|
@ -136,17 +181,28 @@ var intervalId = window.setInterval(function () {
|
||||||
opacity: 0.6
|
opacity: 0.6
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var trace3 = {
|
||||||
|
x: adsb.delay,
|
||||||
|
y: adsb.doppler,
|
||||||
|
mode: 'markers',
|
||||||
|
type: 'scatter',
|
||||||
|
marker: {
|
||||||
|
size: 16,
|
||||||
|
opacity: 0.6
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var data_trace = [trace1, trace2];
|
var data_trace = [trace1, trace2, trace3];
|
||||||
Plotly.newPlot('data', data_trace, layout, config);
|
Plotly.newPlot('data', data_trace, layout, config);
|
||||||
}
|
}
|
||||||
// case update plot
|
// case update plot
|
||||||
else {
|
else {
|
||||||
var trace_update = {
|
var trace_update = {
|
||||||
x: [data.delay, detection.delay],
|
x: [data.delay, detection.delay, adsb.delay],
|
||||||
y: [data.doppler, detection.doppler],
|
y: [data.doppler, detection.doppler, adsb.doppler],
|
||||||
z: [data.data, []],
|
z: [data.data, [], []],
|
||||||
zmax: [Math.max(13, data.maxPower), []]
|
zmax: [Math.max(13, data.maxPower), [], []],
|
||||||
|
text: [[], [], adsb.flight]
|
||||||
};
|
};
|
||||||
Plotly.update('data', trace_update);
|
Plotly.update('data', trace_update);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
1543
lib/sdrplay-3.14.0/SDRplay_RSP_API-Linux-3.14.0.run
Normal file
1543
lib/sdrplay-3.14.0/SDRplay_RSP_API-Linux-3.14.0.run
Normal file
File diff suppressed because it is too large
Load diff
|
@ -61,7 +61,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
// setup capture
|
// setup capture
|
||||||
uint32_t fs, fc;
|
uint32_t fs, fc;
|
||||||
std::string type, path, replayFile;
|
uint16_t port_capture;
|
||||||
|
std::string type, path, replayFile, ip_capture;
|
||||||
bool saveIq, state, loop;
|
bool saveIq, state, loop;
|
||||||
tree["capture"]["fs"] >> fs;
|
tree["capture"]["fs"] >> fs;
|
||||||
tree["capture"]["fc"] >> fc;
|
tree["capture"]["fc"] >> fc;
|
||||||
|
@ -71,6 +72,8 @@ int main(int argc, char **argv)
|
||||||
tree["capture"]["replay"]["state"] >> state;
|
tree["capture"]["replay"]["state"] >> state;
|
||||||
tree["capture"]["replay"]["loop"] >> loop;
|
tree["capture"]["replay"]["loop"] >> loop;
|
||||||
tree["capture"]["replay"]["file"] >> replayFile;
|
tree["capture"]["replay"]["file"] >> replayFile;
|
||||||
|
tree["network"]["ip"] >> ip_capture;
|
||||||
|
tree["network"]["ports"]["api"] >> port_capture;
|
||||||
Capture *capture = new Capture(type, fs, fc, path);
|
Capture *capture = new Capture(type, fs, fc, path);
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
|
@ -85,7 +88,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
// run capture
|
// run capture
|
||||||
std::thread t1([&]{capture->process(buffer1, buffer2,
|
std::thread t1([&]{capture->process(buffer1, buffer2,
|
||||||
tree["capture"]["device"]);});
|
tree["capture"]["device"], ip_capture, port_capture);
|
||||||
|
});
|
||||||
|
|
||||||
// setup process CPI
|
// setup process CPI
|
||||||
double tCpi;
|
double tCpi;
|
||||||
|
|
|
@ -20,7 +20,8 @@ Capture::Capture(std::string _type, uint32_t _fs, uint32_t _fc, std::string _pat
|
||||||
saveIq = false;
|
saveIq = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Capture::process(IqData *buffer1, IqData *buffer2, c4::yml::NodeRef config)
|
void Capture::process(IqData *buffer1, IqData *buffer2, c4::yml::NodeRef config,
|
||||||
|
std::string ip_capture, uint16_t port_capture)
|
||||||
{
|
{
|
||||||
std::cout << "Setting up device " + type << std::endl;
|
std::cout << "Setting up device " + type << std::endl;
|
||||||
|
|
||||||
|
@ -31,7 +32,8 @@ void Capture::process(IqData *buffer1, IqData *buffer2, c4::yml::NodeRef config)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
httplib::Client cli("http://127.0.0.1:3000");
|
httplib::Client cli("http://" + ip_capture + ":"
|
||||||
|
+ std::to_string(port_capture));
|
||||||
httplib::Result res = cli.Get("/capture");
|
httplib::Result res = cli.Get("/capture");
|
||||||
|
|
||||||
// if capture status changed
|
// if capture status changed
|
||||||
|
|
|
@ -59,8 +59,11 @@ public:
|
||||||
/// @param buffer1 Buffer for reference samples.
|
/// @param buffer1 Buffer for reference samples.
|
||||||
/// @param buffer2 Buffer for surveillance samples.
|
/// @param buffer2 Buffer for surveillance samples.
|
||||||
/// @param config Yaml config for device.
|
/// @param config Yaml config for device.
|
||||||
|
/// @param ip_capture IP address of capture API.
|
||||||
|
/// @param port_capture Port of capture API.
|
||||||
/// @return Void.
|
/// @return Void.
|
||||||
void process(IqData *buffer1, IqData *buffer2, c4::yml::NodeRef config);
|
void process(IqData *buffer1, IqData *buffer2, c4::yml::NodeRef config,
|
||||||
|
std::string ip_capture, uint16_t port_capture);
|
||||||
|
|
||||||
std::unique_ptr<Source> factory_source(const std::string& type,
|
std::unique_ptr<Source> factory_source(const std::string& type,
|
||||||
c4::yml::NodeRef config);
|
c4::yml::NodeRef config);
|
||||||
|
|
67
src/capture/simulator/Simulator.cpp
Normal file
67
src/capture/simulator/Simulator.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "Simulator.h"
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
Simulator::Simulator(std::string _type, uint32_t _fc, uint32_t _fs,
|
||||||
|
std::string _path, bool *_saveIq,
|
||||||
|
uint32_t _n_min = 1000,
|
||||||
|
std::string _falseTargetsConfigFilePath,
|
||||||
|
std::string _configFilePath)
|
||||||
|
: Source(_type, _fc, _fs, _path, _saveIq)
|
||||||
|
{
|
||||||
|
n_min = _n_min;
|
||||||
|
u_int64_t total_samples = 0;
|
||||||
|
false_targets_config_file_path = _falseTargetsConfigFilePath;
|
||||||
|
config_file_path = _configFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Simulator::start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Simulator::stop()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Simulator::process(IqData *buffer1, IqData *buffer2)
|
||||||
|
{
|
||||||
|
const u_int32_t samples_per_iteration = 1000;
|
||||||
|
|
||||||
|
Target false_targets = Target(false_targets_config_file_path, config_file_path, fs, fc);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
uint32_t n_start = buffer1->get_length();
|
||||||
|
if (n_start < n_min)
|
||||||
|
{
|
||||||
|
|
||||||
|
// create a random number generator
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_real_distribution<> dis(-(2 ^ 14), 2 ^ 14);
|
||||||
|
|
||||||
|
buffer1->lock();
|
||||||
|
buffer2->lock();
|
||||||
|
for (uint16_t i = 0; i < samples_per_iteration; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
buffer1->push_back({(double)dis(gen), (double)dis(gen)});
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::complex<double> response = false_targets.process(buffer1);
|
||||||
|
response += std::complex<double>((double)dis(gen), (double)dis(gen));
|
||||||
|
buffer2->push_back(response);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
buffer2->push_back({(double)dis(gen), (double)dis(gen)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total_samples += samples_per_iteration;
|
||||||
|
buffer1->unlock();
|
||||||
|
buffer2->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Simulator::replay(IqData *buffer1, IqData *buffer2, std::string file, bool loop)
|
||||||
|
{
|
||||||
|
}
|
85
src/capture/simulator/Simulator.h
Normal file
85
src/capture/simulator/Simulator.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/// @file Simulator.h
|
||||||
|
/// @class Simulator
|
||||||
|
/// @brief A class to generate simulated IQ data with false targets.
|
||||||
|
/// @details This class generates simulated IQ data with false targets.
|
||||||
|
/// It generates a random reference and surveillance signal and uses the
|
||||||
|
/// Target class to add false targets to the surveillance signal.
|
||||||
|
///
|
||||||
|
/// @author bennysomers
|
||||||
|
/// @todo Simulate a single false target
|
||||||
|
/// @todo Simulate false targets
|
||||||
|
/// @todo Simulate realistic target motion
|
||||||
|
/// @todo Simulate N channels, instead of just 2
|
||||||
|
/// @todo Add more waveforms (e.g. LFM).
|
||||||
|
|
||||||
|
#ifndef SIMULATOR_H
|
||||||
|
#define SIMULATOR_H
|
||||||
|
|
||||||
|
#include "capture/Source.h"
|
||||||
|
#include "Target.h"
|
||||||
|
#include "data/IqData.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <complex>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
class Simulator : public Source
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/// @brief Number of samples to generate each loop.
|
||||||
|
/// @details This is the threshold for the minimum number of samples
|
||||||
|
/// left in the buffer before new samples will be generated.
|
||||||
|
uint32_t n_min;
|
||||||
|
|
||||||
|
/// @brief Total number of samples generated.
|
||||||
|
/// @details This is used to keep track of the total number of samples
|
||||||
|
/// generated, so that the Doppler shift can be calculated.
|
||||||
|
u_int64_t total_samples;
|
||||||
|
|
||||||
|
/// @brief Path to the false targets configuration file.
|
||||||
|
std::string false_targets_config_file_path;
|
||||||
|
|
||||||
|
/// @brief Path to the radar configuration file.
|
||||||
|
std::string config_file_path;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief Constructor.
|
||||||
|
/// @param type Type of source. = "IQSimulator"
|
||||||
|
/// @param fc Center frequency (Hz).
|
||||||
|
/// @param fs Sample rate (Hz).
|
||||||
|
/// @param path Path to save IQ data.
|
||||||
|
/// @param saveIq Pointer to boolean to save IQ data.
|
||||||
|
/// @param n Number of samples.
|
||||||
|
/// @return The object.
|
||||||
|
Simulator(std::string type, uint32_t fc, uint32_t fs, std::string path,
|
||||||
|
bool *saveIq, uint32_t n_min,
|
||||||
|
std::string false_targets_config_file_path = "config/false_targets.yml",
|
||||||
|
std::string config_file_path = "config/config.yml");
|
||||||
|
|
||||||
|
/// @brief Implement capture function on IQSimulator.
|
||||||
|
/// @param buffer1 Pointer to reference buffer.
|
||||||
|
/// @param buffer2 Pointer to surveillance buffer.
|
||||||
|
/// @return Void.
|
||||||
|
void process(IqData *buffer1, IqData *buffer2);
|
||||||
|
|
||||||
|
/// @brief Call methods to start capture.
|
||||||
|
/// @return Void.
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/// @brief Call methods to gracefully stop capture.
|
||||||
|
/// @return Void.
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
/// @brief Implement replay function on IQSimulator.
|
||||||
|
/// @param buffer1 Pointer to reference buffer.
|
||||||
|
/// @param buffer2 Pointer to surveillance buffer.
|
||||||
|
/// @param file Path to file to replay data from.
|
||||||
|
/// @param loop True if samples should loop at EOF.
|
||||||
|
/// @return Void.
|
||||||
|
void replay(IqData *buffer1, IqData *buffer2, std::string file, bool loop);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
226
src/capture/simulator/Target.cpp
Normal file
226
src/capture/simulator/Target.cpp
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
#include "Target.h"
|
||||||
|
|
||||||
|
// this is straight up copied from blah2.cpp, but I don't know the best way to access that function here.
|
||||||
|
// edit: put it in utilities?
|
||||||
|
std::string ryml_get_file_copy(const char *filename);
|
||||||
|
|
||||||
|
// constants
|
||||||
|
const std::string Target::VALID_TYPE[2] = {"static", "moving_radar"};
|
||||||
|
const std::string Target::VALID_STATE[1] = {"active"};
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
Target::Target(std::string false_tgt_config_path, std::string config_path, uint32_t fs, uint32_t fc)
|
||||||
|
{
|
||||||
|
// Read in the false targets config file
|
||||||
|
std::string config = ryml_get_file_copy(false_tgt_config_path.c_str());
|
||||||
|
ryml::Tree tree = ryml::parse_in_arena(ryml::to_csubstr(config));
|
||||||
|
|
||||||
|
// Create a FalseTarget object for each target in the config file
|
||||||
|
for (auto target_node : tree["targets"].children())
|
||||||
|
{
|
||||||
|
if (target_node["state"].val() == VALID_STATE[0])
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
targets.push_back(FalseTarget(target_node, fs, fc));
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the socket using details from the config file.
|
||||||
|
config = ryml_get_file_copy(config_path.c_str());
|
||||||
|
tree = ryml::parse_in_arena(ryml::to_csubstr(config));
|
||||||
|
|
||||||
|
std::string ip;
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
|
tree["network"]["ip"] >> ip;
|
||||||
|
tree["network"]["ports"]["falsetargets"] >> port;
|
||||||
|
|
||||||
|
socket = new Socket(ip, port);
|
||||||
|
|
||||||
|
sample_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::complex<double> Target::process(IqData *ref_buffer)
|
||||||
|
{
|
||||||
|
std::complex<double> response = std::complex<double>(0, 0);
|
||||||
|
// loop through each target
|
||||||
|
for (auto &target : targets)
|
||||||
|
{
|
||||||
|
response += target.process(ref_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// output false target truth
|
||||||
|
if (sample_counter % 100000 == 0)
|
||||||
|
{
|
||||||
|
rapidjson::Document document;
|
||||||
|
document.SetObject();
|
||||||
|
rapidjson::Document::AllocatorType &allocator = document.GetAllocator();
|
||||||
|
rapidjson::Value json_false_targets(rapidjson::kArrayType);
|
||||||
|
for (auto target : targets)
|
||||||
|
{
|
||||||
|
json_false_targets.PushBack(target.to_json(allocator), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.AddMember("false_targets", json_false_targets, allocator);
|
||||||
|
rapidjson::StringBuffer strbuf;
|
||||||
|
rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
|
||||||
|
writer.SetMaxDecimalPlaces(2);
|
||||||
|
document.Accept(writer);
|
||||||
|
|
||||||
|
socket->sendData(strbuf.GetString());
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_counter++;
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FalseTarget::get_range()
|
||||||
|
{
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FalseTarget::set_range(double _range)
|
||||||
|
{
|
||||||
|
range = _range;
|
||||||
|
delay = range / Constants::c;
|
||||||
|
delay_samples = delay * fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FalseTarget::get_delay()
|
||||||
|
{
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FalseTarget::set_delay(double _delay)
|
||||||
|
{
|
||||||
|
delay = _delay;
|
||||||
|
range = delay * Constants::c;
|
||||||
|
delay_samples = delay * fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FalseTarget::FalseTarget(c4::yml::NodeRef target_node, uint32_t _fs, uint32_t _fc)
|
||||||
|
{
|
||||||
|
|
||||||
|
target_node["id"] >> id;
|
||||||
|
target_node["type"] >> type;
|
||||||
|
fs = _fs;
|
||||||
|
fc = _fc;
|
||||||
|
sample_counter = 0;
|
||||||
|
|
||||||
|
if (type == TgtGen::VALID_TYPE[0])
|
||||||
|
{
|
||||||
|
target_node["location"]["range"] >> range;
|
||||||
|
delay = range / Constants::c;
|
||||||
|
delay_samples = delay * fs;
|
||||||
|
target_node["velocity"]["doppler"] >> doppler;
|
||||||
|
target_node["rcs"] >> rcs;
|
||||||
|
}
|
||||||
|
else if (type == TgtGen::VALID_TYPE[1])
|
||||||
|
{
|
||||||
|
target_node["location"]["range"] >> range;
|
||||||
|
start_range = range;
|
||||||
|
delay = range / Constants::c;
|
||||||
|
delay_samples = delay * fs;
|
||||||
|
target_node["velocity"]["doppler"] >> doppler;
|
||||||
|
target_node["velocity"]["dopplerRate"] >> doppler_rate;
|
||||||
|
target_node["rcs"] >> rcs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Invalid target type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::complex<double> FalseTarget::process(IqData *ref_buffer)
|
||||||
|
{
|
||||||
|
uint32_t buffer_length = ref_buffer->get_length();
|
||||||
|
std::complex<double> response = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = Conversions::db2lin(rcs) * ref_buffer->get_sample(buffer_length - delay_samples);
|
||||||
|
response *= std::exp(std::polar<double>(1, 2 * M_PI * doppler * buffer_length / fs));
|
||||||
|
|
||||||
|
if (type == TgtGen::VALID_TYPE[1])
|
||||||
|
{
|
||||||
|
double range_rate = -1 * doppler * Constants::c / 2.0 / fc;
|
||||||
|
set_range(range + (range_rate / fs));
|
||||||
|
|
||||||
|
// very basic PD controller
|
||||||
|
// will need tuning for different fs
|
||||||
|
doppler_rate += 0.0000001 * (range - start_range) / start_range; // target tends towards start_range
|
||||||
|
// doppler_rate -= doppler / std::abs(doppler) / std::max(std::abs(doppler), 0.1) / 100; // target tends towards 0 Doppler
|
||||||
|
doppler_rate = std::clamp(doppler_rate, -5.0, 5.0); // clamp to a reasonable value
|
||||||
|
doppler += doppler_rate / fs; // update doppler
|
||||||
|
doppler = std::clamp(doppler,
|
||||||
|
std::max(-range, -250.0),
|
||||||
|
std::min(range, 250.0)); // clamp to range
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_counter++;
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value FalseTarget::to_json(rapidjson::Document::AllocatorType &allocator)
|
||||||
|
{
|
||||||
|
|
||||||
|
rapidjson::Value target(rapidjson::kObjectType);
|
||||||
|
|
||||||
|
target.AddMember("id", id, allocator);
|
||||||
|
target.AddMember("type", rapidjson::Value(type.c_str(), allocator).Move(), allocator);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (type == TgtGen::VALID_TYPE[0])
|
||||||
|
{
|
||||||
|
target.AddMember("range", range, allocator);
|
||||||
|
target.AddMember("delay", delay, allocator);
|
||||||
|
target.AddMember("delay_samples", delay_samples, allocator);
|
||||||
|
target.AddMember("doppler", doppler, allocator);
|
||||||
|
target.AddMember("rcs", rcs, allocator);
|
||||||
|
}
|
||||||
|
else if (type == TgtGen::VALID_TYPE[1])
|
||||||
|
{
|
||||||
|
target.AddMember("range", range, allocator);
|
||||||
|
target.AddMember("start_range", start_range, allocator);
|
||||||
|
target.AddMember("delay", delay, allocator);
|
||||||
|
target.AddMember("delay_samples", delay_samples, allocator);
|
||||||
|
target.AddMember("doppler", doppler, allocator);
|
||||||
|
target.AddMember("doppler_rate", doppler_rate, allocator);
|
||||||
|
target.AddMember("rcs", rcs, allocator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Invalid target type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << '\n';
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ryml_get_file_copy(const char *filename)
|
||||||
|
{
|
||||||
|
std::ifstream in(filename, std::ios::in | std::ios::binary);
|
||||||
|
if (!in)
|
||||||
|
{
|
||||||
|
std::cerr << "could not open " << filename << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
std::ostringstream contents;
|
||||||
|
contents << in.rdbuf();
|
||||||
|
return contents.str();
|
||||||
|
}
|
143
src/capture/simulator/Target.h
Normal file
143
src/capture/simulator/Target.h
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/// @file TgtGen.h
|
||||||
|
/// @class TgtGen
|
||||||
|
/// @brief A class to generate false targets.
|
||||||
|
|
||||||
|
/// @details
|
||||||
|
/// Static Targets: remain at a fixed range/delay and Doppler.
|
||||||
|
|
||||||
|
/// @author bennysomers
|
||||||
|
/// @todo Simulate a false target moving in radar coordinates
|
||||||
|
/// @todo Simulate a false target moving in spatial coordinates
|
||||||
|
|
||||||
|
#ifndef TGTGEN_H
|
||||||
|
#define TGTGEN_H
|
||||||
|
|
||||||
|
#include "data/IqData.h"
|
||||||
|
#include "utilities/Conversions.h"
|
||||||
|
#include "data/meta/Constants.h"
|
||||||
|
#include "process/utility/Socket.h"
|
||||||
|
|
||||||
|
#include <ryml/ryml.hpp>
|
||||||
|
#include <ryml/ryml_std.hpp>
|
||||||
|
#include <c4/format.hpp>
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "rapidjson/writer.h"
|
||||||
|
#include "rapidjson/stringbuffer.h"
|
||||||
|
#include "rapidjson/filewritestream.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <fstream>
|
||||||
|
#include <complex>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
class FalseTarget
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/// @brief fs
|
||||||
|
uint32_t fs;
|
||||||
|
|
||||||
|
/// @brief fc
|
||||||
|
uint32_t fc;
|
||||||
|
|
||||||
|
/// @brief Target delay
|
||||||
|
double delay;
|
||||||
|
|
||||||
|
/// @brief Target delay in samples
|
||||||
|
uint32_t delay_samples;
|
||||||
|
|
||||||
|
/// @brief Target range
|
||||||
|
double range;
|
||||||
|
|
||||||
|
/// @brief Target starting range
|
||||||
|
double start_range;
|
||||||
|
|
||||||
|
/// @brief Sample counter
|
||||||
|
uint64_t sample_counter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief Target type.
|
||||||
|
std::string type;
|
||||||
|
|
||||||
|
/// @brief Target Doppler
|
||||||
|
double doppler;
|
||||||
|
|
||||||
|
/// @brief Target Doppler Rate
|
||||||
|
double doppler_rate;
|
||||||
|
|
||||||
|
/// @brief Target RCS
|
||||||
|
double rcs;
|
||||||
|
|
||||||
|
/// @brief Target ID
|
||||||
|
u_int32_t id;
|
||||||
|
|
||||||
|
/// @brief Constructor for targets.
|
||||||
|
/// @return The object.
|
||||||
|
FalseTarget(c4::yml::NodeRef target_node, uint32_t _fs, uint32_t _fc);
|
||||||
|
|
||||||
|
/// @brief Generate the signal from a false target.
|
||||||
|
/// @param ref_buffer Pointer to reference buffer.
|
||||||
|
/// @return Target reflection signal.
|
||||||
|
std::complex<double> process(IqData *ref_buffer);
|
||||||
|
|
||||||
|
/// @brief Getter for range.
|
||||||
|
/// @return Range in meters.
|
||||||
|
double get_range();
|
||||||
|
|
||||||
|
/// @brief Setter for range.
|
||||||
|
/// @param range Range in meters.
|
||||||
|
void set_range(double range);
|
||||||
|
|
||||||
|
/// @brief Getter for delay.
|
||||||
|
/// @return Delay in seconds.
|
||||||
|
double get_delay();
|
||||||
|
|
||||||
|
/// @brief Setter for delay.
|
||||||
|
/// @param delay Delay in seconds.
|
||||||
|
void set_delay(double delay);
|
||||||
|
|
||||||
|
/// @brief Outputs false target truth as JSON
|
||||||
|
/// @return JSON string.
|
||||||
|
rapidjson::Value to_json(rapidjson::Document::AllocatorType &allocator);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TgtGen
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/// @brief Vector of false targets.
|
||||||
|
std::vector<FalseTarget> targets;
|
||||||
|
|
||||||
|
/// @brief Socket to send false target data.
|
||||||
|
Socket *socket;
|
||||||
|
|
||||||
|
/// @brief Sample counter
|
||||||
|
uint64_t sample_counter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief The valid false target types.
|
||||||
|
static const std::string VALID_TYPE[2];
|
||||||
|
|
||||||
|
/// @brief The valid false target states.
|
||||||
|
static const std::string VALID_STATE[1];
|
||||||
|
|
||||||
|
/// @brief Constructor.
|
||||||
|
/// @param false_tgt_config_path Path to false targets configuration file.
|
||||||
|
/// @param config_path Path to blah2 config file.
|
||||||
|
/// @param fs Sample rate (Hz).
|
||||||
|
/// @param fc Center frequency (Hz).
|
||||||
|
/// @return The object.
|
||||||
|
TgtGen(std::string false_tgt_config_path, std::string config_path, uint32_t fs, uint32_t fc);
|
||||||
|
|
||||||
|
/// @brief Generate the signal from all false targets.
|
||||||
|
/// @param ref_buffer Pointer to reference buffer.
|
||||||
|
/// @return Targets reflection signal.
|
||||||
|
std::complex<double> process(IqData *ref_buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
std::string ryml_get_file(const char *filename);
|
|
@ -6,7 +6,12 @@ const uint32_t Socket::MTU = 1024;
|
||||||
|
|
||||||
Socket::Socket(const std::string& ip, uint16_t port)
|
Socket::Socket(const std::string& ip, uint16_t port)
|
||||||
: endpoint(asio::ip::address::from_string(ip), port), socket(io_context) {
|
: endpoint(asio::ip::address::from_string(ip), port), socket(io_context) {
|
||||||
|
try {
|
||||||
socket.connect(endpoint);
|
socket.connect(endpoint);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Error connecting to endpoint: " << e.what() << std::endl;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Socket::~Socket()
|
Socket::~Socket()
|
||||||
|
|
Loading…
Reference in a new issue