From 9070d9a6db461148adc683e0cc3a8fc123473716 Mon Sep 17 00:00:00 2001 From: 30hours Date: Mon, 8 Apr 2024 12:09:28 +0000 Subject: [PATCH] Fix hackrf parameters in config --- config/config-hackrf.yml | 85 ++++++++++++ config/{radar4-usrp.yml => config-usrp.yml} | 0 src/capture/Capture.cpp | 31 ++++- src/capture/Capture.h | 2 +- src/capture/hackrf/HackRf.cpp | 135 ++++++++++++++++++++ src/capture/hackrf/HackRf.h | 84 ++++++++++++ src/capture/hackrf/README.md | 7 + 7 files changed, 342 insertions(+), 2 deletions(-) create mode 100644 config/config-hackrf.yml rename config/{radar4-usrp.yml => config-usrp.yml} (100%) create mode 100644 src/capture/hackrf/HackRf.cpp create mode 100644 src/capture/hackrf/HackRf.h create mode 100644 src/capture/hackrf/README.md diff --git a/config/config-hackrf.yml b/config/config-hackrf.yml new file mode 100644 index 0000000..cba6840 --- /dev/null +++ b/config/config-hackrf.yml @@ -0,0 +1,85 @@ +capture: + fs: 2000000 + fc: 204640000 + device: + type: "HackRF" + serial: + - "FIRST_DEVICE_SERIAL_NUMBER" + - "SECOND_DEVICE_SERIAL_NUMBER" + gain_lna: [32, 32] + gain_vga: [30, 30] + amp_enable: [false, false] + + replay: + state: false + loop: true + file: '/opt/blah2/replay/file.rspduo' + +process: + data: + cpi: 0.5 + buffer: 1.5 + overlap: 0 + ambiguity: + delayMin: -10 + delayMax: 400 + dopplerMin: -200 + dopplerMax: 200 + clutter: + delayMin: -10 + delayMax: 400 + detection: + pfa: 0.00001 + nGuard: 2 + nTrain: 6 + minDelay: 5 + minDoppler: 15 + nCentroid: 6 + tracker: + initiate: + M: 3 + N: 5 + maxAcc: 10 + delete: 10 + smooth: "none" + +network: + ip: 0.0.0.0 + ports: + api: 3000 + map: 3001 + detection: 3002 + track: 3003 + timestamp: 4000 + timing: 4001 + iqdata: 4002 + config: 4003 + +truth: + adsb: + enabled: false + tar1090: 'adsb.30hours.dev' + adsb2dd: 'adsb2dd.30hours.dev' + ais: + enabled: false + ip: 0.0.0.0 + 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: + iq: true + map: false + detection: false + timing: false + path: "/blah2/save/" diff --git a/config/radar4-usrp.yml b/config/config-usrp.yml similarity index 100% rename from config/radar4-usrp.yml rename to config/config-usrp.yml diff --git a/src/capture/Capture.cpp b/src/capture/Capture.cpp index 9097ec0..f1a7844 100644 --- a/src/capture/Capture.cpp +++ b/src/capture/Capture.cpp @@ -1,12 +1,13 @@ #include "Capture.h" #include "rspduo/RspDuo.h" #include "usrp/Usrp.h" +#include "hackrf/HackRf.h" #include #include #include // constants -const std::string Capture::VALID_TYPE[2] = {"RspDuo", "Usrp"}; +const std::string Capture::VALID_TYPE[3] = {"RspDuo", "Usrp", "HackRF"}; // constructor Capture::Capture(std::string _type, uint32_t _fs, uint32_t _fc, std::string _path) @@ -90,6 +91,34 @@ std::unique_ptr Capture::factory_source(const std::string& type, c4::yml return std::make_unique(type, fc, fs, path, &saveIq, address, subdev, antenna, gain); } + else if (type == VALID_TYPE[2]) + { + std::vector serial; + std::vector gainLna, gainVga; + std::vector ampEnable; + std::string _serial; + uint8_t _gainLna, _gainVga; + bool _ampEnable; + config["serial"][0] >> _serial; + serial.push_back(_serial); + config["serial"][1] >> _serial; + serial.push_back(_serial); + config["gain_lna"][0] >> _gainLna; + gainLna.push_back(_gainLna); + config["gain_lna"][1] >> _gainLna; + gainLna.push_back(_gainLna); + config["gain_vga"][0] >> _gainVga; + gainVga.push_back(_gainVga); + config["gain_vga"][1] >> _gainVga; + gainVga.push_back(_gainVga); + config["amp_enable"][0] >> _ampEnable; + ampEnable.push_back(_ampEnable); + config["amp_enable"][1] >> _ampEnable; + ampEnable.push_back(_ampEnable); + + return std::make_unique(type, fc, fs, path, &saveIq, + serial, gainLna, gainVga, ampEnable); + } // Handle unknown type std::cerr << "Error: Source type does not exist." << std::endl; return nullptr; diff --git a/src/capture/Capture.h b/src/capture/Capture.h index e0ab1f9..1e441a7 100644 --- a/src/capture/Capture.h +++ b/src/capture/Capture.h @@ -19,7 +19,7 @@ class Capture { private: /// @brief The valid capture devices. - static const std::string VALID_TYPE[2]; + static const std::string VALID_TYPE[3]; /// @brief The capture device type. std::string type; diff --git a/src/capture/hackrf/HackRf.cpp b/src/capture/hackrf/HackRf.cpp new file mode 100644 index 0000000..42ad7b5 --- /dev/null +++ b/src/capture/hackrf/HackRf.cpp @@ -0,0 +1,135 @@ +#include "HackRf.h" + +#include +#include +#include +#include + +// constructor +HackRf::HackRf(std::string _type, uint32_t _fc, uint32_t _fs, + std::string _path, bool *_saveIq, std::vector _serial, + std::vector _gainLna, std::vector _gainVga, + std::vector _ampEnable) + : Source(_type, _fc, _fs, _path, _saveIq) +{ + serial = _serial; + ampEnable = _ampEnable; + + // validate LNA gain + std::unordered_set validLna; + for (uint8_t gain = 0; gain <= 40; gain += 8) { + validLna.insert(gain); + } + for (uint8_t gain : _gainLna) { + if (validLna.find(gain) == validLna.end()) { + throw std::invalid_argument("Invalid LNA gain value"); + } + } + gainLna = _gainLna; + + // validate VGA gain + std::unordered_set validVga; + for (uint8_t gain = 0; gain <= 62; gain += 2) { + validVga.insert(gain); + } + for (uint8_t gain : _gainVga) { + if (validVga.find(gain) == validVga.end()) { + throw std::invalid_argument("Invalid LNA gain value"); + } + } + gainVga = _gainVga; +} + +void HackRf::check_status(uint8_t status, std::string message) +{ + if (status != HACKRF_SUCCESS) + { + throw std::runtime_error("[HackRF] " + message); + } +} + +void HackRf::start() +{ + // global hackrf config + int status; + status = hackrf_init(); + check_status(status, "Failed to initialise HackRF"); + hackrf_device_list_t *list; + list = hackrf_device_list(); + if (list->devicecount < 2) + { + check_status(-1, "Failed to find 2 HackRF devices."); + } + + // reference config + status = hackrf_open_by_serial(serial[0].c_str(), &dev[0]); + check_status(status, "Failed to open device."); + status = hackrf_set_freq(dev[0], fc); + check_status(status, "Failed to set frequency."); + status = hackrf_set_sample_rate(dev[0], fs); + check_status(status, "Failed to set sample rate."); + status = hackrf_set_amp_enable(dev[0], ampEnable[0] ? 1 : 0); + check_status(status, "Failed to set AMP status."); + status = hackrf_set_lna_gain(dev[0], gainLna[0]); + check_status(status, "Failed to set LNA gain."); + status = hackrf_set_vga_gain(dev[0], gainVga[0]); + check_status(status, "Failed to set VGA gain."); + + // surveillance config + status = hackrf_open_by_serial(serial[1].c_str(), &dev[1]); + check_status(status, "Failed to open device."); + status = hackrf_set_freq(dev[1], fc); + check_status(status, "Failed to set frequency."); + status = hackrf_set_sample_rate(dev[1], fs); + check_status(status, "Failed to set sample rate."); + status = hackrf_set_amp_enable(dev[1], ampEnable[1] ? 1 : 0); + check_status(status, "Failed to set AMP status."); + status = hackrf_set_lna_gain(dev[1], gainLna[1]); + check_status(status, "Failed to set LNA gain."); + status = hackrf_set_vga_gain(dev[1], gainVga[1]); + check_status(status, "Failed to set VGA gain."); + status = hackrf_set_hw_sync_mode(dev[1], 1); + check_status(status, "Failed to enable hardware synchronising."); +} + +void HackRf::stop() +{ + hackrf_stop_rx(dev[0]); + hackrf_stop_rx(dev[1]); + hackrf_close(dev[0]); + hackrf_close(dev[1]); + hackrf_exit(); +} + +void HackRf::process(IqData *buffer1, IqData *buffer2) +{ + int status; + status = hackrf_start_rx(dev[1], &rx_callback, buffer2); + check_status(status, "Failed to start RX streaming."); + status = hackrf_start_rx(dev[0], &rx_callback, buffer1); + check_status(status, "Failed to start RX streaming."); +} + +int HackRf::rx_callback(hackrf_transfer* transfer) +{ + IqData* buffer_blah2 = (IqData*)transfer->rx_ctx; + int8_t* buffer_hackrf = (int8_t*) transfer->buffer; + + buffer_blah2->lock(); + + for (size_t i = 0; i < transfer->valid_length; i+2) + { + double iqi = static_cast(buffer_hackrf[i]); + double iqq = static_cast(buffer_hackrf[i+1]); + buffer_blah2->push_back({iqi, iqq}); + } + + buffer_blah2->unlock(); + + return 0; +} + +void HackRf::replay(IqData *buffer1, IqData *buffer2, std::string _file, bool _loop) +{ + return; +} diff --git a/src/capture/hackrf/HackRf.h b/src/capture/hackrf/HackRf.h new file mode 100644 index 0000000..6bb1329 --- /dev/null +++ b/src/capture/hackrf/HackRf.h @@ -0,0 +1,84 @@ +/// @file HackRf.h +/// @class HackRf +/// @brief A class to capture data on the HackRF. +/// @author sdn-ninja +/// @author 30hours +/// @todo Replay functionality. + +#ifndef HACKRF_H +#define HACKRF_H + +#include "capture/Source.h" +#include "data/IqData.h" + +#include +#include +#include +#include + +class HackRf : public Source +{ +private: + + /// @brief Vector of serial numbers. + /// @details Serial as given by hackrf_info. + std::vector serial; + + /// @brief RX LNA (IF) gain, 0-40dB, 8dB steps. + std::vector gainLna; + + /// @brief RX VGA (baseband) gain, 0-62dB, 2dB steps. + std::vector gainVga; + + /// @brief Enable extra amplifier U13 on receive. + std::vector ampEnable; + + /// @brief Vector of pointers to HackRF devices. + std::vector dev; + + /// @brief Check status of HackRF API returns. + /// @param status Return code of API call. + /// @param message Message if API call error. + void check_status(uint8_t status, std::string message); + + /// @brief Callback function for HackRF samples. + /// @param transfer HackRF transfer object. + /// @return Void. + static int rx_callback(hackrf_transfer* transfer); + +public: + + /// @brief Constructor. + /// @param fc Center frequency (Hz). + /// @param path Path to save IQ data. + /// @return The object. + HackRf(std::string type, uint32_t fc, uint32_t fs, std::string path, + bool *saveIq, std::vector serial, + std::vector gainLna, std::vector gainVga, + std::vector ampEnable); + + /// @brief Implement capture function on HackRF. + /// @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 HackRF. + /// @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 \ No newline at end of file diff --git a/src/capture/hackrf/README.md b/src/capture/hackrf/README.md new file mode 100644 index 0000000..7851fcc --- /dev/null +++ b/src/capture/hackrf/README.md @@ -0,0 +1,7 @@ +# HackRF setup for blah2 + +This requires 2 HackRF units with a shared clock signal and a shared hardware trigger. + +# Instructions + +TODO \ No newline at end of file