Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev zmq #56

Merged
merged 23 commits into from
Jul 30, 2021
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7802baa
Adding zeromq stuff
jeroenbeijer Jul 20, 2021
bc08938
Adding zeromq stuff
jeroenbeijer Jul 20, 2021
5e33dd6
removed bak files
jeroenbeijer Jul 21, 2021
ac9dc50
removed some build artifacts
jeroenbeijer Jul 21, 2021
096d91b
removed some build artifacts
jeroenbeijer Jul 21, 2021
c1f9edd
revert pro file
jeroenbeijer Jul 21, 2021
320e8a1
added qrc file
jeroenbeijer Jul 21, 2021
c77d75b
Update ci-windows-build.sh
jeroenbeijer Jul 21, 2021
19a3deb
Update ci-windows-build.yml
jeroenbeijer Jul 21, 2021
7df187b
trying to fix the ci build
jeroenbeijer Jul 21, 2021
08d933d
trying to fix the ci build
jeroenbeijer Jul 21, 2021
8c7a9e6
winsock2 not on unix
jeroenbeijer Jul 21, 2021
8dfcba4
trying to fix the ci build
jeroenbeijer Jul 21, 2021
044f194
added libsodium to release
jeroenbeijer Jul 21, 2021
c5df4df
Merge pull request #55 from jeroenbeijer/master
jontio Jul 21, 2021
f23c900
Update .gitignore
jontio Jul 21, 2021
a1f0470
bit of tidying and removal of 96k setting for 10500burst
jontio Jul 22, 2021
f5b5778
changed to QtConcurrent::run, fixed hanging bug in zmq receiver when …
jontio Jul 24, 2021
eb76851
added bitrate message for zmq receiver. added to msk demodulator atte…
jontio Jul 25, 2021
7b87374
added zmq_audiosender class and removed the code that was doing the s…
jontio Jul 26, 2021
d9794d4
removed if statments from closeing audio
jontio Jul 27, 2021
71389d7
release version update
jontio Jul 28, 2021
8c7ec7e
zmq receiver changed from blocking to nonblocking
jontio Jul 29, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-windows-build.yml
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ jobs:
with:
msystem: MINGW64
update: true
install: git mingw-w64-x86_64-toolchain autoconf libtool mingw-w64-x86_64-cpputest mingw-w64-x86_64-qt5 mingw-w64-x86_64-cmake mingw-w64-x86_64-libvorbis zip p7zip unzip
install: git mingw-w64-x86_64-toolchain autoconf libtool mingw-w64-x86_64-cpputest mingw-w64-x86_64-qt5 mingw-w64-x86_64-cmake mingw-w64-x86_64-libvorbis mingw-w64-x86_64-zeromq zip p7zip unzip
# build for windows
- name: Windows-CI-Build
if: ${{ matrix.os == 'windows-latest' }}
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -32,8 +32,8 @@ qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
.qmake.cache
.qmake.stash

# qtcreator generated files
*.pro.user*
18 changes: 12 additions & 6 deletions JAERO/JAERO.pro
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
#if you are having trubbles focus on things like "LIBS += -L$$OGG_PATH/src/.libs"
#remember to compile libvorbis,libogg, and libcorrect before compiling this

DEFINES += JAERO_VERSION=\\\"v1.0.4.12-alpha\\\"
DEFINES += JAERO_VERSION=\\\"v1.0.4.13-alpha\\\"

QT += multimedia core network gui svg sql

@@ -85,7 +85,10 @@ SOURCES += mainwindow.cpp \
$$JFFT_PATH/jfft.cpp \
util/stdio_utils.cpp \
util/file_utils.cpp \
util/RuntimeError.cpp
util/RuntimeError.cpp \
zmq_audiosender.cpp \
zmq_audioreceiver.cpp


HEADERS += mainwindow.h \
coarsefreqestimate.h \
@@ -119,17 +122,20 @@ HEADERS += mainwindow.h \
$$JFFT_PATH/jfft.h \
util/stdio_utils.h \
util/file_utils.h \
util/RuntimeError.h
util/RuntimeError.h \
zmq_audioreceiver.h \
zmq_audiosender.h


# Tell the qcustomplot header that it will be used as library:
DEFINES += QCUSTOMPLOT_USE_LIBRARY
#qcustom plot is called different names on different systems
win32 {
#message("windows")
LIBS += -lqcustomplot2
LIBS += -lqcustomplot2 -llibzmq
} else {
#message("not windows")
LIBS += -lqcustomplot
LIBS += -lqcustomplot -lzmq
}

FORMS += mainwindow.ui \
@@ -159,7 +165,7 @@ QMAKE_CXXFLAGS_RELEASE += -O3
#QMAKE_CXXFLAGS_RELEASE *= -O3

#for static building order seems to matter
LIBS += -lcorrect -lvorbis -lvorbisenc -logg -lacars
LIBS += -lcorrect -lvorbis -lvorbisenc -logg -lacars

#desktop
desktop.path = /usr/share/applications
38 changes: 31 additions & 7 deletions JAERO/aerol.cpp
Original file line number Diff line number Diff line change
@@ -1407,8 +1407,6 @@ QByteArray &AeroL::Decode(QVector<short> &bits, bool soft)//0 bit --> oldest bit

uchar SEQINDICATOR=((byte1&0xF0)>>4);
uchar SUTYPE=byte1&0x0F;
uchar QNO=((byte2&0xF0)>>4);
uchar REFNO=byte2&0x07;
quint32 AESID=byte3<<8*2|byte4<<8*1|byte5<<8*0;
int GES=byte6;

@@ -1446,8 +1444,6 @@ QByteArray &AeroL::Decode(QVector<short> &bits, bool soft)//0 bit --> oldest bit

int BytesInSU=0;
if((SUTYPE>=1)&&(SUTYPE<=11))BytesInSU=SUTYPE;
bool SignalingInfoSU=false;
if(SUTYPE==15)SignalingInfoSU=true;

