Update capture architecture to add Source parent class

This commit is contained in:
30hours 2024-01-18 13:17:54 +00:00
parent 068ae901f1
commit 175b2bffe3
11 changed files with 246 additions and 178 deletions

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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<Source> 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<Source> 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<RspDuo>(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<std::string> antenna;
std::vector<double> 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<Usrp>(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)

View file

@ -7,7 +7,13 @@
#define CAPTURE_H
#include <string>
#include <memory>
#include <ryml/ryml.hpp>
#include <ryml/ryml_std.hpp> // optional header, provided for std:: interop
#include <c4/format.hpp> // 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<Source> 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.

19
src/capture/Source.cpp Normal file
View file

@ -0,0 +1,19 @@
#include "Source.h"
#include <iostream>
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;
}

79
src/capture/Source.h Normal file
View file

@ -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 <string>
#include <stdint.h>
#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

View file

@ -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;
}

View file

@ -20,6 +20,7 @@
#define RSPDUO_H
#include "sdrplay_api.h"
#include "capture/Source.h"
#include "data/IqData.h"
#include <stdint.h>
@ -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

View file

@ -1,26 +1,22 @@
#include "Usrp.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <uhd/usrp/multi_usrp.hpp>
#include <complex>
#include <uhd/usrp/multi_usrp.hpp>
// 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<std::string> _antenna,
std::vector<double> _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<std::string> antenna = {"RX2", "RX2"};
std::vector<double> 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<std::complex<float>> usrpBuffer1(samps_per_buff);
std::vector<std::complex<float>> 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;
}

View file

@ -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 <stdint.h>
#include <string>
#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<std::string> antenna;
/// @brief USRP gain for each channel.
std::vector<double> 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<std::string> antenna, std::vector<double> 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