diff --git a/CMakeLists.txt b/CMakeLists.txt index f515860..d9aa892 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ target_link_libraries(sdrplay PUBLIC /usr/local/lib/libsdrplay_api.so.3.07) add_executable(blah2 src/blah2.cpp src/capture/Capture.cpp + src/capture/Source.cpp src/capture/rspduo/RspDuo.cpp src/capture/usrp/Usrp.cpp src/process/ambiguity/Ambiguity.cpp diff --git a/config/radar4-usrp.yml b/config/radar4-usrp.yml index 0339eb0..4600666 100644 --- a/config/radar4-usrp.yml +++ b/config/radar4-usrp.yml @@ -1,7 +1,12 @@ capture: fs: 2000000 fc: 204640000 - type: "Usrp" + device: + type: "Usrp" + address: "localhost" + subdev: "A:A A:B" + antenna: ["RX2", "RX2"] + gain: [20.0, 20.0] replay: state: false loop: true diff --git a/src/blah2.cpp b/src/blah2.cpp index bcda965..2af675a 100644 --- a/src/blah2.cpp +++ b/src/blah2.cpp @@ -64,7 +64,7 @@ int main(int argc, char **argv) bool saveIq, state, loop; tree["capture"]["fs"] >> fs; tree["capture"]["fc"] >> fc; - tree["capture"]["type"] >> type; + tree["capture"]["device"]["type"] >> type; tree["save"]["iq"] >> saveIq; tree["save"]["path"] >> path; tree["capture"]["replay"]["state"] >> state; @@ -83,7 +83,8 @@ int main(int argc, char **argv) IqData *buffer2 = new IqData((int) (tBuffer*fs)); // run capture - std::thread t1([&]{capture->process(buffer1, buffer2);}); + std::thread t1([&]{capture->process(buffer1, buffer2, + tree["capture"]["device"]);}); // setup process CPI double tCpi; diff --git a/src/capture/Capture.cpp b/src/capture/Capture.cpp index edd893e..c56018e 100644 --- a/src/capture/Capture.cpp +++ b/src/capture/Capture.cpp @@ -16,62 +16,81 @@ Capture::Capture(std::string _type, uint32_t _fs, uint32_t _fc, std::string _pat fc = _fc; path = _path; replay = false; + saveIq = false; } -void Capture::process(IqData *buffer1, IqData *buffer2) +void Capture::process(IqData *buffer1, IqData *buffer2, c4::yml::NodeRef config) { - if (is_type_valid(type)) - { - std::cout << "Setting up device " + type << std::endl; + std::cout << "Setting up device " + type << std::endl; - // RspDuo device + std::unique_ptr device = factory_source(type, config); + + if (!replay) + { + device->start(); + device->process(buffer1, buffer2); + } + else + { + device->replay(buffer1, buffer2, file, loop); + } + + // capture status thread + std::thread t1([&]{ + while (true) + { + httplib::Client cli("http://127.0.0.1:3000"); + httplib::Result res = cli.Get("/capture"); + + // if capture status changed + if ((res->body == "true") != saveIq) + { + saveIq = res->body == "true"; + if (saveIq) + { + device->open_file(); + } + else + { + device->close_file(); + } + } + + sleep(1); + } + }); +} + +std::unique_ptr Capture::factory_source(const std::string& type, c4::yml::NodeRef config) +{ if (type == VALID_TYPE[0]) { - //RspDuo *device = new RspDuo(this->fc, this->path); + return std::make_unique(type, fc, fs, path, &saveIq); } - - // Usrp device - if (type == VALID_TYPE[1]) + else if (type == VALID_TYPE[1]) { - //Usrp *device = new Usrp(this->fc, this->path); + std::string address, subdev; + std::vector antenna; + std::vector gain; + std::string _antenna; + double _gain; + config["address"] >> address; + config["subdev"] >> subdev; + config["antenna"][0] >> _antenna; + antenna.push_back(_antenna); + config["antenna"][1] >> _antenna; + antenna.push_back(_antenna); + config["gain"][0] >> _gain; + gain.push_back(_gain); + config["gain"][1] >> _gain; + gain.push_back(_gain); + + return std::make_unique(type, fc, fs, path, &saveIq, + address, subdev, antenna, gain); } - Usrp *device = new Usrp(this->fc, this->fs, this->path); - - // capture status thread - std::thread t1([&]{ - while (true) - { - httplib::Client cli("http://127.0.0.1:3000"); - httplib::Result res = cli.Get("/capture"); - - // if capture status changed - if ((res->body == "true") != device->get_capture()) - { - device->set_capture(res->body == "true"); - if (device->get_capture()) - { - device->open_file(); - } - else - { - device->close_file(); - } - } - - sleep(1); - } - }); - - if (!replay) - { - device->start(); - device->process(buffer1, buffer2); - } - else - { - device->replay(buffer1, buffer2, file, loop); - } - } + // Handle unknown type + std::cerr << "Error: Source type does not exist." << std::endl; + return nullptr; } void Capture::set_replay(bool _loop, std::string _file) diff --git a/src/capture/Capture.h b/src/capture/Capture.h index 3a3d3a0..097c72c 100644 --- a/src/capture/Capture.h +++ b/src/capture/Capture.h @@ -7,7 +7,13 @@ #define CAPTURE_H #include +#include +#include +#include // optional header, provided for std:: interop +#include // needed for the examples below + #include "data/IqData.h" +#include "capture/Source.h" class Capture { @@ -15,6 +21,9 @@ private: /// @brief The valid capture devices. static const std::string VALID_TYPE[2]; + /// @brief True if IQ data to be saved. + bool saveIq; + /// @brief True if file replay is enabled. bool replay; @@ -34,9 +43,6 @@ public: /// @brief Center frequency (Hz). uint32_t fc; - /// @brief True if IQ data is saved to file. - bool saveIq; - /// @brief Absolute path to IQ save location. std::string path; @@ -51,8 +57,12 @@ public: /// @brief Implement the capture process. /// @param buffer1 Buffer for reference samples. /// @param buffer2 Buffer for surveillance samples. + /// @param config Yaml config for device. /// @return Void. - void process(IqData *buffer1, IqData *buffer2); + void process(IqData *buffer1, IqData *buffer2, c4::yml::NodeRef config); + + std::unique_ptr factory_source(const std::string& type, + c4::yml::NodeRef config); /// @brief Set parameters to enable file replay. /// @param loop True if replay file should loop when complete. diff --git a/src/capture/Source.cpp b/src/capture/Source.cpp new file mode 100644 index 0000000..52bf1ad --- /dev/null +++ b/src/capture/Source.cpp @@ -0,0 +1,19 @@ +#include "Source.h" + +#include + +Source::Source() +{ + +} + +// constructor +Source::Source(std::string _type, uint32_t _fc, uint32_t _fs, + std::string _path, bool *_saveIq) +{ + type = _type; + fc = _fc; + fs = _fs; + path = _path; + saveIq = _saveIq; +} diff --git a/src/capture/Source.h b/src/capture/Source.h new file mode 100644 index 0000000..18650a7 --- /dev/null +++ b/src/capture/Source.h @@ -0,0 +1,79 @@ +/// @file Source.h +/// @class Source +/// @brief An abstract class for capture sources. +/// @author 30hours + +#ifndef SOURCE_H +#define SOURCE_H + +#include +#include +#include "data/IqData.h" + +class Source +{ +protected: + + /// @brief The capture device type. + std::string type; + + /// @brief Center frequency (Hz). + uint32_t fc; + + /// @brief Sampling frequency (Hz). + uint32_t fs; + + /// @brief Absolute path to IQ save location. + std::string path; + + /// @brief True if IQ data to be saved. + bool *saveIq; + +public: + + Source(); + + /// @brief Constructor. + /// @param type The capture device type. + /// @param fs Sampling frequency (Hz). + /// @param fc Center frequency (Hz). + /// @param path Absolute path to IQ save location. + /// @return The object. + Source(std::string type, uint32_t fc, uint32_t fs, + std::string path, bool *saveIq); + + /// @brief Implement the capture process. + /// @param buffer1 Buffer for reference samples. + /// @param buffer2 Buffer for surveillance samples. + /// @return Void. + virtual void process(IqData *buffer1, IqData *buffer2) = 0; + + /// @brief Call methods to start capture. + /// @return Void. + virtual void start() = 0; + + /// @brief Call methods to gracefully stop capture. + /// @return Void. + virtual void stop() = 0; + + /// @brief Implement replay function on RSPduo. + /// @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. + virtual void replay(IqData *buffer1, IqData *buffer2, + std::string file, bool loop) = 0; + + /// @brief Open a new file to record IQ. + /// @details First creates a new file from current timestamp. + /// @return Void. + virtual void open_file() = 0; + + /// @brief Close IQ file gracefully. + /// @return Void. + virtual void close_file() = 0; + +}; + +#endif \ No newline at end of file diff --git a/src/capture/rspduo/RspDuo.cpp b/src/capture/rspduo/RspDuo.cpp index 8da0d81..70fd2b2 100644 --- a/src/capture/rspduo/RspDuo.cpp +++ b/src/capture/rspduo/RspDuo.cpp @@ -56,9 +56,10 @@ IqData *buffer1; IqData *buffer2; // constructor -RspDuo::RspDuo(uint32_t _fc, std::string _path) +RspDuo::RspDuo(std::string _type, uint32_t _fc, uint32_t _fs, + std::string _path, bool *_saveIq) + : Source(_type, _fc, _fs, _path, _saveIq) { - fc = _fc; nDecimation = DEF_DECIMATION_NR; usb_bulk_fg = false; small_verbose_fg = false; @@ -70,8 +71,6 @@ RspDuo::RspDuo(uint32_t _fc, std::string _path) rf_notch_fg = false; dab_notch_fg = false; chunk_time_nr = DEF_CHUNK_TIME_NR; - path = _path; - capture = false; } std::string RspDuo::set_file(std::string path) @@ -690,13 +689,3 @@ void RspDuo::finish() return; } -void RspDuo::set_capture(bool _capture) -{ - capture = _capture; - capture_fg = capture; -} - -bool RspDuo::get_capture() -{ - return capture; -} diff --git a/src/capture/rspduo/RspDuo.h b/src/capture/rspduo/RspDuo.h index e3080d8..ae8bc6d 100644 --- a/src/capture/rspduo/RspDuo.h +++ b/src/capture/rspduo/RspDuo.h @@ -20,6 +20,7 @@ #define RSPDUO_H #include "sdrplay_api.h" +#include "capture/Source.h" #include "data/IqData.h" #include @@ -27,11 +28,9 @@ #define BUFFER_SIZE_NR 1024 -class RspDuo +class RspDuo : public Source { private: - /// @brief Center frequency (Hz) - uint32_t fc; /// @brief chunk time of recording (s) int chunk_time_nr; /// @brief AGC bandwidth (Hz) @@ -54,10 +53,6 @@ private: bool small_verbose_fg; /// @brief Debugging. bool more_verbose_fg; - /// @brief File path. - std::string path; - /// @brief True if capture is enabled. - bool capture; /// @brief Maximum frequency (Hz). static const double MAX_FREQUENCY_NR; @@ -188,7 +183,14 @@ public: /// @param fc Center frequency (Hz). /// @param path Path to save IQ data. /// @return The object. - RspDuo(uint32_t fc, std::string path); + RspDuo(std::string type, uint32_t fc, uint32_t fs, + std::string path, bool *saveIq); + + /// @brief Implement capture function on RSPduo. + /// @param buffer1 Pointer to reference buffer. + /// @param buffer2 Pointer to surveillance buffer. + /// @return Void. + void process(IqData *buffer1, IqData *buffer2); /// @brief Get file name from path. /// @return String of file name based on current time. @@ -202,12 +204,6 @@ public: /// @return Void. void stop(); - /// @brief Implement capture function on RSPduo. - /// @param buffer1 Pointer to reference buffer. - /// @param buffer2 Pointer to surveillance buffer. - /// @return Void. - void process(IqData *buffer1, IqData *buffer2); - /// @brief Implement replay function on RSPduo. /// @param buffer1 Pointer to reference buffer. /// @param buffer2 Pointer to surveillance buffer. @@ -223,15 +219,6 @@ public: /// @brief Close IQ file gracefully. /// @return Void. void close_file(); - - /// @brief Setter for capture. - /// @param capture True if capture is enabled. - /// @return Void. - void set_capture(bool capture); - - /// @brief Getter for capture. - /// @return True if capture is true. - bool get_capture(); }; #endif \ No newline at end of file diff --git a/src/capture/usrp/Usrp.cpp b/src/capture/usrp/Usrp.cpp index 41db95c..5577e01 100644 --- a/src/capture/usrp/Usrp.cpp +++ b/src/capture/usrp/Usrp.cpp @@ -1,26 +1,22 @@ #include "Usrp.h" -#include -#include -#include -#include #include -#include -#include -#include #include #include - -#include #include +#include // constructor -Usrp::Usrp(uint32_t _fc, uint32_t _fs, std::string _path) +Usrp::Usrp(std::string _type, uint32_t _fc, uint32_t _fs, + std::string _path, bool *_saveIq, std::string _address, + std::string _subdev, std::vector _antenna, + std::vector _gain) + : Source(_type, _fc, _fs, _path, _saveIq) { - fc = _fc; - fs = _fs; - path = _path; - capture = false; + address = _address; + subdev = _subdev; + antenna = _antenna; + gain = _gain; } std::string Usrp::set_file(std::string path) @@ -39,12 +35,6 @@ void Usrp::stop() void Usrp::process(IqData *buffer1, IqData *buffer2) { - // tmp vars - std::string address = "localhost"; - std::string subdev = "A:A A:B"; - std::vector antenna = {"RX2", "RX2"}; - std::vector gain = {20.0, 20.0}; - // create a USRP object uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(address); @@ -72,7 +62,7 @@ void Usrp::process(IqData *buffer1, IqData *buffer2) uhd::rx_streamer::sptr rxStreamer = usrp->get_rx_stream(streamArgs); // allocate buffers to receive with samples (one buffer per channel) - const size_t samps_per_buff = 1024; + const size_t samps_per_buff = rxStreamer->get_max_num_samps(); std::vector> usrpBuffer1(samps_per_buff); std::vector> usrpBuffer2(samps_per_buff); @@ -90,12 +80,12 @@ void Usrp::process(IqData *buffer1, IqData *buffer2) while(true) { - // Receive samples + // receive samples size_t nReceived = rxStreamer->recv(buff_ptrs, samps_per_buff, metadata); // print errors if (metadata.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) { - std::cerr << "Error during reception: " << metadata.strerror() << std::endl; + std::cerr << "Error: " << metadata.strerror() << std::endl; } buffer1->lock(); @@ -107,36 +97,14 @@ void Usrp::process(IqData *buffer1, IqData *buffer2) } buffer1->unlock(); buffer2->unlock(); + + sleep(0.01); } } void Usrp::replay(IqData *buffer1, IqData *buffer2, std::string _file, bool _loop) { - short i1, q1, i2, q2; - int rv; - FILE *file_replay = fopen(_file.c_str(), "rb"); - - while (true) - { - rv = fread(&i1, 1, sizeof(short), file_replay); - rv = fread(&q1, 1, sizeof(short), file_replay); - rv = fread(&i2, 1, sizeof(short), file_replay); - rv = fread(&q2, 1, sizeof(short), file_replay); - - buffer1->lock(); - buffer2->lock(); - - if (buffer1->get_length() < buffer1->get_n()) - { - buffer1->push_back({(double)i1, (double)q1}); - buffer2->push_back({(double)i2, (double)q2}); - } - - buffer1->unlock(); - buffer2->unlock(); - - } - + return; } void Usrp::open_file() @@ -148,14 +116,3 @@ void Usrp::close_file() { return; } - - -void Usrp::set_capture(bool _capture) -{ - capture = _capture; -} - -bool Usrp::get_capture() -{ - return capture; -} diff --git a/src/capture/usrp/Usrp.h b/src/capture/usrp/Usrp.h index 3f376d2..37e0d1f 100644 --- a/src/capture/usrp/Usrp.h +++ b/src/capture/usrp/Usrp.h @@ -5,44 +5,60 @@ /// /// Should work on all USRP models EXCEPT discontinued (USRP1, USRP2). /// Networked models require an IP address in the config file. +/// Requires a USB 3.0 cable for higher data rates. /// /// @author 30hours +/// @todo Add replay to Usrp. +/// @todo Add IQ data saving to Usrp. +/// @todo Fix single overflow per CPI. +/// @todo Fix occasional timeout ERROR_CODE_TIMEOUT. #ifndef USRP_H #define USRP_H +#include "capture/Source.h" #include "data/IqData.h" #include #include -#define BUFFER_SIZE_NR 1024 - -class Usrp +class Usrp : public Source { private: - /// @brief Center frequency (Hz) - uint32_t fc; - /// @brief Sampling rate (Hz) - uint32_t fs; - - /// @brief File path. - std::string path; - /// @brief True if capture is enabled. - bool capture; + /// @brief Address of USRP device. + /// @details "localhost" if USB, else IP address. + std::string address; + + /// @brief Subdevice string for USRP. + /// @details See docs. + std::string subdev; + + /// @brief Antenna string for each channel. + std::vector antenna; + + /// @brief USRP gain for each channel. + std::vector gain; public: /// @brief Constructor. /// @param fc Center frequency (Hz). /// @param path Path to save IQ data. /// @return The object. - Usrp(uint32_t fc, uint32_t fs, std::string path); + Usrp(std::string type, uint32_t fc, uint32_t fs, std::string path, + bool *saveIq, std::string address, std::string subdev, + std::vector antenna, std::vector gain); /// @brief Get file name from path. /// @return String of file name based on current time. std::string set_file(std::string path); + /// @brief Implement capture function on USRP. + /// @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(); @@ -51,12 +67,6 @@ public: /// @return Void. void stop(); - /// @brief Implement capture function on RSPduo. - /// @param buffer1 Pointer to reference buffer. - /// @param buffer2 Pointer to surveillance buffer. - /// @return Void. - void process(IqData *buffer1, IqData *buffer2); - /// @brief Implement replay function on RSPduo. /// @param buffer1 Pointer to reference buffer. /// @param buffer2 Pointer to surveillance buffer. @@ -72,15 +82,6 @@ public: /// @brief Close IQ file gracefully. /// @return Void. void close_file(); - - /// @brief Setter for capture. - /// @param capture True if capture is enabled. - /// @return Void. - void set_capture(bool capture); - - /// @brief Getter for capture. - /// @return True if capture is true. - bool get_capture(); }; #endif \ No newline at end of file