decline+=((QString)" SU %1 of %2. AES: %3 GES: %4").arg(SUindex+1).arg(SUTotal).arg((((QString)"%1").arg(AESID,6, 16, QChar('0'))).toUpper()).arg((((QString)"%1").arg(GES,2, 16, QChar('0'))).toUpper()) ;
/*decline+=" \"";
@@ -1735,6 +1731,10 @@ QByteArray &AeroL::Decode(QVector<short> &bits, bool soft)//0 bit --> oldest bit
break;
case Log_on_confirm:
decline+="Log_on_confirm";

{
SendLogOnOff(k, "Log on confirm");
}
break;
case Log_control_P_channel_log_off_request:
decline+="Log_control_P_channel_log_off_request";
@@ -2166,9 +2166,21 @@ void AeroL::SendCAssignment(int k, QString decline)
QString beam = " Global Beam ";
if(byte7&0x80)beam=" Spot Beam ";

item.message = "Receive Freq: " + receive + beam + "Transmit " + transmit + "\r\n" + decline;
emit ACARSsignal(item);
}
void AeroL::SendLogOnOff(int k, QString text)
{
ACARSItem item;
item.isuitem.AESID=((uchar)infofield[k*12-1+2])<<8*2|((uchar)infofield[k*12-1+3])<<8*1|((uchar)infofield[k*12-1+4])<<8*0;
item.isuitem.GESID=infofield[k*12-1+5];

item.hastext = true;
item.downlink = true;
item.nonacars = true;
item.valid = true;

item.message = "Receive Freq: " + receive + beam + "Transmit " + transmit + "\r\n" + decline;
item.message = text;
emit ACARSsignal(item);
}

@@ -2182,6 +2194,8 @@ QByteArray &AeroL::DecodeC(QVector<short> &bits)
quint16 bit=0;
quint16 soft_bit=0;

QString hex = "000000";

for(int i=0;i<bits.size();i++)
{

@@ -2394,6 +2408,14 @@ QByteArray &AeroL::DecodeC(QVector<short> &bits)
decline+=" GES = "+infofield.mid(4,1).toHex().toUpper();
decline+=" Call_progress \r\n";
emit Call_progress_Signal(infofield);

QString thex = infofield.mid(1,3).toHex().toUpper();

if(thex.length() == 6)
{
hex = thex;
}

}
break;

@@ -2457,13 +2479,15 @@ QByteArray &AeroL::DecodeC(QVector<short> &bits)
}
}

// send for external decoding
emit Voicesignal(data, hex);

//25 primary fields. this is where the audio lives in a compressed format
for(int i=0;i<25;i++)
{
emit Voicesignal(data.mid(i*12,12));//send one frame at a time
emit Voicesignal(data.mid(i*12,12));//send one frame at a time
}


// reset for next block
index = -1;
}// end of frame
58 changes: 41 additions & 17 deletions JAERO/aerol.h
Original file line number Diff line number Diff line change
@@ -397,26 +397,47 @@ class AeroLScrambler
public:
AeroLScrambler()
{
reset();
}
void reset()
{
QVector<int> state;
position=0;
pre_state.resize(5000);
int tmp[]={1,1,0,1,0,0,1,0,1,0,1,1,0,0,1,-1};
state.clear();
for(int i=0;tmp[i]>=0;i++)state.push_back(tmp[i]);


// populate the vector so we can reuse it
for(int a = 0; a<5000;a++)
{

int val0 = state.at(0)^state.at(14);
pre_state[a]=val0;
for(int i=state.size()-1;i>0;i--)
{
state[i]=state.at(i-1);
}
state[0] =val0;

}
}

void update(QVector<int> &data)
{
for(int j=0;j<data.size();j++)
{
int val0=state.at(0)^state.at(14);
data[j] = data.at(j)^val0;
for(int i=state.size()-1;i>0;i--)state[i]=state.at(i-1);
state[0]=val0;
data[j] = data.at(j)^pre_state.at(position);
position++;
}

}
void reset()
{

position = 0;
}
private:
QVector<int> state;

QVector<int> pre_state;
int position;
};

class PuncturedCode
@@ -626,7 +647,7 @@ class RTChannelDeleaveFECScram
bool cont = false;


if((((blockptr-(64*5))%(64*3))==0) && (blockptr /64 == 5 || blockptr /64 == targetBlocks || blockptr/64 == 8 || blockptr/64 == 50))
if((((blockptr-(64*5))%(64*3))==0) && (blockptr /64 == 5 || blockptr /64 == targetBlocks || blockptr/64 == 11 || blockptr/64 == 50))
{
cont = true;
}
@@ -666,6 +687,10 @@ class RTChannelDeleaveFECScram
lastpacketstate=OK_R_Packet;

return OK_R_Packet;
}else{

return Nothing;

}
}

@@ -682,11 +707,7 @@ class RTChannelDeleaveFECScram
else
{

if(blockptr/64 ==5){
return Nothing;
}

if(blockptr/64 == 8){
if(blockptr/64 == 11){

// we should be able to peek at the SU after the initial SU and figure out the number of SU's in this
// burst
@@ -703,15 +724,15 @@ class RTChannelDeleaveFECScram

}

targetBlocks = (targetSUSize*3) +2;
targetBlocks = ((targetSUSize+1)*3) +2;

return Nothing;
}

// this should be the target blocks for this T packet
if(blockptr/64 == targetBlocks)
{
for(int i=0;i<targetSUSize;i++)
for(int i=0;i<targetSUSize-3;i++)
{
crcok=crc16.calcusingbitsandcheck(deconvol.data()+(8*6)+(8*12)*i,8*12);

@@ -890,6 +911,7 @@ class AeroL : public QIODevice
void DataCarrierDetect(bool status);
void ACARSsignal(ACARSItem &acarsitem);
void Errorsignal(QString &error);
void Voicesignal(QByteArray &data, QString &hex);
void Voicesignal(const QByteArray &data);
void CChannelAssignmentSignal(CChannelAssignmentItem &item);
void Call_progress_Signal(QByteArray infofield);
@@ -915,6 +937,8 @@ public slots:
bool Start();
void Stop();
void SendCAssignment(int k, QString decline);
void SendLogOnOff(int k, QString text);

CChannelAssignmentItem CreateCAssignmentItem(QByteArray su);
QByteArray &Decode(QVector<short> &bits, bool soft = false);
QByteArray &DecodeC(QVector<short> &bits);
11 changes: 7 additions & 4 deletions JAERO/audioburstmskdemodulator.cpp
Original file line number Diff line number Diff line change
@@ -3,16 +3,19 @@
#include <QDebug>

AudioBurstMskDemodulator::AudioBurstMskDemodulator(QObject *parent)
: BurstMskDemodulator(parent),
m_audioInput(NULL)
: BurstMskDemodulator(parent),
m_audioInput(NULL)
{
//
//
}

void AudioBurstMskDemodulator::start()
{
BurstMskDemodulator::start();
if(m_audioInput)m_audioInput->start(this);
if(!settings.zmqAudio)
{
if(m_audioInput)m_audioInput->start(this);
}
}

void AudioBurstMskDemodulator::stop()
11 changes: 7 additions & 4 deletions JAERO/audioburstoqpskdemodulator.cpp
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@
#include <QDebug>

AudioBurstOqpskDemodulator::AudioBurstOqpskDemodulator(QObject *parent)
: BurstOqpskDemodulator(parent),
m_audioInput(NULL)
: BurstOqpskDemodulator(parent),
m_audioInput(NULL)
{
demod2=new BurstOqpskDemodulator(this);
demod2->channel_select_other=true;
@@ -15,7 +15,10 @@ void AudioBurstOqpskDemodulator::start()
{
BurstOqpskDemodulator::start();
demod2->start();
if(m_audioInput)m_audioInput->start(this);
if(!settings.zmqAudio)
{
if(m_audioInput)m_audioInput->start(this);
}
}

void AudioBurstOqpskDemodulator::stop()
@@ -40,7 +43,7 @@ void AudioBurstOqpskDemodulator::setSettings(Settings _settings)
//set the format
m_format.setSampleRate(settings.Fs);
if(settings.channel_stereo)m_format.setChannelCount(2);
else m_format.setChannelCount(1);
else m_format.setChannelCount(1);
m_format.setSampleSize(16);
m_format.setCodec("audio/pcm");
m_format.setByteOrder(QAudioFormat::LittleEndian);
11 changes: 7 additions & 4 deletions JAERO/audiomskdemodulator.cpp
Original file line number Diff line number Diff line change
@@ -3,16 +3,19 @@
#include <QDebug>

AudioMskDemodulator::AudioMskDemodulator(QObject *parent)
: MskDemodulator(parent),
m_audioInput(NULL)
: MskDemodulator(parent),
m_audioInput(NULL)
{
//
//
}

void AudioMskDemodulator::start()
{
MskDemodulator::start();
if(m_audioInput)m_audioInput->start(this);
if(!settings.zmqAudio)
{
if(m_audioInput)m_audioInput->start(this);
}
}

void AudioMskDemodulator::stop()
13 changes: 9 additions & 4 deletions JAERO/audiooqpskdemodulator.cpp
Original file line number Diff line number Diff line change
@@ -3,16 +3,21 @@
#include <QDebug>

AudioOqpskDemodulator::AudioOqpskDemodulator(QObject *parent)
: OqpskDemodulator(parent),
m_audioInput(NULL)
: OqpskDemodulator(parent),
m_audioInput(NULL)
{
//
//
}

void AudioOqpskDemodulator::start()
{
OqpskDemodulator::start();
if(m_audioInput)m_audioInput->start(this);

if(!settings.zmqAudio)
{
if(m_audioInput)m_audioInput->start(this);
}

}

void AudioOqpskDemodulator::stop()
227 changes: 122 additions & 105 deletions JAERO/burstmskdemodulator.cpp
Original file line number Diff line number Diff line change
@@ -127,7 +127,10 @@ void BurstMskDemodulator::setSQL(bool state)
{
sql=state;
}

void BurstMskDemodulator::setCPUReduce(bool state)
{
cpuReduce=state;
}
void BurstMskDemodulator::setScatterPointType(ScatterPointType type)
{
scatterpointtype=type;
@@ -395,7 +398,8 @@ qint64 BurstMskDemodulator::writeData(const char *data, qint64 len)
if(fabs(dval)>maxval)maxval=fabs(dval);
spectrumcycbuff[spectrumcycbuff_ptr]=dval;
spectrumcycbuff_ptr++;spectrumcycbuff_ptr%=spectrumnfft;
if(timer.elapsed()>150)
//if(timer.elapsed()>150)
if((!cpuReduce && timer.elapsed()>150) || (cpuReduce && timer.elapsed()>1000))
{
timer.start();
emit OrgOverlapedBuffer(spectrumcycbuff);
@@ -592,152 +596,157 @@ qint64 BurstMskDemodulator::writeData(const char *data, qint64 len)
}


cval= mixer2.WTCISValue()*(val_to_demod)*vol_gain;

cpx_type sig2 = cpx_type(matchedfilter_re->FIRUpdateAndProcess(cval.real()),matchedfilter_im->FIRUpdateAndProcess(cval.imag()));

if(cntr>(startProcessing*SamplesPerSymbol) && cntr<endRotation)
if(startstop > 0 || mse < signalthreshold)
{

cpx_type symboltone_pt=sig2*symboltone_rotator*imag;
double er=std::tanh(symboltone_pt.imag())*(symboltone_pt.real());
symboltone_rotator=symboltone_rotator*std::exp(imag*er*0.5);
symboltone_averotator=symboltone_averotator*0.999+0.001*symboltone_rotator;
cval= mixer2.WTCISValue()*(val_to_demod)*vol_gain;

symboltone_pt=cpx_type((symboltone_pt.real()),a1.update(symboltone_pt.real()));
cpx_type sig2 = cpx_type(matchedfilter_re->FIRUpdateAndProcess(cval.real()),matchedfilter_im->FIRUpdateAndProcess(cval.imag()));

double progress = (double)cntr-(SamplesPerSymbol*(startProcessing));
double goal = endRotation-(SamplesPerSymbol*startProcessing);
progress = progress/goal;
if(cntr>(startProcessing*SamplesPerSymbol) && cntr<endRotation)
{

//x4 pll
double st_err=std::arg((st_osc_half.WTCISValue())*std::conj(symboltone_pt));
cpx_type symboltone_pt=sig2*symboltone_rotator*imag;
double er=std::tanh(symboltone_pt.imag())*(symboltone_pt.real());
symboltone_rotator=symboltone_rotator*std::exp(imag*er*0.5);
symboltone_averotator=symboltone_averotator*0.999+0.001*symboltone_rotator;

st_err*=0.5*(1.0-progress*progress);
st_osc_half.AdvanceFractionOfWave(-(1.0/(2.0*M_PI))*st_err*0.05);
st_osc.SetPhaseDeg(st_osc_half.GetPhaseDeg()+(360.0*(1.0-ee)));
}
symboltone_pt=cpx_type((symboltone_pt.real()),a1.update(symboltone_pt.real()));

sig2*=symboltone_averotator;
rotator=rotator*std::exp(imag*rotator_freq);
sig2*=rotator;
double progress = (double)cntr-(SamplesPerSymbol*(startProcessing));
double goal = endRotation-(SamplesPerSymbol*startProcessing);
progress = progress/goal;

//x4 pll
double st_err=std::arg((st_osc_half.WTCISValue())*std::conj(symboltone_pt));

//Measure ebno
ebnomeasure->Update(std::abs(sig2));
st_err*=0.5*(1.0-progress*progress);
st_osc_half.AdvanceFractionOfWave(-(1.0/(2.0*M_PI))*st_err*0.05);
st_osc.SetPhaseDeg(st_osc_half.GetPhaseDeg()+(360.0*(1.0-ee)));
}

//send ebno when right time
if(cntr== endRotation + (200*SamplesPerSymbol))
{
emit EbNoMeasurmentSignal(ebnomeasure->EbNo);
}
sig2*=symboltone_averotator;
rotator=rotator*std::exp(imag*rotator_freq);
sig2*=rotator;

//AGC
sig2*=agc2->Update(std::abs(sig2));

//clipping
double abval=std::abs(sig2);
if(abval>2.84)sig2=(2.84/abval)*sig2;
//Measure ebno
ebnomeasure->Update(std::abs(sig2));

//normal symbol timer
cpx_type pt_d = delayedsmpl.update_dont_touch(sig2);
cpx_type pt_msk=cpx_type(sig2.real(), pt_d.imag());
//send ebno when right time
if(cntr== endRotation + (200*SamplesPerSymbol))
{
emit EbNoMeasurmentSignal(ebnomeasure->EbNo);
}

double st_eta = std::abs(pt_msk);
st_eta=st_iir_resonator.update(st_eta);
//AGC
sig2*=agc2->Update(std::abs(sig2));

cpx_type st_m1=cpx_type(st_eta,-delayt8.update(st_eta));
cpx_type st_out=st_osc.WTCISValue()*st_m1;
//clipping
double abval=std::abs(sig2);
if(abval>2.84)sig2=(2.84/abval)*sig2;

double st_angle_error=std::arg(st_out);
//acquire the symbol oscillation
if(cntr>endRotation)
{
st_osc.AdvanceFractionOfWave(-st_angle_error*0.002/360.0);
}
//normal symbol timer
cpx_type pt_d = delayedsmpl.update_dont_touch(sig2);
cpx_type pt_msk=cpx_type(sig2.real(), pt_d.imag());

//sample times
if(st_osc.IfHavePassedPoint(ee))
{
double st_eta = std::abs(pt_msk);
st_eta=st_iir_resonator.update(st_eta);

//carrier tracking
double ct_xt=tanh(sig2.imag())*sig2.real();
double ct_xt_d=tanh(pt_d.real())*pt_d.imag();
cpx_type st_m1=cpx_type(st_eta,-delayt8.update(st_eta));
cpx_type st_out=st_osc.WTCISValue()*st_m1;

double ct_ec=ct_xt_d-ct_xt;
if(ct_ec>M_PI)ct_ec=M_PI;
if(ct_ec<-M_PI)ct_ec=-M_PI;
if(ct_ec>M_PI_2)ct_ec=M_PI_2;
if(ct_ec<-M_PI_2)ct_ec=-M_PI_2;
if(cntr>(startProcessing*SamplesPerSymbol))
double st_angle_error=std::arg(st_out);
//acquire the symbol oscillation
if(cntr>endRotation)
{
rotator=rotator*std::exp(imag*ct_ec*0.25);//correct carrier phase
if(cntr>endRotation)
{
rotator_freq=rotator_freq+ct_ec*0.0001;//correct carrier frequency
}
st_osc.AdvanceFractionOfWave(-st_angle_error*0.002/360.0);
}

//gui feedback
if(cntr >= (endRotation + 100*SamplesPerSymbol) && pointbuff_ptr<pointbuff.size())
//sample times
if(st_osc.IfHavePassedPoint(ee))
{
if(pointbuff_ptr<pointbuff.size())

//carrier tracking
double ct_xt=tanh(sig2.imag())*sig2.real();
double ct_xt_d=tanh(pt_d.real())*pt_d.imag();

double ct_ec=ct_xt_d-ct_xt;
if(ct_ec>M_PI)ct_ec=M_PI;
if(ct_ec<-M_PI)ct_ec=-M_PI;
if(ct_ec>M_PI_2)ct_ec=M_PI_2;
if(ct_ec<-M_PI_2)ct_ec=-M_PI_2;
if(cntr>(startProcessing*SamplesPerSymbol))
{
rotator=rotator*std::exp(imag*ct_ec*0.25);//correct carrier phase
if(cntr>endRotation)
{
rotator_freq=rotator_freq+ct_ec*0.0001;//correct carrier frequency
}
}

//gui feedback
if(cntr >= (endRotation + 100*SamplesPerSymbol) && pointbuff_ptr<pointbuff.size())
{
ASSERTCH(pointbuff,pointbuff_ptr);
pointbuff[pointbuff_ptr]=pt_msk*0.75;
if(pointbuff_ptr<pointbuff.size())pointbuff_ptr++;
if(pointbuff_ptr<pointbuff.size())
{
ASSERTCH(pointbuff,pointbuff_ptr);
pointbuff[pointbuff_ptr]=pt_msk*0.75;
if(pointbuff_ptr<pointbuff.size())pointbuff_ptr++;
}
if(scatterpointtype==SPT_constellation&&(pointbuff_ptr==pointbuff.size()))
{
pointbuff_ptr++;
emit ScatterPoints(pointbuff);
}
}
if(scatterpointtype==SPT_constellation&&(pointbuff_ptr==pointbuff.size()))

//calc MSE of the points
if(cntr>(startProcessing*SamplesPerSymbol))
{
pointbuff_ptr++;
emit ScatterPoints(pointbuff);
double tda=(fabs((pt_msk*0.75).real())-1.0);
double tdb=(fabs((pt_msk*0.75).imag())-1.0);
mse=msema->Update((tda*tda)+(tdb*tdb));
}
}

//calc MSE of the points
if(cntr>(startProcessing*SamplesPerSymbol))
{
double tda=(fabs((pt_msk*0.75).real())-1.0);
double tdb=(fabs((pt_msk*0.75).imag())-1.0);
mse=msema->Update((tda*tda)+(tdb*tdb));
}

//soft bits
double imagin = diffdecode.UpdateSoft(pt_msk.imag());

//soft bits
double imagin = diffdecode.UpdateSoft(pt_msk.imag());
int ibit=qRound((imagin)*127.0+128.0);
if(ibit>255)ibit=255;
if(ibit<0)ibit=0;

int ibit=qRound((imagin)*127.0+128.0);
if(ibit>255)ibit=255;
if(ibit<0)ibit=0;
RxDataBits.push_back((uchar)ibit);

RxDataBits.push_back((uchar)ibit);
double real = diffdecode.UpdateSoft(pt_msk.real());

double real = diffdecode.UpdateSoft(pt_msk.real());
real =- real;

real =- real;
ibit=qRound((real)*127.0+128.0);

ibit=qRound((real)*127.0+128.0);
if(ibit>255)ibit=255;
if(ibit<0)ibit=0;

if(ibit>255)ibit=255;
if(ibit<0)ibit=0;

RxDataBits.push_back((uchar)ibit);

RxDataBits.push_back((uchar)ibit);
// push them out to decode
if(RxDataBits.size() >= 12)
{
emit processDemodulatedSoftBits(RxDataBits);
RxDataBits.clear();
}

// push them out to decode
if(RxDataBits.size() >= 12)
{
emit processDemodulatedSoftBits(RxDataBits);
RxDataBits.clear();
}

}
st_osc.WTnextFrame();
st_osc_half.WTnextFrame();

st_osc.WTnextFrame();
st_osc_half.WTnextFrame();
mixer2.WTnextFrame();
mixer_center.WTnextFrame();

mixer2.WTnextFrame();
mixer_center.WTnextFrame();
}
}

return len;
@@ -750,3 +759,11 @@ void BurstMskDemodulator::DCDstatSlot(bool _dcd)
dcd=_dcd;
}

void BurstMskDemodulator::dataReceived(const QByteArray &audio,quint32 sampleRate)
{
if(sampleRate!=Fs)
{
qDebug()<<"Sample rate not supported by demodulator";
}
writeData(audio, audio.length());
}
7 changes: 6 additions & 1 deletion JAERO/burstmskdemodulator.h
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ class BurstMskDemodulator : public QIODevice
double Fs;
int symbolspercycle;
double signalthreshold;
bool zmqAudio;
Settings()
{
coarsefreqest_fft_power=13;//2^coarsefreqest_fft_power
@@ -42,6 +43,7 @@ class BurstMskDemodulator : public QIODevice
Fs=8000;//Hz
symbolspercycle=16;
signalthreshold=0.6;
zmqAudio=false;
}
};
explicit BurstMskDemodulator(QObject *parent);
@@ -58,6 +60,7 @@ class BurstMskDemodulator : public QIODevice
void invalidatesettings();
void setAFC(bool state);
void setSQL(bool state);
void setCPUReduce(bool state);
void setScatterPointType(ScatterPointType type);
double getCurrentFreq();
private:
@@ -140,7 +143,6 @@ class BurstMskDemodulator : public QIODevice
//delay for trident detection
DelayThing<double> d2;


//trident shape thing
QVector<double> tridentbuffer;
int tridentbuffer_ptr;
@@ -188,6 +190,7 @@ class BurstMskDemodulator : public QIODevice

DelayThing<cpx_type> delayedsmpl;

bool cpuReduce;

signals:
void ScatterPoints(const QVector<cpx_type> &buffer);
@@ -209,6 +212,8 @@ class BurstMskDemodulator : public QIODevice
public slots:
void CenterFreqChangedSlot(double freq_center);
void DCDstatSlot(bool dcd);
void dataReceived(const QByteArray &audio, quint32 sampleRate);


};

42 changes: 23 additions & 19 deletions JAERO/burstoqpskdemodulator.cpp
Original file line number Diff line number Diff line change
@@ -172,6 +172,12 @@ void BurstOqpskDemodulator::setSQL(bool state)
sql=state;
}

void BurstOqpskDemodulator::setCPUReduce(bool state)
{
cpuReduce=state;

}

void BurstOqpskDemodulator::setScatterPointType(ScatterPointType type)
{
scatterpointtype=type;
@@ -297,6 +303,14 @@ qint64 BurstOqpskDemodulator::writeData(const char *data, qint64 len)
return len;
}

void BurstOqpskDemodulator::dataReceived(const QByteArray &audio,quint32 sampleRate)
{
if(sampleRate!=Fs)
{
qDebug()<<"Sample rate not supported by demodulator";
}
writeData(audio, audio.length());
}

void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
{
@@ -342,7 +356,9 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
if(fabs(dval)>maxval)maxval=fabs(dval);
spectrumcycbuff[spectrumcycbuff_ptr]=dval;
spectrumcycbuff_ptr++;spectrumcycbuff_ptr%=spectrumnfft;
if(timer.elapsed()>150)

if((!cpuReduce && timer.elapsed()>150) || (cpuReduce && timer.elapsed()>1000))

{
sendscatterpoints=true;
timer.start();
@@ -373,7 +389,6 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
if(pdet.update(bt_sig))
{
tridentbuffer_ptr=0;

}

if(tridentbuffer_ptr<tridentbuffer_sz)//fill trident buffer
@@ -385,7 +400,6 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
{
tridentbuffer_ptr++;


//base
in=tridentbuffer.mid(0,qRound(128.0*SamplesPerSymbol));
in.resize(out_base.size());
@@ -401,9 +415,7 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
//diff
for(int i=0;i<out_abs_diff.size();i++)
{

out_abs_diff[i]=(std::abs(out_top[i])-std::abs(out_base[i]));

}

//find best trident loc
@@ -464,7 +476,6 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
//set gain given estimate
vol_gain=1.4142*500.0/minval;


//set when we want to store points for display
//if using rotation bias correction
//pointbuff_ptr=-128-128-256;//-128-128;//-400;//-500;//-100;
@@ -490,10 +501,8 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
mse=0;
msema->Zero();


}


}//end of trident check

//mix
@@ -512,16 +521,11 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
startstop=startstopstart;
}



}
if(startstop==0)
{
startstop--;
// qDebug()<<"stop";

emit SignalStatus(false);

}

if((cntr>((256-10)*SamplesPerSymbol))&&insertpreamble)
@@ -555,27 +559,26 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)

//correct carrier phase


sig2*=symboltone_averotator;

rotator=rotator*std::exp(imag*rotator_freq);
sig2*=rotator;

double sig2abs = std::abs(sig2);

//Measure ebno
ebnomeasure->Update(std::abs(sig2));
ebnomeasure->Update(sig2abs);

//send ebno when right time
if(fabs(cntr-((128.0+128.0+128.0)*SamplesPerSymbol))<0.5)emit EbNoMeasurmentSignal(ebnomeasure->EbNo);

//AGC
sig2*=agc2->Update(std::abs(sig2));
sig2*=agc2->Update(sig2abs);

//clipping
double abval=std::abs(sig2);
if(abval>2.84)sig2=(2.84/abval)*sig2;



//normal symbol timer
double st_diff=delays.update(abval*abval)-(abval*abval);
double st_d1out=delayt41.update(st_diff);
@@ -683,7 +686,7 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)
}


//if(startstop>0)//if signal then may as well demodulate
if(startstop>0)//if signal then may as well demodulate
{


@@ -732,3 +735,4 @@ void BurstOqpskDemodulator::writeDataSlot(const char *data, qint64 len)

return;
}

12 changes: 10 additions & 2 deletions JAERO/burstoqpskdemodulator.h
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ class BurstOqpskDemodulator : public QIODevice
double Fs;
double signalthreshold;
bool channel_stereo;
bool zmqAudio;
Settings()
{
coarsefreqest_fft_power=13;//2^coarsefreqest_fft_power
@@ -39,12 +40,14 @@ class BurstOqpskDemodulator : public QIODevice
Fs=48000;//Hz
signalthreshold=0.6;
channel_stereo=false;
zmqAudio=false;
}
};
explicit BurstOqpskDemodulator(QObject *parent);
~BurstOqpskDemodulator();
void setAFC(bool state);
void setSQL(bool state);
void setCPUReduce(bool state);
void setSettings(Settings settings);
void invalidatesettings();
void ConnectSinkDevice(QIODevice *datasinkdevice);
@@ -57,8 +60,7 @@ class BurstOqpskDemodulator : public QIODevice
void setScatterPointType(ScatterPointType type);

//--L/R channel selection
bool channel_select_other;
//
bool channel_select_other;

signals:
void ScatterPoints(const QVector<cpx_type> &buffer);
@@ -213,9 +215,15 @@ class BurstOqpskDemodulator : public QIODevice

bool channel_stereo;

bool cpuReduce;



public slots:
void CenterFreqChangedSlot(double freq_center);
void writeDataSlot(const char *data, qint64 len);
void dataReceived(const QByteArray &audio, quint32 sampleRate);


};

43 changes: 41 additions & 2 deletions JAERO/gui_classes/settingsdialog.cpp
Original file line number Diff line number Diff line change
@@ -118,6 +118,16 @@ void SettingsDialog::poulatepublicvars()

ui->checkTCPAsClient->setEnabled(ui->checkOutputADSMessageToTCP->isChecked());

localAudioOutEnabled=ui->ambeEnabled->isChecked();
zmqAudioOutEnabled=ui->remoteAmbeEnabled->isChecked();
zmqAudioOutBind=ui->lineEditZMQBind->text();
zmqAudioOutTopic=ui->lineEditZMQBindTopic->text();

zmqAudioInputAddress = ui->lineEditZmqConnectAddress->text();
zmqAudioInputTopic = ui->lineEditZmqTopic->text();
zmqAudioInputEnabled = ui->checkBoxZMQ->isChecked();


}


@@ -147,8 +157,27 @@ void SettingsDialog::populatesettings()
ui->checkOutputADSMessageToTCP->setChecked(settings.value("checkOutputADSMessageToTCP",false).toBool());
ui->checkTCPAsClient->setChecked(settings.value("checkTCPAsClient",false).toBool());

//these have been tested so far as lineEditplanelookup
//http://www.flightradar24.com/data/airplanes/{REG}

ui->ambeEnabled->setChecked(settings.value("localAudioOutEnabled", true).toBool());
ui->remoteAmbeEnabled->setChecked(settings.value("remoteAudioOutEnabled", false).toBool());


if(!ui->remoteAmbeEnabled->isChecked())
{
ui->lineEditZMQBind->setEnabled(false);
ui->lineEditZMQBindTopic->setEnabled(false);

}
ui->lineEditZMQBind->setText(settings.value("remoteAudioOutBindAddress", "tcp://*:5551").toString());
ui->lineEditZMQBindTopic->setText(settings.value("remoteAudioOutBindTopic", "JAERO").toString());

ui->checkBoxZMQ->setChecked(settings.value("zmqAudioInputEnabled", false).toBool());
ui->lineEditZmqConnectAddress->setText(settings.value("zmqAudioInputReceiveAddress", "tcp://127.0.0.1:6003").toString());


QString default_topic = settings_name.remove(QRegExp( "JAERO \\[" )).remove(QRegExp( "\\]" ));

ui->lineEditZmqTopic->setText(settings.value("zmqAudioInputReceiveTopic", default_topic).toString());

on_lineEditlogdir_editingFinished();

@@ -176,6 +205,16 @@ void SettingsDialog::accept()
settings.setValue("checkOutputADSMessageToTCP", ui->checkOutputADSMessageToTCP->isChecked());
settings.setValue("checkTCPAsClient", ui->checkTCPAsClient->isChecked());

settings.setValue("localAudioOutEnabled", ui->ambeEnabled->isChecked());
settings.setValue("remoteAudioOutEnabled", ui->remoteAmbeEnabled->isChecked());
settings.setValue("remoteAudioOutBindAddress",ui->lineEditZMQBind->text());
settings.setValue("remoteAudioOutBindTopic",ui->lineEditZMQBindTopic->text());


settings.setValue("zmqAudioInputEnabled", ui->checkBoxZMQ->isChecked());
settings.setValue("zmqAudioInputReceiveAddress", ui->lineEditZmqConnectAddress->text());
settings.setValue("zmqAudioInputReceiveTopic", ui->lineEditZmqTopic->text());

poulatepublicvars();
QDialog::accept();
}
15 changes: 15 additions & 0 deletions JAERO/gui_classes/settingsdialog.h
Original file line number Diff line number Diff line change
@@ -51,6 +51,21 @@ class SettingsDialog : public QDialog
bool tcp_for_ads_messages_enabled;
bool tcp_as_client_enabled;


bool cpuSaveMode;
bool disableAcarsConsole;

bool localAudioOutEnabled;
bool zmqAudioOutEnabled;
QString zmqAudioOutBind;
QString zmqAudioOutTopic;

bool zmqAudioInputEnabled;
QString zmqAudioInputAddress;
QString zmqAudioInputTopic;



private:
Ui::SettingsDialog *ui;
void poulatepublicvars();
318 changes: 305 additions & 13 deletions JAERO/gui_classes/settingsdialog.ui
Original file line number Diff line number Diff line change
@@ -2,12 +2,15 @@
<ui version="4.0">
<class>SettingsDialog</class>
<widget class="QDialog" name="SettingsDialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>451</width>
<height>665</height>
<height>720</height>
</rect>
</property>
<property name="sizePolicy">
@@ -19,13 +22,7 @@
<property name="minimumSize">
<size>
<width>451</width>
<height>665</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>451</width>
<height>665</height>
<height>720</height>
</size>
</property>
<property name="windowTitle">
@@ -208,17 +205,17 @@ eg &quot;localhost:12345 localhost:12346&quot;</string>
<x>10</x>
<y>470</y>
<width>401</width>
<height>101</height>
<height>151</height>
</rect>
</property>
<property name="title">
<string>Soundcard</string>
<string>Audio source</string>
</property>
<widget class="QComboBox" name="comboBoxsoundcard">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<y>20</y>
<width>381</width>
<height>22</height>
</rect>
@@ -227,8 +224,8 @@ eg &quot;localhost:12345 localhost:12346&quot;</string>
<widget class="QCheckBox" name="checkBoxlogwidebandwidthenable">
<property name="geometry">
<rect>
<x>20</x>
<y>67</y>
<x>10</x>
<y>120</y>
<width>321</width>
<height>19</height>
</rect>
@@ -237,6 +234,95 @@ eg &quot;localhost:12345 localhost:12346&quot;</string>
<string>Enable widebandwidth (CPU intensive)</string>
</property>
</widget>
<widget class="QCheckBox" name="checkBoxZMQ">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>101</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>ZMQ Audio</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEditZmqConnectAddress">
<property name="geometry">
<rect>
<x>190</x>
<y>60</y>
<width>201</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_12">
<property name="geometry">
<rect>
<x>120</x>
<y>60</y>
<width>61</width>
<height>25</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Address</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLabel" name="label_13">
<property name="geometry">
<rect>
<x>130</x>
<y>90</y>
<width>51</width>
<height>25</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Topic</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLineEdit" name="lineEditZmqTopic">
<property name="geometry">
<rect>
<x>190</x>
<y>90</y>
<width>101</width>
<height>20</height>
</rect>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_6">
<property name="geometry">
@@ -443,6 +529,132 @@ eg &quot;localhost:12345 localhost:12346&quot;</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="voicesettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>8</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Voice Settings</string>
</attribute>
<widget class="QGroupBox" name="groupBox_3">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>401</width>
<height>191</height>
</rect>
</property>
<property name="title">
<string>Voice decoding</string>
</property>
<widget class="QLabel" name="labelBindAddress">
<property name="geometry">
<rect>
<x>20</x>
<y>110</y>
<width>121</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Socket bind address</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLineEdit" name="lineEditZMQBind">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>150</x>
<y>110</y>
<width>221</width>
<height>20</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>tcp://*:5550</string>
</property>
</widget>
<widget class="QCheckBox" name="ambeEnabled">
<property name="geometry">
<rect>
<x>20</x>
<y>30</y>
<width>171</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>JAERO voice decoding</string>
</property>
</widget>
<widget class="QCheckBox" name="remoteAmbeEnabled">
<property name="geometry">
<rect>
<x>20</x>
<y>70</y>
<width>171</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>Remote voice decoding</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>20</x>
<y>150</y>
<width>121</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Topic</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLineEdit" name="lineEditZMQBindTopic">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>150</x>
<y>150</y>
<width>91</width>
<height>20</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>JAERO</string>
</property>
</widget>
</widget>
</widget>
</widget>
</item>
<item>
@@ -497,5 +709,85 @@ eg &quot;localhost:12345 localhost:12346&quot;</string>
</hint>
</hints>
</connection>
<connection>
<sender>checkBoxZMQ</sender>
<signal>toggled(bool)</signal>
<receiver>comboBoxsoundcard</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>75</x>
<y>581</y>
</hint>
<hint type="destinationlabel">
<x>231</x>
<y>641</y>
</hint>
</hints>
</connection>
<connection>
<sender>checkBoxZMQ</sender>
<signal>toggled(bool)</signal>
<receiver>lineEditZmqConnectAddress</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>75</x>
<y>581</y>
</hint>
<hint type="destinationlabel">
<x>326</x>
<y>580</y>
</hint>
</hints>
</connection>
<connection>
<sender>checkBoxZMQ</sender>
<signal>toggled(bool)</signal>
<receiver>lineEditZmqTopic</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>75</x>
<y>581</y>
</hint>
<hint type="destinationlabel">
<x>287</x>
<y>610</y>
</hint>
</hints>
</connection>
<connection>
<sender>remoteAmbeEnabled</sender>
<signal>toggled(bool)</signal>
<receiver>lineEditZMQBind</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>126</x>
<y>129</y>
</hint>
<hint type="destinationlabel">
<x>281</x>
<y>170</y>
</hint>
</hints>
</connection>
<connection>
<sender>remoteAmbeEnabled</sender>
<signal>toggled(bool)</signal>
<receiver>lineEditZMQBindTopic</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>126</x>
<y>129</y>
</hint>
<hint type="destinationlabel">
<x>216</x>
<y>210</y>
</hint>
</hints>
</connection>
</connections>
</ui>
2 changes: 1 addition & 1 deletion JAERO/jconvolutionalcodec.cpp
Original file line number Diff line number Diff line change
@@ -200,7 +200,7 @@ QVector<int> &JConvolutionalCodec::Decode_Continuous(QByteArray& soft_bits_in)//
return decoded_bits;
}

//this is a bit of a hack just to compre soft with hard decoding. paddinglength must be a multiple of 8
// unpack the re-encoded bytes
QVector<int> &JConvolutionalCodec::Decode_Continuous_hard(const QByteArray& soft_bits_in)//0-->-1 128-->0 255-->1
{
int k=(2*nparitybits*paddinglength)/8;//msg is padded frount and back both times by paddinglength
2 changes: 1 addition & 1 deletion JAERO/main.cpp
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ int main(int argc, char *argv[])
QApplication::setApplicationVersion("1.0.4.4");

QCommandLineParser cmdparser;
cmdparser.setApplicationDescription("Demodulatoe and decode Satcom ACARS");
cmdparser.setApplicationDescription("Demodulate and decode Satcom ACARS");
cmdparser.addHelpOption();
cmdparser.addVersionOption();

122 changes: 67 additions & 55 deletions JAERO/mainwindow.cpp

Large diffs are not rendered by default.

13 changes: 12 additions & 1 deletion JAERO/mainwindow.h
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
#include <QMainWindow>
#include <QUdpSocket>
#include <QLabel>

#include "audiooqpskdemodulator.h"
#include "audiomskdemodulator.h"
#include "audioburstoqpskdemodulator.h"
@@ -21,6 +22,9 @@

#include "audiooutdevice.h"
#include "compressedaudiodiskwriter.h"
#include "zmq_audioreceiver.h"
#include "zmq_audiosender.h"


namespace Ui {
class MainWindow;
@@ -34,6 +38,8 @@ class MainWindow : public QMainWindow
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

signals:

private:
enum DemodType{NoDemodType,MSK,OQPSK,BURSTOQPSK,BURSTMSK};
Ui::MainWindow *ui;
@@ -57,7 +63,6 @@ class MainWindow : public QMainWindow
AudioBurstMskDemodulator *audioburstmskdemodulator;
AudioBurstMskDemodulator::Settings audioburstmskdemodulatorsettings;


//bottom textedit output
QList<QPointer<QUdpSocket> > udpsockets_bottom_textedit;

@@ -88,6 +93,11 @@ class MainWindow : public QMainWindow
ArincParse arincparser;

QSound *beep;

//ZeroMQ Audio Receiver
ZMQAudioReceiver *zmq_audio_receiver;
ZMQAudioSender *zmq_audio_sender;

protected:
void closeEvent(QCloseEvent *event);

@@ -118,6 +128,7 @@ private slots:
void on_tabWidget_currentChanged(int index);
void on_actionSound_Out_toggled(bool mute);
void on_actionReduce_CPU_triggered(bool checked);

};

#endif // MAINWINDOW_H
22 changes: 16 additions & 6 deletions JAERO/mskdemodulator.cpp
Original file line number Diff line number Diff line change
@@ -134,6 +134,7 @@ void MskDemodulator::invalidatesettings()

void MskDemodulator::setSettings(Settings _settings)
{
last_applied_settings=_settings;
if(_settings.Fs!=Fs)emit SampleRateChanged(_settings.Fs);
Fs=_settings.Fs;
lockingbw=_settings.lockingbw;
@@ -368,14 +369,16 @@ qint64 MskDemodulator::writeData(const char *data, qint64 len)
cpx_type cval= mixer2.WTCISValue()*(dval);
cpx_type sig2 = cpx_type(matchedfilter_re->FIRUpdateAndProcess(cval.real()),matchedfilter_im->FIRUpdateAndProcess(cval.imag()));

double dabval = std::sqrt(sig2.real()*sig2.real() + sig2.imag()*sig2.imag());

//Measure ebno
ebnomeasure->Update(std::abs(sig2));
ebnomeasure->Update(dabval);

//AGC
sig2*=agc->Update(std::abs(sig2));
sig2*=agc->Update(dabval);

//clipping
double abval=std::abs(sig2);
double abval=std::sqrt(sig2.real()*sig2.real() + sig2.imag()*sig2.imag());
if(abval>2.84)sig2=(2.84/abval)*sig2;

cpx_type pt_d = delayedsmpl.update_dont_touch(sig2);
@@ -522,6 +525,13 @@ void MskDemodulator::DCDstatSlot(bool _dcd)

}




void MskDemodulator::dataReceived(const QByteArray &audio,quint32 sampleRate)
{
if(sampleRate!=Fs)
{
qDebug()<<"Sample rate different than expected. Trying to change demodulator sample rate";
last_applied_settings.Fs=sampleRate;
setSettings(last_applied_settings);
}
writeData(audio, audio.length());
}
5 changes: 5 additions & 0 deletions JAERO/mskdemodulator.h
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ class MskDemodulator : public QIODevice
double Fs;
int symbolspercycle;
double signalthreshold;
bool zmqAudio;
Settings()
{
coarsefreqest_fft_power=13;//2^coarsefreqest_fft_power
@@ -39,6 +40,7 @@ class MskDemodulator : public QIODevice
Fs=48000;//Hz
symbolspercycle=16;
signalthreshold=0.5;
zmqAudio=false;
}
};
explicit MskDemodulator(QObject *parent);
@@ -140,6 +142,7 @@ class MskDemodulator : public QIODevice
int coarseCounter;
bool cpuReduce;

Settings last_applied_settings;

signals:
void ScatterPoints(const QVector<cpx_type> &buffer);
@@ -160,6 +163,8 @@ public slots:
void FreqOffsetEstimateSlot(double freq_offset_est);
void CenterFreqChangedSlot(double freq_center);
void DCDstatSlot(bool dcd);
void dataReceived(const QByteArray &audio, quint32 sampleRate);


};

59 changes: 31 additions & 28 deletions JAERO/oqpskdemodulator.cpp
Original file line number Diff line number Diff line change
@@ -56,7 +56,7 @@ OqpskDemodulator::OqpskDemodulator(QObject *parent)
connect(coarsefreqestimate, SIGNAL(FreqOffsetEstimate(double)),this,SLOT(FreqOffsetEstimateSlot(double)));

RootRaisedCosine rrc;
rrc.design(1,55,48000,10500/2);
rrc.design(1,55,Fs,10500/2);
fir_re=new FIR(rrc.Points.size());
fir_im=new FIR(rrc.Points.size());
for(int i=0;i<rrc.Points.size();i++)
@@ -66,7 +66,7 @@ OqpskDemodulator::OqpskDemodulator(QObject *parent)
}

//st delays
double T=48000.0/5250.0;
double T=Fs/5250.0;
delays.setdelay(1);
delayt41.setdelay(T/4.0);
delayt42.setdelay(T/4.0);
@@ -84,8 +84,8 @@ OqpskDemodulator::OqpskDemodulator(QObject *parent)
st_iir_resonator.init();

//st osc
st_osc.SetFreq(10500,48000);
st_osc_ref.SetFreq(10500,48000);
st_osc.SetFreq(10500,Fs);
st_osc_ref.SetFreq(10500,Fs);

//ct LPF
ct_iir_loopfilter.a.resize(3);
@@ -108,7 +108,7 @@ OqpskDemodulator::OqpskDemodulator(QObject *parent)
//just for 8400
//maybe another type of filter would be better?
RootRaisedCosine rrc_pre_imp;
rrc_pre_imp.design(1,1024,48000,10500/2);//8096,48000,10500/2);
rrc_pre_imp.design(1,1024,Fs,10500/2);//8096,48000,10500/2);
fir_pre.SetKernel(rrc_pre_imp.Points);
mixer_fir_pre.SetFreq(freq_center,Fs);

@@ -205,8 +205,8 @@ void OqpskDemodulator::setSettings(Settings _settings)
if(fir_im) delete fir_im;

RootRaisedCosine rrc;
if(fb==8400)rrc.design(0.6,55,48000,fb/2);
else rrc.design(1.0,55,48000,fb/2);
if(fb==8400)rrc.design(0.6,55,Fs,fb/2);
else rrc.design(1.0,55,Fs,fb/2);
fir_re=new FIR(rrc.Points.size());
fir_im=new FIR(rrc.Points.size());
for(int i=0;i<rrc.Points.size();i++)
@@ -216,7 +216,7 @@ void OqpskDemodulator::setSettings(Settings _settings)
}

//st delays
double T=48000.0/(fb/2);
double T=Fs/(fb/2);
delays.setdelay(1);
delayt41.setdelay(T/4.0);
delayt42.setdelay(T/4.0);
@@ -264,8 +264,11 @@ void OqpskDemodulator::setSettings(Settings _settings)
st_iir_resonator.init();

//st osc
st_osc.SetFreq(fb,48000);
st_osc_ref.SetFreq(fb,48000);

st_osc.SetFreq(fb,Fs);
st_osc_ref.SetFreq(fb,Fs);



//ebno measurement ok at 10.5k not
ebnomeasure->setup_update(Fs,fb);
@@ -452,10 +455,13 @@ qint64 OqpskDemodulator::writeData(const char *data, qint64 len)
}

//Measure ebno
ebnomeasure->Update(std::abs(sig2));

double dabval = std::sqrt(sig2.real()*sig2.real() + sig2.imag()*sig2.imag());

ebnomeasure->Update(dabval);

//AGC
sig2*=agc->Update(std::abs(sig2));
sig2*=agc->Update(dabval);

//clipping
double abval=std::abs(sig2);
@@ -535,7 +541,7 @@ qint64 OqpskDemodulator::writeData(const char *data, qint64 len)
if(!slowdown)
{
ASSERTCH(pointbuff,pointbuff_ptr);
pointbuff[pointbuff_ptr]=pt_qpsk;
pointbuff.replace(pointbuff_ptr,pt_qpsk);
pointbuff_ptr++;pointbuff_ptr%=pointbuff.size();
//if(scatterpointtype==SPT_constellation&&(pointbuff_ptr%100==0))emit ScatterPoints(pointbuff);
if(scatterpointtype==SPT_constellation&&sendscatterpoints){sendscatterpoints=false;emit ScatterPoints(pointbuff);}
@@ -545,7 +551,7 @@ qint64 OqpskDemodulator::writeData(const char *data, qint64 len)
{
cpx_type st_phase_offset_pt=st_osc_ref.WTCISValue()*std::conj(st_osc.WTCISValue());
ASSERTCH(phasepointbuff,phasepointbuff_ptr);
phasepointbuff[phasepointbuff_ptr]=st_phase_offset_pt;
phasepointbuff.replace(phasepointbuff_ptr,st_phase_offset_pt);
phasepointbuff_ptr++;phasepointbuff_ptr%=phasepointbuff.size();
//if(scatterpointtype==SPT_phaseoffsetest)emit ScatterPoints(phasepointbuff);
if(scatterpointtype==SPT_phaseoffsetest&&sendscatterpoints){sendscatterpoints=false;emit ScatterPoints(phasepointbuff);}
@@ -554,21 +560,8 @@ qint64 OqpskDemodulator::writeData(const char *data, qint64 len)
//calc MSE of the points
mse=msecalc->Update(pt_qpsk);

/*
//hard BPSK demod x2
bool pt_qpsk_imag_demod=0;
bool pt_qpsk_real_demod=0;
if(pt_qpsk.imag()>0)pt_qpsk_imag_demod=1;
if(pt_qpsk.real()>0)pt_qpsk_real_demod=1;
//if you want packed bits
bc.LoadSymbol(pt_qpsk_imag_demod);
bc.LoadSymbol(pt_qpsk_real_demod);
while(bc.DataAvailable)
if(mse<signalthreshold)
{
bc.GetNextSymbol();
RxDataBytes.push_back((uchar)bc.Result);
}*/

