PicoScenes API Docs
 
Loading...
Searching...
No Matches
AbstractSDRFrontEnd.hxx
Go to the documentation of this file.
1//
2// Created by Zhiping Jiang on 5/2/21.
3//
4
5#ifndef PICOSCENES_PLATFORM_ABSTRACTSDRFRONTEND_HXX
6#define PICOSCENES_PLATFORM_ABSTRACTSDRFRONTEND_HXX
7
8#include <deque>
9#include "BoostHeaders.hxx"
10#include "Intrinsics.hxx"
11#include "SystemTools.hxx"
12#include "AbstractFrontEnd.hxx"
14#include "BBSignalsFileWriter.hxx"
15#include "LicenseService.hxx"
17
22public:
31
38 virtual CS16Vector generateSignal(const ModularPicoScenesTxFrame& frame, uint8_t numTxAntenna) = 0;
39
44 virtual std::vector<CS16Vector> generateMultiChannelSignals(const ModularPicoScenesTxFrame& frame, const uint8_t numTxAntenna) {
45 auto signals = generateSignal(frame, numTxAntenna);
46 auto numSamples = static_cast<int64_t>(signals.size()) / numTxAntenna;
47
48 std::vector multiChannelSignals(numTxAntenna, CS16Vector(numSamples));
49 for (auto channelIndex = 0; channelIndex < numTxAntenna; channelIndex++) {
50 Intrinsics::fastCopyN(signals.cbegin() + numSamples * channelIndex, numSamples, multiChannelSignals[channelIndex].begin());
51 }
52
53 return multiChannelSignals;
54 }
55
65 virtual void prebuildSignals(ModularPicoScenesTxFrame& frame, const uint8_t numTxAntenna) {
66 frame.prebuiltSignals = std::move(generateMultiChannelSignals(frame, numTxAntenna));
67 }
68
76 virtual int transmitSignalsFromFile(const std::string& signalSourceFile, uint64_t repeat) = 0;
77
78 virtual int32_t transmitSignals(const std::vector<const void*>& signals, int64_t bufferLength, double postfixDuration) = 0;
79
80 virtual int transmitSignalsContinuously(const std::vector<const void*>& multiChannelHeaders, int64_t numSignalsPerAntenna, bool burstStart, bool burstEnd) = 0;
81
91 int transmit(const ModularPicoScenesTxFrame& frame) override {
92 static std::shared_ptr<BBSignalsFileWriter<std::complex<int16_t>>> signalWriter;
94 startTx();
95
96 if (txSignalDumpFilePath && !signalWriter) {
98 signalWriter = std::make_shared<BBSignalsFileWriter<std::complex<int16_t>>>(*txSignalDumpFilePath);
99 }
100
101 auto numTxChannels = userSpecifiedTxChannels().size();
102 size_t txResult{};
103 std::vector<CS16Vector> inplaceGeneratedSignals{};
104 if (frame.prebuiltSignals.empty()) {
105 inplaceGeneratedSignals = std::move(generateMultiChannelSignals(frame, numTxChannels));
106 txResult = transmitSignal(inplaceGeneratedSignals, frame.txParameters.postfixPaddingTime);
107 } else {
108 txResult = transmitSignal(frame.prebuiltSignals, frame.txParameters.postfixPaddingTime);
109 }
110 const auto& ref2Signals = !frame.prebuiltSignals.empty() ? frame.prebuiltSignals : inplaceGeneratedSignals;
111
112 // TODO to fix
113 // if (signalWriter)
114 // signalWriter->write2DStream(ref2Signals);
115
116 if (!txResult) {
117 LoggingService_SDR_debug_printf("<%s>(%s)-->%s | PPDU: %u x %u (%.3f us)", getReferredInterfaceName(), DeviceSubtype2String(getFrontEndSubtype()), frame.toString(), ref2Signals[0].size(), ref2Signals.size(), 1e6f * ref2Signals[0].size() / getTxSamplingRate());
118 } else {
119 LoggingService_SDR_debug_printf("<%s>(%s) tx failure. | PPDU: %u x %u (%.3f us)", getReferredInterfaceName(), DeviceSubtype2String(getFrontEndSubtype()), ref2Signals[0].size(), ref2Signals.size(), 1e6f * ref2Signals[0].size() / getTxSamplingRate());
120 }
121
122 return 0;
123 }
124
125 virtual size_t transmitSignal(const CS16Vector& signals, const uint8_t numTxChannels, const double postfixDuration) {
126 int64_t numSignalsPerAntenna = signals.size() / numTxChannels;
127
128 auto signalHeaders = std::vector<const void*>(numTxChannels);
129 for (auto channelIndex = 0; channelIndex < numTxChannels; channelIndex++) {
130 signalHeaders[channelIndex] = signals.data() + channelIndex * numSignalsPerAntenna;
131 }
132
133 return transmitSignals(signalHeaders, numSignalsPerAntenna, postfixDuration);
134 }
135
136 virtual size_t transmitSignal(const std::vector<CS16Vector>& multiChannelSignals, const double postfixDuration) {
137 int64_t numSignalsPerAntenna = multiChannelSignals[0].size();
138 uint8_t numTxChannels = multiChannelSignals.size();
139
140 auto signalHeaders = std::vector<const void*>(numTxChannels);
141 for (auto channelIndex = 0; channelIndex < numTxChannels; channelIndex++) {
142 signalHeaders[channelIndex] = multiChannelSignals[channelIndex].data();
143 }
144
145 return transmitSignals(signalHeaders, numSignalsPerAntenna, postfixDuration);
146 }
147
148 virtual int32_t transmitSignalInBatchedSingleBurst(const std::vector<std::vector<const void*>>& multipleSignals, const std::vector<int64_t>& signalLength, const std::vector<double>& postfixDurations, uint32_t repeat) = 0;
149
150 int transmitFramesInBatch(const std::vector<const ModularPicoScenesTxFrame*>& frames, const uint32_t repeat) override {
151 static std::shared_ptr<BBSignalsFileWriter<std::complex<int16_t>>> signalWriter;
152 if (!txServiceStarted)
153 startTx();
154
155 if (txSignalDumpFilePath && !signalWriter) {
157 signalWriter = std::make_shared<BBSignalsFileWriter<std::complex<int16_t>>>(*txSignalDumpFilePath);
158 }
159
160 std::vector<std::vector<CS16Vector>> frameSignals;
161 std::vector<std::vector<const void*>> frameSignalHeads;
162 std::vector<int64_t> framePPDULengths;
163 std::vector<double> framePostfixDurations;
164 for (const auto* frame: frames) {
165 if (!frame->prebuiltSignals.empty()) {
166 std::vector<const void*> signalHeaders;
167 signalHeaders.reserve(frame->prebuiltSignals.size());
168 for (const auto& column: frame->prebuiltSignals)
169 signalHeaders.emplace_back(column.data());
170 frameSignalHeads.emplace_back(signalHeaders);
171 framePPDULengths.emplace_back(frame->prebuiltSignals.at(0).size());
172 framePostfixDurations.emplace_back(frame->txParameters.postfixPaddingTime);
173 } else {
174 frameSignals.emplace_back(generateMultiChannelSignals(*frame, userSpecifiedTxChannels().size()));
175 std::vector<const void*> signalHeaders;
176 for (const auto& column: frameSignals.back())
177 signalHeaders.emplace_back(column.data());
178 frameSignalHeads.emplace_back(signalHeaders);
179 framePPDULengths.emplace_back(frameSignals.back().at(0).size());
180 framePostfixDurations.emplace_back(frame->txParameters.postfixPaddingTime);
181 }
182 }
183
184 const auto txResult = transmitSignalInBatchedSingleBurst(frameSignalHeads, framePPDULengths, framePostfixDurations, repeat);
185
186 auto totalTransmitSamples = [&] {
187 size_t total{0};
188 for (auto i = 0; i < framePPDULengths.size(); i++) {
189 total += framePPDULengths[i] + static_cast<int64_t>(std::round(framePostfixDurations[i] * getTxSamplingRate()));
190 }
191 total *= repeat;
192 return total;
193 }();
194 [[maybe_unused]] auto latestResult = getLastTxStatus();
195
196 // TODO temporarily disable this field
197 // if (signalWriter) {
198 // for (auto r = 0; r < repeat; r++) {
199 // for (auto i = 0; i < framePPDULengths.size(); i++) {
200 // signalWriter->write2DStream(frameSignalHeads[i], framePPDULengths[i]);
201 // size_t zeroLength = static_cast<int64_t>(std::round(framePostfixDurations[i] * getTxSamplingRate()));
202 // signalWriter->writeZerosTo2DStream(zeroLength);
203 // }
204 // }
205 // }
206
207 if (!txResult) {
208 LoggingService_SDR_debug_printf("%s(%s) batch-Tx %u frames w/ %u repeat. Total Tx: %u samples (%.3f us) | 1st frame -->%s | PPDU: %u (%.3f us)", getReferredInterfaceName(), DeviceType2String(getFrontEndType()), frames.size(), repeat, totalTransmitSamples, 1e6f * totalTransmitSamples / getTxSamplingRate(), frames[0]->toString(), framePPDULengths[0], 1e6f * framePPDULengths[0] / getTxSamplingRate());
209 } else {
210 LoggingService_SDR_warning_printf("%s(%s) FAILED to batch-Tx %u frames w/ %u repeats. Total Tx: %u samples (%.3f us) | 1st frame -->%s | PPDU: %u (%.3f us)", getReferredInterfaceName(), DeviceType2String(getFrontEndType()), frames.size(), repeat, totalTransmitSamples, 1e6f * totalTransmitSamples / getTxSamplingRate(), frames[0]->toString(), framePPDULengths[0], 1e6f * framePPDULengths[0] / getTxSamplingRate());
211 }
212
213 return txResult;
214 }
215
219 template<int repeat = 1, typename... Frames, typename = std::enable_if_t<(std::is_same_v<std::remove_cvref_t<Frames>, ModularPicoScenesTxFrame*> && ...) || (std::is_same_v<std::remove_cvref_t<Frames>, ModularPicoScenesTxFrame> && ...) || ((std::is_same_v<std::remove_cvref_t<Frames>, std::shared_ptr<ModularPicoScenesTxFrame>> || std::is_same_v<std::remove_cvref_t<Frames>, std::unique_ptr<ModularPicoScenesTxFrame>>) && ...)>>
220 [[maybe_unused]] int transmitFramesInBatch(Frames&&... frames) {
221 return AbstractFrontEnd::transmitFramesInBatch<repeat>(std::forward<Frames>(frames)...);
222 }
223
224 // int transmitTest(const ModularPicoScenesTxFrame &frame1, const ModularPicoScenesTxFrame &frame2) {
225 // ModularPicoScenesTxFrame t1, t2, t3;
226 // auto t4 = std::make_shared<ModularPicoScenesTxFrame>();
227 // auto t5 = std::make_shared<ModularPicoScenesTxFrame>();
228 // auto t6 = std::make_unique<ModularPicoScenesTxFrame>();
229 // auto t7 = std::make_unique<ModularPicoScenesTxFrame>();
230 // transmitFramesInBatch(t4, t6);
231 // transmitFramesInBatch(t6, t7);
232 // transmitFramesInBatch(t1, t2, t3);
233 // return transmitFramesInBatch(frame1, frame2);
234 // }
235
236 virtual std::optional<double> getCurrentNoiseFloor() = 0;
237
238 [[nodiscard]] virtual SDRFrontEndTxStatus getLastTxStatus() const = 0;
239
240 virtual void clearTxStatus() = 0;
241
242 void setTxSignalDumpFilePath(const std::string& txSignalDumpFilePathV) {
243 AbstractSDRFrontEnd::txSignalDumpFilePath = txSignalDumpFilePathV;
244 }
245
246 void setRxSignalDumpFilePath(const std::string& rxSignalDumpFilePathV) {
247 rxSignalDumpFilePath = rxSignalDumpFilePathV;
248 }
249
250 void setRxSignalDumpDelayedStartDuration(const double delayedStartDuration) {
251 rxSignalDumpDelayedStartDuration = delayedStartDuration;
252 }
253
254 void setSignalReplayFilePath(const std::string& signalReplayFilePath) {
255 rxSignalReplayFilePath = signalReplayFilePath;
256 }
257
258 void setTxSignalReplayDelayMs(const std::optional<uint32_t>& txSignalReplayDelayMs) {
259 txSignalReplayDelay_ms = txSignalReplayDelayMs;
260 }
261
262 ChannelBandwidthEnum getRxChannelBandwidthMode() override {
263 return rxCBW;
264 }
265
266 void setRxChannelBandwidthMode(ChannelBandwidthEnum rxCbw) override {
267 rxCBW = rxCbw;
268 LoggingService_SDR_info_print("<{}> sets RX channel bandwidth (CBW) to [{}].", getReferredInterfaceName(), ChannelBandwidth2String(getRxChannelBandwidthMode()));
269 }
270
271 void setTxIQMismatch(double iq_ratio_db, double iq_crosstalk_degree) override {
272 getUserSpecifiedTxParameters().txIQAmplitudeImbalance_dB = iq_ratio_db;
273 getUserSpecifiedTxParameters().txIQPhaseImbalance_rad = iq_crosstalk_degree / 360 * M_PI;
274 LoggingService_SDR_info_print("<{}> sets Tx IQ mismatch ratio (DB) to [{}] and IQ crosstalk degree to [{}].", getReferredInterfaceName(), getTxIqRatioDB(), getTxIqCrossTalkDegree());
275 }
276
277 void setRxIQMismatch(double iq_ratio_db, double iq_crosstalk_degree) override {
278 rxIQMismatchRatioDb = iq_ratio_db;
279 rxIQMismatchRatioDegree = iq_crosstalk_degree;
280 LoggingService_SDR_info_print("<{}> sets Rx IQ mismatch ratio (DB) to [{}] and IQ crosstalk degree to [{}].", getReferredInterfaceName(), getRxIqRatioDB(), getRxIqCrossTalkDegree());
281 }
282
283 double getTxIqRatioDB() override {
284 return getUserSpecifiedTxParameters().txIQAmplitudeImbalance_dB;
285 }
286
287 double getTxIqCrossTalkDegree() override {
288 return getUserSpecifiedTxParameters().txIQPhaseImbalance_rad / M_PI * 360;
289 }
290
291 double getRxIqRatioDB() override {
292 return rxIQMismatchRatioDb;
293 }
294
295 double getRxIqCrossTalkDegree() override {
297 }
298
299 double getRxSensitivity() override {
300 return rxSensitivity;
301 }
302
303 void setRxSensitivity(const double rxSensitivityV) override {
304 rxSensitivity = rxSensitivityV;
305 LoggingService_SDR_info_print("{}'s RX sensitivity is changed to [{}] dB.", getReferredInterfaceName(), getRxSensitivity());
306 }
307
308 void setCarrierFrequencyOffset4TxEncoding(double carrierFrequencyOffset) override {
309 userSpecifiedTxParameters.carrierFrequencyOffset = carrierFrequencyOffset;
310 LoggingService_SDR_info_print("<{}> sets TX carrier frequency offset to [{}].", getReferredInterfaceName(), *getCarrierFrequencyOffset4TxEncoding());
311 }
312
313 std::optional<double> getCarrierFrequencyOffset4TxEncoding() override {
314 return userSpecifiedTxParameters.carrierFrequencyOffset;
315 }
316
317 void setSamplingFrequencyOffset4TxEncoding(double samplingFrequencyOffset) override {
318 userSpecifiedTxParameters.samplingRateOffset = samplingFrequencyOffset;
319 LoggingService_SDR_info_print("<{}> sets TX sampling frequency offset to [{}].", getReferredInterfaceName(), *getSamplingFrequencyOffset4TxEncoding());
320 }
321
322 std::optional<double> getSamplingFrequencyOffset4TxEncoding() override {
323 return userSpecifiedTxParameters.samplingRateOffset;
324 }
325
326 void setCarrierFrequencyOffset4RxDecoding(double rxCarrierFrequencyOffsetV) override {
327 rxCarrierFrequencyOffset = rxCarrierFrequencyOffsetV;
328 LoggingService_SDR_info_print("<{}> sets RX carrier frequency offset to [{}].", getReferredInterfaceName(), *getCarrierFrequencyOffset4RxDecoding());
329 }
330
331 std::optional<double> getCarrierFrequencyOffset4RxDecoding() override {
333 }
334
335 void setSamplingFrequencyOffset4RxDecoding(double samplingFrequencyOffset) override {
336 rxSamplingFrequencyOffset = samplingFrequencyOffset;
337 LoggingService_SDR_info_print("<{}> sets RX sampling frequency offset to [{}].", getReferredInterfaceName(), *getSamplingFrequencyOffset4RxDecoding());
338 }
339
340 std::optional<double> getSamplingFrequencyOffset4RxDecoding() override {
342 }
343
344 double getSamplingRate() override {
345 const auto txRate = getTxSamplingRate();
346 const auto rxRate = getRxSamplingRate();
347
348 if (txRate == rxRate)
349 return txRate;
350
351 LoggingService_SDR_warning_print(fmt::format("<{}> has different Tx and Rx sampling rates (Tx={} MHz, Rx={} MHz), return Rx rate.", getReferredInterfaceName(), txRate / 1e6, rxRate / 1e6));
352 return rxRate;
353 }
354
355 void setSamplingRate(double samplingRate) override {
356 setTxSamplingRate(samplingRate);
357 setRxSamplingRate(samplingRate);
358 }
359
360 double getTxResampleRatio() override {
361 return getUserSpecifiedTxParameters().resampleRatio;
362 }
363
364 void setTxResampleRatio(double txResampleRatioV) override {
365 if (!txChannels.empty()) {
366 getUserSpecifiedTxParameters().resampleRatio = txResampleRatioV;
367 LoggingService_SDR_info_print("<{}> sets TX resample ratio to [{}].", getReferredInterfaceName(), getTxResampleRatio());
368 }
369 }
370
371 double getRxResampleRatio() override {
372 return rxResampleRatio;
373 }
374
375 bool isRxResampleBypassFIR() override {
376 return rxResampleBypassFIR;
377 }
378
379 void setRxResampleBypassFIR(const bool bypass) override {
380 if (!rxChannels.empty()) {
381 rxResampleBypassFIR = bypass;
382 LoggingService_SDR_info_print("<{}> sets RX resample bypass FIR to [{}].", getReferredInterfaceName(), isRxResampleBypassFIR());
383 }
384 }
385
386 bool isTxSplitHighLow() override {
387 return getUserSpecifiedTxParameters().splitHighLow;
388 }
389
390 void setTxSplitHighLow(const bool split) override {
391 getUserSpecifiedTxParameters().splitHighLow = split;
392 }
393
394 bool isRxMergeHighLow() override {
395 return mergeHighLow;
396 }
397
398 void setRxMergeHighLow(const bool merge) override {
399 mergeHighLow = merge;
400 }
401
402 void setRxResampleRatio(double rxResampleRatioV) override {
403 rxResampleRatio = rxResampleRatioV;
404 LoggingService_SDR_info_print("<{}> sets RX resample ratio to [{}].", getReferredInterfaceName(), getRxResampleRatio());
405 }
406
407 double getRxOfdmSymbolOffset() override {
408 return rxOFDMSymbolOffset;
409 }
410
411 void setRxOfdmSymbolOffset(const double rxOfdmSymbolOffset) override {
412 rxOFDMSymbolOffset = rxOfdmSymbolOffset;
413 LoggingService_SDR_info_print("{}'s RX OFDM Symbol Offset is changed to [{}].", getReferredInterfaceName(), getRxOfdmSymbolOffset());
414 }
415
418 }
419
420 void getNumSamplesSavedBeforeStart(const double numSamplesSavedBeforeStartV) override {
421 numSamplesSavedBeforeStart = numSamplesSavedBeforeStartV;
422 }
423
424 uint8_t getTxChainMask() override {
425 std::bitset<8> txcmBits;
426 for (const auto& txch: userSpecifiedTxChannels())
427 txcmBits.set(txch, true);
428
429 return txcmBits.to_ulong();
430 }
431
432 void setTxChainMask(const uint8_t txChainMask) override {
433 std::bitset<8> txcmBits{txChainMask};
434 std::vector<size_t> newTxChannels;
435 for (size_t i = 0; i < txcmBits.size(); i++) {
436 if (txcmBits[i])
437 newTxChannels.emplace_back(i);
438 }
439 setTxChannels(newTxChannels);
440 }
441
442 uint8_t getRxChainMask() override {
443 std::bitset<8> rxcmBits;
444 for (const auto& rxch: userSpecifiedRxChannels())
445 rxcmBits.set(rxch, true);
446
447 return rxcmBits.to_ulong();
448 }
449
450 void setRxChainMask(const uint8_t rxChainMask) override {
451 std::bitset<8> rxcmBits{rxChainMask};
452 std::vector<size_t> newRxChannels;
453 for (size_t i = 0; i < rxcmBits.size(); i++) {
454 if (rxcmBits[i])
455 newRxChannels.emplace_back(i);
456 }
457 setRxChannels(newRxChannels);
458 }
459
460 [[nodiscard]] const std::vector<size_t>& userSpecifiedTxChannels() const override {
461 return txChannels;
462 }
463
464 [[deprecated("Use 'const std::vector<size_t>& userSpecifiedTxChannels() const' instead")]]
465 std::vector<size_t> getTxChannels() override {
466 return txChannels;
467 }
468
469 void setTxChannels(const std::vector<size_t>& txChannelsN) override {
470 txChannels = txChannelsN;
471 std::stringstream ss;
472 // If we deliberately set empty txChannels, it means we want to disable Tx
473 if (!txChannelsN.empty()) {
474 std::copy(txChannels.cbegin(), txChannels.cend() - 1, std::ostream_iterator<int>(ss, ","));
475 ss << txChannels.back();
476 LoggingService_SDR_info_print("<{}> sets Tx-Channel to [{}].", getReferredInterfaceName(), ss.str());
477 }
478 }
479
480 [[nodiscard]] const std::vector<size_t>& userSpecifiedRxChannels() const override {
481 return rxChannels;
482 }
483
484 [[deprecated("Use 'const std::vector<size_t>& userSpecifiedRxChannels() const' instead")]]
485 std::vector<size_t> getRxChannels() override {
486 return rxChannels;
487 }
488
489 void setRxChannels(const std::vector<size_t>& rxChannelsN) override {
490 rxChannels = rxChannelsN;
491 std::stringstream ss;
492 // If we deliberately set empty rxChannels, it means we want to disable Rx
493 if (!rxChannelsN.empty()) {
494 std::copy(rxChannels.cbegin(), rxChannels.cend() - 1, std::ostream_iterator<int>(ss, ","));
495 ss << rxChannels.back();
496 }
497 LoggingService_SDR_info_print("<{}> sets Rx-Channel to [{}].", getReferredInterfaceName(), ss.str());
498 }
499
500 bool isFullDuplexEnabled() override {
501 return fullDuplex;
502 }
503
504 void setFullDuplex(const bool enableFullDuplex) override {
505 fullDuplex = enableFullDuplex;
506 }
507
508 [[nodiscard]] SDRFrontEndTransferType getTransferType() const override {
509 return transferType;
510 }
511
512 void setTransferType(const SDRFrontEndTransferType transferTypeV) override {
513 transferType = transferTypeV;
514 }
515
516 void setNumThreads4RxDecoding(const uint8_t numThreads) override {
517 numDecodingThreads = numThreads;
518 LoggingService_SDR_info_print("<{}> sets {}-thread parallel baseband decoding.", getReferredInterfaceName(), numDecodingThreads);
519 }
520
521 void printStatus() override {
522 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
523 }
524
525 ExtraInfo buildExtraInfo() override {
526 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
527 }
528
529 std::tuple<double, double, double> getChannelAndBandwidth() override {
530 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
531 }
532
533 int setChannelAndBandwidth(double control, double bw, double center) override {
534 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
535 }
536
537 int setChannelAndBandwidth(std::optional<double> control, std::optional<double> bw, std::optional<double> center) override {
538 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
539 }
540
541 [[deprecated("Use 'getTxCarrierFrequencies' or 'getRxCarrierFrequencies' instead")]]
542 double getCarrierFrequency() override {
543 if (!userSpecifiedTxChannels().empty()) {
544 return getTxCarrierFrequencies()[0];
545 }
546 if (!userSpecifiedRxChannels().empty()) {
547 return getRxCarrierFrequencies()[0];
548 }
549 return 0.0;
550 }
551
552 void setCarrierFrequency(double carrierFrequency) override {
553 if (!userSpecifiedTxChannels().empty()) {
554 setTxCarrierFrequencies(std::vector<double>(userSpecifiedTxChannels().size(), carrierFrequency));
555 }
556 if (!userSpecifiedRxChannels().empty()) {
557 setRxCarrierFrequencies(std::vector<double>(userSpecifiedRxChannels().size(), carrierFrequency));
558 }
559 }
560
561 double getControlChannelFrequency() override {
562 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
563 }
564
565 void setControlChannelFrequency(double controlFrequency) override {
566 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
567 }
568
569 double getRxChannelBandwidth() override {
570 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
571 }
572
573 void setRxChannelBandwidth(double rxcbw) override {
574 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
575 }
576
577 double getTxpower() override {
578 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
579 }
580
581 void setTxpower(double txpower) override {
582 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
583 }
584
585 double getRxGain() override {
586 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
587 }
588
589 void setRxGain(double rxGain) override {
590 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
591 }
592
593 void setRxGain(double rxGain, uint8_t channel) override {
594 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
595 }
596
597 uint16_t getChannelFlags() override {
598 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
599 }
600
601 std::string getClockSource() override {
602 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
603 }
604
605 void setClockSource(const std::string& clockSource) override {
606 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
607 }
608
609 void setClockSources(const std::vector<std::string>& clockSources) override {
610 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
611 }
612
613 std::vector<std::string> getClockSources() override {
614 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
615 }
616
617 std::string getTimeSource() override {
618 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
619 }
620
621 void setTimeSource(const std::string& timeSource) override {
622 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
623 }
624
625 void setTimeSources(const std::vector<std::string>& timeSources) override {
626 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
627 }
628
629 std::vector<std::string> getTimeSources() override {
630 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
631 }
632
633 double getMasterClockRate() override {
634 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
635 }
636
637 void setMasterClockRate(double masterClockRate) override {
638 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
639 }
640
641 double getSDRFrontEndTime() override {
642 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
643 }
644
645 std::string getTxAntenna() override {
646 return getTxAntennas().at(0);
647 }
648
649 void setTxAntenna(const std::string& txAnt) override {
650 setTxAntennas({txAnt});
651 }
652
653 std::string getRxAntenna() override {
654 return getRxAntennas().at(0);
655 }
656
657 void setRxAntenna(const std::string& rxAnt) override {
658 setRxAntennas({rxAnt});
659 }
660
661 std::vector<std::string> getTxAntennas() override {
662 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
663 }
664
665 void setTxAntennas(const std::vector<std::string>& txAnts) override {
666 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
667 }
668
669 std::vector<std::string> getRxAntennas() override {
670 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
671 }
672
673 void setRxAntennas(const std::vector<std::string>& rxAnts) override {
674 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
675 }
676
677 double getFilterBandwidth() override {
678 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
679 }
680
681 void setFilterBandwidth(double bw) override {
682 throw std::runtime_error(fmt::format("<{}> does not support operation: {}.", getReferredInterfaceName(), std::string(BOOST_CURRENT_FUNCTION)));
683 }
684
685protected:
686 std::optional<uint32_t> txSignalReplayDelay_ms;
687 std::optional<std::string> txSignalDumpFilePath;
688 std::optional<std::string> rxSignalDumpFilePath;
689 std::optional<double> rxSignalDumpDelayedStartDuration;
690 std::optional<std::string> rxSignalReplayFilePath;
691
692 bool fullDuplex{false};
695 std::vector<size_t> txChannels{}; // TwinRx has no Tx channel
696 std::vector<size_t> rxChannels{}; // LFTX and BasicTx have no Rx channel
697
698 ChannelBandwidthEnum rxCBW{ChannelBandwidthEnum::CBW_20};
699 double rxResampleRatio{1.0};
701 bool mergeHighLow{false};
702 double rxOFDMSymbolOffset{0.75};
704 double rxSensitivity{10};
707 std::optional<double> rxCarrierFrequencyOffset{};
708 std::optional<double> rxSamplingFrequencyOffset{};
709
710 // Override hardware information refresh methods
712 // Default implementation - derived classes should override
713 }
714
716 // Default implementation - derived classes should override
717 // boardInfo.motherboardSerial = SDRSerialNumber;
718 // boardInfo.motherboardModel = SDRHWName;
719 // boardInfo.fpgaImageFlavor = SDRHWType;
720 }
721
723 // Default implementation - derived classes should override
724 }
725
727 // Derived classes should override this
728 }
729
731 // Derived classes should override this
732 }
733
735 // Derived classes should override this
736 }
737
739 // Default implementation - derived classes should override
740 }
741
743 // Default implementation - derived classes should override
744 }
745
747 // Derived classes should override this
748 }
749
751 // Derived classes should override this
752 }
753
755 // Derived classes should override this
756 }
757
759 // Derived classes should override this
760 }
761};
762
763#endif // PICOSCENES_PLATFORM_ABSTRACTSDRFRONTEND_HXX
#define LoggingService_SDR_warning_printf(...)
#define LoggingService_SDR_debug_printf(...)
#define LoggingService_SDR_info_print(...)
#define LoggingService_SDR_warning_print(...)
SDRFrontEndTransferType
The SDRFrontEndTransferType enum denotes the 8-bit or 16-bit SDR frontend data depth.
@ CS16
16-bit complex sign
The shared abstract frontend interface for both SDR and NIC.
PicoScenesDeviceSubtype getFrontEndSubtype() const
Return the PicoScenesDeviceType subtype of this frontend.
std::string referredInterfaceName
the user specified frontend name
virtual int startTx()
Activate internal Tx service loop.
PicoScenesFrameTxParameters & getUserSpecifiedTxParameters()
bool txServiceStarted
indicate whether Tx service is running
PicoScenesFrameTxParameters userSpecifiedTxParameters
user-specified Tx parameters
PicoScenesDeviceType getFrontEndType() const
Return the PicoScenesDeviceType of this frontend.
const std::string & getReferredInterfaceName() const
Get the user-specified frontend name.
The shared abstract frontend for SDR devices only.
double getRxGain() override
Get the total Rx gain. However, currently only QCA9300 and SDR frontend support this method.
void setTxpower(double txpower) override
Set the Tx power (in dB)
void setRxChainMask(const uint8_t rxChainMask) override
Set Rx chain mask. Setting Rx chain mask means to use only the selected Rx chains for signal receptio...
void refreshHardwareInfoForAGCSupport() override
std::string getRxAntenna() override
Get the Rx antenna.
virtual std::optional< double > getCurrentNoiseFloor()=0
double getTxpower() override
get the transmission power (Tx power)
virtual void prebuildSignals(ModularPicoScenesTxFrame &frame, const uint8_t numTxAntenna)
Generate the baseband signal via AbstractSDRFrontEnd::generateSignal and save the data into the prebu...
void setCarrierFrequencyOffset4TxEncoding(double carrierFrequencyOffset) override
Set the current carrier frequency offset (CFO) value for the baseband signal generation.
std::optional< uint32_t > txSignalReplayDelay_ms
int transmitFramesInBatch(const std::vector< const ModularPicoScenesTxFrame * > &frames, const uint32_t repeat) override
Transmit frames in batch with precise inter-frame timing.
std::string getTxAntenna() override
Get the Tx antenna.
virtual void clearTxStatus()=0
void setMasterClockRate(double masterClockRate) override
Set the USRP master clock rate (in Hz)
double getRxIqCrossTalkDegree() override
Get the I/Q mismatch degree of the user-specified Tx I/Q mismatch.
const std::vector< size_t > & userSpecifiedRxChannels() const override
std::optional< double > rxSamplingFrequencyOffset
void setSamplingFrequencyOffset4RxDecoding(double samplingFrequencyOffset) override
Set the user-specified Rx path SFO,.
void setCarrierFrequency(double carrierFrequency) override
Get the RF carrier frequency.
std::optional< double > getCarrierFrequencyOffset4TxEncoding() override
Get the current carrier frequency offset (CFO) value for the baseband signal generation.
void setCarrierFrequencyOffset4RxDecoding(double rxCarrierFrequencyOffsetV) override
Set the CFO value for baseband decoding.
void refreshHardwareInfoForClockAndTimeSources() override
void setTxSplitHighLow(const bool split) override
double getTxIqCrossTalkDegree() override
Get the I/Q mismatch angle of the user-specified Tx I/Q mismatch.
virtual SDRFrontEndTxStatus getLastTxStatus() const =0
void refreshHardwareInfoForSamplingRateRanges() override
void setRxAntennas(const std::vector< std::string > &rxAnts) override
Specify antenna for each Rx chain.
void setRxChannelBandwidthMode(ChannelBandwidthEnum rxCbw) override
Set the CBW value for Wi-Fi baseband decoder, invoked by "--rx-cbw" option.
void setTransferType(const SDRFrontEndTransferType transferTypeV) override
void setTxSignalReplayDelayMs(const std::optional< uint32_t > &txSignalReplayDelayMs)
void setTxResampleRatio(double txResampleRatioV) override
Set Tx signal resample ratio.
void setRxResampleBypassFIR(const bool bypass) override
void setRxSignalDumpDelayedStartDuration(const double delayedStartDuration)
std::string getClockSource() override
Get the clock source.
virtual int32_t transmitSignalInBatchedSingleBurst(const std::vector< std::vector< const void * > > &multipleSignals, const std::vector< int64_t > &signalLength, const std::vector< double > &postfixDurations, uint32_t repeat)=0
void setRxChannels(const std::vector< size_t > &rxChannelsN) override
Set the number of the active Rx channels, starting from 0.
std::vector< std::string > getTxAntennas() override
void setRxOfdmSymbolOffset(const double rxOfdmSymbolOffset) override
Set Rx OFDM symbol offset, default is 0.
int setChannelAndBandwidth(double control, double bw, double center) override
Set the <contorlfreq-bandwidth-centerfreq> channel parameter.
double getTxResampleRatio() override
Get the user-specified Tx signal resample ratio.
double getSDRFrontEndTime() override
Obtain the SDR hardware time.
virtual int transmitSignalsContinuously(const std::vector< const void * > &multiChannelHeaders, int64_t numSignalsPerAntenna, bool burstStart, bool burstEnd)=0
std::vector< size_t > rxChannels
void setTxChainMask(const uint8_t txChainMask) override
Set Tx chain mask. Setting Tx chain mask means to use only the selected Tx chain for signal transmiss...
int transmitFramesInBatch(Frames &&... frames)
AbstractSDRFrontEnd(const std::string &referredInterfaceName)
Create AbstractSDRFrontEnd object according to the user-specified frontend name referredInterfaceName...
void setRxGain(double rxGain) override
Set the total Rx gain. However, currently only QCA9300 and SDR frontend support this method.
std::optional< std::string > rxSignalReplayFilePath
int setChannelAndBandwidth(std::optional< double > control, std::optional< double > bw, std::optional< double > center) override
Set the <contorlfreq-bandwidth-centerfreq> channel parameter, but with optional.
std::vector< size_t > getTxChannels() override
Get the numbers of the active Tx channels, starting from 0.
void setFilterBandwidth(double bw) override
Set the hardware frontend filter bandwidth.
ExtraInfo buildExtraInfo() override
Build an ExtraInfo object describing the current frontend status.
double getTxIqRatioDB() override
Get the I/Q mismatch ratio of the user-specified Tx I/Q mismatch.
void refreshHardwareInfoForSupportedAntennas() override
SDRFrontEndTransferType transferType
double getCarrierFrequency() override
Get the RF carrier frequency.
void setRxAntenna(const std::string &rxAnt) override
Set the Rx antenna.
void setTxAntenna(const std::string &txAnt) override
Set the Tx antenna.
double getSamplingRate() override
Get the baseband sampling rate.
std::optional< std::string > txSignalDumpFilePath
void setRxSensitivity(const double rxSensitivityV) override
Set Rx sensitivity.
void setRxResampleRatio(double rxResampleRatioV) override
Set the Rx signal rasample ratio.
void setFullDuplex(const bool enableFullDuplex) override
Set the Frontend is in Tx/Rx loopback mode, in this mode Tx and Rx are open simultaneously,...
virtual size_t transmitSignal(const CS16Vector &signals, const uint8_t numTxChannels, const double postfixDuration)
void refreshHardwareInfoForFrequencyRanges() override
void setRxSignalDumpFilePath(const std::string &rxSignalDumpFilePathV)
double getRxOfdmSymbolOffset() override
Get the user-specified Rx OFDM symbol offset value.
std::tuple< double, double, double > getChannelAndBandwidth() override
Get the <contorlfreq-bandwidth-centerfreq> channel parameter.
std::vector< std::string > getClockSources() override
Get the list of currently set clock sources.
std::optional< double > rxCarrierFrequencyOffset
double getRxResampleRatio() override
Get the user-specified Rx resampling ratio.
std::vector< size_t > getRxChannels() override
Get the number of the active Rx channels, starting from 0.
void setTxSignalDumpFilePath(const std::string &txSignalDumpFilePathV)
void refreshHardwareInfoForFrontEndProfiles() override
void refreshHardwareInfoForSensors() override
void setClockSources(const std::vector< std::string > &clockSources) override
Set multiple clock sources for different motherboards.
uint8_t getRxChainMask() override
Get Rx chain mask.
std::optional< std::string > rxSignalDumpFilePath
std::optional< double > getSamplingFrequencyOffset4TxEncoding() override
Get the current sampilng frequency offset (SFO) value for the baseband signal generation.
void refreshHardwareInfoForMasterClockRates() override
const std::vector< size_t > & userSpecifiedTxChannels() const override
void setSamplingFrequencyOffset4TxEncoding(double samplingFrequencyOffset) override
Set the current sampling frequency offset (SFO) value for the baseband signal generation.
void setRxMergeHighLow(const bool merge) override
void refreshHardwareInfoForGainRanges() override
ChannelBandwidthEnum rxCBW
void setTxIQMismatch(double iq_ratio_db, double iq_crosstalk_degree) override
Set Tx I/Q mismatch.
ChannelBandwidthEnum getRxChannelBandwidthMode() override
Get the current CBW value of Wi-Fi baseband decoder.
uint8_t getTxChainMask() override
Get the Tx chain mask.
void setSignalReplayFilePath(const std::string &signalReplayFilePath)
bool isFullDuplexEnabled() override
Check whether the Frontend is in Tx/Rx loopback mode.
void setRxIQMismatch(double iq_ratio_db, double iq_crosstalk_degree) override
Set Rx I/Q mismatch.
void setTimeSources(const std::vector< std::string > &timeSources) override
Set multiple time sources for different motherboards.
void setRxGain(double rxGain, uint8_t channel) override
Set the Rx gain for the specified channel. However, currently only QCA9300 and SDR frontend support t...
virtual int32_t transmitSignals(const std::vector< const void * > &signals, int64_t bufferLength, double postfixDuration)=0
void printStatus() override
Print a status string to command line.
void refreshHardwareInfoForSupportedChannels() override
std::string getTimeSource() override
Get the timing source.
double getFilterBandwidth() override
get the hardware-frontend filter bandwidth
double getNumSamplesSavedBeforeStart() override
std::optional< double > getCarrierFrequencyOffset4RxDecoding() override
Check if user specifies the Rx path CFO; if specified, return the Rx path CFO.
void setControlChannelFrequency(double controlFrequency) override
Get the control channel frequency of <contorlfreq-bandwidth-centerfreq> channel parameter.
void refreshHardwareInfoForTemperatures() override
virtual CS16Vector generateSignal(const ModularPicoScenesTxFrame &frame, uint8_t numTxAntenna)=0
Generate the baseband signal for ModularPicoScenesTxFrame frame with an optional numTxAntenna specify...
void setTxAntennas(const std::vector< std::string > &txAnts) override
Specify antenna for each Tx chain.
void setNumThreads4RxDecoding(const uint8_t numThreads) override
std::vector< size_t > txChannels
double getMasterClockRate() override
Get the USRP master clock rate (in Hz)
double getRxSensitivity() override
Get the Rx sensitivity of SDR baseband implemntation.
bool isRxResampleBypassFIR() override
std::vector< std::string > getRxAntennas() override
uint16_t getChannelFlags() override
Get the old ChannelFlags descriptor.
void setClockSource(const std::string &clockSource) override
Set the clock source. For USRP, it can be "external", "mimo", "internal".
double getRxChannelBandwidth() override
Get the 802.11 Channel Bandwidth parameter (20e6/40e6/80e6/160e6/320e6) of the Rx path.
int transmit(const ModularPicoScenesTxFrame &frame) override
Transmit a ModularPicoScenesTxFrame frame via current frontend hardware.
std::optional< double > getSamplingFrequencyOffset4RxDecoding() override
Get the user-specified Rx path SFO, default is 0.
void setTxChannels(const std::vector< size_t > &txChannelsN) override
This methods is fundamentally.
std::optional< double > rxSignalDumpDelayedStartDuration
virtual std::vector< CS16Vector > generateMultiChannelSignals(const ModularPicoScenesTxFrame &frame, const uint8_t numTxAntenna)
Generate the baseband signal via AbstractSDRFrontEnd::generateSignal, convert to SignalType type,...
void setSamplingRate(double samplingRate) override
set sampling rate (in Hz)
bool isRxMergeHighLow() override
void setTimeSource(const std::string &timeSource) override
Set the timing source. For USRP, it can be "external", "mimo", "internal".
void setRxChannelBandwidth(double rxcbw) override
Set the Rx channel bandwidth parameter of the <contorlfreq-bandwidth-centerfreq> channel parameters.
void refreshHardwareInfoForBoards() override
SDRFrontEndTransferType getTransferType() const override
void getNumSamplesSavedBeforeStart(const double numSamplesSavedBeforeStartV) override
std::vector< std::string > getTimeSources() override
Get the list of currently set time sources.
double getControlChannelFrequency() override
Get the control channel frequency of <contorlfreq-bandwidth-centerfreq> channel parameter.
bool isTxSplitHighLow() override
double getRxIqRatioDB() override
Get the I/Q mismatch ratio of the user-specified Rx I/Q mismatch.
virtual size_t transmitSignal(const std::vector< CS16Vector > &multiChannelSignals, const double postfixDuration)
virtual int transmitSignalsFromFile(const std::string &signalSourceFile, uint64_t repeat)=0
Transmits baseband signals from a .bbsignals file.
static const std::string SDR_Tx2File
static std::shared_ptr< LicenseService > getInstance()
This class holds all the configuration (including the SDR hardware related settings) of SDR frontend.
virtual void setRxSamplingRate(double rxRate)=0
virtual void setTxSamplingRate(double txRate)=0
virtual double getTxSamplingRate()=0
virtual void setRxCarrierFrequencies(std::vector< double > carrierFreqs)=0
virtual void setTxCarrierFrequencies(std::vector< double > carrierFreqs)=0
virtual std::vector< double > getTxCarrierFrequencies()=0
virtual std::vector< double > getRxCarrierFrequencies()=0
virtual double getRxSamplingRate()=0
OutputIterator fastCopyN(InputIterator first, std::size_t count, OutputIterator result)