mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-22 08:04:49 -05:00
Merge branch 'freq_scanner' of https://github.com/srcejon/sdrangel into freq_scanner
This commit is contained in:
commit
2a85550fd9
Binary file not shown.
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 115 KiB |
Binary file not shown.
@ -33,26 +33,32 @@ If the fixed position slider is engaged (7) this control is disabled.
|
||||
|
||||
Use this control to decimate the baseband samples by a power of two. Consequently the baseband sample rate is reduced by this factor in the channel.
|
||||
|
||||
<h3>3: Channel (sink) sample rate</h3>
|
||||
<h3>3: Number of sample bits</h3>
|
||||
|
||||
Recording number of bits for an I or Q sample. Can be 8, 16 or 32 resulting in ci8_le, ci16_le or ci32_le file format respectively. 32 bit samples are actually coded as 24 bits i.e the 8 most significant bits are zero.
|
||||
|
||||
This recording format is defined for the whole file you cannot have different formats per capture.
|
||||
|
||||
<h3>4: Channel (sink) sample rate</h3>
|
||||
|
||||
Shows the channel sink sample rate in kS/s. The record capture is effectively recorded at this rate.
|
||||
|
||||
<h3>4: Number of record captures</h3>
|
||||
<h3>5: Number of record captures</h3>
|
||||
|
||||
SigMF can collate many sequences or captures in the same data file (it uses an index in its meta data). This is the number of captures already recorded (not counting the current one if recording).
|
||||
|
||||
<h3>5: Recording time</h3>
|
||||
<h3>6: Recording time</h3>
|
||||
|
||||
This is the current recording time of the whole file (all captures)
|
||||
|
||||
<h3>6: Record size</h3>
|
||||
<h3>7: Record size</h3>
|
||||
|
||||
This is the total number of bytes including all captures. This corresponds to the size of the `.sigmf-data` file. The number is possibly suffixed by a multiplier character:
|
||||
- **k**: _kilo_ for kilobytes
|
||||
- **M**: _mega_ for megabytes
|
||||
- **G**: _giga_ for gigabytes
|
||||
|
||||
<h3>7: Fixed frequency shift positions</h3>
|
||||
<h3>8: Fixed frequency shift positions</h3>
|
||||
|
||||
Use the checkbox to move the shift frequency at definite positions where the chain of half band decimation filters match an exact bandwidth and shift. The effect is to bypass the last interpolator and NCO and thus can save CPU cycles. This may be useful at high sample rates at the expense of not getting exactly on the desired spot.
|
||||
|
||||
@ -62,7 +68,7 @@ When this is engaged the frequency control (1) is disabled.
|
||||
|
||||
This is a GUI only feature when using API it is up to the API client to calculate the desired position. Starting from the center any position lower or higher at the bandwidth divided by two times the decimation factor yields the desired property.
|
||||
|
||||
<h3>8: Spectrum squelch</h3>
|
||||
<h3>9: Spectrum squelch</h3>
|
||||
|
||||
Recording can be triggered by specifying a power level. If any peak in the spectrum exceeds this level then recording is triggered. This button only activates the detection system. When squelch is open the level button (9) lits up in green (as on the screenshot). To activate triggered recording you have to use (12).
|
||||
|
||||
@ -70,36 +76,36 @@ You can try to see for which squelch level you obtain the desired triggering bef
|
||||
|
||||
Note that spectrum polling is done every 200 ms. If the signal of interest is shorter you may want to tweak the spectrum controls using the "Maximum" averaging type and a number of averaging samples making the averaging period (appearing in the tooltip) larger than 200 ms. Please refer to spectrum controls documentation in the main window readme (link in 15) for more details.
|
||||
|
||||
<h3>9: Squelch level</h3>
|
||||
<h3>10: Squelch level</h3>
|
||||
|
||||
This is the squelch level as discussed above. To try to find the correct value you can use the spectrum display (15).
|
||||
|
||||
<h3>10: Pre recording period<h3>
|
||||
<h3>11: Pre recording period<h3>
|
||||
|
||||
This is the number of seconds of data that will be prepended before the start of recording point. Thus you can make sure that the signal of interest will be fully recorded. Works in both spectrum squelch triggered and manual mode.
|
||||
|
||||
<h3>11: Post recording period</h3>
|
||||
<h3>12: Post recording period</h3>
|
||||
|
||||
This applies to spectrum squelch triggered recording only. This is the number of seconds recorded after the squelch closes. If the squelch opens again during this period then the counter is reset and recording will stop only after this period of time is elapsed without the squelch re-opening.
|
||||
|
||||
This is useful if you want to record a bunch of transient bursts or just make sure that the recording does not stop too abruptly.
|
||||
|
||||
<h3>12: Enable/disable spectrum squelch triggered recording</h3>
|
||||
<h3>13: Enable/disable spectrum squelch triggered recording</h3>
|
||||
|
||||
Use this button to effectively apply spectrum squelch to recording. In this mode recording on and off will be under the control of the squelch system. Thus when active the normal record button (13) is disabled. However its color changes to reflect the recording status as described next.
|
||||
|
||||
<h3>13: Record button</h3>
|
||||
<h3>14: Record button</h3>
|
||||
|
||||
Use this button to start/stop recording. Note that with SigMF start/stop recording is starting/stopping a new capture in the same file. Until the file is changed with (14) the same file will be used until the device is stopped or channel plugin is dismissed.
|
||||
|
||||
The button turns red if recording is active.
|
||||
|
||||
<h3>14: Select output file</h3>
|
||||
<h3>15: Select output file</h3>
|
||||
|
||||
Use this button to open a file dialog that lets you specify the location and name of the output files. SigMF creates two files actually one meta file with extension `.sigmf-meta` and one data file with extension `.sigmf-data` that contains the actual IQ data. There you specify the name of the meta file (`.sigmf-meta` extension) and a data file with `.sigmf-data` extension will be created using the same root name as the meta file.
|
||||
|
||||
The path of the selected meta file appears at the right of the button. If it is empty or invalid recording will not be effective.
|
||||
|
||||
<h3>15: Channel spectrum</h3>
|
||||
<h3>16: Channel spectrum</h3>
|
||||
|
||||
This is the spectrum display of the IQ stream seen by the channel. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md)
|
||||
|
@ -328,6 +328,7 @@ void SigMFFileSink::applySettings(const SigMFFileSinkSettings& settings, bool fo
|
||||
<< "m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
|
||||
<< "m_log2Decim: " << settings.m_log2Decim
|
||||
<< "m_fileRecordName: " << settings.m_fileRecordName
|
||||
<< "m_log2RecordSampleSize: " << settings.m_log2RecordSampleSize
|
||||
<< "force: " << force;
|
||||
|
||||
QList<QString> reverseAPIKeys;
|
||||
@ -362,6 +363,9 @@ void SigMFFileSink::applySettings(const SigMFFileSinkSettings& settings, bool fo
|
||||
if ((settings.m_squelchRecordingEnable != m_settings.m_squelchRecordingEnable) || force) {
|
||||
reverseAPIKeys.append("squelchRecordingEnable");
|
||||
}
|
||||
if ((settings.m_log2RecordSampleSize != m_settings.m_log2RecordSampleSize) || force) {
|
||||
reverseAPIKeys.append("log2RecordSampleSize");
|
||||
}
|
||||
|
||||
if (m_settings.m_streamIndex != settings.m_streamIndex)
|
||||
{
|
||||
@ -569,6 +573,9 @@ void SigMFFileSink::webapiUpdateChannelSettings(
|
||||
if (channelSettingsKeys.contains("squelchRecordingEnable")) {
|
||||
settings.m_squelchRecordingEnable = response.getSigMfFileSinkSettings()->getSquelchRecordingEnable() != 0;
|
||||
}
|
||||
if (channelSettingsKeys.contains("log2RecordSampleSize")) {
|
||||
settings.m_log2RecordSampleSize = response.getSigMfFileSinkSettings()->getLog2RecordSampleSize();
|
||||
}
|
||||
if (channelSettingsKeys.contains("streamIndex")) {
|
||||
settings.m_streamIndex = response.getSigMfFileSinkSettings()->getStreamIndex();
|
||||
}
|
||||
@ -625,6 +632,7 @@ void SigMFFileSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings&
|
||||
response.getSigMfFileSinkSettings()->setPreRecordTime(settings.m_preRecordTime);
|
||||
response.getSigMfFileSinkSettings()->setSquelchPostRecordTime(settings.m_squelchPostRecordTime);
|
||||
response.getSigMfFileSinkSettings()->setSquelchRecordingEnable(settings.m_squelchRecordingEnable ? 1 : 0);
|
||||
response.getSigMfFileSinkSettings()->setLog2RecordSampleSize(settings.m_log2RecordSampleSize);
|
||||
response.getSigMfFileSinkSettings()->setStreamIndex(settings.m_streamIndex);
|
||||
response.getSigMfFileSinkSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||
|
||||
@ -793,6 +801,9 @@ void SigMFFileSink::webapiFormatChannelSettings(
|
||||
if (channelSettingsKeys.contains("squelchRecordingEnable")) {
|
||||
swgSigMFFileSinkSettings->setSquelchRecordingEnable(settings.m_squelchRecordingEnable ? 1 : 0);
|
||||
}
|
||||
if (channelSettingsKeys.contains("log2RecordSampleSize")) {
|
||||
swgSigMFFileSinkSettings->setLog2RecordSampleSize(settings.m_log2RecordSampleSize);
|
||||
}
|
||||
if (channelSettingsKeys.contains("streamIndex")) {
|
||||
swgSigMFFileSinkSettings->setStreamIndex(settings.m_streamIndex);
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ bool SigMFFileSinkGUI::handleMessage(const Message& message)
|
||||
ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2);
|
||||
ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2));
|
||||
displayRate();
|
||||
updateAbsoluteCenterFrequency();
|
||||
|
||||
if (m_fixedPosition)
|
||||
{
|
||||
@ -274,6 +275,7 @@ void SigMFFileSinkGUI::displaySettings()
|
||||
ui->postSquelchTime->setValue(m_settings.m_squelchPostRecordTime);
|
||||
ui->postSquelchTimeText->setText(tr("%1").arg(m_settings.m_squelchPostRecordTime));
|
||||
ui->squelchedRecording->setChecked(m_settings.m_squelchRecordingEnable);
|
||||
ui->recordSampleSize->setCurrentIndex((int) m_settings.m_log2RecordSampleSize - 3);
|
||||
|
||||
if (!m_settings.m_spectrumSquelchMode)
|
||||
{
|
||||
@ -431,6 +433,12 @@ void SigMFFileSinkGUI::on_decimationFactor_currentIndexChanged(int index)
|
||||
}
|
||||
}
|
||||
|
||||
void SigMFFileSinkGUI::on_recordSampleSize_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_log2RecordSampleSize = index + 3;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void SigMFFileSinkGUI::on_fixedPosition_toggled(bool checked)
|
||||
{
|
||||
m_fixedPosition = checked;
|
||||
@ -506,6 +514,7 @@ void SigMFFileSinkGUI::on_squelchedRecording_toggled(bool checked)
|
||||
|
||||
void SigMFFileSinkGUI::on_record_toggled(bool checked)
|
||||
{
|
||||
ui->recordSampleSize->setEnabled(!checked);
|
||||
m_sigMFFileSink->record(checked);
|
||||
}
|
||||
|
||||
@ -603,6 +612,7 @@ void SigMFFileSinkGUI::makeUIConnections()
|
||||
{
|
||||
QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &SigMFFileSinkGUI::on_deltaFrequency_changed);
|
||||
QObject::connect(ui->decimationFactor, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SigMFFileSinkGUI::on_decimationFactor_currentIndexChanged);
|
||||
QObject::connect(ui->recordSampleSize, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SigMFFileSinkGUI::on_recordSampleSize_currentIndexChanged);
|
||||
QObject::connect(ui->fixedPosition, &QCheckBox::toggled, this, &SigMFFileSinkGUI::on_fixedPosition_toggled);
|
||||
QObject::connect(ui->position, &QSlider::valueChanged, this, &SigMFFileSinkGUI::on_position_valueChanged);
|
||||
QObject::connect(ui->spectrumSquelch, &ButtonSwitch::toggled, this, &SigMFFileSinkGUI::on_spectrumSquelch_toggled);
|
||||
|
@ -113,6 +113,7 @@ private slots:
|
||||
void handleSourceMessages();
|
||||
void on_deltaFrequency_changed(qint64 value);
|
||||
void on_decimationFactor_currentIndexChanged(int index);
|
||||
void on_recordSampleSize_currentIndexChanged(int index);
|
||||
void on_fixedPosition_toggled(bool checked);
|
||||
void on_position_valueChanged(int value);
|
||||
void on_spectrumSquelch_toggled(bool checked);
|
||||
|
@ -183,6 +183,41 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="recordSampleSizeLabel">
|
||||
<property name="text">
|
||||
<string>b</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="recordSampleSize">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>55</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Record sample size I or Q (bits)</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>16</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>32</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
|
@ -44,6 +44,7 @@ void SigMFFileSinkSettings::resetToDefaults()
|
||||
m_preRecordTime = 0;
|
||||
m_squelchPostRecordTime = 0;
|
||||
m_squelchRecordingEnable = false;
|
||||
m_log2RecordSampleSize = 5;
|
||||
m_streamIndex = 0;
|
||||
m_useReverseAPI = false;
|
||||
m_reverseAPIAddress = "127.0.0.1";
|
||||
@ -91,6 +92,7 @@ QByteArray SigMFFileSinkSettings::serialize() const
|
||||
s.writeS32(21, m_workspaceIndex);
|
||||
s.writeBlob(22, m_geometryBytes);
|
||||
s.writeBool(23, m_hidden);
|
||||
s.writeU32(24, m_log2RecordSampleSize);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -163,6 +165,8 @@ bool SigMFFileSinkSettings::deserialize(const QByteArray& data)
|
||||
d.readS32(21, &m_workspaceIndex, 0);
|
||||
d.readBlob(22, &m_geometryBytes);
|
||||
d.readBool(23, &m_hidden, false);
|
||||
d.readU32(24, &tmp, 5);
|
||||
m_log2RecordSampleSize = (tmp < 3 ? 3 : tmp > 5 ? 5 : tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ struct SigMFFileSinkSettings
|
||||
int m_preRecordTime;
|
||||
int m_squelchPostRecordTime;
|
||||
bool m_squelchRecordingEnable;
|
||||
uint32_t m_log2RecordSampleSize;
|
||||
int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx).
|
||||
bool m_useReverseAPI;
|
||||
QString m_reverseAPIAddress;
|
||||
|
@ -72,7 +72,7 @@ void SigMFFileSinkSink::startRecording()
|
||||
m_fileSink.feed(p2Begin, p2End, false);
|
||||
}
|
||||
|
||||
m_byteCount += m_preRecordFill * sizeof(Sample);
|
||||
m_byteCount += m_preRecordFill * ((1<<m_settings.m_log2RecordSampleSize)/4); // sizeof(Sample);
|
||||
|
||||
if (m_sinkSampleRate > 0) {
|
||||
m_msCount += (m_preRecordFill * 1000) / m_sinkSampleRate;
|
||||
@ -149,7 +149,7 @@ void SigMFFileSinkSink::feed(const SampleVector::const_iterator& begin, const Sa
|
||||
}
|
||||
}
|
||||
|
||||
m_byteCount += nbToWrite * sizeof(Sample);
|
||||
m_byteCount += nbToWrite * ((1<<m_settings.m_log2RecordSampleSize)/4); // sizeof(Sample);
|
||||
|
||||
if (m_sinkSampleRate > 0) {
|
||||
m_msCount += (nbToWrite * 1000) / m_sinkSampleRate;
|
||||
@ -159,7 +159,7 @@ void SigMFFileSinkSink::feed(const SampleVector::const_iterator& begin, const Sa
|
||||
{
|
||||
m_fileSink.feed(beginw, endw, true);
|
||||
int nbSamples = endw - beginw;
|
||||
m_byteCount += nbSamples * sizeof(Sample);
|
||||
m_byteCount += nbSamples * ((1<<m_settings.m_log2RecordSampleSize)/4); // sizeof(Sample);
|
||||
|
||||
if (m_sinkSampleRate > 0) {
|
||||
m_msCount += (nbSamples * 1000) / m_sinkSampleRate;
|
||||
@ -293,6 +293,10 @@ void SigMFFileSinkSink::applySettings(const SigMFFileSinkSettings& settings, boo
|
||||
}
|
||||
}
|
||||
|
||||
if ((settings.m_log2RecordSampleSize != m_settings.m_log2RecordSampleSize) || force) {
|
||||
m_fileSink.setLog2RecordSampleSize(settings.m_log2RecordSampleSize);
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
m_settings.m_fileRecordName = fileRecordName;
|
||||
}
|
||||
|
@ -668,7 +668,7 @@ void DemodAnalyzer::handleDataPipeToBeDeleted(int reason, QObject *object)
|
||||
}
|
||||
|
||||
int DemodAnalyzer::webapiActionsPost(
|
||||
const QStringList& featureActionsKeys,
|
||||
const QStringList&,
|
||||
SWGSDRangel::SWGFeatureActions& query,
|
||||
QString& errorMessage) {
|
||||
|
||||
|
@ -29,9 +29,9 @@ QString KissEngine::getName() const
|
||||
void KissEngine::configure(int n, bool inverse)
|
||||
{
|
||||
m_fft.configure(n, inverse);
|
||||
if(n > m_in.size())
|
||||
if(n > (int) m_in.size())
|
||||
m_in.resize(n);
|
||||
if(n > m_out.size())
|
||||
if(n > (int) m_out.size())
|
||||
m_out.resize(n);
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,8 @@ SigMFFileRecord::SigMFFileRecord() :
|
||||
m_metaRecord = new sigmf::SigMF<sigmf::Global<core::DescrT, sdrangel::DescrT>,
|
||||
sigmf::Capture<core::DescrT, sdrangel::DescrT>,
|
||||
sigmf::Annotation<core::DescrT> >();
|
||||
// sizeof(FixReal) is either 2 or 4 thus log2 sample size is either 4 (size 16) or 5 (size 32)
|
||||
m_log2RecordSampleSize = (sizeof(FixReal) / 2) + 3;
|
||||
}
|
||||
|
||||
SigMFFileRecord::SigMFFileRecord(const QString& fileName, const QString& hardwareId) :
|
||||
@ -71,6 +73,8 @@ SigMFFileRecord::SigMFFileRecord(const QString& fileName, const QString& hardwar
|
||||
m_metaRecord = new sigmf::SigMF<sigmf::Global<core::DescrT, sdrangel::DescrT>,
|
||||
sigmf::Capture<core::DescrT, sdrangel::DescrT>,
|
||||
sigmf::Annotation<core::DescrT> >();
|
||||
// sizeof(FixReal) is either 2 or 4 thus log2 sample size is either 4 (size 16) or 5 (size 32)
|
||||
m_log2RecordSampleSize = (sizeof(FixReal) / 2) + 3;
|
||||
}
|
||||
|
||||
SigMFFileRecord::~SigMFFileRecord()
|
||||
@ -139,7 +143,7 @@ void SigMFFileRecord::setFileName(const QString& fileName)
|
||||
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_sampleStart = m_initialBytesCount / ((1<<m_log2RecordSampleSize)/4); // sizeof(Sample);
|
||||
|
||||
m_recordStart = false;
|
||||
}
|
||||
@ -245,7 +249,8 @@ void SigMFFileRecord::makeHeader()
|
||||
m_metaRecord->global.access<sdrangel::GlobalT>().arch = QString(QSysInfo::currentCpuArchitecture()).toStdString();
|
||||
m_metaRecord->global.access<sdrangel::GlobalT>().os = QString(QSysInfo::prettyProductName()).toStdString();
|
||||
QString endianSuffix = QSysInfo::ByteOrder == QSysInfo::LittleEndian ? "le" : "be";
|
||||
int size = 8*sizeof(FixReal);
|
||||
int size = 1<<m_log2RecordSampleSize;
|
||||
qDebug("SigMFFileRecord::makeHeader: %u %u", m_log2RecordSampleSize, (1<<m_log2RecordSampleSize));
|
||||
m_metaRecord->global.access<core::GlobalT>().datatype = QString("ci%1_%2").arg(size).arg(endianSuffix).toStdString();
|
||||
}
|
||||
|
||||
@ -294,11 +299,75 @@ void SigMFFileRecord::feed(const SampleVector::const_iterator& begin, const Samp
|
||||
|
||||
if (begin < end) // if there is something to put out
|
||||
{
|
||||
m_sampleFile.write(reinterpret_cast<const char*>(&*(begin)), (end - begin)*sizeof(Sample));
|
||||
// m_sampleFile.write(reinterpret_cast<const char*>(&*(begin)), (end - begin)*sizeof(Sample));
|
||||
feedConv(begin, end);
|
||||
m_sampleCount += end - begin;
|
||||
}
|
||||
}
|
||||
|
||||
void SigMFFileRecord::feedConv(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
|
||||
{
|
||||
uint32_t desiredIorQSampleSize = 1<<m_log2RecordSampleSize;
|
||||
|
||||
if (2*desiredIorQSampleSize == 8*sizeof(Sample)) // if size of sample matches desired sample size write directly
|
||||
{
|
||||
m_sampleFile.write(reinterpret_cast<const char*>(&*(begin)), (end - begin)*sizeof(Sample));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t nsamples = (end - begin);
|
||||
|
||||
// Only the 24 LSBits of the 32 bits samples are significant
|
||||
if (desiredIorQSampleSize == 32) // can only be 16 bit samples => x8 (16 -> 24)
|
||||
{
|
||||
if (nsamples > m_samples32.size()) {
|
||||
m_samples32.resize(nsamples);
|
||||
}
|
||||
std::transform(
|
||||
begin,
|
||||
end,
|
||||
m_samples32.begin(),
|
||||
[](const Sample& s) -> Sample32 {
|
||||
return Sample32{s.real()<<8, s.imag()<<8};
|
||||
}
|
||||
);
|
||||
m_sampleFile.write(reinterpret_cast<const char*>(&*(m_samples32.begin())), nsamples*sizeof(Sample32));
|
||||
}
|
||||
else if (desiredIorQSampleSize == 16) // can only be 32 bit samples size => /8 (24 -> 16)
|
||||
{
|
||||
if (nsamples > m_samples16.size()) {
|
||||
m_samples16.resize(nsamples);
|
||||
}
|
||||
std::transform(
|
||||
begin,
|
||||
end,
|
||||
m_samples16.begin(),
|
||||
[](const Sample& s) -> Sample16 {
|
||||
return Sample16{(qint16)(s.real()>>8), (qint16)(s.imag()>>8)};
|
||||
}
|
||||
);
|
||||
m_sampleFile.write(reinterpret_cast<const char*>(&*(m_samples16.begin())), nsamples*sizeof(Sample16));
|
||||
}
|
||||
else // can only be 8 bit desired sample size
|
||||
{
|
||||
// divide by 8 for 16 -> 8 (sizeof(sample) == 4) or 16 for 24 -> 8 (sizeod(Sample) == 8)
|
||||
// thus division of a I or Q sample is done with >>(2*sizeof(sample)) operation
|
||||
if (nsamples > m_samples8.size()) {
|
||||
m_samples8.resize(nsamples);
|
||||
}
|
||||
std::transform(
|
||||
begin,
|
||||
end,
|
||||
m_samples8.begin(),
|
||||
[](const Sample& s) -> Sample8 {
|
||||
return Sample8{(qint8)(s.real()>>(2*sizeof(Sample))), (qint8)(s.imag()>>(2*sizeof(Sample)))};
|
||||
}
|
||||
);
|
||||
m_sampleFile.write(reinterpret_cast<const char*>(&*(m_samples8.begin())), nsamples*sizeof(Sample8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SigMFFileRecord::start()
|
||||
{
|
||||
}
|
||||
|
@ -57,8 +57,24 @@ public:
|
||||
unsigned int getNbCaptures() const;
|
||||
uint64_t getInitialMsCount() const { return m_initialMsCount; }
|
||||
uint64_t getInitialBytesCount() const { return m_initialBytesCount; }
|
||||
void setLog2RecordSampleSize(uint32_t log2RecordSampleSize) { m_log2RecordSampleSize = log2RecordSampleSize; }
|
||||
|
||||
private:
|
||||
struct Sample8 {
|
||||
qint8 m_real;
|
||||
qint8 m_imag;
|
||||
};
|
||||
|
||||
struct Sample16 {
|
||||
qint16 m_real;
|
||||
qint16 m_imag;
|
||||
};
|
||||
|
||||
struct Sample32 {
|
||||
qint32 m_real;
|
||||
qint32 m_imag;
|
||||
};
|
||||
|
||||
QString m_hardwareId;
|
||||
QString m_fileName;
|
||||
QString m_sampleFileName;
|
||||
@ -75,12 +91,17 @@ private:
|
||||
quint64 m_sampleCount;
|
||||
quint64 m_initialMsCount;
|
||||
quint64 m_initialBytesCount;
|
||||
uint32_t m_log2RecordSampleSize;
|
||||
sigmf::SigMF<sigmf::Global<core::DescrT, sdrangel::DescrT>,
|
||||
sigmf::Capture<core::DescrT, sdrangel::DescrT>,
|
||||
sigmf::Annotation<core::DescrT> > *m_metaRecord;
|
||||
std::vector<Sample8> m_samples8;
|
||||
std::vector<Sample16> m_samples16;
|
||||
std::vector<Sample32> m_samples32;
|
||||
void makeHeader();
|
||||
void makeCapture();
|
||||
void clearMeta();
|
||||
void feedConv(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SIGMF_FILERECORD_H
|
||||
|
@ -14562,6 +14562,10 @@ margin-bottom: 20px;
|
||||
"type" : "integer",
|
||||
"description" : "Automatic recording triggered by spectrum squalch * 0 - disabled * 1 - enabled\n"
|
||||
},
|
||||
"log2RecordSampleSize" : {
|
||||
"type" : "integer",
|
||||
"description" : "log2 of recording sample (I or Q) size in bits. Can be 3, 4 or 5."
|
||||
},
|
||||
"streamIndex" : {
|
||||
"type" : "integer",
|
||||
"description" : "MIMO channel. Not relevant when connected to SI (single Rx)."
|
||||
@ -58773,7 +58777,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2024-03-03T22:27:13.533+01:00
|
||||
Generated 2024-03-04T22:20:15.730+01:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,6 +34,9 @@ SigMFFileSinkSettings:
|
||||
Automatic recording triggered by spectrum squalch
|
||||
* 0 - disabled
|
||||
* 1 - enabled
|
||||
log2RecordSampleSize:
|
||||
type: integer
|
||||
description: log2 of recording sample (I or Q) size in bits. Can be 3, 4 or 5.
|
||||
streamIndex:
|
||||
description: MIMO channel. Not relevant when connected to SI (single Rx).
|
||||
type: integer
|
||||
|
@ -51,4 +51,4 @@ export IMAGE_CODEGEN_VERSION=${image_tag_codegen}
|
||||
export IMAGE_SERVER_VERSION=${image_tag_server}
|
||||
export SDRANGEL_BASE=${sdrangel_codebase}
|
||||
|
||||
docker-compose -f compose.yml ${stack_name} ${action}
|
||||
docker compose -f compose.yml ${stack_name} ${action}
|
||||
|
@ -34,6 +34,9 @@ SigMFFileSinkSettings:
|
||||
Automatic recording triggered by spectrum squalch
|
||||
* 0 - disabled
|
||||
* 1 - enabled
|
||||
log2RecordSampleSize:
|
||||
type: integer
|
||||
description: log2 of recording sample (I or Q) size in bits. Can be 3, 4 or 5.
|
||||
streamIndex:
|
||||
description: MIMO channel. Not relevant when connected to SI (single Rx).
|
||||
type: integer
|
||||
|
@ -14562,6 +14562,10 @@ margin-bottom: 20px;
|
||||
"type" : "integer",
|
||||
"description" : "Automatic recording triggered by spectrum squalch * 0 - disabled * 1 - enabled\n"
|
||||
},
|
||||
"log2RecordSampleSize" : {
|
||||
"type" : "integer",
|
||||
"description" : "log2 of recording sample (I or Q) size in bits. Can be 3, 4 or 5."
|
||||
},
|
||||
"streamIndex" : {
|
||||
"type" : "integer",
|
||||
"description" : "MIMO channel. Not relevant when connected to SI (single Rx)."
|
||||
@ -58773,7 +58777,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2024-03-03T22:27:13.533+01:00
|
||||
Generated 2024-03-04T22:20:15.730+01:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -48,6 +48,8 @@ SWGSigMFFileSinkSettings::SWGSigMFFileSinkSettings() {
|
||||
m_squelch_post_record_time_isSet = false;
|
||||
squelch_recording_enable = 0;
|
||||
m_squelch_recording_enable_isSet = false;
|
||||
log2_record_sample_size = 0;
|
||||
m_log2_record_sample_size_isSet = false;
|
||||
stream_index = 0;
|
||||
m_stream_index_isSet = false;
|
||||
use_reverse_api = 0;
|
||||
@ -94,6 +96,8 @@ SWGSigMFFileSinkSettings::init() {
|
||||
m_squelch_post_record_time_isSet = false;
|
||||
squelch_recording_enable = 0;
|
||||
m_squelch_recording_enable_isSet = false;
|
||||
log2_record_sample_size = 0;
|
||||
m_log2_record_sample_size_isSet = false;
|
||||
stream_index = 0;
|
||||
m_stream_index_isSet = false;
|
||||
use_reverse_api = 0;
|
||||
@ -132,6 +136,7 @@ SWGSigMFFileSinkSettings::cleanup() {
|
||||
|
||||
|
||||
|
||||
|
||||
if(reverse_api_address != nullptr) {
|
||||
delete reverse_api_address;
|
||||
}
|
||||
@ -180,6 +185,8 @@ SWGSigMFFileSinkSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&squelch_recording_enable, pJson["squelchRecordingEnable"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&log2_record_sample_size, pJson["log2RecordSampleSize"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
|
||||
@ -244,6 +251,9 @@ SWGSigMFFileSinkSettings::asJsonObject() {
|
||||
if(m_squelch_recording_enable_isSet){
|
||||
obj->insert("squelchRecordingEnable", QJsonValue(squelch_recording_enable));
|
||||
}
|
||||
if(m_log2_record_sample_size_isSet){
|
||||
obj->insert("log2RecordSampleSize", QJsonValue(log2_record_sample_size));
|
||||
}
|
||||
if(m_stream_index_isSet){
|
||||
obj->insert("streamIndex", QJsonValue(stream_index));
|
||||
}
|
||||
@ -375,6 +385,16 @@ SWGSigMFFileSinkSettings::setSquelchRecordingEnable(qint32 squelch_recording_ena
|
||||
this->m_squelch_recording_enable_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGSigMFFileSinkSettings::getLog2RecordSampleSize() {
|
||||
return log2_record_sample_size;
|
||||
}
|
||||
void
|
||||
SWGSigMFFileSinkSettings::setLog2RecordSampleSize(qint32 log2_record_sample_size) {
|
||||
this->log2_record_sample_size = log2_record_sample_size;
|
||||
this->m_log2_record_sample_size_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGSigMFFileSinkSettings::getStreamIndex() {
|
||||
return stream_index;
|
||||
@ -500,6 +520,9 @@ SWGSigMFFileSinkSettings::isSet(){
|
||||
if(m_squelch_recording_enable_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_log2_record_sample_size_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_stream_index_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
@ -75,6 +75,9 @@ public:
|
||||
qint32 getSquelchRecordingEnable();
|
||||
void setSquelchRecordingEnable(qint32 squelch_recording_enable);
|
||||
|
||||
qint32 getLog2RecordSampleSize();
|
||||
void setLog2RecordSampleSize(qint32 log2_record_sample_size);
|
||||
|
||||
qint32 getStreamIndex();
|
||||
void setStreamIndex(qint32 stream_index);
|
||||
|
||||
@ -136,6 +139,9 @@ private:
|
||||
qint32 squelch_recording_enable;
|
||||
bool m_squelch_recording_enable_isSet;
|
||||
|
||||
qint32 log2_record_sample_size;
|
||||
bool m_log2_record_sample_size_isSet;
|
||||
|
||||
qint32 stream_index;
|
||||
bool m_stream_index_isSet;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user