// soft bits
int ibit=qRound(0.75*pt_qpsk.imag()*127.0+128.0);
@@ -597,6 +590,7 @@ qint64 OqpskDemodulator::writeData(const char *data, qint64 len)
}
}
}
}
sig2_last=sig2;

//-----
@@ -686,3 +680,12 @@ void OqpskDemodulator::DCDstatSlot(bool _dcd)
dcd=_dcd;

}

void OqpskDemodulator::dataReceived(const QByteArray &audio,quint32 sampleRate)
{
if(sampleRate!=Fs)
{
qDebug()<<"Sample rate not supported by demodulator";
}
writeData(audio, audio.length());
}
3 changes: 3 additions & 0 deletions JAERO/oqpskdemodulator.h
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ class OqpskDemodulator : public QIODevice
double fb;
double Fs;
double signalthreshold;
bool zmqAudio;
Settings()
{
coarsefreqest_fft_power=14;//13;//2^coarsefreqest_fft_power
@@ -33,6 +34,7 @@ class OqpskDemodulator : public QIODevice
fb=10500;//bps
Fs=48000;//Hz
signalthreshold=0.65;//0.6;
zmqAudio=false;
}
};
explicit OqpskDemodulator(QObject *parent);
@@ -145,6 +147,7 @@ public slots:
void FreqOffsetEstimateSlot(double freq_offset_est);
void CenterFreqChangedSlot(double freq_center);
void DCDstatSlot(bool _dcd);
void dataReceived(const QByteArray &audio, quint32 sampleRate);

};

