- initial commit

git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@2 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2014-07-19 08:20:53 +00:00
commit 28847d44d8
1153 changed files with 442315 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+177
View File
@@ -0,0 +1,177 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
#ifndef __JUCE_HEADER_AD7F5AFA07457368__
#define __JUCE_HEADER_AD7F5AFA07457368__
//[Headers] -- You can add your own extra header files here --
#include "JuceHeader.h"
#include "Receiver.h"
#include "Transmitter.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Introjucer.
Describe your class and how it works here!
//[/Comments]
*/
class ControlComponent : public Component,
public TextEditor::Listener,
public ChangeBroadcaster,
public ChangeListener,
public ButtonListener,
public ReceiverStatusListener,
public Timer,
public SliderListener,
public ComboBoxListener
{
public:
//==============================================================================
ControlComponent (ReceiverInterface *pReceiverControlListener, TransmitterInterface *pTransmitterControlListener);
~ControlComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g);
void resized();
void buttonClicked (Button* buttonThatWasClicked);
void sliderValueChanged (Slider* sliderThatWasMoved);
void comboBoxChanged (ComboBox* comboBoxThatHasChanged);
void mouseDown (const MouseEvent& e);
private:
//[UserVariables] -- You can add your own custom variables in this section.
ReceiverInterface *m_pReceiverControlListener;
TransmitterInterface *m_pTransmitterControlListener;
params_t m_params;
status_t m_status;
cma_mode m_cmaModeSelected;
void receiverStatusChanged(ReceiverInterface *pReceiver);
void changeListenerCallback(juce::ChangeBroadcaster* source);
void textEditorFocusLost (TextEditor &textEditor);
void textEditorTextChanged (TextEditor &textEditor);
void textEditorReturnKeyPressed (TextEditor &textEditor);
bool m_userParamEntryinProgress;
ScopedPointer<TooltipWindow> m_tooltipWindow;
void timerCallback();
//[/UserVariables]
//==============================================================================
ScopedPointer<GroupComponent> groupComponent3;
ScopedPointer<GroupComponent> m_GroupSymbolTimingRecovery2;
ScopedPointer<GroupComponent> groupComponent;
ScopedPointer<GroupComponent> groupDFE;
ScopedPointer<GroupComponent> groupCMA;
ScopedPointer<GroupComponent> groupCarrierPhaseRecovery;
ScopedPointer<GroupComponent> m_GroupSymbolTimingRecovery;
ScopedPointer<ToggleButton> toggleButtonCPREnable;
ScopedPointer<ToggleButton> toggleButtonDFEEnable;
ScopedPointer<ToggleButton> toggleButtonSTREnable;
ScopedPointer<TextEditor> m_entrySTRLoopFilterLead_0;
ScopedPointer<TextEditor> m_entrySTRLoopFilterLag_0;
ScopedPointer<TextEditor> m_entryCPRLoopFilterLead_0;
ScopedPointer<TextEditor> m_entryCPRLoopFilterLag_0;
ScopedPointer<TextButton> m_buttonDfeOnUpdateFromDfeOff;
ScopedPointer<TextButton> m_buttonResetDFE;
ScopedPointer<TextButton> m_buttonResetCMA;
ScopedPointer<GroupComponent> groupComponent2;
ScopedPointer<TextEditor> m_entryCmaMu;
ScopedPointer<TextEditor> m_entryDfeMu;
ScopedPointer<Label> m_labelPowerRF;
ScopedPointer<Label> m_labelPowerDDC;
ScopedPointer<Label> m_labelPowerMF;
ScopedPointer<Label> m_labelPowerCPR;
ScopedPointer<Label> m_labelPowerAGC2;
ScopedPointer<Label> m_labelPowerEQ;
ScopedPointer<Label> m_labelSnrCurrent;
ScopedPointer<Label> m_labelSnrCma;
ScopedPointer<Label> m_labelSnrDfeOn;
ScopedPointer<Label> m_labelSnrDfeOff;
ScopedPointer<Label> m_labelSnrSymbolMag;
ScopedPointer<Label> m_labelSnrSymbolPhase;
ScopedPointer<Label> m_labelNoiseStr;
ScopedPointer<Label> m_labelSymbolReceivedCount;
ScopedPointer<TextButton> m_buttonResetReset;
ScopedPointer<TextEditor> m_entryAgcMu_0;
ScopedPointer<ToggleButton> toggleButtonCmaTrainingEnable;
ScopedPointer<ToggleButton> toggleButtonDfeTrainingEnable;
ScopedPointer<TextButton> m_buttonDfeOffUpdateFromCma;
ScopedPointer<TextEditor> m_entryNumBitsPerSymbol;
ScopedPointer<TextEditor> m_entrySymbolRate;
ScopedPointer<TextEditor> m_entryDdcFrequency;
ScopedPointer<Label> m_labelDdcDeltaFreq;
ScopedPointer<Label> m_labelStrDeltaFreq;
ScopedPointer<Label> m_labelCprState;
ScopedPointer<Label> m_labelStrState;
ScopedPointer<ToggleButton> toggleButtonAgcEnable;
ScopedPointer<Label> m_labelAgcState;
ScopedPointer<ToggleButton> toggleButtonAgcMuForceTrack;
ScopedPointer<Label> m_labelDdcMinI;
ScopedPointer<Label> m_labelDdcMaxI;
ScopedPointer<Label> m_labelDdcMinQ;
ScopedPointer<Label> m_labelDdcMaxQ;
ScopedPointer<Label> m_labelDdcMinMag;
ScopedPointer<Label> m_labelDdcMaxMag;
ScopedPointer<Label> m_labelDdcPhiMinI;
ScopedPointer<Label> m_labelDdcPhiMaxI;
ScopedPointer<Label> m_labelDdcPhiMinQ;
ScopedPointer<Label> m_labelDdcPhiMaxQ;
ScopedPointer<TextEditor> m_entryAgcMu_1;
ScopedPointer<TextEditor> m_entryCPRLoopFilterLead_1;
ScopedPointer<TextEditor> m_entryCPRLoopFilterLag_1;
ScopedPointer<TextEditor> m_entrySTRLoopFilterLead_1;
ScopedPointer<TextEditor> m_entrySTRLoopFilterLag_1;
ScopedPointer<ToggleButton> toggleButtonSTRLoopFilterForceTrack;
ScopedPointer<ToggleButton> toggleButtonCPRLoopFilterForceTrack;
ScopedPointer<ToggleButton> toggleButtonDfeAutoUpdateEnable;
ScopedPointer<Label> m_labelEbN0;
ScopedPointer<Label> m_labelFrameTotalCount;
ScopedPointer<Label> m_labelFrameDataCount;
ScopedPointer<Label> m_labelFrameIdleCount;
ScopedPointer<Label> m_labelFrameInvalidCount;
ScopedPointer<Label> m_labelFrameByteCount;
ScopedPointer<TextButton> m_buttonResetStatistic;
ScopedPointer<Slider> m_sliderCarrierPhase;
ScopedPointer<TextButton> m_buttonResetCPR;
ScopedPointer<TextButton> m_buttonResetStr;
ScopedPointer<ComboBox> comboBoxCmaMode;
ScopedPointer<ToggleButton> toggleButtonCMAEnable;
ScopedPointer<Label> m_labelPowerDecision;
ScopedPointer<Label> m_labelPowerDecisionMag;
ScopedPointer<Label> m_labelPowerDecisionPhase;
ScopedPointer<Label> m_labelNoiseCpr;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ControlComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]
#endif // __JUCE_HEADER_AD7F5AFA07457368__
+423
View File
@@ -0,0 +1,423 @@
// --------------------------------------------------------------
#include <string.h>
#include <math.h>
#include <crc/crc.h>
#include <radio/symbol.h>
#include "Frame.hpp"
// --------------------------------------------------------------
// Scrambler
// --------------------------------------------------------------
Scrambler::Scrambler(uint32_t state, uint32_t poly)
: m_state(state)
, m_poly(poly)
{
}
Scrambler::~Scrambler()
{
}
uint32_t Scrambler::stateGet()
{
return m_state;
}
void Scrambler::stateSet(uint32_t state)
{
m_state = state;
}
uint8_t Scrambler::process(uint8_t src)
{
uint32_t i;
uint8_t res;
res = (uint8_t)(src ^ m_state);
for (i=0; i < 8; i++)
{
if (m_state & 0x0001)
{
m_state = (m_state >> 1) ^ m_poly;
}
else
{
m_state = (m_state >> 1);
}
}
return res;
}
void Scrambler::process(uint8_t *pSrcDst, uint32_t len)
{
while(len--)
{
*pSrcDst = process(*pSrcDst);
pSrcDst++;
}
}
// --------------------------------------------------------------
// Formatter
// --------------------------------------------------------------
Formatter::Formatter(IFormatter *pFrameHandler)
: m_scrambler(FRAME_SCRAMBLER_SEED, FRAME_SCRAMBLER_POLY)
, m_pFrameHandler(pFrameHandler)
, m_dataCount(0)
, m_idleCount(0)
{
resetStats();
memset(&m_frame, 0, sizeof(frame_t));
// Set preamble
m_frame.hdr.preamble[0] = FRAME_PREAMBLE_IV;
m_frame.hdr.preamble[1] = ~(m_frame.hdr.preamble[0]);
}
Formatter::~Formatter()
{
}
void Formatter::idle()
{
if (m_dataCount)
{
// Commit partial DATA frame
commit(FRAME_TYPE_DATA, m_dataCount);
m_dataCount = 0;
}
else
{
// IDLE frame not full
if (m_idleCount < FRAME_NUM_BYTES_PER_FRAME)
{
m_frame.data[m_idleCount++] = 0;
}
if (m_idleCount == FRAME_NUM_BYTES_PER_FRAME)
{
// Commit full IDLE frame of size FRAME_NUM_BYTES_PER_FRAME
commit(FRAME_TYPE_IDLE, m_idleCount);
m_idleCount = 0;
}
}
}
void Formatter::process(uint8_t data)
{
if (m_idleCount)
{
// Commit partial IDLE frame
commit(FRAME_TYPE_IDLE, m_idleCount);
m_idleCount = 0;
}
else
{
// DATA frame not full
if (m_dataCount < FRAME_NUM_BYTES_PER_FRAME)
{
m_frame.data[m_dataCount++] = data;
}
if (m_dataCount == FRAME_NUM_BYTES_PER_FRAME)
{
// Commit full DATA frame of size FRAME_NUM_BYTES_PER_FRAME
commit(FRAME_TYPE_DATA, m_dataCount);
m_dataCount = 0;
}
}
}
void Formatter::process(void *pData, uint32_t len)
{
uint8_t *pByte;
pByte = (uint8_t*)pData;
while(len--)
{
process(*(pByte++));
}
}
frame_statistics_t Formatter::getStats()
{
return m_frameStats;
}
void Formatter::resetStats()
{
memset(&m_frameStats, 0, sizeof(frame_statistics_t));
}
void Formatter::commit(frame_type frameType, uint32_t dataCount)
{
// Commit frame
m_frame.hdr.length = (uint16_t)dataCount;
m_frame.hdr.type = (uint16_t)frameType;
m_frame.hdr.crc16 = Crc16(FRAME_CRC16_POLY, FRAME_CRC16_IV, m_frame.data, FRAME_NUM_BYTES_PER_FRAME);
m_frame.hdr.prn_state = m_scrambler.stateGet();
m_scrambler.process(m_frame.data, FRAME_NUM_BYTES_PER_FRAME);
m_scrambler.process((uint8_t*)&m_frame.hdr.crc16, sizeof(m_frame.hdr.crc16));
m_scrambler.process((uint8_t*)&m_frame.hdr.type, sizeof(m_frame.hdr.type));
m_scrambler.process((uint8_t*)&m_frame.hdr.length, sizeof(m_frame.hdr.length));
m_pFrameHandler->onFrame((void*)&m_frame, sizeof(frame_t));
}
// --------------------------------------------------------------
// Deformatter
// --------------------------------------------------------------
DeFormatter::DeFormatter(IDeFormatter *pDataHandler)
: m_pDataHandler(pDataHandler)
, m_scrambler(FRAME_SCRAMBLER_SEED, FRAME_SCRAMBLER_POLY)
, m_dataCount(0)
, m_enable(0)
{
resetStats();
}
DeFormatter::~DeFormatter()
{
}
void DeFormatter::process(uint8_t data)
{
uint8_t *pData;
pData = (uint8_t*)&m_frame;
pData += 2;
if (!m_enable)
return;
pData[m_dataCount++] = data;
if (m_dataCount == (sizeof(frame_t)-2))
{
m_scrambler.stateSet(m_frame.hdr.prn_state);
m_scrambler.process(m_frame.data, FRAME_NUM_BYTES_PER_FRAME);
m_scrambler.process((uint8_t*)&m_frame.hdr.crc16, sizeof(m_frame.hdr.crc16));
m_scrambler.process((uint8_t*)&m_frame.hdr.type, sizeof(m_frame.hdr.type));
m_scrambler.process((uint8_t*)&m_frame.hdr.length, sizeof(m_frame.hdr.length));
uint16_t crc16_ist = Crc16(FRAME_CRC16_POLY, FRAME_CRC16_IV, m_frame.data, FRAME_NUM_BYTES_PER_FRAME);
if (crc16_ist == m_frame.hdr.crc16)
{
// Frame is valid
if (m_frame.hdr.type == FRAME_TYPE_DATA)
{
m_frameStats.numDataBytes += m_frame.hdr.length;
m_pDataHandler->onData(m_frame.data, m_frame.hdr.length);
}
}
m_frameStats.numDataFrame += (uint32_t)(m_frame.hdr.type == FRAME_TYPE_DATA);
m_frameStats.numIdleFrame += (uint32_t)(m_frame.hdr.type == FRAME_TYPE_IDLE);
m_frameStats.numInvalidFrame += (uint32_t)(crc16_ist != m_frame.hdr.crc16);
m_frameStats.numTotalFrame++;
m_dataCount = 0;
m_enable = 0;
}
}
frame_statistics_t DeFormatter::getStats()
{
return m_frameStats;
}
void DeFormatter::resetStats()
{
memset(&m_frameStats, 0, sizeof(frame_statistics_t));
}
void DeFormatter::onReset()
{
m_dataCount = 0;
m_enable = 1;
};
void DeFormatter::onData(data_t data)
{
process((uint8_t)data);
}
Symbolizer::Symbolizer(ISymbolizer *pSymbolHandler)
: m_pSymbolHandler(pSymbolHandler)
, m_symbolBitCount(0)
, m_lastSymbol(0)
, m_symbolMask(0)
{
setNumBitsPerSymbol(8);
}
Symbolizer::~Symbolizer()
{
}
void Symbolizer::setNumBitsPerSymbol(uint32_t nBitsPerSym)
{
m_symbolBitCount = 0;
m_nBitsPerSym = nBitsPerSym;
m_lastSymbol = 0;
m_symbolMask = 0;
for(uint32_t k=0; k < nBitsPerSym; k++)
{
m_symbolMask <<= 1;
m_symbolMask |= 1;
}
}
void Symbolizer::process(data_t src)
{
uint32_t i;
static symbol_t dst;
// Speed up
if (m_nBitsPerSym == SIZEOF_DATA_BITS)
{
m_pSymbolHandler->onSymbol(differentialEncode((symbol_t)src));
return;
}
// Transmission order MSB first
for (i=0; i < SIZEOF_DATA_BITS; i++)
{
dst <<= 1;
dst |= (symbol_t)((src >> (SIZEOF_DATA_BITS-1) & 1) != 0);
src <<= 1;
m_symbolBitCount++;
if (m_symbolBitCount == m_nBitsPerSym)
{
m_pSymbolHandler->onSymbol(differentialEncode(dst));
m_symbolBitCount = 0;
dst = 0;
}
}
}
void Symbolizer::process(void *pSrc, uint32_t len)
{
data_t *pData;
pData = (data_t*)pSrc;
while(len--)
{
process(*(pData++));
}
}
symbol_t Symbolizer::differentialEncode(symbol_t symbol)
{
// Differential encode
m_lastSymbol = (symbol_t)(m_symbolMask & (symbol + m_lastSymbol));
return m_lastSymbol;
}
void Symbolizer::onFrame(void *pFrame, uint32_t size)
{
data_t *pData = (data_t*)pFrame;
while(size)
{
process(*(pData++));
size -= sizeof(data_t);
}
}
DeSymbolizer::DeSymbolizer(IData *pDataHandler)
: m_pDataHandler(pDataHandler)
, m_dataBitCount(0)
, m_lastSymbol(0)
, m_symbolMask(0)
, m_nBitsPerSym(0)
{
setNumBitsPerSymbol(8);
}
DeSymbolizer::~DeSymbolizer()
{
}
void DeSymbolizer::setNumBitsPerSymbol(uint32_t nBitsPerSym)
{
m_nBitsPerSym = nBitsPerSym;
m_symbolMask = 0;
for(uint32_t k=0; k < nBitsPerSym; k++)
{
m_symbolMask <<= 1;
m_symbolMask |= 1;
}
m_bitCount = 0;
m_dataBitCount = 0;
m_lastSymbol = 0;
}
void DeSymbolizer::process(symbol_t src)
{
uint32_t i, j;
static data_t dst;
static uint16_t preamble;
uint16_t preamble_soll;
symbol_t symSync;
const uint32_t frameLengthInBits = 8*sizeof(frame_t);
src = differentialDecode(src);
symSync = src;
preamble_soll = ((uint16_t)FRAME_PREAMBLE_IV << 8) | (~(uint16_t)FRAME_PREAMBLE_IV & 0xFF);
j = 0;
for (i=0; i < m_nBitsPerSym; i++)
{
preamble <<= 1;
preamble |= (symbol_t)((symSync >> (m_nBitsPerSym-1) & 1) != 0);
symSync <<= 1;
m_bitCount++;
if (preamble == preamble_soll)
{
preamble = 0;
// We have data sync
if (m_bitCount == frameLengthInBits)
{
m_dataBitCount = 0;
m_pDataHandler->onReset();
j = i + 1;
src = symSync;
}
if (m_bitCount >= frameLengthInBits)
{
m_bitCount = 0;
}
}
}
// Transmission order MSB first
for (i=j; i < m_nBitsPerSym; i++)
{
dst <<= 1;
dst |= (symbol_t)((src >> (m_nBitsPerSym-1) & 1) != 0);
src <<= 1;
m_dataBitCount++;
if (m_dataBitCount == SIZEOF_DATA_BITS)
{
m_pDataHandler->onData(dst);
m_dataBitCount = 0;
dst = 0;
}
}
}
symbol_t DeSymbolizer::differentialDecode(symbol_t symbol)
{
symbol_t res;
// Differential decode
res = (symbol_t)(m_symbolMask & (symbol - m_lastSymbol));
m_lastSymbol = symbol;
return res;
}
// --------------------------------------------------------------
+307
View File
@@ -0,0 +1,307 @@
// --------------------------------------------------------------
#ifndef _FRAME_HPP_
#define _FRAME_HPP_
#include <radio/radio_types.h>
#include <radio/cpx.h>
// --------------------------------------------------------------
// Constants
// --------------------------------------------------------------
#define FRAME_CRC16_IV 0x0000
#define FRAME_CRC16_POLY 0x1021
#define FRAME_PREAMBLE_IV 0x55
#define FRAME_SCRAMBLER_SEED 0x12345678
#define FRAME_SCRAMBLER_POLY 0x80C18601
#define FRAME_NUM_BYTES_PER_FRAME 256
//#define FRAME_TYPE_IDLE 0x01
//#define FRAME_TYPE_DATA 0x02
// --------------------------------------------------------------
// Types
// --------------------------------------------------------------
enum frame_type
{
FRAME_TYPE_UNKNOWN = 0,
FRAME_TYPE_IDLE,
FRAME_TYPE_DATA
};
#pragma pack(push)
#pragma pack(1)
typedef struct _frame_hdr_t
{
uint8_t preamble[2];
uint32_t prn_state;
uint16_t crc16;
uint16_t type;
uint16_t length;
} frame_hdr_t;
typedef struct _frame_t
{
frame_hdr_t hdr;
uint8_t data[FRAME_NUM_BYTES_PER_FRAME];
} frame_t;
#pragma pack(pop)
typedef struct _frame_statistics_t
{
uint32_t numTotalFrame;
uint32_t numInvalidFrame;
uint32_t numIdleFrame;
uint32_t numDataFrame;
uint32_t numDataBytes;
} frame_statistics_t;
#define SIZEOF_SYMBOL_BITS (8*sizeof(symbol_t))
#define SIZEOF_DATA_BITS (8*sizeof(data_t))
// --------------------------------------------------------------
// Scrambler
// --------------------------------------------------------------
class Scrambler
{
public:
Scrambler(uint32_t state, uint32_t poly);
~Scrambler();
uint32_t stateGet();
void stateSet(uint32_t state);
uint8_t process(uint8_t src);
void process(uint8_t *pSrcDst, uint32_t len);
private:
uint32_t m_state;
uint32_t m_poly;
};
class IFormatter
{
public:
IFormatter() {}
virtual ~IFormatter() {}
virtual void onFrame(void *pFrame, uint32_t size) = 0;
};
class Formatter
{
public:
Formatter(IFormatter *pFrameHandler);
~Formatter();
void idle();
void process(uint8_t data);
void process(void *pData, uint32_t len);
frame_statistics_t getStats();
void resetStats();
private:
Scrambler m_scrambler;
IFormatter *m_pFrameHandler;
frame_t m_frame;
uint32_t m_dataCount;
uint32_t m_idleCount;
frame_statistics_t m_frameStats;
void commit(frame_type frameType, uint32_t m_dataCount);
};
class ISymbolizer
{
public:
ISymbolizer() {}
virtual ~ISymbolizer() {}
virtual void onSymbol(symbol_t symbol) = 0;
};
class Symbolizer : public IFormatter
{
public:
Symbolizer(ISymbolizer *pSymbolHandler);
~Symbolizer();
void process(data_t src);
void process(void *pSrc, uint32_t len);
void setNumBitsPerSymbol(uint32_t nBitsPerSym);
private:
uint32_t m_nBitsPerSym;
ISymbolizer *m_pSymbolHandler;
uint32_t m_symbolBitCount;
symbol_t m_lastSymbol;
symbol_t m_symbolMask;
symbol_t differentialEncode(symbol_t symbol);
void onFrame(void *pFrame, uint32_t size) override;
};
class IData
{
public:
IData() {}
virtual ~IData() {}
virtual void onData(data_t data) = 0;
virtual void onReset() = 0;
};
class IDeFormatter
{
public:
IDeFormatter() {}
virtual ~IDeFormatter() {}
virtual void onData(void *pData, uint32_t size) = 0;
};
class DeFormatter : public IData
{
public:
DeFormatter(IDeFormatter *pDataHandler);
~DeFormatter();
void process(uint8_t data);
frame_statistics_t getStats();
void resetStats();
private:
IDeFormatter *m_pDataHandler;
Scrambler m_scrambler;
uint32_t m_dataCount;
frame_t m_frame;
frame_statistics_t m_frameStats;
bool m_enable;
void onData(data_t data) override;
void onReset() override;
};
class DeSymbolizer
{
public:
DeSymbolizer(IData *pDataHandler);
~DeSymbolizer();
void process(symbol_t src);
void setNumBitsPerSymbol(uint32_t nBitsPerSym);
private:
uint32_t m_nBitsPerSym;
IData *m_pDataHandler;
uint32_t m_bitCount;
uint32_t m_dataBitCount;
symbol_t m_lastSymbol;
symbol_t m_symbolMask;
symbol_t differentialDecode(symbol_t symbol);
};
class FrameReceiver
{
public:
FrameReceiver(IDeFormatter *pRawFrameHandler)
: m_deformatter(pRawFrameHandler)
, m_desymbolizer( &m_deformatter)
, m_framesCount(0)
, m_byteCount(0)
{
}
~FrameReceiver()
{
}
frame_statistics_t getStats()
{
return m_deformatter.getStats();
}
void resetStats()
{
m_deformatter.resetStats();
}
void setNumBitsPerSymbol(uint32_t nBitsPerSym)
{
m_desymbolizer.setNumBitsPerSymbol(nBitsPerSym);
m_deformatter.resetStats();
}
void process(symbol_t symbol)
{
m_desymbolizer.process(symbol);
}
private:
DeFormatter m_deformatter;
DeSymbolizer m_desymbolizer;
uint32_t m_framesCount;
uint32_t m_byteCount;
};
class UnitFrameTransmitter
{
public:
UnitFrameTransmitter(uint32_t nBitsPerSym, ISymbolizer *pReceiver)
: m_symbolizer(pReceiver)
, m_formatter(&m_symbolizer)
{
m_symbolizer.setNumBitsPerSymbol(nBitsPerSym);
}
~UnitFrameTransmitter()
{
}
void process()
{
uint32_t i;
for (i=0; i < 12; i++)
{
m_formatter.process((uint8_t)i);
}
for (i=0; i < 100; i++)
{
m_formatter.idle();
}
for (i=0; i < 100; i++)
{
m_formatter.process((uint8_t)i);
}
m_formatter.idle();
}
private:
Symbolizer m_symbolizer;
Formatter m_formatter;
};
class UnitFrameReceiver : public ISymbolizer, public IDeFormatter
{
public:
UnitFrameReceiver(uint32_t nBitsPerSym)
: m_deformatter(this)
, m_desymbolizer(&m_deformatter)
{
m_desymbolizer.setNumBitsPerSymbol(nBitsPerSym);
}
~UnitFrameReceiver()
{
}
private:
DeFormatter m_deformatter;
DeSymbolizer m_desymbolizer;
void onSymbol(symbol_t symbol) override
{
m_desymbolizer.process(symbol);
}
void onData(void *pData, uint32_t size) override
{
// Received raw data
(void)pData;
(void)size;
}
};
// --------------------------------------------------------------
#endif // _FRAME_HPP_
+311
View File
@@ -0,0 +1,311 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "GraphComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
GraphComponent::GraphComponent ()
: m_maxNumPoints(1024)
, m_maxNumCurves(2)
, m_graphMinX(-1.0)
, m_graphMinY(-1.0)
, m_graphMaxX(1.0)
, m_graphMaxY(1.0)
, m_tickStepX(0.1)
, m_tickStepY(0.1)
{
//[UserPreSize]
m_pCurves = new Curve[m_maxNumCurves];
for (int i=0; i < m_maxNumCurves; i++)
{
m_pCurves[i].alloc(m_maxNumPoints);
}
//[/UserPreSize]
setSize (400, 400);
//[Constructor] You can add your own custom stuff here..
//[/Constructor]
}
GraphComponent::~GraphComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
//[Destructor]. You can add your own custom destruction code here..
delete [] m_pCurves;
//[/Destructor]
}
//==============================================================================
void GraphComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
juce::Point<float> p;
juce::Colour c;
//[/UserPrePaint]
g.fillAll (Colours::black);
//[UserPaint] Add your own custom painting code here..
g.setColour (juce::Colours::white);
g.setOpacity(0.25);
drawMainTicks(g);
g.setOpacity(1.00);
g.setColour (juce::Colours::limegreen);
drawCurve(g, 0);
g.setOpacity(1.00);
g.setColour (juce::Colours::red);
drawCurve(g, 1);
g.setColour (juce::Colours::white);
g.setOpacity(1.0);
drawBorder(g);
// g.setColour (juce::Colours::limegreen);
// g.setOpacity(0.5);
// drawReference(g, 4, 1.0, 11);
//[/UserPaint]
}
void GraphComponent::resized()
{
//[UserResized] Add your own custom resize handling here..
m_screenWidth = 3*getWidth()/4;
m_screenHeight = 3*getHeight()/4;
m_screenOffsetX = (getWidth()-m_screenWidth)/2;
m_screenOffsetY = (getHeight()-m_screenHeight)/2;
//[/UserResized]
}
void GraphComponent::mouseDown (const MouseEvent& e)
{
//[UserCode_mouseDown] -- Add your code here...
(void)e;
//[/UserCode_mouseDown]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void GraphComponent::receiverStatusChanged(ReceiverInterface *pReceiver)
{
uint32_t i, j;
uint32_t N;
const cpx_t *pW;
float minX = 1000;
float maxX = -1000;
float minY = 1000;
float maxY = -1000;
j = 0;
N = pReceiver->getNumWeightsCMA();
pW = pReceiver->getWeightsCMA();
for (i=0; i < N; i++)
{
m_pCurves[j].m_pPointArray[i].x = (float)i;
m_pCurves[j].m_pPointArray[i].y = CpxMagS(pW[i]);
if (m_pCurves[j].m_pPointArray[i].y < minY)
{
minY = m_pCurves[j].m_pPointArray[i].y;
}
if (m_pCurves[j].m_pPointArray[i].y > maxY)
{
maxY = m_pCurves[j].m_pPointArray[i].y;
}
}
m_pCurves[j].m_numPoints = N;
maxX = (float)(N-1);
j = 1;
N = pReceiver->getNumWeightsDFE();
pW = pReceiver->getWeightsDFE();
for (i=0; i < N; i++)
{
m_pCurves[j].m_pPointArray[i].x = (float)i;
m_pCurves[j].m_pPointArray[i].y = CpxMagS(pW[i]);
if (m_pCurves[j].m_pPointArray[i].y < minY)
{
minY = m_pCurves[j].m_pPointArray[i].y;
}
if (m_pCurves[j].m_pPointArray[i].y > maxY)
{
maxY = m_pCurves[j].m_pPointArray[i].y;
}
}
m_pCurves[j].m_numPoints = N;
minY = 0;
minX = 0;
maxY = ceil(maxY);
if (N > maxX)
{
maxX = (float)(N-1);
}
setGraphBounds(minX, maxX, minY, maxY);
repaint();
}
void GraphComponent::setGraphBounds(float minX, float maxX, float minY, float maxY)
{
m_graphMinX = minX;
m_graphMaxX = maxX;
m_graphMinY = minY;
m_graphMaxY = maxY;
m_tickStepX = (maxX - minX)/10;
m_tickStepY = (maxY - minY)/10;
}
float GraphComponent::getScreenCoordX(float x)
{
if ((x > m_graphMaxX) || (x < m_graphMinX))
return 0;
return m_screenOffsetX + (float)(m_screenWidth*(x-m_graphMinX)/(m_graphMaxX-m_graphMinX));
}
float GraphComponent::getScreenCoordY(float y)
{
if ((y > m_graphMaxY) || (y < m_graphMinY))
return 0;
return m_screenOffsetY + (float)(m_screenHeight*(1-(y-m_graphMinY)/(m_graphMaxY-m_graphMinY)));
}
void GraphComponent::drawCurve(Graphics& g, uint32_t index)
{
uint32_t i;
float x0, y0;
float x1, y1;
for (i=1; i < m_pCurves[index].m_numPoints; i++)
{
x0 = getScreenCoordX(m_pCurves[index].m_pPointArray[i-1].x);
y0 = getScreenCoordY(m_pCurves[index].m_pPointArray[i-1].y);
x1 = getScreenCoordX(m_pCurves[index].m_pPointArray[i].x);
y1 = getScreenCoordY(m_pCurves[index].m_pPointArray[i].y);
g.drawLine(x0, y0, x1, y1, 1.f);
}
}
void GraphComponent::drawBorder(Graphics& g)
{
g.drawVerticalLine((int)getScreenCoordX(m_graphMinX), getScreenCoordY(m_graphMaxY), getScreenCoordY(m_graphMinY));
g.drawVerticalLine((int)getScreenCoordX(m_graphMaxX), getScreenCoordY(m_graphMaxY), getScreenCoordY(m_graphMinY));
g.drawHorizontalLine((int)getScreenCoordY(m_graphMinY), getScreenCoordX(m_graphMinX), getScreenCoordX(m_graphMaxX));
g.drawHorizontalLine((int)getScreenCoordY(m_graphMaxY), getScreenCoordX(m_graphMinX), getScreenCoordX(m_graphMaxX));
}
void GraphComponent::drawMainTicks(Graphics& g)
{
float pos;
pos = m_graphMinX;
while(pos < m_graphMaxX)
{
pos += m_tickStepX;
g.drawVerticalLine((int)getScreenCoordX(pos), getScreenCoordY(m_graphMaxY), getScreenCoordY(m_graphMinY));
}
pos = m_graphMinY;
while(pos < m_graphMaxY)
{
pos += m_tickStepY;
g.drawHorizontalLine((int)getScreenCoordY(pos), getScreenCoordX(m_graphMinX), getScreenCoordX(m_graphMaxX));
}
}
void GraphComponent::drawReference(Graphics& g, uint32_t numConst, float radius, float size)
{
float step;
float s;
float i, q;
float x, y;
uint32_t xx, yy;
uint32_t N;
N = (uint32_t)(sqrt((float)numConst));
s = (float)(radius/sqrt(2));
step = 2*s/(N-1);
i = -s;
xx = N;
while(xx--)
{
q = -s;
yy = N;
while(yy--)
{
x = getScreenCoordX(i);
y = getScreenCoordY(q);
g.drawEllipse(x-size/2, y-size/2, size, size, 1.5);
q += step;
}
i += step;
}
}
void GraphComponent::drawCross(Graphics& g, juce::Point<float> point, float size)
{
float x, y;
x = getScreenCoordX(point.getX());
y = getScreenCoordY(point.getY());
g.drawLine(x-size/2, y+size/2, x+size/2, y-size/2, 1.f);
g.drawLine(x+size/2, y+size/2, x-size/2, y-size/2, 1.f);
}
void GraphComponent::drawCircle(Graphics& g, juce::Point<float> point, float size)
{
float x, y;
x = getScreenCoordX(point.getX());
y = getScreenCoordY(point.getY());
g.drawEllipse(x-size/2, y-size/2, size, size, 1.5);
}
//[/MiscUserCode]
//==============================================================================
//[EndFile] You can add extra defines here...
//[/EndFile]
+129
View File
@@ -0,0 +1,129 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
#ifndef __GRAPH_COMPONENT__
#define __GRAPH_COMPONENT__
//[Headers] -- You can add your own extra header files here --
#include "JuceHeader.h"
#include "Receiver.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Introjucer.
Describe your class and how it works here!
//[/Comments]
*/
class GraphComponent : public Component,
public ReceiverStatusListener
{
public:
//==============================================================================
GraphComponent ();
~GraphComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
void setGraphBounds(float minX, float maxX, float minY, float maxY);
//[/UserMethods]
void paint (Graphics& g);
void resized();
void mouseDown (const MouseEvent& e);
private:
//[UserVariables] -- You can add your own custom variables in this section.
typedef struct _point_t
{
float x;
float y;
} point_t;
class Curve
{
uint32_t m_maxNumPoints;
public:
point_t *m_pPointArray;
uint32_t m_numPoints;
Curve()
: m_pPointArray(0)
, m_maxNumPoints(0)
, m_numPoints(0)
{
}
~Curve()
{
if (m_pPointArray)
delete m_pPointArray;
}
void alloc(uint32_t maxNumPoints)
{
m_maxNumPoints = maxNumPoints;
if (m_pPointArray)
delete m_pPointArray;
m_pPointArray = new point_t[m_maxNumPoints];
}
};
uint32_t m_screenWidth;
uint32_t m_screenHeight;
uint32_t m_screenOffsetX;
uint32_t m_screenOffsetY;
float m_graphMinX;
float m_graphMinY;
float m_graphMaxX;
float m_graphMaxY;
float m_tickStepX;
float m_tickStepY;
uint32_t m_maxNumPoints;
uint32_t m_maxNumCurves;
Curve *m_pCurves;
float getScreenCoordX(float x);
float getScreenCoordY(float y);
void drawBorder(Graphics& g);
void drawMainTicks(Graphics& g);
void drawCurve(Graphics& g, uint32_t index);
void drawReference(Graphics& g, uint32_t numConst, float radius, float size);
void drawCross(Graphics& g, juce::Point<float> point, float size);
void drawCircle(Graphics& g, juce::Point<float> point, float size);
void receiverStatusChanged(ReceiverInterface *pReceiver);
//[/UserVariables]
//==============================================================================
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]
#endif // __GRAPH_COMPONENT__
+256
View File
@@ -0,0 +1,256 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "IQPlaneComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
IQPlaneComponent::IQPlaneComponent (uint32 maxNumPoints)
: m_maxNumPoints(maxNumPoints), m_numPoints(0)
{
//[UserPreSize]
m_pPointArray = new sym_err_t[maxNumPoints];
//[/UserPreSize]
setSize (400, 400);
//[Constructor] You can add your own custom stuff here..
m_numConst = 4;
for (int i=0; i < NUM_TRACKER_POINTS; i++)
{
m_trackerPoints[i].isEnabled = 0;
}
//[/Constructor]
}
IQPlaneComponent::~IQPlaneComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
//[Destructor]. You can add your own custom destruction code here..
delete(m_pPointArray);
m_pPointArray = nullptr;
//[/Destructor]
}
//==============================================================================
void IQPlaneComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
juce::Point<float> p;
juce::Colour c;
uint32_t i;
//[/UserPrePaint]
g.fillAll (Colours::black);
//[UserPaint] Add your own custom painting code here..
if (m_pPointArray != nullptr)
{
for (i=0; i < m_numPoints; i++)
{
p.setX(m_pPointArray[i].soft_sym.real);
p.setY(m_pPointArray[i].soft_sym.imag);
c = Colour(juce::Colours::white).interpolatedWith(Colour(juce::Colours::red), 20*dabs(m_pPointArray[i].err_mag)).interpolatedWith(Colour(juce::Colours::blue), 20*dabs(m_pPointArray[i].err_phi));
g.setColour (c);
drawCross(g, p, 7);
}
}
m_numPoints = 0;
g.setColour (juce::Colours::limegreen);
g.setOpacity(0.5);
drawReference(g, 4, 1.0, 11);
for (i=0; i < NUM_TRACKER_POINTS; i++)
{
if (m_trackerPoints[i].isEnabled)
{
g.setColour (m_trackerPoints[i].color);
drawCircle(g, m_trackerPoints[i].point, m_trackerPoints[i].size);
}
}
//[/UserPaint]
}
void IQPlaneComponent::resized()
{
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
void IQPlaneComponent::mouseDown (const MouseEvent& e)
{
//[UserCode_mouseDown] -- Add your code here...
(void)e;
//[/UserCode_mouseDown]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void IQPlaneComponent::receiverStatusChanged(ReceiverInterface *pReceiver)
{
params_t params;
params = pReceiver->getParams();
m_numConst = (uint32_t)pow(2.0, params.numBitsPerSymbol);
repaint();
}
void IQPlaneComponent::trackerPointEnable(uint32_t id, juce::Colour color, cpx_t pos, float size)
{
m_trackerPoints[id].color = color;
m_trackerPoints[id].isEnabled = 1;
m_trackerPoints[id].point.setX(pos.real);
m_trackerPoints[id].point.setY(pos.imag);
m_trackerPoints[id].size = size;
}
void IQPlaneComponent::trackerPointDisable(uint32_t id)
{
m_trackerPoints[id].isEnabled = 0;
}
void IQPlaneComponent::pointAdd(sym_err_t *pPoint, uint32_t numPoints)
{
uint32_t i;
uint32_t numFill;
if (m_numPoints >= m_maxNumPoints)
return;
numFill = (uint32_t)__min(m_maxNumPoints-m_numPoints, numPoints);
for (i=0; i < numFill; i++)
{
m_pPointArray[m_numPoints++] = pPoint[i];
}
}
float IQPlaneComponent::getScreenCoordX(float x)
{
if ((x > 1.0) || (x < -1.0))
return 0;
return (float)(getWidth()*(1.0 + x)/2);
}
float IQPlaneComponent::getScreenCoordY(float y)
{
if ((y > 1.0) || (y < -1.0))
return 0;
return (float)(getHeight()*(1.0 + y)/2);
}
void IQPlaneComponent::drawReference(Graphics& g, uint32_t numConst, float radius, float size)
{
float step;
float s;
float i, q;
float x, y;
uint32_t xx, yy;
uint32_t N;
N = (uint32_t)(sqrt((float)numConst));
s = (float)(radius/sqrt(2));
step = 2*s/(N-1);
i = -s;
xx = N;
while(xx--)
{
q = -s;
yy = N;
while(yy--)
{
x = getScreenCoordX(i);
y = getScreenCoordY(q);
g.drawEllipse(x-size/2, y-size/2, size, size, 1.5);
q += step;
}
i += step;
}
}
void IQPlaneComponent::drawCross(Graphics& g, juce::Point<float> point, float size)
{
float x, y;
x = getScreenCoordX(point.getX());
y = getScreenCoordY(point.getY());
g.drawLine(x-size/2, y+size/2, x+size/2, y-size/2, 1.f);
g.drawLine(x+size/2, y+size/2, x-size/2, y-size/2, 1.f);
}
void IQPlaneComponent::drawCircle(Graphics& g, juce::Point<float> point, float size)
{
float x, y;
x = getScreenCoordX(point.getX());
y = getScreenCoordY(point.getY());
g.drawEllipse(x-size/2, y-size/2, size, size, 1.5);
}
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Introjucer information section --
This is where the Introjucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="IQPlaneComponent" componentName=""
parentClasses="public Component, public ReceiverStatusListener"
constructorParams="uint32 maxNumPoints" variableInitialisers="m_maxNumPoints(maxNumPoints), m_numPoints(0)"
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330"
fixedSize="0" initialWidth="400" initialHeight="400">
<METHODS>
<METHOD name="mouseDown (const MouseEvent&amp; e)"/>
</METHODS>
<BACKGROUND backgroundColour="ff000000"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]
+93
View File
@@ -0,0 +1,93 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
#ifndef __JUCE_HEADER_6591F9469DB772__
#define __JUCE_HEADER_6591F9469DB772__
//[Headers] -- You can add your own extra header files here --
#include "JuceHeader.h"
#include "Receiver.h"
#define NUM_TRACKER_POINTS 4
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Introjucer.
Describe your class and how it works here!
//[/Comments]
*/
class IQPlaneComponent : public Component,
public ReceiverStatusListener
{
public:
//==============================================================================
IQPlaneComponent (uint32 maxNumPoints);
~IQPlaneComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
void pointAdd(sym_err_t *pPoint, uint32_t numPoints);
void trackerPointEnable(uint32_t id, juce::Colour color, cpx_t pos, float size);
void trackerPointDisable(uint32_t id);
//[/UserMethods]
void paint (Graphics& g);
void resized();
void mouseDown (const MouseEvent& e);
private:
//[UserVariables] -- You can add your own custom variables in this section.
typedef struct _trackerPoint_t
{
bool isEnabled;
juce::Colour color;
juce::Point<float> point;
float size;
} trackerPoint_t;
sym_err_t *m_pPointArray;
uint32 m_maxNumPoints;
uint32 m_numPoints;
float getScreenCoordX(float x);
float getScreenCoordY(float y);
void drawReference(Graphics& g, uint32_t numConst, float radius, float size);
void drawCross(Graphics& g, juce::Point<float> point, float size);
void drawCircle(Graphics& g, juce::Point<float> point, float size);
void receiverStatusChanged(ReceiverInterface *pReceiver);
uint32_t m_numConst;
trackerPoint_t m_trackerPoints[NUM_TRACKER_POINTS];
//[/UserVariables]
//==============================================================================
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IQPlaneComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]
#endif // __JUCE_HEADER_6591F9469DB772__
+160
View File
@@ -0,0 +1,160 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "IQPoint.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
IQPoint::IQPoint (uint32 id)
: m_id(id)
{
//[UserPreSize]
//[/UserPreSize]
setSize (10, 10);
//[Constructor] You can add your own custom stuff here..
m_alpha = 1.0f;
setVisible(false);
//[/Constructor]
}
IQPoint::~IQPoint()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void IQPoint::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
g.setColour (m_color.withMultipliedAlpha(m_alpha));
drawCross(g);
//[/UserPaint]
}
void IQPoint::resized()
{
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void IQPoint::drawPoint(Graphics& g)
{
g.fillEllipse (getLocalBounds().toFloat());
}
void IQPoint::drawCross(Graphics& g)
{
Rectangle<float> coord;
coord = getLocalBounds().toFloat();
g.drawLine(coord.getTopLeft().getX(), coord.getTopLeft().getY(), coord.getBottomRight().getX(), coord.getBottomRight().getY(), 1.f);
g.drawLine(coord.getTopRight().getX(), coord.getTopRight().getY(), coord.getBottomLeft().getX(), coord.getBottomLeft().getY(), 1.f);
}
void IQPoint::drawPlusSign(Graphics& g)
{
(void)g;
}
void IQPoint::start()
{
m_alpha = 1.0f;
startTimer (1000 / 20);
setVisible(true);
repaint();
}
void IQPoint::stop()
{
stopTimer ();
setVisible(false);
m_alpha = 1.0f;
repaint();
}
void IQPoint::setColor(Colour color)
{
m_color = color;
repaint();
}
void IQPoint::timerCallback()
{
// Reduce the alpha level of the flash slightly so it fades out
m_alpha -= 0.06f*m_alpha;
if (m_alpha < 0.05f)
{
stop();
sendChangeMessage();
// Once we've finsihed flashing send a change message to trigger the next component to flash
}
repaint();
}
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Introjucer information section --
This is where the Introjucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="IQPoint" componentName=""
parentClasses="public Component, public ChangeBroadcaster, public Timer"
constructorParams="uint32 id" variableInitialisers="m_id(id)"
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330"
fixedSize="0" initialWidth="10" initialHeight="10">
<BACKGROUND backgroundColour="ffffff"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]
+84
View File
@@ -0,0 +1,84 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
#ifndef __JUCE_HEADER_7516F6CE21DC98C8__
#define __JUCE_HEADER_7516F6CE21DC98C8__
//[Headers] -- You can add your own extra header files here --
#include "JuceHeader.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Introjucer.
Describe your class and how it works here!
//[/Comments]
*/
class IQPoint : public Component,
public ChangeBroadcaster,
public Timer
{
public:
//==============================================================================
IQPoint (uint32 id);
~IQPoint();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
LinkedListPointer<IQPoint> nextListItem;
void start();
void stop();
void setColor(Colour color);
void drawCross(Graphics& g);
//[/UserMethods]
void paint (Graphics& g);
void resized();
private:
//[UserVariables] -- You can add your own custom variables in this section.
uint32 m_id;
Colour m_color;
int m_pos_x;
int m_pos_y;
void timerCallback() override;
float m_alpha;
void drawPoint(Graphics& g);
void drawPlusSign(Graphics& g);
//[/UserVariables]
//==============================================================================
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IQPoint)
};
//[EndFile] You can add extra defines here...
//[/EndFile]
#endif // __JUCE_HEADER_7516F6CE21DC98C8__
+24
View File
@@ -0,0 +1,24 @@
#include "LogComponent.h"
#include <cstdio>
#include <cstdarg>
LogComponent::LogComponent(LogHandler *pLogHandler)
: m_pLogHandler(pLogHandler)
{
}
LogComponent::~LogComponent(void)
{
}
void LogComponent::log(const char* format, ...)
{
char log_buf[257];
String s;
va_list argptr;
va_start(argptr, format);
vsprintf(log_buf, format, argptr);
va_end(argptr);
s = String(log_buf);
// m_pLogHandler->handleMessage(s);
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef _LOGCOMPONENT_H_
#define _LOGCOMPONENT_H_
#include "JuceHeader.h"
// ---------------------------------------------------
class LogHandler
{
public:
LogHandler() {}
virtual ~LogHandler() {}
virtual void handleMessage(String msg) = 0;
};
class LogComponent
{
public:
LogComponent(LogHandler *pLogHandler);
~LogComponent(void);
void log(const char* format, ...);
private:
LogHandler *m_pLogHandler;
};
#endif // _LOGCOMPONENT_H_
+101
View File
@@ -0,0 +1,101 @@
/*
==============================================================================
This file was auto-generated by the Introjucer!
It contains the basic startup code for a Juce application.
==============================================================================
*/
#include "../JuceLibraryCode/JuceHeader.h"
#include "MainComponent.h"
//==============================================================================
class MPSKReceiverApplication : public JUCEApplication
{
public:
//==============================================================================
MPSKReceiverApplication() {}
const String getApplicationName() override { return ProjectInfo::projectName; }
const String getApplicationVersion() override { return ProjectInfo::versionString; }
bool moreThanOneInstanceAllowed() override { return true; }
//==============================================================================
void initialise (const String& commandLine) override
{
// This method is where you should put your application's initialisation code..
(void)commandLine;
mainWindow = new MainWindow();
}
void shutdown() override
{
// Add your application's shutdown code here..
mainWindow = nullptr; // (deletes our window)
}
//==============================================================================
void systemRequestedQuit() override
{
// This is called when the app is being asked to quit: you can ignore this
// request and let the app carry on running, or call quit() to allow the app to close.
quit();
}
void anotherInstanceStarted (const String& commandLine) override
{
(void)commandLine;
// When another instance of the app is launched while this one is running,
// this method is invoked, and the commandLine parameter tells you what
// the other instance's command-line arguments were.
}
//==============================================================================
/*
This class implements the desktop window that contains an instance of
our MainContentComponent class.
*/
class MainWindow : public DocumentWindow
{
public:
MainWindow() : DocumentWindow ("M-QAM Transceiver",
Colours::lightgrey,
DocumentWindow::allButtons)
{
setContentOwned (new MainComponent(), true);
centreWithSize (getWidth(), getHeight());
setVisible (true);
}
void closeButtonPressed()
{
// This is called when the user tries to close this window. Here, we'll just
// ask the app to quit when this happens, but you can change this to do
// whatever you need.
JUCEApplication::getInstance()->systemRequestedQuit();
}
/* Note: Be careful if you override any DocumentWindow methods - the base
class uses a lot of them, so by overriding you might break its functionality.
It's best to do all your work in your content component instead, but if
you really have to override any DocumentWindow methods, make sure your
subclass also calls the superclass's method.
*/
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
};
private:
ScopedPointer<MainWindow> mainWindow;
};
//==============================================================================
// This macro generates the main() routine that launches the app.
START_JUCE_APPLICATION (MPSKReceiverApplication)
+219
View File
@@ -0,0 +1,219 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "MainComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
MainComponent::MainComponent ()
: m_TextEditor(new TextEditor),
m_sharedAudioDeviceManager(nullptr),
m_AudioDeviceSelectorComponent(new AudioDeviceSelectorComponent (getSharedAudioDeviceManager(), 0, 256, 0, 256, true, true, true, false)),
m_pReceiver(new Receiver(this)),
m_pTransmitter(new Transmitter()),
m_ControlComponent(new ControlComponent(m_pReceiver, m_pTransmitter)), m_log(this),
m_pReceiverControl(m_pReceiver)
{
addAndMakeVisible (tabbedComponent = new TabbedComponent (TabbedButtonBar::TabsAtTop));
tabbedComponent->setTabBarDepth (38);
tabbedComponent->setCurrentTabIndex (-1);
addAndMakeVisible (m_pIQPlaneComponent = new IQPlaneComponent (256));
m_pIQPlaneComponent->setName ("IQPlaneComponent");
addAndMakeVisible (m_pGraphComponent = new GraphComponent());
m_pGraphComponent->setName ("GraphComponent");
//[UserPreSize]
//[/UserPreSize]
setSize (1280, 1024);
//[Constructor] You can add your own custom stuff here..
m_samplerate = 48000;
// m_pTransmitter = new Transmitter();
m_pTransmitterControl = m_pTransmitter;
m_TextEditor->setMultiLine (true);
m_TextEditor->setReturnKeyStartsNewLine (true);
m_TextEditor->setReadOnly (true);
m_TextEditor->setScrollbarsShown (true);
m_TextEditor->setCaretVisible (false);
m_TextEditor->setPopupMenuEnabled (true);
m_TextEditor->setFont(juce::Font(juce::Font::getDefaultMonospacedFontName(), 12, juce::Font::plain));
tabbedComponent->addTab (TRANS("Control"), Colours::lightgrey, m_ControlComponent, false);
tabbedComponent->addTab (TRANS("Messages"), Colours::lightgrey, m_TextEditor, false);
tabbedComponent->addTab (TRANS("Audio-Settings"), Colours::lightgrey, m_AudioDeviceSelectorComponent, false);
m_pReceiver->addDataListener(this);
m_pReceiver->addStatusListener(m_ControlComponent);
m_pReceiver->addStatusListener(m_pIQPlaneComponent);
m_pReceiver->addStatusListener(m_pGraphComponent);
getSharedAudioDeviceManager().addChangeListener (this);
getSharedAudioDeviceManager().addAudioCallback (this);
startTimer (1000 / 30);
//[/Constructor]
}
MainComponent::~MainComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
stopTimer();
getSharedAudioDeviceManager().removeAudioCallback (this);
getSharedAudioDeviceManager().removeChangeListener (this);
m_AudioDeviceSelectorComponent = nullptr;
//[/Destructor_pre]
tabbedComponent = nullptr;
m_pIQPlaneComponent = nullptr;
m_pGraphComponent = nullptr;
//[Destructor]. You can add your own custom destruction code here..
m_sharedAudioDeviceManager = nullptr;
//[/Destructor]
}
//==============================================================================
void MainComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
g.fillAll (Colours::white);
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void MainComponent::resized()
{
tabbedComponent->setBounds (8, 8, 800, 1000);
m_pIQPlaneComponent->setBounds (848, 48, 400, 400);
m_pGraphComponent->setBounds (848, 544, 400, 400);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void MainComponent::changeListenerCallback (ChangeBroadcaster*)
{
// dumpDeviceInfo();
}
void MainComponent::audioDeviceIOCallback (const float** inputChannelData,
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples)
{
const ScopedLock sl (m_lock);
(void) numInputChannels;
(void) numOutputChannels;
// m_pReceiver->processBaseband((float*)inputChannelData[0], (float*)inputChannelData[1], numSamples);
m_pTransmitterControl->getData(outputChannelData[0], numSamples);
m_pReceiver->processPassband((float*)inputChannelData[0], numSamples);
}
void MainComponent::audioDeviceAboutToStart (AudioIODevice* device)
{
int bufferSize;
m_samplerate = (float)device->getCurrentSampleRate();
bufferSize = device->getCurrentBufferSizeSamples();
m_pTransmitterControl->setBuffersize(bufferSize);
m_pTransmitterControl->setSamplerate(m_samplerate);
m_pReceiver->setBufSize(bufferSize);
m_pReceiverControl->setSamplerate(m_samplerate);
}
void MainComponent::audioDeviceStopped()
{
}
AudioDeviceManager& MainComponent::getSharedAudioDeviceManager()
{
if (m_sharedAudioDeviceManager == nullptr)
{
m_sharedAudioDeviceManager = new AudioDeviceManager();
m_sharedAudioDeviceManager->initialise (2, 2, 0, true, String::empty, 0);
}
return *m_sharedAudioDeviceManager;
}
void MainComponent::timerCallback()
{
if (m_pIQPlaneComponent == nullptr)
return;
m_pIQPlaneComponent->repaint();
m_pGraphComponent->repaint();
}
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Introjucer information section --
This is where the Introjucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="MainComponent" componentName=""
parentClasses="public Component, public ChangeListener, public AudioIODeviceCallback, public ReceiverDataListener, public LogHandler, public Timer"
constructorParams="" variableInitialisers="m_TextEditor(new TextEditor),&#10;m_sharedAudioDeviceManager(nullptr),&#10;m_AudioDeviceSelectorComponent(new AudioDeviceSelectorComponent (getSharedAudioDeviceManager(), 0, 256, 0, 256, true, true, true, false)),&#10;m_pReceiver(new Receiver(this)),&#10;m_pTransmitter(new Transmitter()),&#10;m_ControlComponent(new ControlComponent(m_pReceiver, m_pTransmitter)), m_log(this),&#10;m_pReceiverControl(m_pReceiver)&#10;"
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330"
fixedSize="1" initialWidth="1280" initialHeight="1024">
<BACKGROUND backgroundColour="ffffffff"/>
<TABBEDCOMPONENT name="new tabbed component" id="4c02ba4e5ea4fa59" memberName="tabbedComponent"
virtualName="" explicitFocusOrder="0" pos="8 8 800 1000" orientation="top"
tabBarDepth="38" initialTab="-1"/>
<GENERICCOMPONENT name="IQPlaneComponent" id="d61ada3176fcc62a" memberName="m_pIQPlaneComponent"
virtualName="" explicitFocusOrder="0" pos="848 48 400 400" class="IQPlaneComponent"
params="256"/>
<GENERICCOMPONENT name="GraphComponent" id="c729f8c175157e1e" memberName="m_pGraphComponent"
virtualName="" explicitFocusOrder="0" pos="848 544 400 400" class="GraphComponent"
params=""/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]
+125
View File
@@ -0,0 +1,125 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Introjucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
==============================================================================
*/
#ifndef __JUCE_HEADER_9002020A4DD09B20__
#define __JUCE_HEADER_9002020A4DD09B20__
//[Headers] -- You can add your own extra header files here --
#include "JuceHeader.h"
#include "IQPlaneComponent.h"
#include "GraphComponent.h"
#include "LogComponent.h"
#include "ControlComponent.h"
#include "Receiver.h"
#include "Transmitter.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Introjucer.
Describe your class and how it works here!
//[/Comments]
*/
class MainComponent : public Component,
public ChangeListener,
public AudioIODeviceCallback,
public ReceiverDataListener,
public LogHandler,
public Timer
{
public:
//==============================================================================
MainComponent ();
~MainComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g);
void resized();
private:
//[UserVariables] -- You can add your own custom variables in this section.
CriticalSection m_lock;
LogComponent m_log;
ScopedPointer<TextEditor> m_TextEditor;
ScopedPointer<Receiver> m_pReceiver;
ScopedPointer<Transmitter> m_pTransmitter;
ScopedPointer<AudioDeviceManager> m_sharedAudioDeviceManager;
ScopedPointer<AudioDeviceSelectorComponent> m_AudioDeviceSelectorComponent;
ScopedPointer<ControlComponent> m_ControlComponent;
ReceiverInterface *m_pReceiverControl;
TransmitterInterface *m_pTransmitterControl;
float m_samplerate;
void timerCallback() override;
AudioDeviceManager& getSharedAudioDeviceManager();
void changeListenerCallback (ChangeBroadcaster*) override;
void audioDeviceIOCallback (const float** inputChannelData,
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples);
void audioDeviceAboutToStart (AudioIODevice* device);
void audioDeviceStopped();
void receiverDataChanged(Receiver *pObj)
{
uint32_t i;
uint32 nSyms;
sym_err_t *pSoftSyms;
nSyms = (uint32)dmin((float)128, (float)pObj->getNumSoftSym());
pSoftSyms = pObj->getSoftSyms();
m_pIQPlaneComponent->pointAdd(pSoftSyms, nSyms);
for (i=0; i < 4; i++)
{
m_pIQPlaneComponent->trackerPointEnable(i, juce::Colours::red, ((ReceiverInterface*)pObj)->getTracker(i), 15);
}
}
void handleMessage(String msg)
{
m_TextEditor->moveCaretToEnd();
m_TextEditor->insertTextAtCaret (msg + newLine);
}
//[/UserVariables]
//==============================================================================
ScopedPointer<TabbedComponent> tabbedComponent;
ScopedPointer<IQPlaneComponent> m_pIQPlaneComponent;
ScopedPointer<GraphComponent> m_pGraphComponent;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]
#endif // __JUCE_HEADER_9002020A4DD09B20__
+156
View File
@@ -0,0 +1,156 @@
#include "MinMaxLemire.h"
MinMaxLemire::MinMaxLemire(uint32_t N)
: width(N)
, minvalues(2*N)
, maxvalues(2*N)
{
}
MinMaxLemire::~MinMaxLemire(void)
{
}
void MinMaxLemire::process(vector<float> & array)
{
maxfifo.push_back(0);
minfifo.push_back(0);
for (uint32_t i = 1; i < width; ++i)
{
if (array[i] > array[i - 1])
{
//overshoot
maxfifo.pop_back();
while (!maxfifo.empty())
{
if (array[i] <= array[maxfifo.back()])
break;
maxfifo.pop_back();
}
}
else
{
minfifo.pop_back();
while (!minfifo.empty())
{
if (array[i] >= array[minfifo.back()])
break;
minfifo.pop_back();
}
}
maxfifo.push_back(i);
minfifo.push_back(i);
}
for (uint32_t i = width; i < array.size(); ++i)
{
maxvalues[i - width] = array[maxfifo.front()];
minvalues[i - width] = array[minfifo.front()];
if (array[i] > array[i - 1])
{
//overshoot
maxfifo.pop_back();
while (!maxfifo.empty())
{
if (array[i] <= array[maxfifo.back()])
break;
maxfifo.pop_back();
}
}
else
{
minfifo.pop_back();
while (!minfifo.empty())
{
if (array[i] >= array[minfifo.back()])
break;
minfifo.pop_back();
}
}
maxfifo.push_back(i);
minfifo.push_back(i);
if (i == width + maxfifo.front())
maxfifo.pop_front();
else
if (i == width + minfifo.front())
minfifo.pop_front();
}
maxvalues[array.size() - width] = array[maxfifo.front()];
minvalues[array.size() - width] = array[minfifo.front()];
}
/*
class simplelemiremaxmin: public minmaxfilter {
public:
simplelemiremaxmin(vector<floattype> & array, uint width) :
maxvalues(array.size() - width + 1),
minvalues(array.size() - width + 1)
{
deque<int> maxfifo, minfifo;
maxfifo.push_back(0);
minfifo.push_back(0);
for (uint i = 1; i < width; ++i) {
if (array[i] > array[i - 1]) { //overshoot
maxfifo.pop_back();
while (!maxfifo.empty()) {
if (array[i] <= array[maxfifo.back()])
break;
maxfifo.pop_back();
}
} else {
minfifo.pop_back();
while (!minfifo.empty()) {
if (array[i] >= array[minfifo.back()])
break;
minfifo.pop_back();
}
}
maxfifo.push_back(i);
minfifo.push_back(i);
}
for (uint i = width; i < array.size(); ++i) {
maxvalues[i - width] = array[maxfifo.front()];
minvalues[i - width] = array[minfifo.front()];
if (array[i] > array[i - 1]) { //overshoot
maxfifo.pop_back();
while (!maxfifo.empty()) {
if (array[i] <= array[maxfifo.back()])
break;
maxfifo.pop_back();
}
} else {
minfifo.pop_back();
while (!minfifo.empty()) {
if (array[i] >= array[minfifo.back()])
break;
minfifo.pop_back();
}
}
maxfifo.push_back(i);
minfifo.push_back(i);
if (i == width + maxfifo.front())
maxfifo.pop_front();
else if (i == width + minfifo.front())
minfifo.pop_front();
}
maxvalues[array.size() - width] = array[maxfifo.front()];
minvalues[array.size() - width] = array[minfifo.front()];
}
vector<floattype> & getmaxvalues() {
return maxvalues;
}
vector<floattype> & getminvalues() {
return minvalues;
}
vector<floattype> maxvalues;
vector<floattype> minvalues;
};
*/
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <cstdint>
#include <vector>
#include <deque>
using namespace std;
class MinMaxLemire
{
public:
MinMaxLemire(uint32_t N);
~MinMaxLemire();
void process(vector<float> & array);
vector<float> & getmaxvalues()
{
return maxvalues;
}
vector<float> & getminvalues()
{
return minvalues;
}
private:
uint32_t width;
vector<float> minvalues;
vector<float> maxvalues;
deque<int32_t> maxfifo, minfifo;
};
+1642
View File
File diff suppressed because it is too large Load Diff
+450
View File
@@ -0,0 +1,450 @@
#ifndef _RECEIVER_H_
#define _RECEIVER_H_
#include <cstdint>
#include <radio/symbol.h>
#include <radio/nco.h>
#include <radio/synchronization.h>
#include <radio/interpolation.h>
#include <radio/statistics.h>
#include <radio/equalizer.h>
#include <radio/agc.h>
#include "JuceHeader.h"
#include "Logcomponent.h"
#include "Frame.hpp"
// ---------------------------------------------------
#define NUM_PASSBAND_SAMPLES_PER_SYM 4
#define NUM_BASEBAND_SAMPLES_PER_SYM 2
#define MODE_PROCESS_PASSBAND 0
#define MODE_PROCESS_BASEBAND 1
#define RCF_TYPE_POLYPHASE_DISCRETE 0
#define RCF_TYPE_POLYPHASE_FARROW 1
#define RCF_TYPE_LAGRANGE 2
#define EQ_ENABLE 1
#define MODULATION_TYPE MAP_MODE_QAM
#define RCF_TYPE RCF_TYPE_POLYPHASE_FARROW
#define MAX_NUMBITS_PERSYM 16
// ---------------------------------------------------
enum eq_mode
{
eq_mode_disabled,
eq_mode_cma,
eq_mode_dfe
};
enum cma_type
{
cma_type_cma = 0,
cma_type_mma,
cma_type_smma
};
enum cma_mode
{
cma_mode_training_disabled = 0,
cma_mode_training_enabled
};
enum dfe_mode
{
dfe_mode_training_disabled = 0,
dfe_mode_training_enabled
};
enum agc_mode
{
agc_mode_disabled = 0,
agc_mode_enabled
};
enum agc_state
{
agc_state_acquisition = 0,
agc_state_track
};
enum cpr_mode
{
cpr_mode_disabled = 0,
cpr_mode_enabled
};
enum cpr_state
{
cpr_state_acquisition = 0,
cpr_state_track
};
enum str_mode
{
str_mode_disabled = 0,
str_mode_enabled
};
enum str_state
{
str_state_acquisition = 0,
str_state_track
};
typedef struct _ml_farrow_coef_hdr_t
{
uint32_t M;
uint32_t N;
} ml_farrow_coef_hdr_t;
typedef struct _minmax_t
{
float min, max;
} minmax_t;
typedef struct _cpx_minmax_t
{
cpx_t min, max;
float magMin, magMax;
float phiAtMinI;
float phiAtMaxI;
float phiAtMinQ;
float phiAtMaxQ;
} cpx_minmax_t;
typedef struct _statistics_t
{
sl_var_t RF;
sl_var_t I_DDC;
sl_var_t Q_DDC;
sl_var_t I_MF;
sl_var_t Q_MF;
sl_var_t I_CPR;
sl_var_t Q_CPR;
sl_var_t I_AGC;
sl_var_t Q_AGC;
sl_var_t I_EQ;
sl_var_t Q_EQ;
sl_var_t I_decision;
sl_var_t Q_decision;
sl_var_t MagDecision;
sl_var_t PhiDecision;
sl_var_t sym_err_mag;
sl_var_t sym_err_phi;
sl_var_t noise;
sl_var_t noise_cma;
sl_var_t noise_str;
sl_var_t noise_cpr;
sl_var_t noise_dfe_on;
sl_var_t noise_dfe_off;
sl_minmax_t sl_min_I;
sl_minmax_t sl_max_I;
sl_minmax_t sl_min_Q;
sl_minmax_t sl_max_Q;
sl_minmax_t sl_min_mag;
sl_minmax_t sl_max_mag;
cpx_minmax_t ddcMinMax;
} statistics_t;
typedef struct _params_t
{
uint32_t numBitsPerSymbol;
float symbolrate;
float samplerate;
float ddc_freq;
float CPR_phase;
bool dfeAutoUpdateEnable;
bool strAutoControlEnable;
bool cprAutoControlEnable;
bool agcAutoControlEnable;
str_mode str_mode;
cpr_mode cpr_mode;
agc_mode agc_mode;
eq_mode eq_mode;
cma_type cmaType;
cma_mode cmaMode;
dfe_mode dfeMode;
lead_lag_coeff_t str_loopfilter_coeff[2];
uint32_t str_loopfilter_coeff_index;
lead_lag_coeff_t cpr_loopfilter_coeff[2];
uint32_t cpr_loopfilter_coeff_index;
float eqMuCma;
float eqMuDfe;
float agcMu[2];
uint32_t agcMu_index;
str_state strState;
cpr_state cprState;
agc_state agc_state;
} params_t;
typedef struct _status_t
{
uint32 numSymbolsReceived;
frame_statistics_t frameStatRx;
float noiseStr;
float noiseCpr;
float EB_N0;
float powerRF_dB;
float powerDDC_dB;
float powerMF_dB;
float powerCPR_dB;
float powerAGC_dB;
float powerEQ_dB;
float powerDecison_dB;
float powerMagDecision_dB;
float powerPhiDecision_dB;
float snrCurrent_dB;
float snrCma_dB;
float snrDfeOn_dB;
float snrDfeOff_dB;
float snrSymbolMagnitude_dB;
float snrSymbolPhase_dB;
float deltaFrequencyCPR;
float deltaFrequencySTR;
float agcGain[2];
minmax_t rfMinMax;
cpx_minmax_t ddcMinMax;
} status_t;
class Receiver;
// ---------------------------------------------------
class ReceiverInterface
{
public:
ReceiverInterface() {}
virtual ~ReceiverInterface() {}
virtual void setSamplerate(float samplerate_hz) = 0;
virtual void setParams(const params_t &params) = 0;
virtual const params_t& getParams() = 0;
virtual const status_t& getStatus() = 0;
virtual const cpx_t& getTracker(uint32 index) = 0;
virtual void reset() = 0;
virtual void statisticsReset() = 0;
virtual void strReset() = 0;
virtual void cprReset() = 0;
virtual void cmaReset() = 0;
virtual void dfeReset() = 0;
virtual void dfeOffUpdateFromCma() = 0;
virtual void dfeOnUpdateFromDfeOff() = 0;
virtual const uint32_t getNumWeightsCMA() = 0;
virtual const cpx_t* getWeightsCMA() = 0;
virtual const uint32_t getNumWeightsDFE() = 0;
virtual const cpx_t* getWeightsDFE() = 0;
};
class ReceiverStatusListener
{
public:
ReceiverStatusListener() {}
virtual ~ReceiverStatusListener() {}
virtual void receiverStatusChanged(ReceiverInterface *pReceiver) = 0;
};
class ReceiverDataListener
{
public:
ReceiverDataListener() {}
virtual ~ReceiverDataListener() {}
virtual void receiverDataChanged(Receiver *pObj) = 0;
};
class Receiver : public ReceiverInterface, public IDeFormatter, public Timer
{
public:
Receiver(LogHandler *pLogHandler);
~Receiver(void);
void init();
void free();
void processBaseband(float *pI, float *pQ, uint32_t len);
void processPassband(float *pRF, uint32_t len);
void setBufSize(uint32 size);
uint32 getNumSoftSym();
sym_err_t getSoftSym(uint32 index);
sym_err_t* getSoftSyms();
void initDefaultParams();
void addStatusListener(ReceiverStatusListener *pListener);
void addDataListener(ReceiverDataListener *pListener);
private:
ListenerList<ReceiverStatusListener> m_statusListeners;
LogComponent m_log;
ReceiverDataListener *m_pDataListener;
CriticalSection m_lock;
cpx_t *m_pPassbandBuffer;
cpx_t *m_pBasebandBuffer;
sym_err_t *m_pSymbolBuffer;
uint32_t m_numSymsInBuffer;
uint32_t m_bufsize;
bool m_ReceiverEnable;
clock_t m_symClock;
pfd_t m_pfdCpr;
cpx_t m_trackers_[4];
cpx_t m_trackers[4];
// Filter
uint32_t m_narm;
uint32_t m_nrcf;
radio_float_t *m_stateArm_I;
radio_float_t *m_stateArm_Q;
radio_float_t *m_coefArm;
radio_float_t *m_coefRCF;
fir_cpx_t *m_pFirArm;
fir_cpx_multirate_t *m_pFirDownArm;
fir_cpx_t *m_pFirRcf;
// Interpolators
ppip_cpx_t *m_pPolyphaseInterpolator;
lgip_cpx_t *m_pLagrangeInterpolator;
ppip_farrow_cpx_t *m_pFarrowInterpolator;
// NCOs
nco_t m_nco_ddc, m_nco_cpr;
radio_float_t m_dOmega_vco;
// Loop-Filter
lead_lag_filter_t m_loop_filter_str;
lead_lag_filter_t m_loop_filter_cpr;
// Gardner Symbol Timing Recovery
str_t m_SymbolTimingRevovery;
timing_corrector_t m_timing_corrector;
radio_float_t m_Vc;
// AGC
// Blind
agc_t agcBlind;
// Equalizer
// Decision directed EQ
dfe_cpx_t m_dfe_on;
dfe_cpx_t m_dfe_off;
cpx_t m_dfe_e_cpx;
// Blind EQ
cma_t m_cma;
// Symbol demapper
sym_map_t *m_pSymMapper;
// Staticstics
sym_stat_t m_sym_stat;
statistics_t m_statistics;
FrameReceiver m_frameReceiver;
params_t m_params;
void timerCallback();
void processBaseband(cpx_t *pIF, uint32_t len);
cpx_t processMatchedFilter(cpx_t x, int32_t m, radio_float_t mu);
int Farrow_open_coeff(ppip_farrow_cpx_t *pObj, char *filename);
void minMaxInit(minmax_t *pObj, radio_float_t min_initial, radio_float_t max_initial)
{
pObj->min = min_initial;
pObj->max = max_initial;
}
void minMaxInit(cpx_minmax_t *pObj, cpx_t min_initial, cpx_t max_initial)
{
pObj->min = min_initial;
pObj->max = max_initial;
pObj->magMin = 1000;
pObj->magMax = -1000;
}
void minMaxProcess(minmax_t *pObj, radio_float_t x)
{
pObj->min = dmin(pObj->min, x);
pObj->max = dmax(pObj->max, x);
}
void minMaxProcess(cpx_minmax_t *pObj, cpx_t x)
{
if (CpxMagS(x) >= pObj->magMax)
{
if (x.real > 0 && x.imag > 0)
pObj->phiAtMaxI = CpxPhiS(x);
if (x.real > 0 && x.imag < 0)
pObj->phiAtMaxQ = CpxPhiS(x);
if (x.real < 0 && x.imag < 0)
pObj->phiAtMinQ = CpxPhiS(x);
if (x.real < 0 && x.imag > 0)
pObj->phiAtMinI = CpxPhiS(x);
}
pObj->min.real = SlidingMinMaxProcess(&m_statistics.sl_min_I, x.real);
pObj->max.real = SlidingMinMaxProcess(&m_statistics.sl_max_I, x.real);
pObj->min.imag = SlidingMinMaxProcess(&m_statistics.sl_min_Q, x.imag);
pObj->max.imag = SlidingMinMaxProcess(&m_statistics.sl_max_Q, x.imag);
pObj->magMin = SlidingMinMaxProcess(&m_statistics.sl_min_mag, CpxMagS(x));
pObj->magMax = SlidingMinMaxProcess(&m_statistics.sl_max_mag, CpxMagS(x));
}
void initFilterArm();
void initFilterRcf();
void initSymbolMapper();
void initSTR();
void initCPR();
void initDDC();
// Interface
void Receiver::setSamplerate(float samplerate_hz) override;
void Receiver::setParams(const params_t &params) override;
params_t& Receiver::getParams() override;
status_t& Receiver::getStatus() override;
void Receiver::reset() override;
void Receiver::strReset() override;
void Receiver::cprReset() override;
void Receiver::dfeReset() override;
void Receiver::cmaReset() override;
void Receiver::statisticsReset() override;
void Receiver::dfeOffUpdateFromCma() override;
void Receiver::dfeOnUpdateFromDfeOff() override;
cpx_t& Receiver::getTracker(uint32 index) override;
void onData(void *pData, uint32_t size) override
{
// Received raw data
(void)pData;
(void)size;
}
const uint32_t getNumWeightsCMA() override
{
return m_cma.eq.N;
}
const cpx_t* getWeightsCMA() override
{
return m_cma.eq.pW;
}
const uint32_t getNumWeightsDFE() override
{
return m_dfe_off.eq.N;
}
const cpx_t* getWeightsDFE() override
{
return m_dfe_off.eq.pW;
}
trace_t m_trace;
};
#endif // _RECEIVER_H_
+116
View File
@@ -0,0 +1,116 @@
#include "Transmitter.h"
Transmitter::Transmitter(void)
: Thread("Transmitter")
, m_symbolizer(this)
, m_formatter(&m_symbolizer)
, m_symbolMapper()
, m_bufferSize(0)
, m_bufferRF(0)
, m_bufferSymRcf(0)
, m_bufferSym(0)
, m_samplerate(192000)
, m_symbolrate(48000)
, m_numBitPerSymbol(2)
, m_carrierFreq(48000)
, m_txBuf(0, 2)
, m_symCount(0)
, m_CoeffRCF(0)
{
SymMapInit(&m_symbolMapper, m_numBitPerSymbol, MAP_MODE_QAM);
FirCpxMultirateUpInit(&m_firUpRcf, NULL, 0, 1);
NCO_Init(&m_duc, m_carrierFreq/m_samplerate, 0);
paramChanged();
bufferResize(2048);
}
Transmitter::~Transmitter(void)
{
stopThread(1000);
if (m_bufferRF)
delete m_bufferRF;
if (m_bufferSymRcf)
delete m_bufferSymRcf;
if (m_bufferSym)
delete m_bufferSym;
if (m_CoeffRCF)
delete m_CoeffRCF;
m_bufferRF = nullptr;
m_bufferSymRcf = nullptr;
m_bufferSym = nullptr;
m_CoeffRCF = nullptr;
FirCpxMultirateFree(&m_firUpRcf);
SymMapFree(&m_symbolMapper);
}
void Transmitter::paramChanged()
{
uint32_t M_up;
uint32_t n_mf;
const ScopedLock sl (m_lock);
m_symbolizer.setNumBitsPerSymbol(m_numBitPerSymbol);
SymMapReinit(&m_symbolMapper, m_numBitPerSymbol, MAP_MODE_QAM);
M_up = (uint32_t)(m_samplerate/m_symbolrate + 0.5);
n_mf = (uint32_t)(TRANSMITTER_RCF_OVERSAMPLING*M_up) + 1;
if (m_CoeffRCF)
delete m_CoeffRCF;
m_CoeffRCF = new radio_float_t[n_mf];
m_kRcf = CalcFirSRRC(m_CoeffRCF, (radio_float_t)m_samplerate, (radio_float_t)2.0/m_symbolrate, TRANSMITTER_RCF_ROLLOFF, n_mf);
FirCpxMultirateUpReinit(&m_firUpRcf, m_CoeffRCF, n_mf, M_up);
NCO_Reinit(&m_duc, m_carrierFreq/m_samplerate, 0);
}
void Transmitter::bufferResize(uint32_t size)
{
stopThread(10000);
m_txBuf.resize(size, 8);
if (size != m_bufferSize)
{
if (m_bufferRF)
{
delete m_bufferRF;
m_bufferRF = nullptr;
}
if (m_bufferSymRcf)
{
delete m_bufferSymRcf;
m_bufferSymRcf = nullptr;
}
if (m_bufferSym)
{
delete m_bufferSym;
m_bufferSym = nullptr;
}
}
m_bufferSize = size;
if (!size)
return;
m_bufferRF = new float[m_bufferSize];
m_bufferSymRcf = new cpx_t[m_bufferSize];
m_bufferSym = new cpx_t[m_bufferSize];
m_symCount = 0;
startThread(0);
}
+251
View File
@@ -0,0 +1,251 @@
#ifndef _TRANSMITTER_H_
#define _TRANSMITTER_H_
#include <cstdint>
#include <radio/symbol.h>
#include <radio/nco.h>
#include <radio/interpolation.h>
#include "JuceHeader.h"
#include "Logcomponent.h"
#include "Frame.hpp"
#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 setCarrierFrequency(float frequency_hz) = 0;
virtual void setSamplerate(float samplerate_hz) = 0;
virtual void setSymbolRate(float symbolrate_bit_per_sec) = 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(float *pData, 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] = pData[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<uint32_t> 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;
fir_cpx_multirate_t m_firUpRcf;
uint32_t m_bufferSize;
float *m_bufferRF;
cpx_t *m_bufferSymRcf;
cpx_t *m_bufferSym;
float m_samplerate;
float m_ddcFrequency;
float m_symbolrate;
uint32_t m_numBitPerSymbol;
radio_float_t *m_CoeffRCF;
radio_float_t m_kRcf;
radio_float_t m_carrierFreq;
nco_t m_duc;
TxBuffer m_txBuf;
uint32_t m_symCount;
// 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++] = SymMapMap(&m_symbolMapper, symbol);
if (m_symCount >= m_bufferSize/m_firUpRcf.L)
{
symCountRcf = FirCpxUpProcess(&m_firUpRcf, m_bufferSym, m_bufferSymRcf, m_symCount);
NCO_MixComplexRealV(&m_duc, m_bufferRF, m_bufferSymRcf, Cpx(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;
paramChanged();
}
void setCarrierFrequency(float frequency_hz) override
{
const ScopedLock sl (m_lock);
m_carrierFreq = frequency_hz;
NCO_Reinit(&m_duc, m_carrierFreq/m_samplerate, 0);
}
void setSymbolRate(float symbolrate_bit_per_sec) override
{
m_symbolrate = symbolrate_bit_per_sec;
paramChanged();
}
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_