- 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:
File diff suppressed because it is too large
Load Diff
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
@@ -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_
|
||||
@@ -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]
|
||||
@@ -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__
|
||||
@@ -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& e)"/>
|
||||
</METHODS>
|
||||
<BACKGROUND backgroundColour="ff000000"/>
|
||||
</JUCER_COMPONENT>
|
||||
|
||||
END_JUCER_METADATA
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
//[EndFile] You can add extra defines here...
|
||||
//[/EndFile]
|
||||
@@ -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__
|
||||
@@ -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]
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
@@ -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), 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) "
|
||||
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]
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
*/
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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 ¶ms) = 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 ¶ms) 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_
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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_
|
||||
Reference in New Issue
Block a user