101 changes: 101 additions & 0 deletions JAERO/zmq_audioreceiver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "zmq_audioreceiver.h"
#include "QDebug"
#include <unistd.h>
#include <zmq.h>

void ZMQAudioReceiver::Start(QString address, QString topic)
{
//stop set prams and start thread
Stop();
setParameters(address,topic);
future = QtConcurrent::run([=]() {
process();
return;
});
//wait till the thread is running so ZMQaudioStop functions correctly
for(int i=0;!running&&i<1000;i++)usleep(1000);
//if it fails after a second then arghhhhh, should not happen
if(!running)
{
qDebug()<<"Failed to start ZMQ receiving thread";
}
}

void ZMQAudioReceiver::Stop()
{
running = false;
if(!future.isFinished())future.waitForFinished();
emit finished();
}

void ZMQAudioReceiver::process()
{
// allocate enough for 96Khz sampling with 1 buffer per second
int recsize = 192000;
context = zmq_ctx_new();
subscriber = zmq_socket(context, ZMQ_SUB);

zmqStatus = zmq_connect(subscriber, _address.toStdString().c_str());
zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, _topic.toStdString().c_str(), 5);

char buf [recsize];
unsigned char rate[4];
quint32 sampleRate;
int received;

running = true;

while(running)
{

//blocking call alternative for topic, here we wait for the topic.
//I guess the sleep has to be less then the idle period between messages???
while(((received = zmq_recv(subscriber, nullptr, 0, ZMQ_DONTWAIT))<0)&&running)
{
usleep(10000);
}
if(!running)break;

//rate message is next
received = zmq_recv(subscriber, rate, 4, ZMQ_DONTWAIT);
if(!running)break;
memcpy(&sampleRate, rate, 4);

//then audio data
received = zmq_recv(subscriber, buf, recsize, ZMQ_DONTWAIT);
if(!running)break;
if(received>=0)
{
QByteArray qdata(buf, received);
emit recAudio(qdata,sampleRate);
}

}

