#ifndef _TRANSMITTER_H_ #define _TRANSMITTER_H_ #include #include #include #include #include "JuceHeader.h" #include "LogComponent.h" #include #include #include using namespace Radio; #define TRANSMITTER_RCF_OVERSAMPLING ((uint32_t)32) #define TRANSMITTER_RCF_ROLLOFF ((radio_float_t)0.35) class Transmitter; // --------------------------------------------------- class TransmitterInterface { public: TransmitterInterface() {} virtual ~TransmitterInterface() {} virtual void reset() = 0; virtual void setBuffersize(uint32_t size) = 0; virtual void setSamplerate(float samplerate_hz) = 0; virtual void setCarrierFrequency(float frequency_hz) = 0; virtual float getCarrierFrequency() = 0; virtual void setSymbolRate(float symbolrate_bit_per_sec) = 0; virtual float getSymbolRate() = 0; virtual void setNumBitPerSymbol(uint32_t numBitPerSymbol) = 0; virtual void getData(float *pRF, uint32_t len) = 0; }; class TxBuffer { public: TxBuffer(uint32_t size, uint32_t numBuffers) : m_ppBuffer(0) , m_capacityPerBuffer(0) , m_numBuffers(0) , m_pT(0) { resize(size, numBuffers); } ~TxBuffer() { resize(0, 0); } void write(RVec const &data, uint32_t len) { uint32_t i; m_pT = Thread::getCurrentThread(); while (m_numfill.get() >= m_numBuffers) { m_pT->wait(100); if (m_pT->threadShouldExit()) return; } for (i=0; i < len; i++) { m_ppBuffer[m_w][i] = data[i]; } m_w++; if (m_w >= m_numBuffers) m_w = 0; m_numfill += 1; } uint32_t read(float *pData) { uint32_t i; if (m_numfill.get() == 0) return 0; for (i=0; i < m_capacityPerBuffer; i++) { pData[i] = m_ppBuffer[m_r][i]; } m_r++; if (m_r >= m_numBuffers) m_r = 0; m_numfill -= 1; if (m_pT) m_pT->notify(); return i; } void resize(uint32_t size, uint32_t numBuffers) { uint32_t i; if ((size != m_capacityPerBuffer) || (numBuffers != m_numBuffers)) { if (m_ppBuffer) { for (i=0; i < m_numBuffers; i++) { delete m_ppBuffer[i]; } delete m_ppBuffer; m_ppBuffer = nullptr; } m_r = 0; m_w = 0; m_numfill = 0; } m_numBuffers = numBuffers; m_capacityPerBuffer = size; if (!size || !numBuffers) return; m_ppBuffer = new float*[m_numBuffers]; for (i=0; i < m_numBuffers; i++) { m_ppBuffer[i] = new float[m_capacityPerBuffer]; } } private: Atomic m_numfill; float **m_ppBuffer; uint32_t m_capacityPerBuffer; uint32_t m_numBuffers; uint32_t m_r; uint32_t m_w; Thread *m_pT; }; class Transmitter : public TransmitterInterface, public ISymbolizer, public juce::Thread { public: Transmitter(void); ~Transmitter(void); void bufferResize(uint32_t size); private: CriticalSection m_lock; Symbolizer m_symbolizer; Formatter m_formatter; sym_map_t m_symbolMapper; Interpolation::UpSampler m_firUp; uint32_t m_bufferSize; RVec m_bufferRF; CVec m_bufferSym; CVec m_bufferSymRcf; float m_samplerate; float m_ddcFrequency; float m_symbolrate; uint32_t m_numBitPerSymbol; radio_float_t *m_pCoeffRCF; radio_float_t m_kRcf; radio_float_t m_carrierFreq; Nco m_duc; TxBuffer m_txBuf; uint32_t m_symCount; uint32_t m_upsampleFactor; // Thread void run() override { uint32_t data; data = 0; while(!threadShouldExit()) { m_formatter.process(&data, sizeof(data)); data++; } } // ISymbolizer void onSymbol(symbol_t symbol) override { uint32_t symCountRcf; const ScopedLock sl (m_lock); m_bufferSym[m_symCount++] = toComplexScalar(SymMapMap(&m_symbolMapper, symbol)); if (m_symCount >= m_bufferSize/m_upsampleFactor) { symCountRcf = m_firUp.process(m_bufferSymRcf, m_bufferSym, m_symCount); m_duc.mixComplexRealV(m_bufferRF, m_bufferSymRcf, ComplexScalar(m_kRcf/4, m_kRcf/4), symCountRcf); m_txBuf.write(m_bufferRF, symCountRcf); m_symCount = 0; } } void paramChanged(); // TransmitterInterface void reset() override { } void setBuffersize(uint32_t size) override { bufferResize(size); paramChanged(); } void setSamplerate(float samplerate_hz) override { m_samplerate = samplerate_hz; m_carrierFreq = samplerate_hz/4; m_symbolrate = samplerate_hz/4; paramChanged(); } void setCarrierFrequency(float frequency_hz) override { const ScopedLock sl (m_lock); m_carrierFreq = frequency_hz; m_duc.init(m_carrierFreq/m_samplerate, 0); } float getCarrierFrequency() override { return m_carrierFreq; } void setSymbolRate(float symbolrate_bit_per_sec) override { m_symbolrate = symbolrate_bit_per_sec; paramChanged(); } float getSymbolRate() override { return m_symbolrate; } void setNumBitPerSymbol(uint32_t numBitPerSymbol) override { m_numBitPerSymbol = numBitPerSymbol; if (m_numBitPerSymbol > 16) m_numBitPerSymbol = 16; paramChanged(); } void getData(float *pRF, uint32_t len) override { uint32_t res; if (len != m_bufferSize) { memset(pRF, 0, len*sizeof(float)); return; } res = m_txBuf.read(pRF); if (!res) memset(pRF, 0, len*sizeof(float)); } }; #endif // _TRANSMITTER_H_