From 754798cafbff9714c06e03c30f5683f5ca65a0af Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 20 Feb 2021 12:16:34 +0100 Subject: [PATCH] SigMF file sink: append data if file exists and has been recorded with SDRangel. Implements #781 --- plugins/channelrx/sigmffilesink/readme.md | 2 + .../sigmffilesink/sigmffilesinksink.cpp | 4 +- sdrbase/dsp/sigmffilerecord.cpp | 70 ++++++++++++++++++- sdrbase/dsp/sigmffilerecord.h | 4 ++ 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/plugins/channelrx/sigmffilesink/readme.md b/plugins/channelrx/sigmffilesink/readme.md index 21691249a..f5e1690ef 100644 --- a/plugins/channelrx/sigmffilesink/readme.md +++ b/plugins/channelrx/sigmffilesink/readme.md @@ -13,6 +13,8 @@ As per SigMF specifications two files are created in fact. If a filename is given without `.sigmf-meta` extension then the `.sigmf-meta` extension is appended automatically. If a filename is given with an extension different of `.sigmf-meta` then the extension is replaced by `.sigmf-meta` automatically. +If the couple `.sigmf-meta`, `.sigmf-data` exists for a file set and it was recorded by SDRangel then new data will be appended as new captures. + It adds a dependency to the [libsigmf library](https://github.com/f4exb/libsigmf) more specifically the `f4exb` fork that supports `multirecordings` and `sdrangel` extensions.

Interface

diff --git a/plugins/channelrx/sigmffilesink/sigmffilesinksink.cpp b/plugins/channelrx/sigmffilesink/sigmffilesinksink.cpp index 0687a46cd..283b9872e 100644 --- a/plugins/channelrx/sigmffilesink/sigmffilesinksink.cpp +++ b/plugins/channelrx/sigmffilesink/sigmffilesinksink.cpp @@ -264,8 +264,8 @@ void SigMFFileSinkSink::applySettings(const SigMFFileSinkSettings& settings, boo { m_fileSink.setFileName(fileBase); m_fileSink.setHardwareId(m_deviceHwId); - m_msCount = 0; - m_byteCount = 0; + m_msCount = m_fileSink.getInitialMsCount(); + m_byteCount = m_fileSink.getInitialBytesCount(); m_recordEnabled = true; } else diff --git a/sdrbase/dsp/sigmffilerecord.cpp b/sdrbase/dsp/sigmffilerecord.cpp index a98407fa5..a1ff6fec1 100644 --- a/sdrbase/dsp/sigmffilerecord.cpp +++ b/sdrbase/dsp/sigmffilerecord.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "libsigmf/sigmf_core_generated.h" @@ -39,7 +40,9 @@ SigMFFileRecord::SigMFFileRecord() : m_recordOn(false), m_recordStart(true), m_sampleStart(0), - m_sampleCount(0) + m_sampleCount(0), + m_initialMsCount(0), + m_initialBytesCount(0) { qDebug("SigMFFileRecord::SigMFFileRecord: test"); setObjectName("SigMFFileSink"); @@ -57,7 +60,9 @@ SigMFFileRecord::SigMFFileRecord(const QString& fileName, const QString& hardwar m_recordOn(false), m_recordStart(true), m_sampleStart(0), - m_sampleCount(0) + m_sampleCount(0), + m_initialMsCount(0), + m_initialBytesCount(0) { qDebug("SigMFFileRecord::SigMFFileRecord: %s", qPrintable(fileName)); setObjectName("SigMFFileSink"); @@ -98,7 +103,66 @@ void SigMFFileRecord::setFileName(const QString& fileName) } m_fileName = fileName; - m_recordStart = true; + + if (QFile::exists(fileName + ".sigmf-data") && QFile::exists(fileName + ".sigmf-meta")) + { + m_metaFileName = m_fileName + ".sigmf-meta"; + std::ifstream metaStream; +#ifdef Q_OS_WIN + metaStream.open(m_metaFileName.toStdWString().c_str()); +#else + metaStream.open(m_metaFileName.toStdString().c_str()); +#endif + std::ostringstream meta_buffer; + meta_buffer << metaStream.rdbuf(); + try + { + from_json(json::parse(meta_buffer.str()), *m_metaRecord); + metaStream.close(); + std::string sdrAngelVersion = m_metaRecord->global.access().version; + + if (sdrAngelVersion.size() != 0) + { + qDebug("SigMFFileRecord::setFileName: appending mode"); + m_metaFile.open(m_metaFileName.toStdString().c_str(), std::ofstream::out); + m_initialMsCount = 0; + + for (auto capture : m_metaRecord->captures) + { + uint64_t length = capture.get().length; + int32_t sampleRate = capture.get().sample_rate; + m_initialMsCount += (length * 1000) / sampleRate; + } + + m_sampleFileName = m_fileName + ".sigmf-data"; + m_sampleFile.open(m_sampleFileName.toStdString().c_str(), std::ios::binary & std::ios::app); + m_initialBytesCount = (uint64_t) m_sampleFile.tellp(); + m_sampleStart = m_initialBytesCount / sizeof(Sample); + + m_recordStart = false; + } + else + { + qDebug("SigMFFileRecord::setFileName: SigMF not recorded with SDRangel. Recreating files..."); + m_initialBytesCount = 0; + m_initialMsCount = 0; + m_recordStart = true; + } + } + catch(const std::exception& e) + { + qInfo("SigMFFileRecord::setFileName: exception: %s. Recreating files...", qPrintable(e.what())); + m_initialBytesCount = 0; + m_initialMsCount = 0; + m_recordStart = true; + } + } + else + { + m_initialBytesCount = 0; + m_initialMsCount = 0; + m_recordStart = true; + } } } diff --git a/sdrbase/dsp/sigmffilerecord.h b/sdrbase/dsp/sigmffilerecord.h index 5ab1d714e..0648c5e50 100644 --- a/sdrbase/dsp/sigmffilerecord.h +++ b/sdrbase/dsp/sigmffilerecord.h @@ -52,6 +52,8 @@ public: void setHardwareId(const QString& hardwareId) { m_hardwareId = hardwareId; } void setMsShift(qint64 msShift) { m_msShift = msShift; } unsigned int getNbCaptures() const; + uint64_t getInitialMsCount() const { return m_initialMsCount; } + uint64_t getInitialBytesCount() const { return m_initialBytesCount; } private: QString m_hardwareId; @@ -68,6 +70,8 @@ private: std::ofstream m_sampleFile; quint64 m_sampleStart; quint64 m_sampleCount; + quint64 m_initialMsCount; + quint64 m_initialBytesCount; sigmf::SigMF, sigmf::Capture, sigmf::Annotation > *m_metaRecord;