if(subscriber)zmq_close(subscriber);
if(context)zmq_ctx_destroy(context);
subscriber=nullptr;
context=nullptr;
}

ZMQAudioReceiver::ZMQAudioReceiver(QObject *parent):
QObject(parent),
running(false),
context(nullptr),
subscriber(nullptr)
{

}

ZMQAudioReceiver::~ZMQAudioReceiver()
{
Stop();
}

void ZMQAudioReceiver::setParameters(QString address, QString topic)
{
_address = address;
_topic = topic;
}


49 changes: 49 additions & 0 deletions JAERO/zmq_audioreceiver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef ZMQ_AUDIORECEIVER_H
#define ZMQ_AUDIORECEIVER_H

#include <QObject>
#include <QByteArray>
#include <QtConcurrent/QtConcurrent>

class ZMQAudioReceiver : public QObject
{
Q_OBJECT

public:

explicit ZMQAudioReceiver(QObject *parent = 0);
~ZMQAudioReceiver();

public slots:

void Stop();
void Start(QString address, QString topic);

signals:

void finished();

private:

void setParameters(QString address, QString topic);
volatile bool running;

void process();

void * volatile context;
void * volatile subscriber;

int zmqStatus;

QString _address;
QString _topic;
int _rate;

QFuture<void> future;

signals:
void recAudio(const QByteArray & audio,quint32 sampleRate);

};

#endif // AUDIORECEIVER_H
51 changes: 51 additions & 0 deletions JAERO/zmq_audiosender.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "zmq_audiosender.h"
#include "zmq.h"
#include <QDebug>

ZMQAudioSender::ZMQAudioSender(QObject *parent) : QObject(parent)
{
zmqStatus = -1;
context = zmq_ctx_new();
publisher = zmq_socket(context, ZMQ_PUB);

int keepalive = 1;
int keepalivecnt = 10;
int keepaliveidle = 1;
int keepaliveintrv = 1;

zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE,(void*)&keepalive, sizeof(ZMQ_TCP_KEEPALIVE));
zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_CNT,(void*)&keepalivecnt,sizeof(ZMQ_TCP_KEEPALIVE_CNT));
zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_IDLE,(void*)&keepaliveidle,sizeof(ZMQ_TCP_KEEPALIVE_IDLE));
zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_INTVL,(void*)&keepaliveintrv,sizeof(ZMQ_TCP_KEEPALIVE_INTVL));
}

void ZMQAudioSender::Start(QString &address, QString &topic)
{
Stop();
// bind socket
this->topic=topic;
connected_url=address.toUtf8().constData();
zmqStatus=zmq_bind(publisher, connected_url.c_str() );
}

void ZMQAudioSender::Stop()
{
if(zmqStatus == 0)
{
zmqStatus = zmq_disconnect(publisher, connected_url.c_str());
}
}

void ZMQAudioSender::Voiceslot(QByteArray &data, QString &hex)
{
std::string topic_text = topic.toUtf8().constData();
zmq_setsockopt(publisher, ZMQ_IDENTITY, topic_text.c_str(), topic_text.length());

if(data.length()!=0)
{
zmq_send(publisher, topic_text.c_str(), topic_text.length(), ZMQ_SNDMORE);
zmq_send(publisher, data.data(), data.length(), 0 );
}
zmq_send(publisher, topic_text.c_str(), 5, ZMQ_SNDMORE);
zmq_send(publisher, hex.toStdString().c_str(), 6, 0 );
}
24 changes: 24 additions & 0 deletions JAERO/zmq_audiosender.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef ZMQ_AUDIOSENDER_H
#define ZMQ_AUDIOSENDER_H

#include <QObject>

class ZMQAudioSender : public QObject
{
Q_OBJECT
public:
explicit ZMQAudioSender(QObject *parent = 0);
void Start(QString &address,QString &topic);
void Stop();
signals:
public slots:
void Voiceslot(QByteArray &data, QString &hex);
private:
void* context;
void* publisher;
int zmqStatus;
std::string connected_url;
QString topic;
};

#endif // ZMQ_AUDIOSENDER_H
4 changes: 2 additions & 2 deletions ci-linux-build.sh
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ set -e
if [[ ! $(sudo echo 0) ]]; then exit; fi

#install dependancies and build tools
sudo apt-get install qt5-default cpputest build-essential qtmultimedia5-dev cmake libvorbis-dev libogg-dev libqt5multimedia5-plugins checkinstall libqcustomplot-dev libqt5svg5-dev -y
sudo apt-get install qt5-default cpputest build-essential qtmultimedia5-dev cmake libvorbis-dev libogg-dev libqt5multimedia5-plugins checkinstall libqcustomplot-dev libqt5svg5-dev libzmq3-dev -y

#get script path
SCRIPT=$(realpath $0)
@@ -170,7 +170,7 @@ Package: ${PACKAGE_NAME}
Source: ${PACKAGE_SOURCE}
Section: base
Priority: extra
Depends: qt5-default (>= 5.12), qtmultimedia5-dev, libvorbis-dev, libogg-dev, libqt5multimedia5-plugins, libqcustomplot-dev, libqt5svg5-dev
Depends: qt5-default (>= 5.12), qtmultimedia5-dev, libvorbis-dev, libogg-dev, libqt5multimedia5-plugins, libqcustomplot-dev, libqt5svg5-dev, libzmq3-dev
Provides: ${PACKAGE_NAME}
Maintainer: ${MAINTAINER}
Version: ${PACKAGE_VERSION%_*}
4 changes: 3 additions & 1 deletion ci-windows-build.sh
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
#fail on first error
set -e

pacman -S --needed --noconfirm git mingw-w64-x86_64-toolchain autoconf libtool mingw-w64-x86_64-cpputest mingw-w64-x86_64-qt5 mingw-w64-x86_64-cmake mingw-w64-x86_64-libvorbis zip p7zip unzip
pacman -S --needed --noconfirm git mingw-w64-x86_64-toolchain autoconf libtool mingw-w64-x86_64-cpputest mingw-w64-x86_64-qt5 mingw-w64-x86_64-cmake mingw-w64-x86_64-libvorbis zip p7zip unzip mingw-w64-x86_64-zeromq

#get script path
SCRIPT=$(realpath $0)
@@ -123,6 +123,8 @@ cp /mingw64/bin/libintl-8.dll $PWD
cp /mingw64/bin/libpcre-1.dll $PWD
cp /mingw64/bin/libbrotlicommon.dll $PWD
cp /mingw64/bin/libiconv-2.dll $PWD
cp /mingw64/bin/libzmq.dll $PWD
cp /mingw64/bin/libsodium-23.dll $PWD
#7za.exe not needed anymore
#cp /usr/lib/p7zip/7za.exe $PWD
#cp /usr/bin/msys-stdc++-6.dll $PWD