├── .github └── workflows │ └── ci-windows-build.yml ├── .gitignore ├── JAERO ├── DSP.cpp ├── DSP.h ├── JAERO.desktop ├── JAERO.pro ├── acarsitem_converter.cpp ├── acarsitem_converter.h ├── aerol.cpp ├── aerol.h ├── arincparse.cpp ├── arincparse.h ├── audioburstmskdemodulator.cpp ├── audioburstmskdemodulator.h ├── audioburstoqpskdemodulator.cpp ├── audioburstoqpskdemodulator.h ├── audiomskdemodulator.cpp ├── audiomskdemodulator.h ├── audiooqpskdemodulator.cpp ├── audiooqpskdemodulator.h ├── audiooutdevice.cpp ├── audiooutdevice.h ├── burstmskdemodulator.cpp ├── burstmskdemodulator.h ├── burstoqpskdemodulator.cpp ├── burstoqpskdemodulator.h ├── coarsefreqestimate.cpp ├── coarsefreqestimate.h ├── compressedaudiodiskwriter.cpp ├── compressedaudiodiskwriter.h ├── databasetext.cpp ├── databasetext.h ├── fftrwrapper.cpp ├── fftrwrapper.h ├── fftwrapper.cpp ├── fftwrapper.h ├── gui_classes │ ├── console.cpp │ ├── console.h │ ├── createeditinputdialog.cpp │ ├── createeditinputdialog.h │ ├── createeditinputdialog.ui │ ├── planelog.cpp │ ├── planelog.h │ ├── planelog.ui │ ├── qled.cpp │ ├── qled.h │ ├── qscatterplot.cpp │ ├── qscatterplot.h │ ├── qspectrumdisplay.cpp │ ├── qspectrumdisplay.h │ ├── settingsdialog.cpp │ ├── settingsdialog.h │ ├── settingsdialog.ui │ ├── textinputwidget.cpp │ └── textinputwidget.h ├── images │ ├── Plane_clip_art.svg │ ├── application-exit.png │ ├── arrow-right-left-512px.svg │ ├── arrow-up-down-512px.svg │ ├── beacon.svg │ ├── clear.png │ ├── connect.png │ ├── cpu.png │ ├── disconnect.png │ ├── eighth note.svg │ ├── export.svg │ ├── globe.svg │ ├── green_cpu.png │ ├── green_led.svg │ ├── import.svg │ ├── log.png │ ├── off_led.svg │ ├── primary-binary.svg │ ├── primary-modem.svg │ ├── red_led.svg │ ├── rx.svg │ ├── settings.png │ ├── sound-off2.png │ ├── sound.png │ ├── stopsort-512px.svg │ └── tx.svg ├── jaero.ico ├── jaero.qrc ├── jaero.rc ├── jconvolutionalcodec.cpp ├── jconvolutionalcodec.h ├── jserialize.cpp ├── jserialize.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── matlab │ ├── expected_input_include.m │ ├── expected_output_include.m │ └── jfastfir.m ├── mqttsubscriber.cpp ├── mqttsubscriber.h ├── mskdemodulator.cpp ├── mskdemodulator.h ├── oqpskdemodulator.cpp ├── oqpskdemodulator.h ├── sbs1.cpp ├── sbs1.h ├── sounds │ └── beep.wav ├── tcpclient.cpp ├── tcpclient.h ├── tcpserver.cpp ├── tcpserver.h ├── tests │ ├── fftrwrapper_tests.cpp │ ├── fftwrapper_tests.cpp │ ├── jfastfir_data.cpp │ ├── jfastfir_data.h │ ├── jfastfir_data_expected_output.cpp │ ├── jfastfir_data_input.cpp │ ├── jfastfir_tests.cpp │ └── testall.cpp ├── util │ ├── RuntimeError.cpp │ ├── RuntimeError.h │ ├── file_utils.cpp │ ├── file_utils.h │ ├── stdio_utils.cpp │ └── stdio_utils.h ├── zmq_audioreceiver.cpp ├── zmq_audioreceiver.h ├── zmq_audiosender.cpp └── zmq_audiosender.h ├── LICENSE ├── README.md ├── basestationlinks ├── ci-create-basestation.sh ├── ci-linux-build.sh ├── ci-windows-build.sh ├── images ├── screenshot-win-main.png └── screenshot-win-planelog.png ├── pi-build.sh ├── samples ├── 10.5k_burst_sample.mp3 ├── 10.5k_sample.ogg ├── 1200bps_burst_sample1.wav ├── 1200bps_burst_sample2.wav ├── 600bps_sample.ogg └── 8400bps_ambe_sample.ogg └── udptextserver ├── license.txt ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui └── udptextserver.pro /.github/workflows/ci-windows-build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | os: [ubuntu-latest, windows-latest] 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | path: JAERO 16 | # install MSYS2 for windows 17 | - name: if windows install MSYS2 18 | if: ${{ matrix.os == 'windows-latest' }} 19 | uses: msys2/setup-msys2@v2 20 | with: 21 | msystem: MINGW64 22 | update: true 23 | 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 24 | # build for windows 25 | - name: Windows-CI-Build 26 | if: ${{ matrix.os == 'windows-latest' }} 27 | run: | 28 | echo 'Running in MSYS2!' 29 | ./JAERO/ci-windows-build.sh 30 | shell: msys2 {0} 31 | # build for linux 32 | - name: Linux-CI-Build 33 | if: ${{ matrix.os == 'ubuntu-latest' }} 34 | run: | 35 | echo 'Running in bash!' 36 | ./JAERO/ci-linux-build.sh 37 | # upload windows artifacts 38 | - name: Upload windows binary artifacts 39 | if: ${{ matrix.os == 'windows-latest' }} 40 | uses: actions/upload-artifact@v2 41 | with: 42 | name: jaero_windows 43 | retention-days: 1 44 | path: | 45 | JAERO/JAERO/release/*.zip 46 | # upload linux artifacts 47 | - name: Upload linux binary artifacts 48 | if: ${{ matrix.os == 'ubuntu-latest' }} 49 | uses: actions/upload-artifact@v2 50 | with: 51 | name: jaero_linux 52 | retention-days: 1 53 | path: | 54 | JAERO/bin/*.tar.gz 55 | release: 56 | needs: build 57 | runs-on: ubuntu-latest 58 | steps: 59 | # download all artifacts for this workflow 60 | - name: Download all workflow artifacts 61 | uses: actions/download-artifact@v2 62 | # Create a release 63 | - name: Create a release 64 | uses: "marvinpinto/action-automatic-releases@latest" 65 | with: 66 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 67 | automatic_release_tag: "latest" 68 | prerelease: true 69 | title: "Development Build" 70 | files: | 71 | jaero_linux/*.tar.gz 72 | jaero_windows/*.zip 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | .qmake.cache 36 | .qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | # other 75 | JAERO/test_output/* 76 | JAERO/matlab/actual_* 77 | JAERO/matlab/*.h 78 | build-*/ 79 | JFFT/* 80 | libacars/* 81 | libaeroambe/* 82 | libcorrect/* 83 | bin/* 84 | JAERO/*.bak 85 | release/jaero/* 86 | JAERO/release 87 | JAERO/JAERO 88 | JAERO/moc_predefs.h 89 | *.bak 90 | -------------------------------------------------------------------------------- /JAERO/JAERO.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=JAERO 4 | GenericName=ACARS demodulator and decoder 5 | Comment=A SatCom ACARS demodulator and decoder for the Aero standard 6 | Exec=/opt/jaero/JAERO 7 | Terminal=false 8 | Icon=/opt/jaero/jaero.ico 9 | Categories=Network;HamRadio; 10 | Keywords=SDR;Radio;HAM; 11 | -------------------------------------------------------------------------------- /JAERO/JAERO.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2015-08-01T20:41:23 4 | # Jonti Olds 5 | # 6 | #------------------------------------------------- 7 | 8 | #the three tricky things will be libvorbis,libogg, and libcorrect 9 | #the settings I have here are for my setup but other most likely will install the libraries 10 | #so you will need to point everything to the right place. 11 | #if you are having trubbles focus on things like "LIBS += -L$$OGG_PATH/src/.libs" 12 | #remember to compile libvorbis,libogg, and libcorrect before compiling this 13 | 14 | DEFINES += JAERO_VERSION=\\\"v1.0.4.14\\\" 15 | 16 | QT += multimedia core network gui svg sql qmqtt 17 | 18 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport 19 | 20 | TARGET = JAERO 21 | TEMPLATE = app 22 | 23 | INSTALL_PATH = /opt/jaero 24 | JFFT_PATH = ../../JFFT/ 25 | 26 | QMAKE_CXXFLAGS += -std=c++11 27 | 28 | INCLUDEPATH += $$JFFT_PATH 29 | 30 | #libacars-2 support 31 | #this is a bit of a mess to get working. 32 | #he put them in libacars-2/libacars but references in libacars-2/libacars only use libacars in paths 33 | #so i have to find where libacars-2 is and add that to the INCLUDEPATH 34 | for(var, $$list($${QMAKE_DEFAULT_INCDIRS})) { 35 | new_inc_path_posibility=$$files($${var}/libacars-2, false) 36 | !equals(new_inc_path_posibility,"") { 37 | #message( "libacars-2 location is "$${new_inc_path_posibility} ) 38 | INCLUDEPATH += $$new_inc_path_posibility 39 | } 40 | } 41 | 42 | DEFINES += _USE_MATH_DEFINES 43 | 44 | #for unit tests 45 | CI { 46 | DEFINES += GENERATE_TEST_OUTPUT_FILES 47 | SOURCES += \ 48 | tests/testall.cpp \ 49 | tests/fftwrapper_tests.cpp \ 50 | tests/fftrwrapper_tests.cpp \ 51 | tests/jfastfir_tests.cpp \ 52 | tests/jfastfir_data_input.cpp \ 53 | tests/jfastfir_data_expected_output.cpp 54 | 55 | HEADERS += \ 56 | tests/jfastfir_data.h 57 | 58 | LIBS += -lCppUTest 59 | 60 | DEFINES+= MATLAB_PATH=\\\"$${PWD}/matlab/\\\" 61 | DEFINES+= TEST_OUTPUT_PATH=\\\"$${PWD}/test_output/\\\" 62 | 63 | } else { 64 | SOURCES += \ 65 | main.cpp 66 | } 67 | 68 | SOURCES += mainwindow.cpp \ 69 | coarsefreqestimate.cpp \ 70 | DSP.cpp \ 71 | gui_classes/createeditinputdialog.cpp \ 72 | mskdemodulator.cpp \ 73 | audiomskdemodulator.cpp \ 74 | gui_classes/console.cpp \ 75 | gui_classes/qscatterplot.cpp \ 76 | gui_classes/qspectrumdisplay.cpp \ 77 | gui_classes/qled.cpp \ 78 | fftwrapper.cpp \ 79 | fftrwrapper.cpp \ 80 | gui_classes/textinputwidget.cpp \ 81 | gui_classes/settingsdialog.cpp \ 82 | aerol.cpp \ 83 | gui_classes/planelog.cpp \ 84 | databasetext.cpp \ 85 | oqpskdemodulator.cpp \ 86 | audiooqpskdemodulator.cpp \ 87 | burstoqpskdemodulator.cpp \ 88 | audioburstoqpskdemodulator.cpp \ 89 | arincparse.cpp \ 90 | tcpserver.cpp \ 91 | sbs1.cpp \ 92 | tcpclient.cpp \ 93 | burstmskdemodulator.cpp \ 94 | audioburstmskdemodulator.cpp \ 95 | jconvolutionalcodec.cpp \ 96 | audiooutdevice.cpp \ 97 | compressedaudiodiskwriter.cpp \ 98 | $$JFFT_PATH/jfft.cpp \ 99 | util/stdio_utils.cpp \ 100 | util/file_utils.cpp \ 101 | util/RuntimeError.cpp \ 102 | zmq_audiosender.cpp \ 103 | zmq_audioreceiver.cpp \ 104 | mqttsubscriber.cpp \ 105 | acarsitem_converter.cpp \ 106 | jserialize.cpp 107 | 108 | 109 | HEADERS += mainwindow.h \ 110 | coarsefreqestimate.h \ 111 | DSP.h \ 112 | gui_classes/createeditinputdialog.h \ 113 | mskdemodulator.h \ 114 | audiomskdemodulator.h \ 115 | gui_classes/console.h \ 116 | gui_classes/qscatterplot.h \ 117 | gui_classes/qspectrumdisplay.h \ 118 | gui_classes/qled.h \ 119 | fftwrapper.h \ 120 | fftrwrapper.h \ 121 | gui_classes/textinputwidget.h \ 122 | gui_classes/settingsdialog.h \ 123 | aerol.h \ 124 | gui_classes/planelog.h \ 125 | databasetext.h \ 126 | oqpskdemodulator.h \ 127 | audiooqpskdemodulator.h \ 128 | burstoqpskdemodulator.h \ 129 | audioburstoqpskdemodulator.h \ 130 | arincparse.h \ 131 | tcpserver.h \ 132 | sbs1.h \ 133 | tcpclient.h \ 134 | burstmskdemodulator.h \ 135 | audioburstmskdemodulator.h \ 136 | jconvolutionalcodec.h \ 137 | audiooutdevice.h \ 138 | compressedaudiodiskwriter.h \ 139 | $$JFFT_PATH/jfft.h \ 140 | util/stdio_utils.h \ 141 | util/file_utils.h \ 142 | util/RuntimeError.h \ 143 | zmq_audioreceiver.h \ 144 | zmq_audiosender.h \ 145 | mqttsubscriber.h \ 146 | acarsitem_converter.h \ 147 | jserialize.h 148 | 149 | # Tell the qcustomplot header that it will be used as library: 150 | DEFINES += QCUSTOMPLOT_USE_LIBRARY 151 | #qcustom plot is called different names on different systems 152 | win32 { 153 | #message("windows") 154 | LIBS += -lqcustomplot2 -llibzmq 155 | } else { 156 | #message("not windows") 157 | LIBS += -lqcustomplot -lzmq 158 | } 159 | 160 | FORMS += mainwindow.ui \ 161 | gui_classes/createeditinputdialog.ui \ 162 | gui_classes/settingsdialog.ui \ 163 | gui_classes/planelog.ui 164 | 165 | RESOURCES += \ 166 | jaero.qrc 167 | 168 | DISTFILES += \ 169 | LICENSE \ 170 | ../README.md \ 171 | ../images/screenshot-win-main.png \ 172 | ../images/screenshot-win-planelog.png 173 | 174 | win32 { 175 | RC_FILE = jaero.rc 176 | 177 | } 178 | 179 | # remove possible other optimization flags 180 | #QMAKE_CXXFLAGS_RELEASE -= -O 181 | QMAKE_CXXFLAGS_RELEASE -= -O2 182 | QMAKE_CXXFLAGS_RELEASE += -O3 183 | 184 | # add the desired -O3 if not present 185 | #QMAKE_CXXFLAGS_RELEASE *= -O3 186 | 187 | #for static building order seems to matter 188 | LIBS += -lcorrect -lvorbis -lvorbisenc -logg -lacars-2 189 | 190 | #desktop 191 | desktop.path = /usr/share/applications 192 | desktop.files += JAERO.desktop 193 | INSTALLS += desktop 194 | 195 | #icon 196 | icon.path = $$INSTALL_PATH 197 | icon.files += jaero.ico 198 | INSTALLS += icon 199 | 200 | #install sounds 201 | soundsDataFiles.path = $$INSTALL_PATH/sounds/ 202 | soundsDataFiles.files = sounds/*.* 203 | INSTALLS += soundsDataFiles 204 | 205 | #install library 206 | target.path=$$INSTALL_PATH 207 | INSTALLS += target 208 | 209 | # disable stupid deprecated-copy warnings 210 | # cluttering up issues 211 | QMAKE_CXXFLAGS += '-Wno-deprecated-copy' 212 | 213 | #QMAKE_CXXFLAGS += '-Werror=format-security' 214 | -------------------------------------------------------------------------------- /JAERO/acarsitem_converter.cpp: -------------------------------------------------------------------------------- 1 | #include "acarsitem_converter.h" 2 | -------------------------------------------------------------------------------- /JAERO/acarsitem_converter.h: -------------------------------------------------------------------------------- 1 | #ifndef ACARSITEM_CONVERTER_H 2 | #define ACARSITEM_CONVERTER_H 3 | 4 | #include "jserialize.h" 5 | #include "aerol.h" 6 | 7 | class ISUItem_QObject : public JSerialize 8 | { 9 | Q_OBJECT 10 | public: 11 | J_SERIALIZE(quint32, AESID) 12 | J_SERIALIZE(uchar, GESID) 13 | J_SERIALIZE(uchar, QNO) 14 | J_SERIALIZE(uchar, SEQNO) 15 | J_SERIALIZE(uchar, REFNO) 16 | J_SERIALIZE(uchar, NOOCTLESTINLASTSSU) 17 | J_SERIALIZE(QByteArray, userdata) 18 | J_SERIALIZE(int, count) 19 | void clear() 20 | { 21 | AESID=0; 22 | GESID=0; 23 | QNO=0; 24 | SEQNO=0; 25 | REFNO=0; 26 | NOOCTLESTINLASTSSU=0; 27 | userdata.clear(); 28 | count=0; 29 | } 30 | 31 | ISUItem_QObject& operator =(const ISUItem& other) 32 | { 33 | AESID=other.AESID; 34 | GESID=other.GESID; 35 | QNO=other.QNO; 36 | SEQNO=other.SEQNO; 37 | REFNO=other.REFNO; 38 | NOOCTLESTINLASTSSU=other.NOOCTLESTINLASTSSU; 39 | userdata=other.userdata; 40 | count=other.count; 41 | return *this; 42 | } 43 | 44 | ISUItem &toISUItem() 45 | { 46 | anISUItem.AESID=AESID; 47 | anISUItem.GESID=GESID; 48 | anISUItem.QNO=QNO; 49 | anISUItem.SEQNO=SEQNO; 50 | anISUItem.REFNO=REFNO; 51 | anISUItem.NOOCTLESTINLASTSSU=NOOCTLESTINLASTSSU; 52 | anISUItem.userdata=userdata; 53 | anISUItem.count=count; 54 | return anISUItem; 55 | } 56 | 57 | operator ISUItem & () 58 | { 59 | return toISUItem(); 60 | } 61 | 62 | private: 63 | ISUItem anISUItem; 64 | 65 | }; 66 | 67 | class ACARSItem_QObject : private JSerialize 68 | { 69 | Q_OBJECT 70 | public: 71 | ISUItem_QObject isuitem; 72 | J_SERIALIZE(char, MODE) 73 | J_SERIALIZE(uchar, TAK) 74 | J_SERIALIZE(QByteArray, LABEL) 75 | J_SERIALIZE(uchar, BI) 76 | J_SERIALIZE(QByteArray, PLANEREG) 77 | J_SERIALIZE(QStringList, dblookupresult) 78 | J_SERIALIZE(bool, nonacars) 79 | J_SERIALIZE(bool, downlink) 80 | J_SERIALIZE(bool, valid) 81 | J_SERIALIZE(bool, hastext) 82 | J_SERIALIZE(bool, moretocome) 83 | J_SERIALIZE(QString, message) 84 | 85 | ACARSItem_QObject() : JSerialize() 86 | { 87 | } 88 | ACARSItem_QObject(const ACARSItem& other) : JSerialize() 89 | { 90 | this->operator =(other); 91 | } 92 | 93 | ACARSItem_QObject& operator =(const ACARSItem& other) 94 | { 95 | isuitem=other.isuitem; 96 | MODE=other.MODE; 97 | TAK=other.TAK; 98 | LABEL=other.LABEL; 99 | BI=other.BI; 100 | PLANEREG=other.PLANEREG; 101 | dblookupresult=other.dblookupresult; 102 | nonacars=other.nonacars; 103 | downlink=other.downlink; 104 | valid=other.valid; 105 | hastext=other.hastext; 106 | moretocome=other.moretocome; 107 | message=other.message; 108 | return *this; 109 | } 110 | 111 | ACARSItem &toACARSItem() 112 | { 113 | anACARSItem.isuitem=isuitem; 114 | anACARSItem.MODE=MODE; 115 | anACARSItem.TAK=TAK; 116 | anACARSItem.LABEL=LABEL; 117 | anACARSItem.BI=BI; 118 | anACARSItem.PLANEREG=PLANEREG; 119 | anACARSItem.dblookupresult=dblookupresult; 120 | anACARSItem.nonacars=nonacars; 121 | anACARSItem.downlink=downlink; 122 | anACARSItem.valid=valid; 123 | anACARSItem.hastext=hastext; 124 | anACARSItem.moretocome=moretocome; 125 | anACARSItem.message=message; 126 | return anACARSItem; 127 | } 128 | 129 | operator ACARSItem & () 130 | { 131 | return toACARSItem(); 132 | } 133 | 134 | bool fromQByteArray(const QByteArray &ba) 135 | { 136 | QDataStream ds(ba); 137 | ds>>(*this); 138 | ds>>isuitem; 139 | if(hasSerializeError()||isuitem.hasSerializeError())return false; 140 | return true; 141 | } 142 | 143 | bool toQByteArray(QByteArray &ba) 144 | { 145 | ba.clear(); 146 | QDataStream ds(&ba,QIODevice::WriteOnly); 147 | ds<<(*this); 148 | ds<operator =(to); 162 | toQByteArray(ba); 163 | return ba; 164 | } 165 | 166 | ACARSItem& convert(const QByteArray &ba) 167 | { 168 | fromQByteArray(ba); 169 | return toACARSItem(); 170 | } 171 | 172 | private: 173 | ACARSItem anACARSItem; 174 | QByteArray ba; 175 | }; 176 | 177 | #endif // ACARSITEM_CONVERTER_H 178 | -------------------------------------------------------------------------------- /JAERO/arincparse.h: -------------------------------------------------------------------------------- 1 | #ifndef ARINCPARSE_H 2 | #define ARINCPARSE_H 3 | 4 | #include "aerol.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define lat_scaller 0.000171661376953125 15 | #define long_scaller 0.000171661376953125 16 | #define alt_scaller 4.0 17 | #define time_scaller 0.125 18 | #define truetrack_scaller 0.087890625 19 | #define trueheading_scaller 0.087890625 20 | #define groundspeed_scaller 0.5 21 | #define machspeed_scaller 0.0005 22 | #define verticalrate_scaller 16 23 | #define windspeed_scaller 0.5 24 | #define truewinddirection_scaller 0.703125 25 | #define temperature_scaller 0.25 26 | #define distance_scaller 0.125 27 | 28 | struct DownlinkHeader 29 | { 30 | bool valid; 31 | QString flightid; 32 | QString OriginatorString; 33 | int MessageNumber; 34 | char BlockSequenceCharacter; 35 | void clear() 36 | { 37 | valid=false; 38 | flightid.clear(); 39 | OriginatorString.clear(); 40 | MessageNumber=-1; 41 | BlockSequenceCharacter=-1; 42 | } 43 | }; 44 | 45 | struct ArincMessage 46 | { 47 | bool valid;//if crc is true 48 | bool downlink;//if is downlink 49 | QString info;//human readable message 50 | QJsonObject info_json; 51 | QString IMI;//ADS AT1 etc 52 | QString tailno;//REG 53 | void clear() 54 | { 55 | valid=false; 56 | downlink=false; 57 | info.clear(); 58 | info_json=QJsonObject(); 59 | IMI.clear(); 60 | tailno.clear(); 61 | } 62 | }; 63 | 64 | typedef enum ADSDownlinkMessages { 65 | Acknowledgement=3, 66 | Negative_Acknowledgement=4, 67 | Noncompliance_Notification=5, 68 | Cancel_Emergency_Mode=6, 69 | Basic_Report=7, 70 | Emergency_Basic_Report=9, 71 | Lateral_Deviation_Change_Event=10, 72 | Flight_Identification_Group=12, 73 | Predicted_Route_Group=13, 74 | Earth_Reference_Group=14, 75 | Air_Reference_Group=15, 76 | Meteorological_Group=16, 77 | Airframe_Identification_Group=17, 78 | Vertical_Rate_Change_Event=18, 79 | Altitude_Range_Event=19, 80 | Waypoint_Change_Event=20, 81 | Intermediate_Projected_Intent_Group=22, 82 | Fixed_Projected_Intent_Group=23 83 | } ADSDownlinkMessages; 84 | 85 | 86 | struct DownlinkBasicReportGroup 87 | { 88 | //Message type 89 | ADSDownlinkMessages messagetype; 90 | //AES 91 | quint32 AESID; 92 | //Downlink header 93 | DownlinkHeader downlinkheader; 94 | //Lat 95 | double latitude; 96 | //Long 97 | double longitude; 98 | //Alt 99 | double altitude; 100 | //Time stamp (seconds past the hour) 101 | double time_stamp; 102 | //FOM 103 | int FOM; 104 | //Message valid 105 | bool valid; 106 | }; 107 | 108 | struct DownlinkEarthReferenceGroup 109 | { 110 | //AES 111 | quint32 AESID; 112 | //Downlink header 113 | DownlinkHeader downlinkheader; 114 | //True track is valid 115 | bool truetrack_isvalid; 116 | //True track 117 | double truetrack; 118 | //Ground speed 119 | double groundspeed; 120 | //Vertical rate 121 | double verticalrate; 122 | //Message valid 123 | bool valid; 124 | }; 125 | 126 | //all messages must contain a basic report group so should always be valid other groups may or maynot be valid 127 | struct DownlinkGroups 128 | { 129 | DownlinkBasicReportGroup adownlinkbasicreportgroup; 130 | DownlinkEarthReferenceGroup adownlinkearthreferencegroup; 131 | void clear() 132 | { 133 | adownlinkbasicreportgroup.valid=false; 134 | adownlinkearthreferencegroup.valid=false; 135 | } 136 | bool isValid() 137 | { 138 | if(adownlinkbasicreportgroup.valid)return true; 139 | return false; 140 | } 141 | }; 142 | 143 | 144 | class ArincParse : public QObject 145 | { 146 | Q_OBJECT 147 | Q_ENUMS(IMIEnum) 148 | Q_ENUMS(MessageSourcesIDS) 149 | public: 150 | 151 | typedef enum IMIEnum { 152 | ADS, 153 | AT1, 154 | DR1, 155 | CC1 156 | } IMIEnum; 157 | 158 | 159 | 160 | typedef enum MessageSourcesIDS { 161 | CFDIU='C', 162 | DFDAU='D', 163 | FMC='F', 164 | CMU_ATS_Functions='L', 165 | CMU_AOC_Applications='M', 166 | System_Control='S', 167 | OAT='O', 168 | Cabin_Terminal_1='1', 169 | Cabin_Terminal_2='2', 170 | Cabin_Terminal_3='3', 171 | Cabin_Terminal_4='4', 172 | User_Terminal5='5', 173 | User_Terminal6='6', 174 | User_Terminal7='7', 175 | User_Terminal8='8', 176 | User_Defined='U', 177 | EICAS_ECAM_EFIS='E', 178 | SDU='Q', 179 | ATSU_ADSU='J', 180 | HF_Data_Radio='T' 181 | } MessageSourcesIDS; 182 | 183 | 184 | explicit ArincParse(QObject *parent = 0); 185 | bool parseDownlinkmessage(ACARSItem &acarsitem, bool onlyuselibacars = false);//QString &msg); 186 | bool parseUplinkmessage(ACARSItem &acarsitem); 187 | 188 | ArincMessage arincmessage; 189 | DownlinkHeader downlinkheader; 190 | 191 | signals: 192 | //void DownlinkBasicReportGroupSignal(DownlinkBasicReportGroup &message); 193 | //void DownlinkEarthReferenceGroupSignal(DownlinkEarthReferenceGroup &message); 194 | void DownlinkGroupsSignal(DownlinkGroups &groups); 195 | public slots: 196 | private: 197 | QBitArray &tobits(QByteArray &bytes); 198 | AeroLcrc16 crc16; 199 | QMetaEnum MetaEnumMessageSourcesIDS; 200 | QMetaEnum MetaEnumIMI; 201 | QMetaObject MetaObject; 202 | QBitArray bitarray; 203 | qint32 extractqint32(QByteArray &ba, int lsbyteoffset, int bitoffset, int numberofbits, bool issigned); 204 | QString middlespacer; 205 | 206 | DownlinkGroups downlinkgroups; 207 | void try_acars_apps(ACARSItem &acarsitem, la_msg_dir msg_dir); 208 | 209 | }; 210 | 211 | 212 | 213 | #endif // ARINCPARSE_H 214 | -------------------------------------------------------------------------------- /JAERO/audioburstmskdemodulator.cpp: -------------------------------------------------------------------------------- 1 | #include "audioburstmskdemodulator.h" 2 | 3 | #include 4 | 5 | AudioBurstMskDemodulator::AudioBurstMskDemodulator(QObject *parent) 6 | : BurstMskDemodulator(parent), 7 | m_audioInput(NULL) 8 | { 9 | // 10 | } 11 | 12 | void AudioBurstMskDemodulator::start() 13 | { 14 | BurstMskDemodulator::start(); 15 | if(!settings.zmqAudio) 16 | { 17 | if(m_audioInput)m_audioInput->start(this); 18 | } 19 | } 20 | 21 | void AudioBurstMskDemodulator::stop() 22 | { 23 | if(m_audioInput)m_audioInput->stop(); 24 | BurstMskDemodulator::stop(); 25 | } 26 | 27 | void AudioBurstMskDemodulator::setSettings(Settings _settings) 28 | { 29 | bool wasopen=isOpen(); 30 | stop(); 31 | 32 | //if Fs has changed or the audio device doesnt exist or the input device has changed then need to redo the audio device 33 | if((_settings.Fs!=settings.Fs)||(!m_audioInput)||(_settings.audio_device_in!=settings.audio_device_in)) 34 | { 35 | settings=_settings; 36 | 37 | if(m_audioInput)m_audioInput->deleteLater(); 38 | 39 | //set the format 40 | m_format.setSampleRate(settings.Fs); 41 | m_format.setChannelCount(1); 42 | m_format.setSampleSize(16); 43 | m_format.setCodec("audio/pcm"); 44 | m_format.setByteOrder(QAudioFormat::LittleEndian); 45 | m_format.setSampleType(QAudioFormat::SignedInt); 46 | 47 | //setup 48 | m_audioInput = new QAudioInput(settings.audio_device_in, m_format, this); 49 | m_audioInput->setBufferSize(settings.Fs*settings.buffersizeinsecs);//buffersizeinsecs seconds of buffer 50 | } 51 | settings=_settings; 52 | BurstMskDemodulator::setSettings(settings); 53 | 54 | if(wasopen)start(); 55 | 56 | } 57 | 58 | AudioBurstMskDemodulator::~AudioBurstMskDemodulator() 59 | { 60 | stop(); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /JAERO/audioburstmskdemodulator.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIOBURSTMSKDEMODULATOR_H 2 | #define AUDIOBURSTMSKDEMODULATOR_H 3 | 4 | #include 5 | #include 6 | 7 | #include "burstmskdemodulator.h" 8 | 9 | class AudioBurstMskDemodulator : public BurstMskDemodulator 10 | { 11 | Q_OBJECT 12 | public: 13 | struct Settings : public BurstMskDemodulator::Settings 14 | { 15 | QAudioDeviceInfo audio_device_in; 16 | double buffersizeinsecs; 17 | Settings() 18 | { 19 | audio_device_in=QAudioDeviceInfo::defaultInputDevice(); 20 | buffersizeinsecs=1.0; 21 | } 22 | }; 23 | explicit AudioBurstMskDemodulator(QObject *parent = 0); 24 | ~AudioBurstMskDemodulator(); 25 | void start(); 26 | void stop(); 27 | void setSettings(Settings settings); 28 | private: 29 | Settings settings; 30 | QAudioFormat m_format; 31 | QAudioInput *m_audioInput; 32 | }; 33 | 34 | #endif // AUDIOBURSTMSKDEMODULATOR_H 35 | -------------------------------------------------------------------------------- /JAERO/audioburstoqpskdemodulator.cpp: -------------------------------------------------------------------------------- 1 | #include "audioburstoqpskdemodulator.h" 2 | #include 3 | 4 | AudioBurstOqpskDemodulator::AudioBurstOqpskDemodulator(QObject *parent) 5 | : BurstOqpskDemodulator(parent), 6 | m_audioInput(NULL) 7 | { 8 | demod2=new BurstOqpskDemodulator(this); 9 | demod2->channel_select_other=true; 10 | connect(this,SIGNAL(writeDataSignal(const char*,qint64)),demod2,SLOT(writeDataSlot(const char*,qint64)),Qt::DirectConnection); 11 | 12 | } 13 | 14 | void AudioBurstOqpskDemodulator::start() 15 | { 16 | BurstOqpskDemodulator::start(); 17 | demod2->start(); 18 | if(!settings.zmqAudio) 19 | { 20 | if(m_audioInput)m_audioInput->start(this); 21 | } 22 | } 23 | 24 | void AudioBurstOqpskDemodulator::stop() 25 | { 26 | if(m_audioInput)m_audioInput->stop(); 27 | BurstOqpskDemodulator::stop(); 28 | demod2->stop(); 29 | } 30 | 31 | void AudioBurstOqpskDemodulator::setSettings(Settings _settings) 32 | { 33 | bool wasopen=isOpen(); 34 | stop(); 35 | 36 | //if Fs has changed or the audio device doesnt exist or the input device has changed then need to redo the audio device 37 | if((_settings.Fs!=settings.Fs)||(!m_audioInput)||(_settings.audio_device_in!=settings.audio_device_in)||(_settings.channel_stereo!=settings.channel_stereo)) 38 | { 39 | settings=_settings; 40 | 41 | if(m_audioInput)m_audioInput->deleteLater(); 42 | 43 | //set the format 44 | m_format.setSampleRate(settings.Fs); 45 | if(settings.channel_stereo)m_format.setChannelCount(2); 46 | else m_format.setChannelCount(1); 47 | m_format.setSampleSize(16); 48 | m_format.setCodec("audio/pcm"); 49 | m_format.setByteOrder(QAudioFormat::LittleEndian); 50 | m_format.setSampleType(QAudioFormat::SignedInt); 51 | 52 | //setup 53 | m_audioInput = new QAudioInput(settings.audio_device_in, m_format, this); 54 | m_audioInput->setBufferSize(settings.Fs*settings.buffersizeinsecs);//buffersizeinsecs seconds of buffer 55 | } 56 | settings=_settings; 57 | 58 | BurstOqpskDemodulator::setSettings(settings); 59 | demod2->setSettings(settings); 60 | 61 | if(wasopen)start(); 62 | 63 | } 64 | 65 | AudioBurstOqpskDemodulator::~AudioBurstOqpskDemodulator() 66 | { 67 | stop(); 68 | } 69 | -------------------------------------------------------------------------------- /JAERO/audioburstoqpskdemodulator.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIOBURSTOQPSKDEMODULATOR_H 2 | #define AUDIOBURSTOQPSKDEMODULATOR_H 3 | 4 | #include 5 | #include 6 | 7 | #include "burstoqpskdemodulator.h" 8 | 9 | class AudioBurstOqpskDemodulator : public BurstOqpskDemodulator 10 | { 11 | Q_OBJECT 12 | public: 13 | struct Settings : public BurstOqpskDemodulator::Settings 14 | { 15 | QAudioDeviceInfo audio_device_in; 16 | double buffersizeinsecs; 17 | Settings() 18 | { 19 | audio_device_in=QAudioDeviceInfo::defaultInputDevice(); 20 | buffersizeinsecs=1.0; 21 | } 22 | }; 23 | explicit AudioBurstOqpskDemodulator(QObject *parent = 0); 24 | ~AudioBurstOqpskDemodulator(); 25 | void start(); 26 | void stop(); 27 | void setSettings(Settings settings); 28 | BurstOqpskDemodulator *demod2; 29 | void invalidatesettings(){demod2->invalidatesettings();BurstOqpskDemodulator::invalidatesettings();} 30 | void setSQL(bool state){demod2->setSQL(state);BurstOqpskDemodulator::setSQL(state);} 31 | void setAFC(bool state){demod2->setAFC(state);BurstOqpskDemodulator::setAFC(state);} 32 | void setScatterPointType(ScatterPointType type){demod2->setScatterPointType(type);BurstOqpskDemodulator::setScatterPointType(type);} 33 | private: 34 | Settings settings; 35 | QAudioFormat m_format; 36 | QAudioInput *m_audioInput; 37 | 38 | 39 | }; 40 | 41 | #endif // AUDIOBURSTOQPSKDEMODULATOR_H 42 | -------------------------------------------------------------------------------- /JAERO/audiomskdemodulator.cpp: -------------------------------------------------------------------------------- 1 | #include "audiomskdemodulator.h" 2 | 3 | #include 4 | 5 | AudioMskDemodulator::AudioMskDemodulator(QObject *parent) 6 | : MskDemodulator(parent), 7 | m_audioInput(NULL) 8 | { 9 | // 10 | } 11 | 12 | void AudioMskDemodulator::start() 13 | { 14 | MskDemodulator::start(); 15 | if(!settings.zmqAudio) 16 | { 17 | if(m_audioInput)m_audioInput->start(this); 18 | } 19 | } 20 | 21 | void AudioMskDemodulator::stop() 22 | { 23 | if(m_audioInput)m_audioInput->stop(); 24 | MskDemodulator::stop(); 25 | } 26 | 27 | void AudioMskDemodulator::setSettings(Settings _settings) 28 | { 29 | bool wasopen=isOpen(); 30 | stop(); 31 | 32 | //if Fs has changed or the audio device doesnt exist or the input device has changed then need to redo the audio device 33 | if((_settings.Fs!=settings.Fs)||(!m_audioInput)||(_settings.audio_device_in!=settings.audio_device_in)) 34 | { 35 | settings=_settings; 36 | 37 | if(m_audioInput)m_audioInput->deleteLater(); 38 | 39 | //set the format 40 | m_format.setSampleRate(settings.Fs); 41 | m_format.setChannelCount(1); 42 | m_format.setSampleSize(16); 43 | m_format.setCodec("audio/pcm"); 44 | m_format.setByteOrder(QAudioFormat::LittleEndian); 45 | m_format.setSampleType(QAudioFormat::SignedInt); 46 | 47 | //setup 48 | m_audioInput = new QAudioInput(settings.audio_device_in, m_format, this); 49 | m_audioInput->setBufferSize(settings.Fs*settings.buffersizeinsecs);//buffersizeinsecs seconds of buffer 50 | } 51 | settings=_settings; 52 | MskDemodulator::setSettings(settings); 53 | 54 | if(wasopen)start(); 55 | 56 | } 57 | 58 | AudioMskDemodulator::~AudioMskDemodulator() 59 | { 60 | stop(); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /JAERO/audiomskdemodulator.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIOMSKDEMODULATOR_H 2 | #define AUDIOMSKDEMODULATOR_H 3 | 4 | #include 5 | #include 6 | 7 | #include "mskdemodulator.h" 8 | 9 | class AudioMskDemodulator : public MskDemodulator 10 | { 11 | Q_OBJECT 12 | public: 13 | struct Settings : public MskDemodulator::Settings 14 | { 15 | QAudioDeviceInfo audio_device_in; 16 | double buffersizeinsecs; 17 | Settings() 18 | { 19 | audio_device_in=QAudioDeviceInfo::defaultInputDevice(); 20 | buffersizeinsecs=1.0; 21 | } 22 | }; 23 | explicit AudioMskDemodulator(QObject *parent = 0); 24 | ~AudioMskDemodulator(); 25 | void start(); 26 | void stop(); 27 | void setSettings(Settings settings); 28 | private: 29 | Settings settings; 30 | QAudioFormat m_format; 31 | QAudioInput *m_audioInput; 32 | }; 33 | 34 | #endif // AUDIOMSKDEMODULATOR_H 35 | -------------------------------------------------------------------------------- /JAERO/audiooqpskdemodulator.cpp: -------------------------------------------------------------------------------- 1 | #include "audiooqpskdemodulator.h" 2 | 3 | #include 4 | 5 | AudioOqpskDemodulator::AudioOqpskDemodulator(QObject *parent) 6 | : OqpskDemodulator(parent), 7 | m_audioInput(NULL) 8 | { 9 | // 10 | } 11 | 12 | void AudioOqpskDemodulator::start() 13 | { 14 | OqpskDemodulator::start(); 15 | 16 | if(!settings.zmqAudio) 17 | { 18 | if(m_audioInput)m_audioInput->start(this); 19 | } 20 | 21 | } 22 | 23 | void AudioOqpskDemodulator::stop() 24 | { 25 | if(m_audioInput)m_audioInput->stop(); 26 | OqpskDemodulator::stop(); 27 | } 28 | 29 | void AudioOqpskDemodulator::setSettings(Settings _settings) 30 | { 31 | bool wasopen=isOpen(); 32 | stop(); 33 | 34 | //if Fs has changed or the audio device doesnt exist or the input device has changed then need to redo the audio device 35 | if((_settings.Fs!=settings.Fs)||(!m_audioInput)||(_settings.audio_device_in!=settings.audio_device_in)) 36 | { 37 | settings=_settings; 38 | 39 | if(m_audioInput)m_audioInput->deleteLater(); 40 | 41 | //set the format 42 | m_format.setSampleRate(settings.Fs); 43 | m_format.setChannelCount(1); 44 | m_format.setSampleSize(16); 45 | m_format.setCodec("audio/pcm"); 46 | m_format.setByteOrder(QAudioFormat::LittleEndian); 47 | m_format.setSampleType(QAudioFormat::SignedInt); 48 | 49 | //setup 50 | m_audioInput = new QAudioInput(settings.audio_device_in, m_format, this); 51 | m_audioInput->setBufferSize(settings.Fs*settings.buffersizeinsecs);//buffersizeinsecs seconds of buffer 52 | } 53 | settings=_settings; 54 | 55 | OqpskDemodulator::setSettings(settings); 56 | 57 | if(wasopen)start(); 58 | 59 | } 60 | 61 | AudioOqpskDemodulator::~AudioOqpskDemodulator() 62 | { 63 | stop(); 64 | } 65 | -------------------------------------------------------------------------------- /JAERO/audiooqpskdemodulator.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIOOQPSKDEMODULATOR_H 2 | #define AUDIOOQPSKDEMODULATOR_H 3 | 4 | #include 5 | #include 6 | 7 | #include "oqpskdemodulator.h" 8 | 9 | class AudioOqpskDemodulator : public OqpskDemodulator 10 | { 11 | Q_OBJECT 12 | public: 13 | struct Settings : public OqpskDemodulator::Settings 14 | { 15 | QAudioDeviceInfo audio_device_in; 16 | double buffersizeinsecs; 17 | Settings() 18 | { 19 | audio_device_in=QAudioDeviceInfo::defaultInputDevice(); 20 | buffersizeinsecs=1.0; 21 | } 22 | }; 23 | explicit AudioOqpskDemodulator(QObject *parent = 0); 24 | ~AudioOqpskDemodulator(); 25 | void start(); 26 | void stop(); 27 | void setSettings(Settings settings); 28 | private: 29 | Settings settings; 30 | QAudioFormat m_format; 31 | QAudioInput *m_audioInput; 32 | }; 33 | 34 | #endif // AUDIOOQPSKDEMODULATOR_H 35 | -------------------------------------------------------------------------------- /JAERO/audiooutdevice.cpp: -------------------------------------------------------------------------------- 1 | #include "audiooutdevice.h" 2 | #include 3 | #include 4 | 5 | AudioOutDevice::AudioOutDevice(QObject *parent) 6 | : QIODevice(parent), 7 | m_audioOutput(NULL) 8 | { 9 | setSettings(settings); 10 | clear(); 11 | } 12 | 13 | void AudioOutDevice::clear() 14 | { 15 | circ_buffer.resize(16000); 16 | circ_buffer_head=0; 17 | circ_buffer_tail=circ_buffer.size()/2; 18 | for(int i=0;istart(this); 31 | } 32 | 33 | void AudioOutDevice::stop() 34 | { 35 | if(m_audioOutput)m_audioOutput->stop(); 36 | close(); 37 | } 38 | 39 | void AudioOutDevice::setSettings(Settings _settings) 40 | { 41 | 42 | bool wasopen=isOpen(); 43 | stop(); 44 | 45 | //if Fs has changed or the audio device doesnt exist or the input device has changed then need to redo the audio device 46 | if((_settings.Fs!=settings.Fs)||(!m_audioOutput)||(_settings.audio_device_out!=settings.audio_device_out)) 47 | { 48 | settings=_settings; 49 | 50 | if(m_audioOutput)m_audioOutput->deleteLater(); 51 | 52 | //set the format 53 | m_format.setSampleRate(settings.Fs); 54 | m_format.setChannelCount(1); 55 | m_format.setSampleSize(16); 56 | m_format.setCodec("audio/pcm"); 57 | m_format.setByteOrder(QAudioFormat::LittleEndian); 58 | m_format.setSampleType(QAudioFormat::SignedInt); 59 | 60 | //setup 61 | m_audioOutput = new QAudioOutput(settings.audio_device_out, m_format, this); 62 | m_audioOutput->setBufferSize(settings.Fs*settings.buffersizeinsecs);//buffersizeinsecs seconds of buffer. this is ignored for a write device. 63 | } 64 | settings=_settings; 65 | 66 | clear(); 67 | 68 | if(wasopen)start(); 69 | } 70 | 71 | AudioOutDevice::~AudioOutDevice() 72 | { 73 | stop(); 74 | } 75 | 76 | qint64 AudioOutDevice::readData(char *data, qint64 maxlen) 77 | { 78 | qint16 *ptr = reinterpret_cast(data); 79 | int numofsamples=(maxlen/sizeof(qint16)); 80 | 81 | int forward=abs(circ_buffer_tail-circ_buffer_head); 82 | int backwards=circ_buffer.size()-forward; 83 | if(circ_buffer_tail>circ_buffer_head) 84 | { 85 | int tmp=forward; 86 | forward=backwards; 87 | backwards=tmp; 88 | } 89 | 90 | //choose the max buffer you wish to process 91 | numofsamples=qMin(forward-1,numofsamples); 92 | 93 | //if we have run out of data return almost nothing 94 | if(numofsamples<1) 95 | { 96 | circ_buffer[circ_buffer_tail]=((double)circ_buffer[circ_buffer_tail])*0.75; 97 | if(maxlen > 2000) 98 | { 99 | for(int i=0;i<2000;i++) 100 | { 101 | *ptr=circ_buffer[circ_buffer_tail]; 102 | ptr++; 103 | } 104 | return 2000; 105 | } 106 | return sizeof(qint16); 107 | } 108 | 109 | //fill in the return data 110 | for(int i=0;i(signed16array.data()); 125 | int numofsamples=(signed16array.size()/sizeof(qint16)); 126 | for(int i=0;icirc_buffer_head) 132 | { 133 | int tmp=forward; 134 | forward=backwards; 135 | backwards=tmp; 136 | } 137 | 138 | //make sure we don't pass the tail 139 | if(backwards>1){circ_buffer_head++;circ_buffer_head%=circ_buffer.size();} 140 | circ_buffer[circ_buffer_head]=*ptr; 141 | 142 | ptr++; 143 | } 144 | } 145 | 146 | qint64 AudioOutDevice::writeData(const char *data, qint64 len) 147 | { 148 | Q_UNUSED(data); 149 | Q_UNUSED(len); 150 | 151 | return 0; 152 | } 153 | 154 | -------------------------------------------------------------------------------- /JAERO/audiooutdevice.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIOOUTDEVICE_H 2 | #define AUDIOOUTDEVICE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class AudioOutDevice : public QIODevice 9 | { 10 | Q_OBJECT 11 | public: 12 | struct Settings 13 | { 14 | QAudioDeviceInfo audio_device_out; 15 | double buffersizeinsecs; 16 | double Fs; 17 | Settings() 18 | { 19 | audio_device_out=QAudioDeviceInfo::defaultOutputDevice(); 20 | buffersizeinsecs=1.0; 21 | Fs=8000; 22 | } 23 | }; 24 | explicit AudioOutDevice(QObject *parent = 0); 25 | ~AudioOutDevice(); 26 | void start(); 27 | void stop(); 28 | void setSettings(Settings settings); 29 | qint64 readData(char *data, qint64 maxlen); 30 | qint64 writeData(const char *data, qint64 len); 31 | public slots: 32 | void audioin(const QByteArray &signed16array); 33 | private: 34 | Settings settings; 35 | QAudioFormat m_format; 36 | QAudioOutput *m_audioOutput; 37 | QVector circ_buffer; 38 | int circ_buffer_head; 39 | int circ_buffer_tail; 40 | void clear(); 41 | 42 | }; 43 | 44 | #endif // AUDIOOUTDEVICE_H 45 | -------------------------------------------------------------------------------- /JAERO/burstmskdemodulator.h: -------------------------------------------------------------------------------- 1 | #ifndef BURSTMSKDEMODULATOR_H 2 | #define BURSTMSKDEMODULATOR_H 3 | 4 | #include 5 | #include "DSP.h" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include "aerol.h" 14 | 15 | #include "fftrwrapper.h" 16 | 17 | typedef FFTrWrapper FFTr; 18 | typedef std::complex cpx_type; 19 | 20 | class CoarseFreqEstimate; 21 | 22 | class BurstMskDemodulator : public QIODevice 23 | { 24 | Q_OBJECT 25 | public: 26 | enum ScatterPointType{ SPT_constellation, SPT_phaseoffseterror, SPT_phaseoffsetest, SPT_None}; 27 | struct Settings 28 | { 29 | int coarsefreqest_fft_power; 30 | double freq_center; 31 | double lockingbw; 32 | double fb; 33 | double Fs; 34 | int symbolspercycle; 35 | double signalthreshold; 36 | bool zmqAudio; 37 | Settings() 38 | { 39 | coarsefreqest_fft_power=13;//2^coarsefreqest_fft_power 40 | freq_center=1000;//Hz 41 | lockingbw=500;//Hz 42 | fb=125;//bps 43 | Fs=8000;//Hz 44 | symbolspercycle=16; 45 | signalthreshold=0.6; 46 | zmqAudio=false; 47 | } 48 | }; 49 | explicit BurstMskDemodulator(QObject *parent); 50 | ~BurstMskDemodulator(); 51 | 52 | void ConnectSinkDevice(QIODevice *datasinkdevice); 53 | void DisconnectSinkDevice(); 54 | 55 | void start(); 56 | void stop(); 57 | qint64 readData(char *data, qint64 maxlen); 58 | qint64 writeData(const char *data, qint64 len); 59 | void setSettings(Settings settings); 60 | void invalidatesettings(); 61 | void setAFC(bool state); 62 | void setSQL(bool state); 63 | void setCPUReduce(bool state); 64 | void setScatterPointType(ScatterPointType type); 65 | double getCurrentFreq(); 66 | private: 67 | 68 | WaveTable mixer_center; 69 | WaveTable mixer2; 70 | 71 | bool sql; 72 | 73 | int spectrumnfft,bbnfft; 74 | 75 | 76 | QVector spectrumcycbuff; 77 | QVector spectrumtmpbuff; 78 | int spectrumcycbuff_ptr; 79 | 80 | double Fs; 81 | double freq_center; 82 | double lockingbw; 83 | double fb; 84 | double symbolspercycle; 85 | double signalthreshold; 86 | 87 | double SamplesPerSymbol; 88 | 89 | FIR *matchedfilter_re; 90 | FIR *matchedfilter_im; 91 | 92 | AGC *agc; 93 | AGC *agc2; 94 | 95 | MSKEbNoMeasure *ebnomeasure; 96 | 97 | MovingAverage *pointmean; 98 | 99 | QVector pointbuff; 100 | int pointbuff_ptr; 101 | 102 | QList tixd; 103 | 104 | DiffDecode diffdecode; 105 | 106 | QVector RxDataBits;//unpacked 107 | 108 | double mse; 109 | 110 | MovingAverage *msema; 111 | 112 | bool afc; 113 | 114 | int scatterpointtype; 115 | 116 | BaceConverter bc; 117 | 118 | QPointer pdatasinkdevice; 119 | 120 | QElapsedTimer timer; 121 | 122 | // trident detector stuff 123 | 124 | //hilbert 125 | QJHilbertFilter hfir; 126 | QVector hfirbuff; 127 | 128 | //delay lines 129 | Delay bt_d1; 130 | Delay< double > bt_ma_diff; 131 | 132 | //MAs 133 | TMovingAverage< std::complex > bt_ma1; 134 | MovingAverage *mav1; 135 | 136 | 137 | //Peak detection 138 | PeakDetector pdet; 139 | 140 | //delay for peak detection alignment 141 | DelayThing< std::complex > d1; 142 | 143 | //delay for trident detection 144 | DelayThing d2; 145 | 146 | //trident shape thing 147 | QVector tridentbuffer; 148 | int tridentbuffer_ptr; 149 | int tridentbuffer_sz; 150 | 151 | int maxvalbin = 0; 152 | double trackfreq = 0; 153 | 154 | //fft for trident 155 | FFTr *fftr; 156 | QVector out_base,out_top; 157 | QVector out_abs_diff; 158 | QVector in; 159 | double maxval; 160 | double vol_gain; 161 | int cntr; 162 | 163 | int startstopstart; 164 | int startstop; 165 | int numPoints; 166 | 167 | const cpx_type imag=cpx_type(0, 1); 168 | WaveTable st_osc; 169 | WaveTable st_osc_half; 170 | 171 | Delay a1; 172 | 173 | double ee; 174 | cpx_type symboltone_averotator; 175 | cpx_type symboltone_rotator; 176 | double carrier_rotation_est; 177 | cpx_type pt_d; 178 | 179 | cpx_type rotator; 180 | double rotator_freq; 181 | 182 | //st 183 | IIR st_iir_resonator; 184 | 185 | Delay delayt8; 186 | 187 | int endRotation; 188 | int startProcessing; 189 | bool dcd; 190 | 191 | DelayThing delayedsmpl; 192 | 193 | bool cpuReduce; 194 | 195 | signals: 196 | void ScatterPoints(const QVector &buffer); 197 | void SymbolPhase(double phase_rad); 198 | void BBOverlapedBuffer(const QVector &buffer); 199 | void OrgOverlapedBuffer(const QVector &buffer); 200 | void Plottables(double freq_est,double freq_center,double bandwidth); 201 | void PeakVolume(double Volume); 202 | void RxData(QByteArray &data);//packed in bytes 203 | void MSESignal(double mse); 204 | void SignalStatus(bool gotasignal); 205 | void WarningTextSignal(const QString &str); 206 | void EbNoMeasurmentSignal(double EbNo); 207 | void SampleRateChanged(double Fs); 208 | void BitRateChanged(double fb,bool burstmode); 209 | void processDemodulatedSoftBits(const QVector &soft_bits); 210 | 211 | 212 | public slots: 213 | void CenterFreqChangedSlot(double freq_center); 214 | void DCDstatSlot(bool dcd); 215 | void dataReceived(const QByteArray &audio, quint32 sampleRate); 216 | 217 | 218 | }; 219 | 220 | 221 | #endif // BURSTMSKDEMODULATOR_H 222 | -------------------------------------------------------------------------------- /JAERO/burstoqpskdemodulator.h: -------------------------------------------------------------------------------- 1 | #ifndef BURSTOQPSKDEMODULATOR_H 2 | #define BURSTOQPSKDEMODULATOR_H 3 | 4 | #include 5 | #include "DSP.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "aerol.h" 13 | 14 | #include "fftrwrapper.h" 15 | 16 | typedef FFTrWrapper FFTr; 17 | typedef std::complex cpx_type; 18 | 19 | class BurstOqpskDemodulator : public QIODevice 20 | { 21 | Q_OBJECT 22 | public: 23 | enum ScatterPointType{ SPT_constellation, SPT_phaseoffseterror, SPT_phaseoffsetest, SPT_None}; 24 | struct Settings 25 | { 26 | int coarsefreqest_fft_power; 27 | double freq_center; 28 | double lockingbw; 29 | double fb; 30 | double Fs; 31 | double signalthreshold; 32 | bool channel_stereo; 33 | bool zmqAudio; 34 | Settings() 35 | { 36 | coarsefreqest_fft_power=13;//2^coarsefreqest_fft_power 37 | freq_center=8000;//Hz 38 | lockingbw=10500;//Hz 39 | fb=10500;//bps 40 | Fs=48000;//Hz 41 | signalthreshold=0.6; 42 | channel_stereo=false; 43 | zmqAudio=false; 44 | } 45 | }; 46 | explicit BurstOqpskDemodulator(QObject *parent); 47 | ~BurstOqpskDemodulator(); 48 | void setAFC(bool state); 49 | void setSQL(bool state); 50 | void setCPUReduce(bool state); 51 | void setSettings(Settings settings); 52 | void invalidatesettings(); 53 | void ConnectSinkDevice(QIODevice *datasinkdevice); 54 | void DisconnectSinkDevice(); 55 | void start(); 56 | void stop(); 57 | qint64 readData(char *data, qint64 maxlen); 58 | qint64 writeData(const char *data, qint64 len); 59 | double getCurrentFreq(); 60 | void setScatterPointType(ScatterPointType type); 61 | 62 | //--L/R channel selection 63 | bool channel_select_other; 64 | 65 | signals: 66 | void ScatterPoints(const QVector &buffer); 67 | void OrgOverlapedBuffer(const QVector &buffer); 68 | void PeakVolume(double Volume); 69 | void SampleRateChanged(double Fs); 70 | void BitRateChanged(double fb, bool burstmode); 71 | void Plottables(double freq_est,double freq_center,double bandwidth); 72 | void BBOverlapedBuffer(const QVector &buffer); 73 | void MSESignal(double mse); 74 | void SignalStatus(bool gotasignal); 75 | void WarningTextSignal(const QString &str); 76 | void EbNoMeasurmentSignal(double EbNo); 77 | void writeDataSignal(const char *data, qint64 len); 78 | void processDemodulatedSoftBits(const QVector &soft_bits); 79 | 80 | 81 | private: 82 | 83 | const cpx_type imag=cpx_type(0, 1); 84 | 85 | QPointer pdatasinkdevice; 86 | bool afc; 87 | bool sql; 88 | int scatterpointtype; 89 | 90 | double Fs; 91 | double freq_center; 92 | double lockingbw; 93 | double fb; 94 | double signalthreshold; 95 | 96 | double SamplesPerSymbol; 97 | bool insertpreamble; 98 | 99 | WaveTable mixer2; 100 | 101 | QVector spectrumcycbuff; 102 | int spectrumcycbuff_ptr; 103 | int spectrumnfft; 104 | 105 | QVector bbcycbuff; 106 | QVector bbtmpbuff; 107 | int bbcycbuff_ptr; 108 | int bbnfft; 109 | 110 | QVector pointbuff; 111 | int pointbuff_ptr; 112 | 113 | QElapsedTimer timer; 114 | 115 | //--symbol timing detection 116 | AGC *agc; 117 | 118 | //hilbert 119 | QJHilbertFilter hfir; 120 | QVector hfirbuff; 121 | 122 | //delay lines 123 | Delay< cpx_type > bt_d1; 124 | Delay< double > bt_ma_diff; 125 | 126 | //MAs 127 | TMovingAverage< std::complex > bt_ma1; 128 | MovingAverage *mav1; 129 | 130 | 131 | //Peak detection 132 | PeakDetector pdet; 133 | 134 | //delay for peak detection alignment 135 | DelayThing< std::complex > d1; 136 | 137 | //delay for trident detection 138 | DelayThing d2; 139 | 140 | //trident shape thing 141 | QVector tridentbuffer; 142 | int tridentbuffer_ptr; 143 | int tridentbuffer_sz; 144 | 145 | //fft for trident 146 | FFTr *fftr; 147 | QVector out_base,out_top; 148 | QVector out_abs_diff; 149 | QVector in; 150 | 151 | //-- 152 | 153 | //--demod 154 | 155 | AGC *agc2; 156 | 157 | 158 | FIR *fir_re; 159 | FIR *fir_im; 160 | 161 | //st 162 | Delay delays; 163 | Delay delayt41; 164 | Delay delayt42; 165 | Delay delayt8; 166 | IIR st_iir_resonator; 167 | WaveTable st_osc; 168 | WaveTable st_osc_ref; 169 | WaveTable st_osc_quarter; 170 | Delay a1; 171 | double ee; 172 | cpx_type symboltone_averotator; 173 | double carrier_rotation_est; 174 | 175 | cpx_type rotator; 176 | double rotator_freq; 177 | 178 | //ct 179 | IIR ct_iir_loopfilter; 180 | 181 | 182 | OQPSKEbNoMeasure *ebnomeasure; 183 | 184 | BaceConverter bc; 185 | QByteArray RxDataBytes;//packed in bytes 186 | QVector RxDataBits;//unpacked soft bits 187 | 188 | 189 | 190 | double mse; 191 | MovingAverage *msema; 192 | 193 | QVector phasepointbuff; 194 | int phasepointbuff_ptr; 195 | 196 | //-- 197 | 198 | 199 | 200 | 201 | DelayThing rotation_bias_delay; 202 | MovingAverage *rotation_bias_ma; 203 | 204 | int startstopstart; 205 | 206 | //old static stuff 207 | cpx_type pt_d; 208 | int yui; 209 | cpx_type sig2_last; 210 | cpx_type symboltone_rotator; 211 | int startstop; 212 | double vol_gain; 213 | int cntr; 214 | double maxval; 215 | 216 | bool channel_stereo; 217 | 218 | bool cpuReduce; 219 | 220 | 221 | 222 | public slots: 223 | void CenterFreqChangedSlot(double freq_center); 224 | void writeDataSlot(const char *data, qint64 len); 225 | void dataReceived(const QByteArray &audio, quint32 sampleRate); 226 | 227 | 228 | }; 229 | 230 | #endif // BURSTOQPSKDEMODULATOR_H 231 | -------------------------------------------------------------------------------- /JAERO/coarsefreqestimate.cpp: -------------------------------------------------------------------------------- 1 | #include "coarsefreqestimate.h" 2 | #include 3 | #include 4 | 5 | CoarseFreqEstimate::CoarseFreqEstimate(QObject *parent) : QObject(parent) 6 | { 7 | coarsefreqest_fft_power=13; 8 | lockingbw=500;//Hz 9 | fb=125; 10 | Fs=8000;//Hz 11 | 12 | nfft=pow(2,coarsefreqest_fft_power); 13 | fft = new FFT(nfft,false); 14 | ifft = new FFT(nfft,true); 15 | hzperbin=Fs/((double)nfft); 16 | out.resize(nfft); 17 | in.resize(nfft); 18 | y.resize(nfft); 19 | z.resize(nfft); 20 | startbin=round(lockingbw/hzperbin); 21 | stopbin=nfft-startbin; 22 | expectedpeakbin=round(fb/(2.0*hzperbin)); 23 | emptyingcountdown=1; 24 | 25 | window.resize(nfft); 26 | window.fill(0); 27 | window[0]=1; 28 | for(int i=1;i<=startbin;i++) 29 | { 30 | double val=cos(M_PI_2*((double)i)/((double)startbin)); 31 | val*=val; 32 | if((nfft-i)<0)break; 33 | if(i>=nfft)break; 34 | window[nfft-i]=val; 35 | window[i]=val; 36 | } 37 | } 38 | 39 | void CoarseFreqEstimate::setSettings(int _coarsefreqest_fft_power,double _lockingbw,double _fb,double _Fs) 40 | { 41 | coarsefreqest_fft_power=_coarsefreqest_fft_power; 42 | lockingbw=_lockingbw;//Hz 43 | fb=_fb; 44 | Fs=_Fs;//Hz 45 | delete ifft; 46 | delete fft; 47 | 48 | nfft=pow(2,coarsefreqest_fft_power); 49 | fft = new FFT(nfft,false); 50 | ifft = new FFT(nfft,true); 51 | hzperbin=Fs/((double)nfft); 52 | out.resize(nfft); 53 | in.resize(nfft); 54 | y.resize(nfft); 55 | z.resize(nfft); 56 | startbin=std::max(round(lockingbw/hzperbin),1.0); 57 | stopbin=nfft-startbin; 58 | expectedpeakbin=round(fb/(2.0*hzperbin)); 59 | 60 | 61 | //use a raised cos window to favor signals in the middle rather than to the edges 62 | window.resize(nfft); 63 | window.fill(0); 64 | window[0]=1; 65 | for(int i=1;i<=startbin;i++) 66 | { 67 | double val=cos(M_PI_2*((double)i)/((double)startbin)); 68 | val*=val; 69 | if((nfft-i)<0)break; 70 | if(i>=nfft)break; 71 | window[nfft-i]=val; 72 | window[i]=val; 73 | } 74 | 75 | 76 | } 77 | 78 | CoarseFreqEstimate::~CoarseFreqEstimate() 79 | { 80 | delete ifft; 81 | delete fft; 82 | } 83 | 84 | void CoarseFreqEstimate::bigchange() 85 | { 86 | emptyingcountdown=4; 87 | for(int i=0;i &data) 91 | { 92 | //fft size must be even. 2^n is best 93 | assert(nfft==data.size()); 94 | 95 | //remove high frequencies then square and do fft and shift (0hz bin is at nfft/2) 96 | fft->transform(data,out); 97 | 98 | //what window would be better? 99 | if(fb!=8400)for(int i=startbin;i<=stopbin;i++)out[i]=0;//this one is a boxcar window so can be pulled easily to the sides 100 | else for(int i=0;itransform(out,in); 103 | for(int i=0;itransform(in,out); 105 | for(int i=0;i=z.size()))continue;//jic 118 | double val=0; 119 | for(int j=-1;j<=1;j++) 120 | { 121 | if(((i-expectedpeakbin-j)<0)||((i+expectedpeakbin+j)>=y.size()))continue;//jic 122 | val+=(y[i-expectedpeakbin-j]+y[i+expectedpeakbin+j]); 123 | } 124 | z[i]=val; 125 | if(z[i]>zmax) 126 | { 127 | zmax=z[i]; 128 | zmaxloc=i; 129 | } 130 | } 131 | freq_offset_est=-((double)(zmaxloc-nfft/2))*hzperbin*0.5; 132 | 133 | //emit the result to whoever wants it 134 | if(emptyingcountdown<=0)emit FreqOffsetEstimate(freq_offset_est); 135 | else {emptyingcountdown--;emit FreqOffsetEstimate(0);} 136 | 137 | } 138 | 139 | -------------------------------------------------------------------------------- /JAERO/coarsefreqestimate.h: -------------------------------------------------------------------------------- 1 | #ifndef COARSEFREQESTIMATE_H 2 | #define COARSEFREQESTIMATE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "fftwrapper.h" 8 | 9 | typedef FFTWrapper FFT; 10 | typedef std::complex cpx_type; 11 | 12 | class CoarseFreqEstimate : public QObject 13 | { 14 | Q_OBJECT 15 | public: 16 | explicit CoarseFreqEstimate(QObject *parent = 0); 17 | ~CoarseFreqEstimate(); 18 | void setSettings(int coarsefreqest_fft_power,double lockingbw,double fb,double Fs); 19 | void bigchange(); 20 | signals: 21 | void FreqOffsetEstimate(double freq_offset_est); 22 | public slots: 23 | void ProcessBasebandData(const QVector &data); 24 | private: 25 | FFT *fft; 26 | FFT *ifft; 27 | QVector out; 28 | QVector in; 29 | QVector window; 30 | QVector y; 31 | QVector z; 32 | double nfft; 33 | double Fs; 34 | int coarsefreqest_fft_power; 35 | double hzperbin; 36 | int startbin,stopbin; 37 | double lockingbw; 38 | double fb; 39 | int expectedpeakbin; 40 | double freq_offset_est; 41 | int emptyingcountdown; 42 | }; 43 | 44 | #endif // COARSEFREQESTIMATE_H 45 | -------------------------------------------------------------------------------- /JAERO/compressedaudiodiskwriter.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPRESSEDAUDIODISKWRITER_H 2 | #define COMPRESSEDAUDIODISKWRITER_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | extern "C" 10 | { 11 | #include 12 | } 13 | 14 | class CompressedAudioDiskWriter : public QObject 15 | { 16 | Q_OBJECT 17 | public: 18 | explicit CompressedAudioDiskWriter(QObject *parent = 0); 19 | ~CompressedAudioDiskWriter(); 20 | 21 | void setLogDir(QString dir); 22 | 23 | signals: 24 | public slots: 25 | void audioin(const QByteArray &signed16arraymono); 26 | void Call_progress_Slot(QByteArray infofield); 27 | private slots: 28 | void timeoutslot(); 29 | private: 30 | 31 | bool os_valid; 32 | bool og_valid; 33 | bool op_valid; 34 | bool vi_valid; 35 | bool vc_valid; 36 | bool vd_valid; 37 | bool vb_valid; 38 | 39 | ogg_stream_state os; // take physical pages, weld into a logical stream of packets 40 | ogg_page og; // one Ogg bitstream page. Vorbis packets are inside 41 | ogg_packet op; // one raw packet of data for decode 42 | 43 | vorbis_info vi; // struct that stores all the static vorbis bitstream settings 44 | vorbis_comment vc; // struct that stores all the user comments 45 | 46 | vorbis_dsp_state vd; // central working state for the packet->PCM decoder 47 | vorbis_block vb; // local working space for packet->PCM decode 48 | 49 | QFile outfile; 50 | 51 | int slowdown; 52 | 53 | QTimer *timeout; 54 | 55 | QString logdir; 56 | 57 | void closeFile(); 58 | void openFileForOutput(QString filename); 59 | 60 | QByteArray current_call_progress_infofield; 61 | }; 62 | 63 | #endif // COMPRESSEDAUDIODISKWRITER_H 64 | -------------------------------------------------------------------------------- /JAERO/databasetext.cpp: -------------------------------------------------------------------------------- 1 | #include "databasetext.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | DataBaseText *dbtext=NULL; 8 | 9 | DataBaseTextUser::DataBaseTextUser(QObject *parent ):QObject(parent) 10 | { 11 | if(dbtext==NULL)dbtext=new DataBaseText(parent); 12 | refcounter=0; 13 | map.clear(); 14 | } 15 | 16 | DataBaseTextUser::~DataBaseTextUser() 17 | { 18 | clear(); 19 | } 20 | 21 | void DataBaseTextUser::clear() 22 | { 23 | QList list=map.values(); 24 | for(int i=0;i1) 36 | { 37 | qDebug()<<"Error more than one entry in DataBaseTextUser map"; 38 | map.clear(); 39 | return NULL; 40 | } 41 | DBase *obj = map.value(ref); 42 | map.remove(ref); 43 | return obj; 44 | } 45 | 46 | void DataBaseTextUser::request(const QString &dirname, const QString &AEStext,DBase* userdata) 47 | { 48 | if(userdata==NULL) 49 | { 50 | dbtext->asyncDbLookupFromAES(dirname,AEStext,-1,this,"result"); 51 | return; 52 | } 53 | if(refcounter<0)refcounter=0; 54 | refcounter++;refcounter%=DataBaseTextUser_MAX_PACKETS_IN_QUEUE; 55 | DBase *obj; 56 | while( (obj=map.take(refcounter))!=NULL )delete obj; 57 | map.insert(refcounter,userdata); 58 | emit dbtext->asyncDbLookupFromAES(dirname,AEStext,refcounter,this,"result"); 59 | } 60 | 61 | //------------ 62 | 63 | DataBaseText::DataBaseText(QObject *parent) : QObject(parent) 64 | { 65 | DataBaseWorkerText *worker = new DataBaseWorkerText; 66 | worker->moveToThread(&workerThread); 67 | connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); 68 | connect(this, &DataBaseText::asyncDbLookupFromAES, worker, &DataBaseWorkerText::DbLookupFromAES); 69 | workerThread.start(); 70 | } 71 | 72 | DataBaseText::~DataBaseText() 73 | { 74 | workerThread.quit(); 75 | workerThread.wait(); 76 | } 77 | 78 | //--------------- 79 | 80 | //from here on main worker. WARING not in main thread. 81 | 82 | void DataBaseWorkerText::DbLookupFromAES(const QString &dirname, const QString &AEStext,int userdata,QObject *sender,const char * member) 83 | { 84 | 85 | QStringList values; 86 | 87 | if(cache.maxCost()<300)cache.setMaxCost(300); 88 | 89 | //serve cached entries 90 | QStringList *pvalues=cache.object(AEStext); 91 | if(pvalues) 92 | { 93 | QStringList values=*pvalues; 94 | if(!values.size()) 95 | { 96 | values.push_back("Not found"); 97 | QMetaObject::invokeMethod(sender,member, Qt::QueuedConnection,Q_ARG(bool, false),Q_ARG(int, userdata),Q_ARG(const QStringList&, values)); 98 | return; 99 | } 100 | QMetaObject::invokeMethod(sender,member, Qt::QueuedConnection,Q_ARG(bool, true),Q_ARG(int, userdata),Q_ARG(const QStringList&, values)); 101 | return; 102 | } 103 | 104 | //open db 105 | if(!db.isOpen()) 106 | { 107 | //get a file that kind of matches, ignore case and add a bit of wildcards 108 | QDir dir(dirname); 109 | QStringList files=dir.entryList(QStringList()<<"basestation*.sqb",QDir::Files | QDir::Readable | QDir::NoDotAndDotDot | QDir::NoDot); 110 | QFile file; 111 | //if the user specified location doesn't contain the basestation file then 112 | //fallback and try the application path 113 | if(files.size())file.setFileName(dir.path()+"/"+files[0]); 114 | if(!files.size()||!file.exists()) 115 | { 116 | dir.setPath(QApplication::applicationDirPath()); 117 | files=dir.entryList(QStringList()<<"basestation*.sqb",QDir::Files | QDir::Readable | QDir::NoDotAndDotDot | QDir::NoDot); 118 | if(files.size())file.setFileName(dir.path()+"/"+files[0]); 119 | } 120 | if(!files.size()||!file.exists()) 121 | { 122 | values.push_back("Database file basestation.sqb not found"); 123 | QMetaObject::invokeMethod(sender,member, Qt::QueuedConnection,Q_ARG(bool, false),Q_ARG(int, userdata),Q_ARG(const QStringList&, values)); 124 | return; 125 | } 126 | //try and open the database 127 | db = QSqlDatabase::addDatabase("QSQLITE"); 128 | db.setDatabaseName(file.fileName()); 129 | if (!db.open()) 130 | { 131 | values.push_back("Cant open SQL database"); 132 | QMetaObject::invokeMethod(sender,member, Qt::QueuedConnection,Q_ARG(bool, false),Q_ARG(int, userdata),Q_ARG(const QStringList&, values)); 133 | return; 134 | } 135 | qDebug()<<"db opened ("<(); 165 | for(int k=0;k 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define DataBaseTextUser_MAX_PACKETS_IN_QUEUE 100 17 | 18 | //Only DataBaseTextUser and DBase should be used directly 19 | 20 | class DataBaseWorkerText : public QObject 21 | { 22 | Q_OBJECT 23 | public: 24 | public slots: 25 | void DbLookupFromAES(const QString &dirname, const QString &AEStext,int userdata,QObject *sender,const char * member); 26 | signals: 27 | private: 28 | QCache cache; 29 | QSqlDatabase db; 30 | 31 | }; 32 | 33 | class DataBaseText : public QObject 34 | { 35 | Q_OBJECT 36 | QThread workerThread; 37 | public: 38 | explicit DataBaseText(QObject *parent = 0); 39 | ~DataBaseText(); 40 | signals: 41 | void asyncDbLookupFromAES(const QString &dirname, const QString &AEStext,int userdata,QObject *sender,const char * member); 42 | public slots: 43 | private slots: 44 | }; 45 | 46 | extern DataBaseText *dbtext; 47 | 48 | class DBase 49 | { 50 | 51 | }; 52 | class DataBaseTextUser : public QObject 53 | { 54 | Q_OBJECT 55 | public: 56 | 57 | enum DataBaseSchema 58 | { 59 | ModeS, 60 | ModeSCountry, 61 | Registration, 62 | Manufacturer, 63 | ICAOTypeCode, 64 | Type, 65 | RegisteredOwners 66 | }; 67 | Q_ENUM(DataBaseSchema) 68 | 69 | 70 | DataBaseTextUser(QObject *parent = 0); 71 | ~DataBaseTextUser(); 72 | void clear(); 73 | DBase* getuserdata(int ref); 74 | public slots: 75 | void request(const QString &dirname, const QString &AEStext,DBase* userdata); 76 | signals: 77 | void result(bool ok, int ref, const QStringList &result); 78 | private: 79 | QMap map; 80 | int refcounter; 81 | private slots: 82 | }; 83 | 84 | 85 | 86 | 87 | #endif // DATABASETEXT_H 88 | -------------------------------------------------------------------------------- /JAERO/fftrwrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "fftrwrapper.h" 2 | #include 3 | 4 | template 5 | FFTrWrapper::FFTrWrapper(int nfft, bool kissfft_scaling) 6 | { 7 | this->kissfft_scaling=kissfft_scaling; 8 | this->nfft=nfft; 9 | fft.init(nfft); 10 | } 11 | 12 | template 13 | FFTrWrapper::~FFTrWrapper() 14 | { 15 | 16 | } 17 | 18 | template 19 | void FFTrWrapper::transform(const QVector &in, QVector< std::complex > &out) 20 | { 21 | assert(in.size()==out.size()); 22 | assert(in.size()==nfft); 23 | fft.fft_real(in,out); 24 | 25 | //for forward kissfft sets the remaining conj complex to 0 26 | if(kissfft_scaling)for(int i=out.size()/2+1;i 30 | void FFTrWrapper::transform(const QVector< std::complex > &in, QVector &out) 31 | { 32 | assert(in.size()==out.size()); 33 | assert(in.size()==nfft); 34 | fft.ifft_real(in,out); 35 | 36 | //for forward kissfft scales by nfft 37 | if(kissfft_scaling)for(int i=0;i; 42 | -------------------------------------------------------------------------------- /JAERO/fftrwrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef FFTRWRAPPER_H 2 | #define FFTRWRAPPER_H 3 | 4 | #include 5 | #include 6 | #include "jfft.h" 7 | 8 | template 9 | class FFTrWrapper 10 | { 11 | public: 12 | FFTrWrapper(int nfft,bool kissfft_scaling=true); 13 | ~FFTrWrapper(); 14 | void transform(const QVector &in, QVector< std::complex > &out); 15 | void transform(const QVector< std::complex > &in, QVector &out); 16 | private: 17 | int nfft; 18 | JFFT fft; 19 | bool kissfft_scaling; 20 | }; 21 | 22 | #endif // FFTRWRAPPER_H 23 | -------------------------------------------------------------------------------- /JAERO/fftwrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "fftwrapper.h" 2 | #include 3 | 4 | template 5 | FFTWrapper::FFTWrapper(int nfft, bool inverse,bool kissfft_scaling) 6 | { 7 | this->nfft=nfft; 8 | fft.init(nfft); 9 | this->inverse=inverse; 10 | this->kissfft_scaling=kissfft_scaling; 11 | } 12 | 13 | template 14 | FFTWrapper::~FFTWrapper() 15 | { 16 | } 17 | 18 | template 19 | void FFTWrapper::transform(const QVector< std::complex > &in, QVector< std::complex > &out) 20 | { 21 | assert(in.size()==out.size()); 22 | assert(in.size()==nfft); 23 | for(int i=0;i; 38 | -------------------------------------------------------------------------------- /JAERO/fftwrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef FFTWRAPPER_H 2 | #define FFTWRAPPER_H 3 | 4 | #include 5 | #include 6 | #include "jfft.h" 7 | 8 | //underlying fft still uses the type in the kiss_fft_type in the c stuff 9 | template 10 | class FFTWrapper 11 | { 12 | public: 13 | FFTWrapper(int nfft, bool inverse, bool kissfft_scaling=true); 14 | ~FFTWrapper(); 15 | void transform(const QVector< std::complex > &in, QVector< std::complex > &out); 16 | private: 17 | JFFT fft; 18 | int nfft; 19 | bool inverse; 20 | bool kissfft_scaling; 21 | }; 22 | 23 | #endif // FFTWRAPPER_H 24 | -------------------------------------------------------------------------------- /JAERO/gui_classes/console.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2012 Denis Shienkov 4 | ** Copyright (C) 2012 Laszlo Papp 5 | ** Contact: http://www.qt-project.org/legal 6 | ** 7 | ** This file is part of the QtSerialPort module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL21$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and Digia. For licensing terms and 15 | ** conditions see http://qt.digia.com/licensing. For further information 16 | ** use the contact form at http://qt.digia.com/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 or version 3 as published by the Free 21 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 22 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 23 | ** following information to ensure the GNU Lesser General Public License 24 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 25 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 26 | ** 27 | ** In addition, as a special exception, Digia gives you certain additional 28 | ** rights. These rights are described in the Digia Qt LGPL Exception 29 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 30 | ** 31 | ** $QT_END_LICENSE$ 32 | ** 33 | ****************************************************************************/ 34 | 35 | #include "console.h" 36 | 37 | #include 38 | 39 | #include 40 | 41 | #include 42 | 43 | 44 | 45 | Console::Console(QWidget *parent) 46 | : QPlainTextEdit(parent) 47 | , localEchoEnabled(false) 48 | { 49 | 50 | //or act as a console device 51 | consoledevice = new ConsoleDevice(this); 52 | connect(consoledevice,SIGNAL(PlainData(QByteArray)),this,SLOT(putPlainData(QByteArray))); 53 | 54 | document()->setMaximumBlockCount(1000); 55 | /*QPalette p = palette(); 56 | p.setColor(QPalette::Base, Qt::white);//black); 57 | p.setColor(QPalette::Text, Qt::black);//green); 58 | setPalette(p);*/ 59 | QFont f=font(); 60 | f.setPointSize(12); 61 | setFont(f); 62 | 63 | setReadOnly(true); 64 | 65 | enableupdates=true; 66 | 67 | } 68 | 69 | void Console::setEnableUpdates(bool enable, QString msg) 70 | { 71 | if(!enableupdates)setPlainText(msg); 72 | if(enable==enableupdates)return; 73 | if(!enable) 74 | { 75 | savedstr=toPlainText(); 76 | setPlainText(msg); 77 | setEnabled(false); 78 | } 79 | else 80 | { 81 | setPlainText(savedstr); 82 | setEnabled(true); 83 | } 84 | enableupdates=enable; 85 | } 86 | 87 | void Console::setEnableUpdates(bool enable) 88 | { 89 | if(enable==enableupdates)return; 90 | if(!enable) 91 | { 92 | savedstr=toPlainText(); 93 | setEnabled(false); 94 | } 95 | else 96 | { 97 | setPlainText(savedstr); 98 | moveCursor(QTextCursor::End); 99 | verticalScrollBar()->setValue(verticalScrollBar()->maximum()); 100 | setEnabled(true); 101 | } 102 | enableupdates=enable; 103 | } 104 | 105 | //sort of works but has problems when the top line is deleted, then everything moves up by 1 line. how to fix? 106 | //if someone could do a better job of this that would be good. 107 | void Console::putPlainData(const QByteArray &_data) 108 | { 109 | 110 | QByteArray data=_data; 111 | data.replace((char)22,""); 112 | 113 | if(!enableupdates || data.length() == 0)return; 114 | 115 | const QTextCursor old_cursor = textCursor(); 116 | const int old_scrollbar_value = verticalScrollBar()->value(); 117 | const bool is_scrolled_down = old_scrollbar_value == verticalScrollBar()->maximum(); 118 | 119 | // Move the cursor to the end of the document. 120 | moveCursor(QTextCursor::End); 121 | 122 | // Insert the text at the position of the cursor (which is the end of the document). 123 | textCursor().insertText(QString(data)); 124 | 125 | if (old_cursor.hasSelection() || !is_scrolled_down) 126 | { 127 | // The user has selected text or scrolled away from the bottom: maintain position. 128 | setTextCursor(old_cursor); 129 | verticalScrollBar()->setValue(old_scrollbar_value); 130 | } 131 | else 132 | { 133 | // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. 134 | moveCursor(QTextCursor::End); 135 | verticalScrollBar()->setValue(verticalScrollBar()->maximum()); 136 | } 137 | } 138 | 139 | void Console::setLocalEchoEnabled(bool set) 140 | { 141 | localEchoEnabled = set; 142 | } 143 | 144 | void Console::clear() 145 | { 146 | //savedstr.clear(); 147 | if(!enableupdates)return; 148 | QPlainTextEdit::clear(); 149 | } 150 | 151 | /*void Console::keyPressEvent(QKeyEvent *e) 152 | { 153 | switch (e->key()) { 154 | // case Qt::Key_Backspace: 155 | // case Qt::Key_Left: 156 | // case Qt::Key_Right: 157 | // case Qt::Key_Up: 158 | // case Qt::Key_Down: 159 | // break; 160 | default: 161 | if (localEchoEnabled) 162 | QPlainTextEdit::keyPressEvent(e); 163 | emit getData(e->text().toLocal8Bit()); 164 | } 165 | }*/ 166 | 167 | /*void Console::mousePressEvent(QMouseEvent *e) 168 | { 169 | Q_UNUSED(e) 170 | setFocus(); 171 | } 172 | 173 | void Console::mouseDoubleClickEvent(QMouseEvent *e) 174 | { 175 | Q_UNUSED(e) 176 | } 177 | 178 | void Console::contextMenuEvent(QContextMenuEvent *e) 179 | { 180 | Q_UNUSED(e) 181 | }*/ 182 | -------------------------------------------------------------------------------- /JAERO/gui_classes/console.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2012 Denis Shienkov 4 | ** Copyright (C) 2012 Laszlo Papp 5 | ** Contact: http://www.qt-project.org/legal 6 | ** 7 | ** This file is part of the QtSerialPort module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL21$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and Digia. For licensing terms and 15 | ** conditions see http://qt.digia.com/licensing. For further information 16 | ** use the contact form at http://qt.digia.com/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 or version 3 as published by the Free 21 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 22 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 23 | ** following information to ensure the GNU Lesser General Public License 24 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 25 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 26 | ** 27 | ** In addition, as a special exception, Digia gives you certain additional 28 | ** rights. These rights are described in the Digia Qt LGPL Exception 29 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 30 | ** 31 | ** $QT_END_LICENSE$ 32 | ** 33 | ****************************************************************************/ 34 | 35 | #ifndef CONSOLE_H 36 | #define CONSOLE_H 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | class ConsoleDevice : public QIODevice 43 | { 44 | Q_OBJECT 45 | public: 46 | explicit ConsoleDevice(QObject *parent = 0) : QIODevice(parent) 47 | { 48 | // 49 | } 50 | qint64 readData(char *data, qint64 len) 51 | { 52 | Q_UNUSED(data); 53 | Q_UNUSED(len); 54 | return 0; 55 | } 56 | qint64 writeData(const char *data, qint64 len) 57 | { 58 | ba.clear(); 59 | ba.append(data,len); 60 | emit PlainData(ba); 61 | return len; 62 | } 63 | ~ConsoleDevice() 64 | { 65 | // 66 | } 67 | signals: 68 | void PlainData(const QByteArray &data); 69 | public slots: 70 | private: 71 | QByteArray ba; 72 | }; 73 | 74 | class Console : public QPlainTextEdit 75 | { 76 | Q_OBJECT 77 | 78 | signals: 79 | void getData(const QByteArray &data); 80 | 81 | public: 82 | explicit Console(QWidget *parent = 0); 83 | 84 | void setLocalEchoEnabled(bool set); 85 | 86 | ConsoleDevice *consoledevice; 87 | public slots: 88 | 89 | void clear(); 90 | 91 | void setEnableUpdates(bool enable, QString msg); 92 | void setEnableUpdates(bool enable); 93 | void putPlainData(const QByteArray &data); 94 | //void putEncodedVaricodeData(const QByteArray &data); 95 | 96 | protected: 97 | //virtual void keyPressEvent(QKeyEvent *e); 98 | //virtual void mousePressEvent(QMouseEvent *e); 99 | //virtual void mouseDoubleClickEvent(QMouseEvent *e); 100 | //virtual void contextMenuEvent(QContextMenuEvent *e); 101 | 102 | private: 103 | bool localEchoEnabled; 104 | 105 | bool enableupdates; 106 | QString savedstr; 107 | }; 108 | 109 | #endif // CONSOLE_H 110 | -------------------------------------------------------------------------------- /JAERO/gui_classes/createeditinputdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "createeditinputdialog.h" 2 | #include "ui_createeditinputdialog.h" 3 | 4 | #include 5 | 6 | CreateEditInputDialog::CreateEditInputDialog(QWidget *parent, const QStringList &outputfmts, bool isEdit) : 7 | QDialog(parent), 8 | ui(new Ui::CreateEditInputDialog) 9 | { 10 | ui->setupUi(this); 11 | 12 | ui->comboBoxformat->insertItems(0,outputfmts); 13 | ui->lineEditfeederport->setValidator(new QIntValidator(1, 65535, this)); 14 | ui->groupBox->setTitle(isEdit?"Edit Feeder Entry":"Add Feeder Entry"); 15 | 16 | checkHostAndPort(); 17 | } 18 | 19 | QString CreateEditInputDialog::getFormat() const 20 | { 21 | return ui->comboBoxformat->currentText(); 22 | } 23 | 24 | QString CreateEditInputDialog::getHost() const 25 | { 26 | return ui->lineEditfeederhost->text(); 27 | } 28 | 29 | QString CreateEditInputDialog::getPort() const 30 | { 31 | return ui->lineEditfeederport->text(); 32 | } 33 | 34 | void CreateEditInputDialog::setFormat(const QString &fmt) 35 | { 36 | int idx=ui->comboBoxformat->findText(fmt); 37 | if (idx==-1) idx=ui->comboBoxformat->count()-1; 38 | ui->comboBoxformat->setCurrentIndex(idx); 39 | } 40 | 41 | void CreateEditInputDialog::setHost(const QString &host) 42 | { 43 | ui->lineEditfeederhost->setText(host); 44 | } 45 | 46 | void CreateEditInputDialog::setPort(const QString &port) 47 | { 48 | ui->lineEditfeederport->setText(port); 49 | } 50 | 51 | CreateEditInputDialog::~CreateEditInputDialog() 52 | { 53 | delete ui; 54 | } 55 | 56 | void CreateEditInputDialog::checkHostAndPort() 57 | { 58 | if (ui->lineEditfeederhost->text().size()>0&&ui->lineEditfeederport->text().size()>0) 59 | ui->buttonBox->button(QDialogButtonBox::Save)->setDisabled(false); 60 | else 61 | ui->buttonBox->button(QDialogButtonBox::Save)->setDisabled(true); 62 | } 63 | 64 | void CreateEditInputDialog::on_lineEditfeederhost_cursorPositionChanged(int, int) 65 | { 66 | checkHostAndPort(); 67 | } 68 | 69 | 70 | void CreateEditInputDialog::on_lineEditfeederport_cursorPositionChanged(int, int) 71 | { 72 | checkHostAndPort(); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /JAERO/gui_classes/createeditinputdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef CREATEEDITINPUTDIALOG_H 2 | #define CREATEEDITINPUTDIALOG_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Ui { 8 | class CreateEditInputDialog; 9 | } 10 | 11 | class CreateEditInputDialog : public QDialog 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit CreateEditInputDialog(QWidget *parent = nullptr, const QStringList &outputfmts = {}, bool isEdit = false); 17 | ~CreateEditInputDialog(); 18 | 19 | QString getFormat() const; 20 | QString getHost() const; 21 | QString getPort() const; 22 | 23 | void setFormat(const QString &fmt); 24 | void setHost(const QString &host); 25 | void setPort(const QString &port); 26 | 27 | static bool addEntry(QWidget *parent, QTableWidget *output, const QStringList &outputfmts) 28 | { 29 | CreateEditInputDialog dialog(parent,outputfmts); 30 | dialog.setWindowFlags(Qt::Dialog|Qt::FramelessWindowHint); 31 | 32 | if (dialog.exec() == QDialog::Accepted) 33 | { 34 | int newRow=output->rowCount(); 35 | output->insertRow(newRow); 36 | output->setItem(newRow,0,new QTableWidgetItem(dialog.getFormat())); 37 | output->setItem(newRow,1,new QTableWidgetItem(dialog.getHost())); 38 | output->setItem(newRow,2,new QTableWidgetItem(dialog.getPort())); 39 | 40 | return true; 41 | } 42 | 43 | return false; 44 | } 45 | 46 | static bool editEntry(QWidget *parent, QTableWidget *output, const QStringList &outputfmts, int row) 47 | { 48 | CreateEditInputDialog dialog(parent,outputfmts,true); 49 | dialog.setWindowFlags(Qt::Dialog|Qt::FramelessWindowHint); 50 | dialog.setFormat(output->item(row,0)->text()); 51 | dialog.setHost(output->item(row,1)->text()); 52 | dialog.setPort(output->item(row,2)->text()); 53 | 54 | if (dialog.exec()==QDialog::Accepted) 55 | { 56 | output->setItem(row,0,new QTableWidgetItem(dialog.getFormat())); 57 | output->setItem(row,1,new QTableWidgetItem(dialog.getHost())); 58 | output->setItem(row,2,new QTableWidgetItem(dialog.getPort())); 59 | 60 | return true; 61 | } 62 | 63 | return false; 64 | } 65 | 66 | 67 | private slots: 68 | void on_lineEditfeederhost_cursorPositionChanged(int,int); 69 | void on_lineEditfeederport_cursorPositionChanged(int,int); 70 | 71 | private: 72 | Ui::CreateEditInputDialog *ui; 73 | 74 | void checkHostAndPort(); 75 | }; 76 | 77 | #endif // CREATEEDITINPUTDIALOG_H 78 | -------------------------------------------------------------------------------- /JAERO/gui_classes/createeditinputdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CreateEditInputDialog 4 | 5 | 6 | Qt::WindowModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 395 13 | 150 14 | 15 | 16 | 17 | 18 | 395 19 | 150 20 | 21 | 22 | 23 | 24 | 395 25 | 150 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 10 35 | 110 36 | 371 37 | 32 38 | 39 | 40 | 41 | Qt::Horizontal 42 | 43 | 44 | QDialogButtonBox::Cancel|QDialogButtonBox::Save 45 | 46 | 47 | 48 | 49 | 50 | 10 51 | 10 52 | 371 53 | 91 54 | 55 | 56 | 57 | GroupBox 58 | 59 | 60 | 61 | 62 | 70 63 | 30 64 | 101 65 | 25 66 | 67 | 68 | 69 | 70 | 71 | 72 | 10 73 | 30 74 | 51 75 | 21 76 | 77 | 78 | 79 | Format 80 | 81 | 82 | 83 | 84 | 85 | 50 86 | 60 87 | 221 88 | 21 89 | 90 | 91 | 92 | 93 | 94 | 95 | 10 96 | 60 97 | 31 98 | 21 99 | 100 | 101 | 102 | Host 103 | 104 | 105 | 106 | 107 | 108 | 280 109 | 60 110 | 31 111 | 21 112 | 113 | 114 | 115 | Port 116 | 117 | 118 | 119 | 120 | 121 | 310 122 | 60 123 | 51 124 | 21 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | buttonBox 134 | accepted() 135 | CreateEditInputDialog 136 | accept() 137 | 138 | 139 | 248 140 | 254 141 | 142 | 143 | 157 144 | 274 145 | 146 | 147 | 148 | 149 | buttonBox 150 | rejected() 151 | CreateEditInputDialog 152 | reject() 153 | 154 | 155 | 316 156 | 260 157 | 158 | 159 | 286 160 | 274 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /JAERO/gui_classes/qled.cpp: -------------------------------------------------------------------------------- 1 | #include "qled.h" 2 | 3 | QLed::QLed(QWidget *parent) 4 | : QLabel(parent) 5 | { 6 | setScaledContents(true); 7 | icon.addFile(":/images/green_led.svg",size(),QIcon::Normal,QIcon::On); 8 | icon.addFile(":/images/off_led.svg",size(),QIcon::Normal,QIcon::Off); 9 | icon.addFile(":/images/red_led.svg",size(),QIcon::Active,QIcon::On); 10 | setLED(QIcon::Off); 11 | } 12 | 13 | void QLed::setLED( QIcon::State state, QIcon::Mode mode) 14 | { 15 | setPixmap(icon.pixmap(size(),mode,state)); 16 | } 17 | 18 | QLed::~QLed() 19 | { 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /JAERO/gui_classes/qled.h: -------------------------------------------------------------------------------- 1 | #ifndef QLED_H 2 | #define QLED_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class QLed : public QLabel 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QLed(QWidget *parent = 0); 13 | void setLED( QIcon::State state = QIcon::Off, QIcon::Mode mode = QIcon::Normal ); 14 | ~QLed(); 15 | QIcon icon; 16 | }; 17 | 18 | #endif // QLED_H 19 | -------------------------------------------------------------------------------- /JAERO/gui_classes/qscatterplot.cpp: -------------------------------------------------------------------------------- 1 | #include "qscatterplot.h" 2 | #include 3 | 4 | QScatterPlot::QScatterPlot(QWidget *parent) 5 | : QCustomPlot(parent) 6 | { 7 | 8 | timer.start(); 9 | 10 | addGraph(); 11 | //xAxis->setVisible(false); 12 | //yAxis->setVisible(false); 13 | axisRect()->setAutoMargins(QCP::msNone); 14 | axisRect()->setMargins(QMargins(0,0,0,0)); 15 | 16 | graph(0)->setPen(QPen(Qt::yellow, 0)); 17 | graph(0)->setLineStyle(QCPGraph::lsNone); 18 | graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 3)); 19 | 20 | QLinearGradient plotGradient; 21 | plotGradient.setStart(0, 0); 22 | plotGradient.setFinalStop(0, 350); 23 | plotGradient.setColorAt(0, QColor(80, 80, 80)); 24 | plotGradient.setColorAt(1, QColor(50, 50, 50)); 25 | 26 | setBackground(QBrush(QColor(Qt::black))); 27 | 28 | xAxis->setRange(-2, 2); 29 | yAxis->setRange(-2, 2); 30 | } 31 | 32 | void QScatterPlot::setDisksize(double disksize) 33 | { 34 | graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, disksize)); 35 | } 36 | 37 | void QScatterPlot::setData(const QVector &points) 38 | { 39 | if(timer.elapsed()<50)return; 40 | timer.start(); 41 | x.resize(points.size()); 42 | y.resize(points.size()); 43 | for(int i=0;isetData(x,y); 49 | replot(); 50 | } 51 | 52 | QScatterPlot::~QScatterPlot() 53 | { 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /JAERO/gui_classes/qscatterplot.h: -------------------------------------------------------------------------------- 1 | #ifndef QSCATTERPLOT_H 2 | #define QSCATTERPLOT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef std::complex cpx_type; 10 | 11 | class QScatterPlot : public QCustomPlot 12 | { 13 | Q_OBJECT 14 | public: 15 | explicit QScatterPlot(QWidget *parent = 0); 16 | ~QScatterPlot(); 17 | void setDisksize(double disksize); 18 | public slots: 19 | void setData(const QVector &points); 20 | private: 21 | QVector x; 22 | QVector y; 23 | QElapsedTimer timer; 24 | }; 25 | 26 | #endif // QSCATTERPLOT_H 27 | -------------------------------------------------------------------------------- /JAERO/gui_classes/qspectrumdisplay.cpp: -------------------------------------------------------------------------------- 1 | #include "qspectrumdisplay.h" 2 | #include 3 | #include 4 | 5 | QSpectrumDisplay::QSpectrumDisplay(QWidget *parent) 6 | : QCustomPlot(parent) 7 | { 8 | 9 | fftr = new FFTr(pow(2,SPECTRUM_FFT_POWER)); 10 | addGraph(); 11 | 12 | timer.start(); 13 | 14 | Fs=8000; 15 | 16 | xAxis->setRange(0, Fs/2); 17 | yAxis->setRange(20, 30); 18 | 19 | freq_center=1000; 20 | fb=125; 21 | 22 | yAxis->setVisible(false); 23 | axisRect()->setAutoMargins(QCP::msBottom); 24 | axisRect()->setMargins(QMargins(0,0,1,0)); 25 | 26 | lockingbwbar = new QCPBars(xAxis, yAxis); 27 | #if QCUSTOMPLOT_VERSION >= 0x020000 28 | #else 29 | addPlottable(lockingbwbar); 30 | #endif 31 | 32 | freqmarker = new QCPBars(xAxis, yAxis); 33 | #if QCUSTOMPLOT_VERSION >= 0x020000 34 | #else 35 | addPlottable(freqmarker); 36 | #endif 37 | freqmarker->setWidth(10); 38 | lockingbwbar->setPen(Qt::NoPen); 39 | lockingbwbar->setBrush(QColor(10, 140, 70, 80)); 40 | freqmarker->setPen(Qt::NoPen); 41 | freqmarker->setBrush(QColor(Qt::yellow)); 42 | 43 | 44 | nfft=pow(2,SPECTRUM_FFT_POWER); 45 | hzperbin=Fs/nfft; 46 | 47 | out.resize(pow(2,SPECTRUM_FFT_POWER)); 48 | in.resize(pow(2,SPECTRUM_FFT_POWER)); 49 | 50 | spec_log_abs_vals.resize(pow(2,SPECTRUM_FFT_POWER)/2); 51 | spec_freq_vals.resize(pow(2,SPECTRUM_FFT_POWER)/2); 52 | for(int i=0;isetWidth(500); 69 | 70 | } 71 | 72 | void QSpectrumDisplay::setSampleRate(double samplerate) 73 | { 74 | Fs=samplerate; 75 | xAxis->setRange(0, Fs/2); 76 | hzperbin=Fs/nfft; 77 | for(int i=0;irange().upper; 93 | lockingbwbar->setWidth(bandwidth); 94 | lockingbwbar->setData(lockingbwbar_x, lockingbwbar_y); 95 | 96 | freqmarker_x[0]=freq_est; 97 | freqmarker_y[0]=0.75*(yAxis->range().upper-yAxis->range().lower)+yAxis->range().lower; 98 | freqmarker->setData(freqmarker_x, freqmarker_y); 99 | 100 | if(timer.elapsed()>100) 101 | { 102 | timer.start(); 103 | replot(); 104 | } 105 | } 106 | 107 | void QSpectrumDisplay::setFFTData(const QVector &data) 108 | { 109 | assert(hann_window.size()==data.size()); 110 | for(int i=0;itransform(in,out); 115 | double maxval=0; 116 | double aveval=0; 117 | for(int i=0;imaxval) 121 | { 122 | maxval=spec_log_abs_vals[i]; 123 | } 124 | aveval+=spec_log_abs_vals[i]; 125 | } 126 | aveval/=spec_log_abs_vals.size(); 127 | if((maxval-aveval)<10) 128 | { 129 | maxval=aveval+10.0; 130 | } 131 | 132 | // spec_log_abs_vals=data; 133 | 134 | graph(0)->setData(spec_freq_vals,spec_log_abs_vals); 135 | //yAxis->setRange(yAxis->range().lower*0.9+0.1*(aveval*0.5), yAxis->range().upper*0.9+0.1*(maxval*1.1)); 136 | yAxis->setRange(aveval-2, yAxis->range().upper*0.5+0.5*(maxval+1)); 137 | 138 | lockingbwbar_y[0]=yAxis->range().upper; 139 | lockingbwbar->setData(lockingbwbar_x, lockingbwbar_y); 140 | freqmarker_y[0]=0.75*(yAxis->range().upper-yAxis->range().lower)+yAxis->range().lower; 141 | freqmarker->setData(freqmarker_x, freqmarker_y); 142 | 143 | if(timer.elapsed()>100) 144 | { 145 | timer.start(); 146 | replot(); 147 | } 148 | 149 | } 150 | 151 | void QSpectrumDisplay::mousePressEvent(QMouseEvent *event) 152 | { 153 | if(event->buttons()&Qt::LeftButton) 154 | { 155 | QPoint point=event->pos(); 156 | double cursorX=xAxis->pixelToCoord(point.x()); 157 | if(cursorX>(Fs/2-lockingbwbar->width()/2)) 158 | { 159 | cursorX=(Fs/2-lockingbwbar->width()/2)-1.0; 160 | } 161 | if(cursorX<(lockingbwbar->width()/2)) 162 | { 163 | cursorX=(lockingbwbar->width()/2)+1.0; 164 | } 165 | lockingbwbar_x[0]=cursorX; 166 | lockingbwbar->setData(lockingbwbar_x, lockingbwbar_y); 167 | CenterFreqChanged(cursorX); 168 | replot(); 169 | } 170 | } 171 | 172 | void QSpectrumDisplay::mouseMoveEvent(QMouseEvent *event) 173 | { 174 | if(event->buttons()&Qt::LeftButton) 175 | { 176 | QPoint point=event->pos(); 177 | double cursorX=xAxis->pixelToCoord(point.x()); 178 | if(cursorX>(Fs/2-lockingbwbar->width()/2)) 179 | { 180 | cursorX=(Fs/2-lockingbwbar->width()/2); 181 | } 182 | if(cursorX<(lockingbwbar->width()/2)) 183 | { 184 | cursorX=(lockingbwbar->width()/2)+1.0-1.0; 185 | } 186 | lockingbwbar_x[0]=cursorX; 187 | lockingbwbar->setData(lockingbwbar_x, lockingbwbar_y); 188 | CenterFreqChanged(cursorX); 189 | replot(); 190 | } 191 | 192 | } 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /JAERO/gui_classes/qspectrumdisplay.h: -------------------------------------------------------------------------------- 1 | #ifndef QSPECTRUMDISPLAY_H 2 | #define QSPECTRUMDISPLAY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "fftrwrapper.h" 10 | 11 | typedef FFTrWrapper FFTr; 12 | typedef std::complex cpx_type; 13 | 14 | #include 15 | #include 16 | 17 | #define SPECTRUM_FFT_POWER 13 18 | 19 | class QSpectrumDisplay : public QCustomPlot 20 | { 21 | Q_OBJECT 22 | public: 23 | explicit QSpectrumDisplay(QWidget *parent = 0); 24 | ~QSpectrumDisplay(); 25 | signals: 26 | void CenterFreqChanged(double freq_center); 27 | public slots: 28 | void setPlottables(double freq_est,double freq_center,double bandwidth); 29 | void setFFTData(const QVector &data); 30 | void setSampleRate(double samplerate); 31 | protected: 32 | void mousePressEvent(QMouseEvent *event); 33 | void mouseMoveEvent(QMouseEvent *event); 34 | private: 35 | QCPBars *freqmarker; 36 | QCPBars *lockingbwbar; 37 | FFTr *fftr; 38 | QVector out; 39 | QVector in; 40 | QVector spec_log_abs_vals; 41 | QVector spec_freq_vals; 42 | QVector hann_window; 43 | double nfft; 44 | double Fs; 45 | QVector freqmarker_x, freqmarker_y; 46 | QVector lockingbwbar_x, lockingbwbar_y; 47 | double freq_center; 48 | double fb; 49 | double hzperbin; 50 | QElapsedTimer timer; 51 | private slots: 52 | }; 53 | 54 | #endif // QSPECTRUMDISPLAY_H 55 | -------------------------------------------------------------------------------- /JAERO/gui_classes/settingsdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGSDIALOG_H 2 | #define SETTINGSDIALOG_H 3 | 4 | #include 5 | #include 6 | 7 | #if defined(Q_OS_UNIX) || defined(Q_OS_LUNX) 8 | #define APPDATALOCATIONS QStandardPaths::AppDataLocation 9 | #else 10 | #define APPDATALOCATIONS QStandardPaths::AppLocalDataLocation 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "mqttsubscriber.h" 18 | 19 | extern QString settings_name; 20 | 21 | namespace Ui { 22 | class SettingsDialog; 23 | } 24 | 25 | class SettingsDialog : public QDialog 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | explicit SettingsDialog(QWidget *parent = 0); 31 | ~SettingsDialog(); 32 | void populatesettings(); 33 | 34 | QAudioDeviceInfo audioinputdevice; 35 | QVector donotdisplaysus; 36 | bool dropnontextmsgs; 37 | QString msgdisplayformat; 38 | bool loggingenable; 39 | QString loggingdirectory; 40 | bool widebandwidthenable; 41 | 42 | QString planesfolder; 43 | QString planelookup; 44 | bool beepontextmessage; 45 | bool onlyuselibacars; 46 | 47 | bool set_station_id_enabled; 48 | QString station_id; 49 | 50 | QJsonArray udp_feeders; 51 | bool udp_for_decoded_messages_enabled; 52 | 53 | 54 | QHostAddress tcp_for_ads_messages_address; 55 | quint16 tcp_for_ads_messages_port; 56 | bool tcp_for_ads_messages_enabled; 57 | bool tcp_as_client_enabled; 58 | 59 | bool cpuSaveMode; 60 | bool disableAcarsConsole; 61 | 62 | bool localAudioOutEnabled; 63 | bool zmqAudioOutEnabled; 64 | QString zmqAudioOutBind; 65 | QString zmqAudioOutTopic; 66 | 67 | bool zmqAudioInputEnabled; 68 | QString zmqAudioInputAddress; 69 | QString zmqAudioInputTopic; 70 | 71 | bool disablePlaneLogWindow; 72 | 73 | MqttSubscriber_Settings_Object mqtt_settings_object; 74 | bool mqtt_enable; 75 | 76 | private: 77 | Ui::SettingsDialog *ui; 78 | QStringList outputformats = {"1", "2", "3", "JSON", "JSONdump"}; 79 | void populatepublicvars(); 80 | bool isUniqueFeederHostPort(const QString &host, const QString &port, int row = -1); 81 | int validateOutputFormatIdx(int idx); 82 | 83 | protected: 84 | void accept(); 85 | 86 | private slots: 87 | 88 | void on_lineEditlogdir_editingFinished(); 89 | void on_lineEditplanesfolder_editingFinished(); 90 | void on_checkOutputADSMessageToTCP_stateChanged(int arg1); 91 | void on_newEntryButton_clicked(); 92 | void on_editEntryButton_clicked(); 93 | void on_removeEntryButton_clicked(); 94 | void on_outputListTable_itemSelectionChanged(); 95 | }; 96 | 97 | #endif // SETTINGSDIALOG_H 98 | -------------------------------------------------------------------------------- /JAERO/gui_classes/textinputwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTINPUTWIDGET_H 2 | #define TEXTINPUTWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class TextInputDevice : public QIODevice 13 | { 14 | Q_OBJECT 15 | public: 16 | explicit TextInputDevice(QPlainTextEdit *parent ) : QIODevice(parent) 17 | { 18 | lastchar=0; 19 | str.clear(); 20 | charpos=0; 21 | preamble_ptr=0; 22 | postamble_ptr=0; 23 | emittedeof=false; 24 | idlebytes.push_back((char)0); 25 | //idlebytes.push_back(12); 26 | idlebytes.push_back(22); 27 | 28 | idle_on_eof=false; 29 | 30 | postamble="\n73 NOCALL"; 31 | 32 | preamble1="NOCALL"; 33 | preamble2="\n NOCALL\n"; 34 | } 35 | 36 | int charpos; 37 | 38 | qint64 readData(char *data, qint64 maxlen) 39 | { 40 | 41 | if(!maxlen)return 0; 42 | 43 | //idling bytes 44 | if(idle_on_eof&&(preamble_ptr>=preamble.size())) 45 | { 46 | if(charpos>=str.size()) 47 | { 48 | int cnt=0; 49 | for(;cnt0)//for some reason a few SYN chars are needed right b4 the data 57 | { 58 | int cnt=0; 59 | for(;cnt0;cnt++) 60 | { 61 | data[cnt]=22; 62 | lastchar--; 63 | } 64 | return cnt; 65 | } 66 | 67 | } 68 | 69 | //preamble text 70 | if((charpos==0)&&(preamble_ptr=str.size()&&(postamble_ptr 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /JAERO/images/arrow-up-down-512px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /JAERO/images/beacon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 48 | 53 | 58 | 63 | 68 | 70 | 76 | 83 | 90 | 92 | 94 | 96 | 98 | image/svg+xml 101 | 104 | 107 | 109 | 112 | Openclipart 115 | 117 | 119 | 121 | 124 | 127 | 130 | 133 | 135 | 137 | 139 | 141 | -------------------------------------------------------------------------------- /JAERO/images/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/clear.png -------------------------------------------------------------------------------- /JAERO/images/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/connect.png -------------------------------------------------------------------------------- /JAERO/images/cpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/cpu.png -------------------------------------------------------------------------------- /JAERO/images/disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/disconnect.png -------------------------------------------------------------------------------- /JAERO/images/eighth note.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | eighth note 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | image/svg+xml 18 | 19 | 20 | 21 | 22 | Openclipart 23 | 24 | 25 | Eighth Note (Stem Facing Up) 26 | 2010-10-27T16:06:43 27 | a single stem facing up eighth note 28 | https://openclipart.org/detail/92869/eighth-note-(stem-facing-up)-by-jaschon 29 | 30 | 31 | jaschon 32 | 33 | 34 | 35 | 36 | black and white 37 | eighth 38 | flag 39 | music 40 | music note 41 | musical notation 42 | quaver 43 | sound 44 | staff 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /JAERO/images/export.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 20 | 26 | 30 | 35 | 37 | 39 | 41 | 43 | 45 | image/svg+xml 48 | 51 | 54 | 56 | 59 | Openclipart 62 | 64 | 66 | export icon 69 | 2013-07-15T19:09:27 72 | An export icon 75 | https://openclipart.org/detail/180890/export-icon-by-dibargatin-180890 78 | 80 | 82 | dibargatin 85 | 87 | 89 | 91 | 93 | android 96 | export 99 | icon 102 | 104 | 106 | 108 | 111 | 114 | 117 | 120 | 122 | 124 | 126 | 128 | -------------------------------------------------------------------------------- /JAERO/images/green_cpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/green_cpu.png -------------------------------------------------------------------------------- /JAERO/images/import.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 20 | 26 | 30 | 35 | 37 | 39 | 41 | 43 | 45 | image/svg+xml 48 | 51 | 54 | 56 | 59 | Openclipart 62 | 64 | 66 | import icon 2 69 | 2013-07-15T19:13:16 72 | An import icon 75 | https://openclipart.org/detail/180895/import-icon-2-by-dibargatin-180895 78 | 80 | 82 | dibargatin 85 | 87 | 89 | 91 | 93 | android 96 | icon 99 | import 102 | 104 | 106 | 108 | 111 | 114 | 117 | 120 | 122 | 124 | 126 | 128 | -------------------------------------------------------------------------------- /JAERO/images/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/log.png -------------------------------------------------------------------------------- /JAERO/images/rx.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Layer 1 12 | 13 | RX 14 | 15 | -------------------------------------------------------------------------------- /JAERO/images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/settings.png -------------------------------------------------------------------------------- /JAERO/images/sound-off2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/sound-off2.png -------------------------------------------------------------------------------- /JAERO/images/sound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/images/sound.png -------------------------------------------------------------------------------- /JAERO/images/stopsort-512px.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 19 | 21 | image/svg+xml 22 | 24 | 25 | 26 | 27 | 28 | 30 | 50 | 54 | 59 | 64 | 65 | -------------------------------------------------------------------------------- /JAERO/images/tx.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Layer 1 12 | 13 | TX 14 | 15 | -------------------------------------------------------------------------------- /JAERO/jaero.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/jaero.ico -------------------------------------------------------------------------------- /JAERO/jaero.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/application-exit.png 4 | images/clear.png 5 | images/connect.png 6 | images/disconnect.png 7 | images/settings.png 8 | images/red_led.svg 9 | images/green_led.svg 10 | images/off_led.svg 11 | images/primary-binary.svg 12 | images/primary-modem.svg 13 | images/rx.svg 14 | images/tx.svg 15 | images/eighth note.svg 16 | images/beacon.svg 17 | images/log.png 18 | images/arrow-right-left-512px.svg 19 | images/arrow-up-down-512px.svg 20 | images/stopsort-512px.svg 21 | images/Plane_clip_art.svg 22 | images/globe.svg 23 | sounds/beep.wav 24 | images/export.svg 25 | images/import.svg 26 | images/sound.png 27 | images/sound-off2.png 28 | images/cpu.png 29 | images/green_cpu.png 30 | 31 | 32 | -------------------------------------------------------------------------------- /JAERO/jaero.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "jaero.ico" 2 | -------------------------------------------------------------------------------- /JAERO/jconvolutionalcodec.h: -------------------------------------------------------------------------------- 1 | #ifndef JCONVOLUTIONALCODEC_H 2 | #define JCONVOLUTIONALCODEC_H 3 | 4 | //new viterbi 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | #include "correct.h" 9 | #ifdef __cplusplus 10 | } 11 | #endif 12 | 13 | #include 14 | 15 | #include 16 | 17 | class JConvolutionalCodec : public QObject 18 | { 19 | Q_OBJECT 20 | public: 21 | explicit JConvolutionalCodec(QObject *parent = 0); 22 | ~JConvolutionalCodec(); 23 | void SetCode(int inv_rate, int order, const QVector poly, int paddinglength=24*4); 24 | QVector &Decode_Continuous(QByteArray& soft_bits_in);//0-->-1 128-->0 255-->1 25 | QVector &Decode_Continuous_hard(const QByteArray& soft_bits_in);//0-->1 26 | 27 | QVector &Decode_soft(QByteArray& soft_bits_in, int size);//0-->-1 128-->0 255-->1 28 | QVector &Decode_hard(const QByteArray& soft_bits_in, int size);//0-->1 29 | 30 | QVector &Soft_To_Hard_Convert(const QByteArray& soft_bits_in);//0-->-1 128-->0 255-->1 31 | 32 | QByteArray &Hard_To_Soft_Convert(QByteArray& hard_bits_in);//0-->-1 128-->0 255-->1 33 | 34 | void printbits(QByteArray msg,int nbits=-1); 35 | int getPaddinglength(){return paddinglength;} 36 | signals: 37 | 38 | public slots: 39 | private: 40 | correct_convolutional *convol; 41 | int constraint; 42 | int nparitybits; 43 | int paddinglength; 44 | QByteArray soft_bits_overlap_buffer_uchar; 45 | QVector decoded_bits;//unpacked 46 | QByteArray decoded;//packed tempory storage 47 | }; 48 | 49 | #endif // JCONVOLUTIONALCODEC_H 50 | -------------------------------------------------------------------------------- /JAERO/jserialize.cpp: -------------------------------------------------------------------------------- 1 | #include "jserialize.h" 2 | #include 3 | 4 | bool JSerialize::fromQByteArray(const QByteArray &ba) 5 | { 6 | m_error=false; 7 | const QMetaObject* metaObj = this->metaObject(); 8 | QDataStream ds(ba); 9 | #ifndef J_SERIALIZE_DROP_CLASSNAME 10 | QString rxclassName; 11 | ds>>rxclassName; 12 | QString className = metaObj->className(); 13 | if(rxclassName!=className) 14 | { 15 | qDebug()<<"rx classname doesn't match expected"; 16 | m_error=true; 17 | return false; 18 | } 19 | #endif 20 | for (int i = 1; i < metaObj->propertyCount(); ++i) 21 | { 22 | const char* propertyName = metaObj->property(i).name(); 23 | const QVariant::Type type = metaObj->property(i).type(); 24 | if(type>=QVariant::UserType) 25 | { 26 | qDebug()<<"fromQByteArray: user type"<>value; 37 | } 38 | else 39 | { 40 | QByteArray ba_tmp; 41 | ds>>ba_tmp; 42 | value=ba_tmp; 43 | //for some reasion some easy types fail on value.convert(type) 44 | //not sure why. i think it muxt be a qt issue. so far ones that 45 | //fail are in type QMetaType::Type but not QVariant::Type 46 | switch((QMetaType::Type)type) 47 | { 48 | case QMetaType::UChar: 49 | value=(uchar)ba_tmp[0]; 50 | break; 51 | case QMetaType::Char: 52 | value=(char)ba_tmp[0]; 53 | break; 54 | default: 55 | if(!value.convert(type)) 56 | { 57 | qDebug()<<"can't convert from byte array to"<>value; 66 | #endif 67 | if(!value.isValid()) 68 | { 69 | qDebug()<<"fail fromQByteArray: QVariant not valid"; 70 | m_error=true; 71 | return false; 72 | } 73 | if(!this->setProperty(propertyName,value)) 74 | { 75 | qDebug()<<"fail fromQByteArray: failed to set property"<metaObject(); 87 | QDataStream ds(&ba,QIODevice::WriteOnly); 88 | #ifndef J_SERIALIZE_DROP_CLASSNAME 89 | QString className = metaObj->className(); 90 | ds<propertyCount(); ++i) 93 | { 94 | const char* propertyName = metaObj->property(i).name(); 95 | const QVariant::Type type = metaObj->property(i).type(); 96 | if(type>=QVariant::UserType) 97 | { 98 | qDebug()<<"toQByteArray: user type"<property(propertyName); 103 | if(!value.isValid()) 104 | { 105 | qDebug()<<"fail toQByteArray: QVariant not valid"; 106 | qFatal("fail toQByteArray: QVariant not valid"); 107 | return false; 108 | } 109 | #ifdef J_SERIALIZE_USE_QBYTEARRAY_AS_FORMAT 110 | //exceptions to the QByteArray format 111 | if(J_SERIALIZE_USE_QBYTEARRAY_AS_FORMAT_EXCEPTIONS) 112 | { 113 | ds< 3 | #include 4 | #include "gui_classes/settingsdialog.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QApplication a(argc, argv); 9 | 10 | QApplication::setApplicationName("JAERO"); 11 | QApplication::setApplicationVersion(QString(JAERO_VERSION)); 12 | 13 | QCommandLineParser cmdparser; 14 | cmdparser.setApplicationDescription("Demodulate and decode Satcom ACARS"); 15 | cmdparser.addHelpOption(); 16 | cmdparser.addVersionOption(); 17 | 18 | QCommandLineOption settingsnameoption(QStringList() << "s" << "settings-name",QApplication::translate("main", "Run with setting name ."),QApplication::translate("main", "name")); 19 | settingsnameoption.setDefaultValue(""); 20 | cmdparser.addOption(settingsnameoption); 21 | 22 | cmdparser.process(a); 23 | settings_name=cmdparser.value(settingsnameoption).trimmed(); 24 | if(settings_name.isEmpty()) 25 | { 26 | QApplication::setApplicationDisplayName(QString(JAERO_VERSION)); 27 | settings_name="JAERO"; 28 | } 29 | else 30 | { 31 | QApplication::setApplicationDisplayName(settings_name); 32 | settings_name="JAERO ["+settings_name+"]"; 33 | } 34 | 35 | MainWindow w; 36 | w.show(); 37 | 38 | return a.exec(); 39 | } 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /JAERO/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "audiooqpskdemodulator.h" 9 | #include "audiomskdemodulator.h" 10 | #include "audioburstoqpskdemodulator.h" 11 | #include "audioburstmskdemodulator.h" 12 | #include "gui_classes/settingsdialog.h" 13 | #include "aerol.h" 14 | #include "gui_classes/planelog.h" 15 | #include 16 | #include 17 | #include "sbs1.h" 18 | #include "gui_classes/qled.h" 19 | 20 | #include "databasetext.h" 21 | 22 | #include "arincparse.h" 23 | 24 | #include "audiooutdevice.h" 25 | #include "compressedaudiodiskwriter.h" 26 | #include "zmq_audioreceiver.h" 27 | #include "zmq_audiosender.h" 28 | 29 | #include "mqttsubscriber.h" 30 | 31 | namespace Ui { 32 | class MainWindow; 33 | } 34 | 35 | class MainWindow : public QMainWindow 36 | { 37 | Q_OBJECT 38 | 39 | public: 40 | explicit MainWindow(QWidget *parent = 0); 41 | ~MainWindow(); 42 | 43 | signals: 44 | 45 | private: 46 | enum class LedState{Disable,Off,On,Overload}; 47 | 48 | enum DemodType{NoDemodType,MSK,OQPSK,BURSTOQPSK,BURSTMSK}; 49 | Ui::MainWindow *ui; 50 | AudioMskDemodulator *audiomskdemodulator; 51 | AudioMskDemodulator::Settings audiomskdemodulatorsettings; 52 | QLabel *ebnolabel; 53 | QLabel *freqlabel; 54 | QLabel *sourcelabel; 55 | QUdpSocket *udpsocket; 56 | 57 | //OQPSK add 58 | AudioOqpskDemodulator *audiooqpskdemodulator; 59 | AudioOqpskDemodulator::Settings audiooqpskdemodulatorsettings; 60 | // 61 | 62 | //Burst OQPSK add 63 | AudioBurstOqpskDemodulator *audioburstoqpskdemodulator; 64 | AudioBurstOqpskDemodulator::Settings audioburstoqpskdemodulatorsettings; 65 | // 66 | 67 | //Burst MSK add 68 | AudioBurstMskDemodulator *audioburstmskdemodulator; 69 | AudioBurstMskDemodulator::Settings audioburstmskdemodulatorsettings; 70 | 71 | QList > feeder_udp_socks; 72 | QList feeder_formats; 73 | 74 | //ambe->pcm->vorbis->ogg->disk 75 | QObject *ambe; 76 | AudioOutDevice *audioout; 77 | CompressedAudioDiskWriter *compresseddiskwriter; 78 | 79 | AeroL *aerol; 80 | AeroL *aerol2; 81 | 82 | MqttSubscriber *mqttsubscriber; 83 | 84 | SettingsDialog *settingsdialog; 85 | 86 | SBS1 *sbs1; 87 | 88 | void acceptsettings(); 89 | 90 | PlaneLog *planelog; 91 | 92 | void log(QString &text); 93 | QFile filelog; 94 | QTextStream outlogstream; 95 | 96 | DemodType typeofdemodtouse; 97 | 98 | void selectdemodulatorconnections(DemodType demodtype); 99 | 100 | ArincParse arincparser; 101 | 102 | QSound *beep; 103 | 104 | //ZeroMQ Audio Receiver 105 | ZMQAudioReceiver *zmq_audio_receiver; 106 | ZMQAudioSender *zmq_audio_sender; 107 | 108 | bool last_dcd; 109 | double last_frequency; 110 | double last_EbNo; 111 | 112 | void setLedState(QLed *led, LedState state); 113 | bool formatACARSItem(const ACARSItem &acarsitem, const QString &msgfmt, QString &humantext, bool &hasMessage); 114 | 115 | protected: 116 | void closeEvent(QCloseEvent *event); 117 | 118 | 119 | private slots: 120 | void DataCarrierDetectStatusSlot(bool dcd); 121 | void SignalStatusSlot(bool signal); 122 | void EbNoSlot(double EbNo); 123 | void WarningTextSlot(QString warning); 124 | void PeakVolumeSlot(double Volume); 125 | void PlottablesSlot(double freq_est,double freq_center,double bandwidth); 126 | void AboutSlot(); 127 | void on_comboBoxbps_currentIndexChanged(const QString &arg1); 128 | void on_comboBoxlbw_currentIndexChanged(const QString &arg1); 129 | void on_comboBoxafc_currentIndexChanged(const QString &arg1); 130 | void on_actionCleanConsole_triggered(); 131 | void on_comboBoxdisplay_currentIndexChanged(const QString &arg1); 132 | void on_actionConnectToUDPPort_toggled(bool arg1); 133 | void on_actionRawOutput_triggered(); 134 | void on_action_Settings_triggered(); 135 | void on_action_PlaneLog_triggered(); 136 | void ACARSslot(ACARSItem &acarsitem); 137 | void CChannelAssignmentSlot(CChannelAssignmentItem &item); 138 | void ERRorslot(QString &error); 139 | 140 | // void result(bool ok, int ref, const QStringList &result); 141 | 142 | void on_tabWidget_currentChanged(int index); 143 | void on_actionSound_Out_toggled(bool mute); 144 | void on_actionReduce_CPU_triggered(bool checked); 145 | 146 | void statusToUDPifJSONset(); 147 | 148 | void onMqttConnectionStateChange(MqttSubscriber::ConnectionState state); 149 | 150 | }; 151 | 152 | #endif // MAINWINDOW_H 153 | -------------------------------------------------------------------------------- /JAERO/matlab/jfastfir.m: -------------------------------------------------------------------------------- 1 | clear all; 2 | close all; 3 | actual_input_include(); 4 | actual_output_include(); 5 | expected_input_include(); 6 | expected_output_include(); 7 | assert(numel(actual_input)==numel(expected_input)); 8 | assert(numel(actual_output)==numel(expected_output)); 9 | plot(real(actual_output));hold on; 10 | plot(real(expected_output));hold off; 11 | xlim([2048 numel(actual_output)]) 12 | legend({'actual output','expected output'}); 13 | title('real'); 14 | figure; 15 | plot(imag(actual_output));hold on; 16 | plot(imag(expected_output));hold off; 17 | xlim([2048 numel(actual_output)]) 18 | legend({'actual output','expected output'}); 19 | title('imag'); -------------------------------------------------------------------------------- /JAERO/mqttsubscriber.h: -------------------------------------------------------------------------------- 1 | #ifndef MQTTSUBSCRIBER_H 2 | #define MQTTSUBSCRIBER_H 3 | 4 | #include 5 | #include "qmqtt.h" 6 | #include "acarsitem_converter.h" 7 | 8 | //#define QMQTT_DEBUG_SUBSCRIBER 9 | 10 | const QString QMQTT_DEFAULT_HOST = "example.com"; 11 | const quint16 QMQTT_DEFAULT_PORT = 8883; 12 | const QString QMQTT_DEFAULT_TOPIC = "acars/jaero"; 13 | const bool QMQTT_DEFAULT_ENCRYPTION = true; 14 | const QString QMQTT_DEFAULT_CLIENTID = "changeme_id_make_random"; 15 | const QString QMQTT_DEFAULT_USERNAME = "changeme_unsername"; 16 | const QByteArray QMQTT_DEFAULT_PASSWORD = "changeme_password"; 17 | const bool QMQTT_DEFAULT_SUBSCRIBE = true; 18 | const bool QMQTT_DEFAULT_PUBLISH = false; 19 | 20 | #define QMQTT_SUBSCRIBE_TIME_IN_MS 10000 21 | 22 | class MqttSubscriber_Settings_Object : public JSerialize 23 | { 24 | Q_OBJECT 25 | public: 26 | J_SERIALIZE(QString,host,QMQTT_DEFAULT_HOST) 27 | J_SERIALIZE(quint16,port,QMQTT_DEFAULT_PORT) 28 | J_SERIALIZE(QString,topic,QMQTT_DEFAULT_TOPIC) 29 | J_SERIALIZE(bool,encryption,QMQTT_DEFAULT_ENCRYPTION) 30 | J_SERIALIZE(QString,clientId,QMQTT_DEFAULT_CLIENTID) 31 | J_SERIALIZE(QString,username,QMQTT_DEFAULT_USERNAME) 32 | J_SERIALIZE(QByteArray,password,QMQTT_DEFAULT_PASSWORD) 33 | J_SERIALIZE(bool,subscribe,QMQTT_DEFAULT_SUBSCRIBE) 34 | J_SERIALIZE(bool,publish,QMQTT_DEFAULT_PUBLISH) 35 | }; 36 | 37 | class MqttSubscriber : public QObject 38 | { 39 | Q_OBJECT 40 | public: 41 | 42 | //has QMQTT::ConnectionState enum is a subset of this 43 | enum ConnectionState 44 | { 45 | STATE_INIT = 0, 46 | STATE_CONNECTING, 47 | STATE_CONNECTED, 48 | STATE_DISCONNECTED, 49 | STATE_CONNECTED_SUBSCRIBED=0xFF 50 | }; 51 | Q_ENUM(ConnectionState) 52 | 53 | explicit MqttSubscriber(QObject* parent = NULL); 54 | virtual ~MqttSubscriber(); 55 | public slots: 56 | void setSettings(const MqttSubscriber_Settings_Object &settings); 57 | void connectToHost(const MqttSubscriber_Settings_Object &settings); 58 | void connectToHost(); 59 | void disconnectFromHost(); 60 | void ACARSslot(ACARSItem &acarsitem); 61 | signals: 62 | void ACARSsignal(ACARSItem &acarsitem); 63 | void connectionStateChange(MqttSubscriber::ConnectionState state); 64 | private: 65 | ACARSItem_QObject aco; 66 | MqttSubscriber_Settings_Object settings; 67 | QMQTT::Client *client; 68 | void delay(int delay_ms); 69 | QList client_list; 70 | int messageId; 71 | 72 | //if you subscribe to something you don't 73 | //have access to m_lastSubscriptionState 74 | //still gets set. 75 | bool m_lastSubscriptionState; 76 | QMQTT::ConnectionState m_lastClientConnectionState; 77 | 78 | void updateState(bool subscriptionState); 79 | void updateState(); 80 | 81 | private slots: 82 | void onConnected(); 83 | void onSubscribed(const QString& topic); 84 | void onReceived(const QMQTT::Message& message); 85 | void onSslErrors(const QList& errors); 86 | void onDisconnected(); 87 | void onClientDestroyed(QObject * = nullptr); 88 | void onSubscribeTimeout(); 89 | void onError(const QMQTT::ClientError error); 90 | void onUnsubscribed(const QString& topic); 91 | }; 92 | 93 | #endif // MQTTSUBSCRIBER_H 94 | -------------------------------------------------------------------------------- /JAERO/mskdemodulator.h: -------------------------------------------------------------------------------- 1 | #ifndef MSKDEMODULATOR_H 2 | #define MSKDEMODULATOR_H 3 | 4 | #include 5 | #include "DSP.h" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include "aerol.h" 14 | 15 | 16 | class CoarseFreqEstimate; 17 | 18 | 19 | class MskDemodulator : public QIODevice 20 | { 21 | Q_OBJECT 22 | public: 23 | enum ScatterPointType{ SPT_constellation, SPT_phaseoffseterror, SPT_phaseoffsetest, SPT_None}; 24 | struct Settings 25 | { 26 | int coarsefreqest_fft_power; 27 | double freq_center; 28 | double lockingbw; 29 | double fb; 30 | double Fs; 31 | int symbolspercycle; 32 | double signalthreshold; 33 | bool zmqAudio; 34 | Settings() 35 | { 36 | coarsefreqest_fft_power=13;//2^coarsefreqest_fft_power 37 | freq_center=1000;//Hz 38 | lockingbw=900;//Hz 39 | fb=600;//bps 40 | Fs=48000;//Hz 41 | symbolspercycle=16; 42 | signalthreshold=0.5; 43 | zmqAudio=false; 44 | } 45 | }; 46 | explicit MskDemodulator(QObject *parent); 47 | ~MskDemodulator(); 48 | 49 | 50 | void ConnectSinkDevice(QIODevice *datasinkdevice); 51 | void DisconnectSinkDevice(); 52 | 53 | 54 | void start(); 55 | void stop(); 56 | qint64 readData(char *data, qint64 maxlen); 57 | qint64 writeData(const char *data, qint64 len); 58 | void setSettings(Settings settings); 59 | void invalidatesettings(); 60 | void setAFC(bool state); 61 | void setSQL(bool state); 62 | void setCPUReduce(bool state); 63 | void setScatterPointType(ScatterPointType type); 64 | double getCurrentFreq(); 65 | private: 66 | WaveTable mixer_center; 67 | WaveTable mixer2; 68 | WaveTable st_osc; 69 | 70 | int spectrumnfft,bbnfft; 71 | 72 | QVector bbcycbuff; 73 | QVector bbtmpbuff; 74 | int bbcycbuff_ptr; 75 | 76 | QVector spectrumcycbuff; 77 | QVector spectrumtmpbuff; 78 | int spectrumcycbuff_ptr; 79 | 80 | CoarseFreqEstimate *coarsefreqestimate; 81 | 82 | double Fs; 83 | double freq_center; 84 | double lockingbw; 85 | double fb; 86 | double signalthreshold; 87 | 88 | double SamplesPerSymbol; 89 | 90 | FIR *matchedfilter_re; 91 | FIR *matchedfilter_im; 92 | 93 | AGC *agc; 94 | 95 | MSKEbNoMeasure *ebnomeasure; 96 | 97 | MovingAverage *pointmean; 98 | 99 | int lastindex; 100 | 101 | QVector pointbuff; 102 | int pointbuff_ptr; 103 | 104 | 105 | DiffDecode diffdecode; 106 | 107 | QVector RxDataBits;//unpacked 108 | 109 | double mse; 110 | 111 | MovingAverage *msema; 112 | 113 | bool afc; 114 | 115 | bool sql; 116 | 117 | int scatterpointtype; 118 | 119 | QVector singlepointphasevector; 120 | 121 | BaceConverter bc; 122 | 123 | QPointer pdatasinkdevice; 124 | 125 | QElapsedTimer timer; 126 | 127 | double ee; 128 | cpx_type pt_d; 129 | 130 | IIR st_iir_resonator; 131 | 132 | MovingAverage *marg; 133 | DelayThing dt; 134 | 135 | DelayThing delayedsmpl; 136 | Delay delayt8; 137 | 138 | bool dcd; 139 | 140 | double correctionfactor; 141 | 142 | int coarseCounter; 143 | bool cpuReduce; 144 | 145 | Settings last_applied_settings; 146 | 147 | signals: 148 | void ScatterPoints(const QVector &buffer); 149 | void SymbolPhase(double phase_rad); 150 | void BBOverlapedBuffer(const QVector &buffer); 151 | void OrgOverlapedBuffer(const QVector &buffer); 152 | void Plottables(double freq_est,double freq_center,double bandwidth); 153 | void PeakVolume(double Volume); 154 | void processDemodulatedSoftBits(const QVector &soft_bits); 155 | void RxData(const QByteArray &data);//packed in bytes 156 | void MSESignal(double mse); 157 | void SignalStatus(bool gotasignal); 158 | void WarningTextSignal(const QString &str); 159 | void EbNoMeasurmentSignal(double EbNo); 160 | void SampleRateChanged(double Fs); 161 | void BitRateChanged(double fb,bool burstmode); 162 | public slots: 163 | void FreqOffsetEstimateSlot(double freq_offset_est); 164 | void CenterFreqChangedSlot(double freq_center); 165 | void DCDstatSlot(bool dcd); 166 | void dataReceived(const QByteArray &audio, quint32 sampleRate); 167 | 168 | 169 | }; 170 | 171 | #endif // MSKDEMODULATOR_H 172 | -------------------------------------------------------------------------------- /JAERO/oqpskdemodulator.h: -------------------------------------------------------------------------------- 1 | #ifndef OQPSKDEMODULATOR_H 2 | #define OQPSKDEMODULATOR_H 3 | 4 | #include 5 | #include "DSP.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "coarsefreqestimate.h" 12 | #include 13 | #include "aerol.h" 14 | 15 | class OqpskDemodulator : public QIODevice 16 | { 17 | Q_OBJECT 18 | public: 19 | enum ScatterPointType{ SPT_constellation, SPT_phaseoffseterror, SPT_phaseoffsetest, SPT_None}; 20 | struct Settings 21 | { 22 | int coarsefreqest_fft_power; 23 | double freq_center; 24 | double lockingbw; 25 | double fb; 26 | double Fs; 27 | double signalthreshold; 28 | bool zmqAudio; 29 | Settings() 30 | { 31 | coarsefreqest_fft_power=14;//13;//2^coarsefreqest_fft_power 32 | freq_center=8000;//Hz 33 | lockingbw=10500;//Hz 34 | fb=10500;//bps 35 | Fs=48000;//Hz 36 | signalthreshold=0.65;//0.6; 37 | zmqAudio=false; 38 | } 39 | }; 40 | explicit OqpskDemodulator(QObject *parent); 41 | ~OqpskDemodulator(); 42 | void setAFC(bool state); 43 | void setSQL(bool state); 44 | void setCPUReduce(bool state); 45 | void setSettings(Settings settings); 46 | void invalidatesettings(); 47 | void ConnectSinkDevice(QIODevice *datasinkdevice); 48 | void DisconnectSinkDevice(); 49 | void start(); 50 | void stop(); 51 | qint64 readData(char *data, qint64 maxlen); 52 | qint64 writeData(const char *data, qint64 len); 53 | double getCurrentFreq(); 54 | void setScatterPointType(ScatterPointType type); 55 | signals: 56 | void ScatterPoints(const QVector &buffer); 57 | void OrgOverlapedBuffer(const QVector &buffer); 58 | void PeakVolume(double Volume); 59 | void SampleRateChanged(double Fs); 60 | void BitRateChanged(double fb,bool burstmode); 61 | void Plottables(double freq_est,double freq_center,double bandwidth); 62 | void BBOverlapedBuffer(const QVector &buffer); 63 | void MSESignal(double mse); 64 | void SignalStatus(bool gotasignal); 65 | void WarningTextSignal(const QString &str); 66 | void EbNoMeasurmentSignal(double EbNo); 67 | void processDemodulatedSoftBits(const QVector &soft_bits); 68 | 69 | private: 70 | QPointer pdatasinkdevice; 71 | bool afc; 72 | bool sql; 73 | int scatterpointtype; 74 | 75 | QVector spectrumcycbuff; 76 | int spectrumcycbuff_ptr; 77 | int spectrumnfft; 78 | 79 | QVector bbcycbuff; 80 | QVector bbtmpbuff; 81 | int bbcycbuff_ptr; 82 | int bbnfft; 83 | 84 | QVector pointbuff; 85 | int pointbuff_ptr; 86 | 87 | QElapsedTimer timer; 88 | 89 | double Fs; 90 | double freq_center; 91 | double lockingbw; 92 | double fb; 93 | double signalthreshold; 94 | 95 | double SamplesPerSymbol; 96 | 97 | FIR *fir_re; 98 | FIR *fir_im; 99 | 100 | //st 101 | Delay delays; 102 | Delay delayt41; 103 | Delay delayt42; 104 | Delay delayt8; 105 | IIR st_iir_resonator; 106 | WaveTable st_osc; 107 | WaveTable st_osc_ref; 108 | 109 | //ct 110 | IIR ct_iir_loopfilter; 111 | 112 | WaveTable mixer_center; 113 | WaveTable mixer2; 114 | 115 | CoarseFreqEstimate *coarsefreqestimate; 116 | 117 | 118 | double mse; 119 | MSEcalc *msecalc; 120 | 121 | QVector phasepointbuff; 122 | int phasepointbuff_ptr; 123 | 124 | AGC *agc; 125 | 126 | OQPSKEbNoMeasure *ebnomeasure; 127 | 128 | BaceConverter bc; 129 | QByteArray RxDataBytes;//packed in bytes 130 | QVector RxDataBits;//unpacked 131 | 132 | 133 | MovingAverage *marg; 134 | DelayThing dt; 135 | 136 | double ee; 137 | 138 | bool dcd; 139 | JFastFir fir_pre; 140 | WaveTable mixer_fir_pre; 141 | 142 | int coarseCounter; 143 | bool cpuReduce; 144 | 145 | 146 | public slots: 147 | void FreqOffsetEstimateSlot(double freq_offset_est); 148 | void CenterFreqChangedSlot(double freq_center); 149 | void DCDstatSlot(bool _dcd); 150 | void dataReceived(const QByteArray &audio, quint32 sampleRate); 151 | 152 | }; 153 | 154 | #endif // OQPSKDEMODULATOR_H 155 | -------------------------------------------------------------------------------- /JAERO/sbs1.cpp: -------------------------------------------------------------------------------- 1 | #include "sbs1.h" 2 | #include 3 | 4 | SBS1::SBS1(QObject *parent) 5 | : QObject(parent) 6 | { 7 | tcpserver=new Tcpserver(this); 8 | tcpclient=new Tcpclient(this); 9 | running=false; 10 | } 11 | 12 | void SBS1::starttcpconnection(const QHostAddress &address, quint16 port, bool behaveasclient) 13 | { 14 | static bool lastbehaveasclient=!behaveasclient; 15 | if(!running)lastbehaveasclient=!behaveasclient; 16 | if(lastbehaveasclient!=behaveasclient) 17 | { 18 | stoptcpconnection(); 19 | } 20 | if(behaveasclient) 21 | { 22 | if(lastbehaveasclient!=behaveasclient) 23 | { 24 | disconnect(this, SIGNAL(SendBAViaTCP(QByteArray&)), 0, 0); 25 | connect(this,SIGNAL(SendBAViaTCP(QByteArray&)),tcpclient,SLOT(SendBAToTCPServer(QByteArray&))); 26 | } 27 | tcpclient->startclient(address,port); 28 | } 29 | else 30 | { 31 | if(lastbehaveasclient!=behaveasclient) 32 | { 33 | disconnect(this, SIGNAL(SendBAViaTCP(QByteArray&)), 0, 0); 34 | connect(this,SIGNAL(SendBAViaTCP(QByteArray&)),tcpserver,SLOT(SendBAToAllTCPClients(QByteArray&))); 35 | } 36 | tcpserver->startserver(address,port); 37 | } 38 | lastbehaveasclient=behaveasclient; 39 | running=true; 40 | } 41 | 42 | void SBS1::stoptcpconnection() 43 | { 44 | disconnect(this, SIGNAL(SendBAViaTCP(QByteArray&)), 0, 0); 45 | tcpserver->stopserver(); 46 | tcpclient->stopclient(); 47 | running=false; 48 | } 49 | 50 | void SBS1::DownlinkBasicReportGroupSlot(DownlinkBasicReportGroup &message) 51 | { 52 | //MSG,3,,,AES,,,,,,Call,ALT(int),,,LAT(float),LONG(float),,,0,0,0,0 53 | QByteArray ba=(((QString)"").sprintf("MSG,3,,,%06X,,,,,,%s,%d,,,%f,%f,,,0,0,0,0\n",message.AESID,message.downlinkheader.flightid.toLatin1().data(),qRound(message.altitude),message.latitude,message.longitude)).toLatin1(); 54 | SendBAViaTCP(ba); 55 | } 56 | 57 | void SBS1::DownlinkEarthReferenceGroupSlot(DownlinkEarthReferenceGroup &message) 58 | { 59 | if(!message.truetrack_isvalid)return; 60 | //MSG,3,,,AES,,,,,,Call,,GroundSpeed(int),TrueTrack(int),,,VerticalRate(int),,0,0,0,0 61 | QByteArray ba=(((QString)"").sprintf("MSG,3,,,%06X,,,,,,%s,,%d,%d,,,%d,,0,0,0,0\n",message.AESID,message.downlinkheader.flightid.toLatin1().data(),qRound(message.groundspeed),qRound(message.truetrack),qRound(message.verticalrate))).toLatin1(); 62 | SendBAViaTCP(ba); 63 | } 64 | 65 | 66 | void SBS1::DownlinkGroupsSlot(DownlinkGroups &groups) 67 | { 68 | if(!groups.isValid())return; 69 | double ts_min=qFloor(groups.adownlinkbasicreportgroup.time_stamp/60.0); 70 | double ts_sec=qFloor(groups.adownlinkbasicreportgroup.time_stamp-ts_min*60.0); 71 | double ts_ms=qFloor((groups.adownlinkbasicreportgroup.time_stamp-ts_min*60.0-ts_sec)*1000.0); 72 | QDateTime now=QDateTime::currentDateTimeUtc(); 73 | QDateTime ts=now; 74 | ts.setTime(QTime(now.time().hour(),ts_min,ts_sec,ts_ms)); 75 | if(ts.secsTo(now)<-1800)ts=ts.addSecs(-3600); 76 | if(ts.secsTo(now)>1800)ts=ts.addSecs(3600); 77 | 78 | 79 | if(qAbs(ts.secsTo(now))>900)//15mins 80 | { 81 | qDebug()<<"Time way out. Check your clock. Dropping packet"; 82 | return; 83 | } 84 | //MSG,3,5,276,4010E9,10088,[2008/11/28,14:53:49.986,2008/11/28,14:58:51.153],,28000,,,53.02551,-2.91389,,,0,0,0,0 85 | //2008/11/28,14:58:51.153,2008/11/28,14:58:51.153 (ts,now) 86 | QByteArray datesandtimestr=((QString)ts.toString("yyyy/MM/dd,hh:mm:ss.zzz")+","+now.toString("yyyy/MM/dd,hh:mm:ss.zzz")).toLatin1(); 87 | //qDebug()< 5 | #include "tcpserver.h" 6 | #include "tcpclient.h" 7 | #include "arincparse.h" 8 | 9 | class SBS1 : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit SBS1(QObject *parent = 0); 14 | void starttcpconnection(const QHostAddress &address, quint16 port, bool behaveasclient); 15 | void stoptcpconnection(); 16 | signals: 17 | void SendBAViaTCP(QByteArray &ba); 18 | public slots: 19 | void DownlinkBasicReportGroupSlot(DownlinkBasicReportGroup &message); 20 | void DownlinkEarthReferenceGroupSlot(DownlinkEarthReferenceGroup &message); 21 | void DownlinkGroupsSlot(DownlinkGroups &groups); 22 | private: 23 | Tcpserver *tcpserver; 24 | Tcpclient *tcpclient; 25 | bool running; 26 | }; 27 | 28 | #endif // SBS1_H 29 | -------------------------------------------------------------------------------- /JAERO/sounds/beep.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/JAERO/sounds/beep.wav -------------------------------------------------------------------------------- /JAERO/tcpclient.cpp: -------------------------------------------------------------------------------- 1 | #include "tcpclient.h" 2 | //#include 3 | 4 | Tcpclient::Tcpclient(QObject *parent) 5 | : QTcpSocket(parent) 6 | { 7 | connectiontimer = new QTimer(this); 8 | connect(connectiontimer, SIGNAL(timeout()), this, SLOT(connectiontimerslot())); 9 | socketState=UnconnectedState; 10 | connect(this,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(stateChangedSlot(QAbstractSocket::SocketState))); 11 | stopclient(); 12 | currentaddress.setAddress(QHostAddress::Null); 13 | currentport=0; 14 | } 15 | 16 | Tcpclient::~Tcpclient() 17 | { 18 | stopclient(); 19 | } 20 | 21 | void Tcpclient::stopclient() 22 | { 23 | connectiontimer->stop(); 24 | abort(); 25 | close(); 26 | } 27 | 28 | void Tcpclient::startclient(const QHostAddress &address, quint16 port) 29 | { 30 | if(currentaddress==address&¤tport==port&&socketState==ConnectedState) 31 | { 32 | // qDebug()<<"all ready connected"; 33 | return; 34 | } 35 | stopclient(); 36 | if(address==QHostAddress::Null || port==0) 37 | { 38 | currentaddress.setAddress(QHostAddress::Null); 39 | currentport=0; 40 | return; 41 | } 42 | // qDebug()<<"trying to connect to port"<start(30000); 47 | } 48 | 49 | void Tcpclient::SendBAToTCPServer(QByteArray &ba) 50 | { 51 | if(!isOpen())return; 52 | write(ba); 53 | } 54 | 55 | void Tcpclient::connectiontimerslot() 56 | { 57 | // qDebug()<<"connectiontimerslot"; 58 | if(socketState==ConnectedState)return; 59 | startclient(currentaddress,currentport); 60 | } 61 | 62 | void Tcpclient::stateChangedSlot(QAbstractSocket::SocketState _socketState) 63 | { 64 | socketState=_socketState; 65 | // qDebug()< 5 | #include 6 | #include 7 | #include 8 | 9 | class Tcpclient : public QTcpSocket 10 | { 11 | Q_OBJECT 12 | public: 13 | Tcpclient(QObject * parent = 0); 14 | ~Tcpclient(); 15 | void startclient(const QHostAddress &address = QHostAddress::LocalHost, quint16 port = 30003); 16 | void stopclient(); 17 | public slots: 18 | void SendBAToTCPServer(QByteArray &ba); 19 | protected: 20 | private: 21 | QHostAddress currentaddress; 22 | quint16 currentport; 23 | QTimer *connectiontimer; 24 | QAbstractSocket::SocketState socketState; 25 | private slots: 26 | void connectiontimerslot(); 27 | void stateChangedSlot(QAbstractSocket::SocketState _socketState); 28 | }; 29 | 30 | #endif // TCPCLIENT_H 31 | -------------------------------------------------------------------------------- /JAERO/tcpserver.cpp: -------------------------------------------------------------------------------- 1 | #include "tcpserver.h" 2 | 3 | //Jonti 2016 4 | 5 | //---------------------- 6 | //one socket per client 7 | //---------------------- 8 | TcpSocketCustom::TcpSocketCustom(QObject *parent) 9 | : QTcpSocket(parent) 10 | { 11 | connect(this,SIGNAL(disconnected()),this,SLOT(ClientDisconnected())); 12 | connect(this,SIGNAL(readyRead()),this,SLOT(dataavail())); 13 | } 14 | TcpSocketCustom::~TcpSocketCustom() 15 | { 16 | disconnectFromHost(); 17 | } 18 | void TcpSocketCustom::Disconnect() 19 | { 20 | disconnectFromHost(); 21 | } 22 | void TcpSocketCustom::ClientDisconnected() 23 | { 24 | // qDebug("Client disconnected"); 25 | deleteLater(); 26 | } 27 | void TcpSocketCustom::WriteBAToTCPClient(QByteArray &ba) 28 | { 29 | write(ba); 30 | } 31 | void TcpSocketCustom::dataavail() 32 | { 33 | while(bytesAvailable()>0)writeDatagramFromTunnel(readAll()); 34 | } 35 | //------------------- 36 | 37 | //------------------------- 38 | // the server that listens 39 | //------------------------- 40 | 41 | Tcpserver::Tcpserver(QObject *parent) 42 | : QTcpServer(parent) 43 | { 44 | currentaddress.setAddress(QHostAddress::Null); 45 | currentport=0; 46 | } 47 | 48 | Tcpserver::~Tcpserver() 49 | { 50 | stopserver(); 51 | emit quitting(); 52 | } 53 | 54 | void Tcpserver::incomingConnection(qintptr socketDescriptor) 55 | { 56 | TcpSocketCustom *tcpSocket= new TcpSocketCustom(this); 57 | if (!tcpSocket->setSocketDescriptor(socketDescriptor)) 58 | { 59 | qDebug("cant create client socket"); 60 | return; 61 | } 62 | connect(this,SIGNAL(SendBAToAllTCPClientsSignal(QByteArray&)),tcpSocket,SLOT(WriteBAToTCPClient(QByteArray&))); 63 | connect(this,SIGNAL(DisconnectAllClients()),tcpSocket,SLOT(Disconnect())); 64 | // qDebug("Client connected"); 65 | //tcpSocket->write(((QByteArray)"hello\n")); 66 | } 67 | 68 | void Tcpserver::SendBAToAllTCPClients(QByteArray &ba) 69 | { 70 | emit SendBAToAllTCPClientsSignal(ba); 71 | } 72 | 73 | //----------------- 74 | void Tcpserver::startserver(const QHostAddress &address, quint16 port) 75 | { 76 | if(currentaddress==address&¤tport==port&&isListening())return; 77 | stopserver(); 78 | if(!listen(address, port)) 79 | { 80 | qDebug()<<"Cant bind to tcp port"< 5 | #include 6 | 7 | 8 | //Jonti 2016 9 | 10 | class TcpSocketCustom: public QTcpSocket 11 | { 12 | Q_OBJECT 13 | public: 14 | TcpSocketCustom(QObject * parent = 0); 15 | ~TcpSocketCustom(); 16 | public slots: 17 | void ClientDisconnected(); 18 | void WriteBAToTCPClient(QByteArray &ba); 19 | void dataavail(); 20 | void Disconnect(); 21 | signals: 22 | void writeDatagramFromTunnel(QByteArray ba); 23 | private: 24 | protected: 25 | }; 26 | 27 | class Tcpserver : public QTcpServer 28 | { 29 | Q_OBJECT 30 | public: 31 | Tcpserver(QObject *parent = 0); 32 | ~Tcpserver(); 33 | void startserver(const QHostAddress &address = QHostAddress::Any, quint16 port = 0); 34 | void stopserver(); 35 | public slots: 36 | void SendBAToAllTCPClients(QByteArray &ba); 37 | signals: 38 | void quitting(); 39 | void SendBAToAllTCPClientsSignal(QByteArray &ba); 40 | void DisconnectAllClients(); 41 | protected: 42 | void incomingConnection(qintptr socketDescriptor); 43 | private: 44 | QHostAddress currentaddress; 45 | quint16 currentport; 46 | 47 | }; 48 | 49 | #endif // TCPSERVER_H 50 | -------------------------------------------------------------------------------- /JAERO/tests/fftrwrapper_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "../fftrwrapper.h" 2 | #include "../util/RuntimeError.h" 3 | #include "../DSP.h" 4 | #include "../util/stdio_utils.h" 5 | 6 | //important for Qt include cpputest last as it mucks up new and causes compiling to fail 7 | #include "CppUTest/TestHarness.h" 8 | 9 | TEST_GROUP(Test_FFTrWrapper) 10 | { 11 | const double doubles_equal_threshold=0.00001; 12 | 13 | void setup() 14 | { 15 | srand(1); 16 | } 17 | 18 | void teardown() 19 | { 20 | // This gets run after every test 21 | } 22 | }; 23 | 24 | TEST(Test_FFTrWrapper, fftrwrapper_matches_unusual_kissfft_scalling_as_expected_by_old_jaero_code_by_default) 25 | { 26 | 27 | //this was obtained from v1.0.4.11 of JAERO 28 | QVector input={-0.997497,0.127171,-0.613392,0.617481,0.170019,-0.040254,-0.299417,0.791925,0.645680,0.493210,-0.651784,0.717887,0.421003,0.027070,-0.392010,-0.970031}; 29 | QVector expected_forward={cpx_type(0.047060,0.000000),cpx_type(-3.660174,-0.220869),cpx_type(-1.565029,-0.944437),cpx_type(-2.388636,-1.697451),cpx_type(2.195807,0.550066),cpx_type(-0.821067,-1.010241),cpx_type(-0.320649,-2.091933),cpx_type(0.297167,-0.537596),cpx_type(-3.481857,0.000000),cpx_type(0.000000,0.000000),cpx_type(0.000000,0.000000),cpx_type(0.000000,0.000000),cpx_type(0.000000,0.000000),cpx_type(0.000000,0.000000),cpx_type(0.000000,0.000000),cpx_type(0.000000,0.000000)}; 30 | QVector expected_forward_backwards={-15.959960,2.034730,-9.814264,9.879696,2.720298,-0.644063,-4.790674,12.670797,10.330882,7.891354,-10.428541,11.486190,6.736045,0.433119,-6.272164,-15.520493}; 31 | int nfft=input.size(); 32 | 33 | CHECK(input.size()==nfft); 34 | CHECK(expected_forward.size()==nfft); 35 | CHECK(expected_forward_backwards.size()==nfft); 36 | 37 | FFTrWrapper fft=FFTrWrapper(nfft); 38 | FFTrWrapper ifft=FFTrWrapper(nfft); 39 | QVector actual_forward; 40 | QVector actual_forward_backwards; 41 | actual_forward.resize(nfft); 42 | actual_forward_backwards.resize(nfft); 43 | CHECK(actual_forward.size()==nfft); 44 | CHECK(actual_forward_backwards.size()==nfft); 45 | fft.transform(input,actual_forward); 46 | ifft.transform(actual_forward,actual_forward_backwards); 47 | 48 | for(int k=0;k input={cpx_type(-0.997497,0.127171),cpx_type(-0.613392,0.617481),cpx_type(0.170019,-0.040254),cpx_type(-0.299417,0.791925),cpx_type(0.645680,0.493210),cpx_type(-0.651784,0.717887),cpx_type(0.421003,0.027070),cpx_type(-0.392010,-0.970031),cpx_type(-0.817194,-0.271096),cpx_type(-0.705374,-0.668203),cpx_type(0.977050,-0.108615),cpx_type(-0.761834,-0.990661),cpx_type(-0.982177,-0.244240),cpx_type(0.063326,0.142369),cpx_type(0.203528,0.214331),cpx_type(-0.667531,0.326090)}; 28 | QVector expected_forward={cpx_type(-4.407605,0.164434),cpx_type(2.204298,2.308064),cpx_type(-2.713014,-1.356784),cpx_type(-2.347572,1.698848),cpx_type(-2.270577,-0.201056),cpx_type(1.611736,-2.136282),cpx_type(-0.902078,1.606222),cpx_type(0.335445,-0.964384),cpx_type(3.648427,0.230720),cpx_type(-2.707027,-3.571981),cpx_type(-1.023916,-0.474082),cpx_type(1.792787,2.825653),cpx_type(-5.574999,0.226081),cpx_type(1.119577,-1.518164),cpx_type(-1.273769,-1.346937),cpx_type(-3.451670,4.544378)}; 29 | QVector expected_forward_backwards={cpx_type(-15.959960,2.034730),cpx_type(-9.814264,9.879696),cpx_type(2.720298,-0.644063),cpx_type(-4.790674,12.670797),cpx_type(10.330882,7.891354),cpx_type(-10.428541,11.486190),cpx_type(6.736045,0.433119),cpx_type(-6.272164,-15.520493),cpx_type(-13.075106,-4.337535),cpx_type(-11.285989,-10.691244),cpx_type(15.632801,-1.737846),cpx_type(-12.189337,-15.850581),cpx_type(-15.714835,-3.907834),cpx_type(1.013215,2.277902),cpx_type(3.256447,3.429304),cpx_type(-10.680502,5.217444)}; 30 | int nfft=input.size(); 31 | 32 | CHECK(input.size()==nfft); 33 | CHECK(expected_forward.size()==nfft); 34 | CHECK(expected_forward_backwards.size()==nfft); 35 | 36 | FFTWrapper fft=FFTWrapper(nfft,false); 37 | FFTWrapper ifft=FFTWrapper(nfft,true); 38 | QVector actual_forward,actual_forward_backwards; 39 | actual_forward.resize(nfft); 40 | actual_forward_backwards.resize(nfft); 41 | CHECK(actual_forward.size()==nfft); 42 | CHECK(actual_forward_backwards.size()==nfft); 43 | fft.transform(input,actual_forward); 44 | ifft.transform(actual_forward,actual_forward_backwards); 45 | 46 | for(int k=0;k input; 3 | extern const QVector expected_output; 4 | extern double Fs; 5 | extern double fb; 6 | -------------------------------------------------------------------------------- /JAERO/tests/jfastfir_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "../fftrwrapper.h" 2 | #include "../util/RuntimeError.h" 3 | #include "../DSP.h" 4 | #include "../util/stdio_utils.h" 5 | #include "../util/file_utils.h" 6 | #include "jfastfir_data.h" 7 | 8 | //important for Qt include cpputest last as it mucks up new and causes compiling to fail 9 | #include "CppUTest/TestHarness.h" 10 | 11 | TEST_GROUP(Test_JFastFir) 12 | { 13 | const double doubles_equal_threshold=0.00001; 14 | 15 | //the strange error that cpputest throws of a memory leak when using QFile only happens so far on linux 16 | void setup() 17 | { 18 | #ifdef __linux__ 19 | MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); 20 | #endif 21 | } 22 | 23 | void teardown() 24 | { 25 | #ifdef __linux__ 26 | MemoryLeakWarningPlugin::turnOnNewDeleteOverloads(); 27 | #endif 28 | } 29 | }; 30 | 31 | TEST(Test_JFastFir, check_matches_old_jaero_code) 32 | { 33 | 34 | 35 | JFastFir fir_pre; 36 | RootRaisedCosine rrc_pre_imp; 37 | rrc_pre_imp.design(0.6,2048,Fs,fb/2); 38 | fir_pre.SetKernel(rrc_pre_imp.Points,4096); 39 | 40 | QVector actual_output(input); 41 | fir_pre.update(actual_output); 42 | 43 | CHECK(input.size()==expected_output.size()); 44 | CHECK(actual_output.size()==expected_output.size()); 45 | 46 | 47 | File_Utils::Matlab::print(QString(MATLAB_PATH)+"actual_input_include.m","actual_input",input); 48 | File_Utils::Matlab::print(QString(MATLAB_PATH)+"actual_output_include.m","actual_output",actual_output); 49 | 50 | 51 | //the first 4096 samples need not match 52 | for(int k=4096;k 3 | #include 4 | 5 | RuntimeError::RuntimeError(const std::string &arg, const char *file, int line,int parameter) : 6 | std::runtime_error(arg) 7 | { 8 | std::ostringstream o; 9 | o << file << ":" << line << ": " << arg<<" ("< 5 | #include 6 | 7 | class RuntimeError : public std::runtime_error 8 | { 9 | public: 10 | RuntimeError(const std::string &arg, const char *file, int line,int parameter); 11 | ~RuntimeError() throw(); 12 | const char *what() const throw(); 13 | private: 14 | std::string msg; 15 | }; 16 | #define RUNTIME_ERROR(description, parameter) throw RuntimeError(description, __FILE__, __LINE__,parameter); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /JAERO/util/file_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "file_utils.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "RuntimeError.h" 7 | 8 | namespace File_Utils 9 | { 10 | 11 | static void create_path_if_needed_for(const QString &filename) 12 | { 13 | QFileInfo fileinfo(filename); 14 | QDir dir; 15 | if(!dir.mkpath(fileinfo.absoluteDir().absolutePath())) 16 | { 17 | RUNTIME_ERROR("Failed to file path",1); 18 | return; 19 | } 20 | } 21 | 22 | namespace Matlab 23 | { 24 | 25 | void print(const QString &filename,const char *name,const QVector &result) 26 | { 27 | create_path_if_needed_for(filename); 28 | QFile data(filename); 29 | if(!data.open(QFile::WriteOnly | QFile::Truncate)) 30 | { 31 | RUNTIME_ERROR("Failed to open file for writing",1); 32 | return; 33 | } 34 | QTextStream out(&data); 35 | 36 | for(int k=0;k=0)out< &result) 47 | { 48 | create_path_if_needed_for(filename); 49 | QFile data(filename); 50 | if(!data.open(QFile::WriteOnly | QFile::Truncate)) 51 | { 52 | RUNTIME_ERROR("Failed to open file for writing",1); 53 | return; 54 | } 55 | QTextStream out(&data); 56 | 57 | for(int k=0;k &result) 72 | { 73 | create_path_if_needed_for(filename); 74 | QFile data(filename); 75 | if(!data.open(QFile::WriteOnly | QFile::Truncate)) 76 | { 77 | RUNTIME_ERROR("Failed to open file for writing",1); 78 | return; 79 | } 80 | QTextStream out(&data); 81 | 82 | for(int k=0;k "< &result) 92 | { 93 | create_path_if_needed_for(filename); 94 | QFile data(filename); 95 | if(!data.open(QFile::WriteOnly | QFile::Truncate)) 96 | { 97 | RUNTIME_ERROR("Failed to open file for writing",1); 98 | return; 99 | } 100 | QTextStream out(&data); 101 | 102 | for(int k=0;k "< 4 | #include "../DSP.h" 5 | 6 | namespace File_Utils 7 | { 8 | 9 | namespace Matlab 10 | { 11 | void print(const QString &filename, const char *name, const QVector &result); 12 | void print(const QString &filename, const char *name, const QVector &result); 13 | } 14 | 15 | namespace CPP 16 | { 17 | void print(const QString &filename, const char *name, const QVector &result); 18 | void print(const QString &filename, const char *name, const QVector &result); 19 | } 20 | 21 | } 22 | 23 | #endif // FILE_UTILS_H 24 | 25 | -------------------------------------------------------------------------------- /JAERO/util/stdio_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "stdio_utils.h" 2 | 3 | namespace Stdio_Utils 4 | { 5 | namespace Matlab 6 | { 7 | 8 | void print(const char *name,const QVector &result) 9 | { 10 | for(int k=0;k=0)printf("%f+%fi",result[k].real(),result[k].imag()); 14 | else printf("%f%fi",result[k].real(),result[k].imag()); 15 | if((k+1) &result) 21 | { 22 | for(int k=0;k &result) 37 | { 38 | for(int k=0;k %s={",name); 41 | printf("cpx_type(%f,%f)",result[k].real(),result[k].imag()); 42 | if((k+1) &result) 48 | { 49 | for(int k=0;k %s={",name); 52 | printf("%f",result[k]); 53 | if((k+1) 4 | #include "../DSP.h" 5 | 6 | //cpputest doesn't like qDebug() so have to use printf 7 | 8 | namespace Stdio_Utils 9 | { 10 | 11 | namespace Matlab 12 | { 13 | void print(const char *name,const QVector &result); 14 | void print(const char *name,const QVector &result); 15 | } 16 | 17 | namespace CPP 18 | { 19 | void print(const char *name,const QVector &result); 20 | void print(const char *name,const QVector &result); 21 | } 22 | 23 | } 24 | 25 | #endif // STDIO_UTILS_H 26 | -------------------------------------------------------------------------------- /JAERO/zmq_audioreceiver.cpp: -------------------------------------------------------------------------------- 1 | #include "zmq_audioreceiver.h" 2 | #include "QDebug" 3 | #include 4 | #include 5 | 6 | //this is so I can easily use old streams that some people are still using for testing. 7 | //commenting this out is for the old format that didn't have samplerate info message. 8 | //without this samplerate is always 48000 and wont work for streams that are using anything else. 9 | //10500bps streams are at 48000 and are what I use for testing. 10 | #define ZMQ_HAS_SAMPLERATE_MESSAGE 11 | 12 | void ZMQAudioReceiver::Start(QString address, QString topic) 13 | { 14 | //stop set prams and start thread 15 | Stop(); 16 | setParameters(address,topic); 17 | future = QtConcurrent::run([=]() { 18 | process(); 19 | return; 20 | }); 21 | //wait till the thread is running so ZMQaudioStop functions correctly 22 | for(int i=0;!running&&i<1000;i++)usleep(1000); 23 | //if it fails after a second then arghhhhh, should not happen 24 | if(!running) 25 | { 26 | qDebug()<<"Failed to start ZMQ receiving thread"; 27 | } 28 | } 29 | 30 | void ZMQAudioReceiver::Stop() 31 | { 32 | running = false; 33 | if(!future.isFinished())future.waitForFinished(); 34 | emit finished(); 35 | } 36 | 37 | void ZMQAudioReceiver::process() 38 | { 39 | // allocate enough for 96Khz sampling with 1 buffer per second 40 | int recsize = 192000; 41 | context = zmq_ctx_new(); 42 | subscriber = zmq_socket(context, ZMQ_SUB); 43 | 44 | zmqStatus = zmq_connect(subscriber, _address.toStdString().c_str()); 45 | zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, _topic.toStdString().c_str(), 5); 46 | 47 | char buf [recsize]; 48 | unsigned char rate[4]; 49 | quint32 sampleRate=48000; 50 | int received; 51 | 52 | running = true; 53 | 54 | while(running) 55 | { 56 | 57 | //blocking call alternative for topic, here we wait for the topic. 58 | //I guess the sleep has to be less then the idle period between messages??? 59 | while(((received = zmq_recv(subscriber, nullptr, 0, ZMQ_DONTWAIT))<0)&&running) 60 | { 61 | usleep(10000); 62 | } 63 | if(!running)break; 64 | 65 | //rate message is next 66 | #ifdef ZMQ_HAS_SAMPLERATE_MESSAGE 67 | received = zmq_recv(subscriber, rate, 4, ZMQ_DONTWAIT); 68 | if(!running)break; 69 | memcpy(&sampleRate, rate, 4); 70 | #endif 71 | 72 | //then audio data 73 | received = zmq_recv(subscriber, buf, recsize, ZMQ_DONTWAIT); 74 | if(!running)break; 75 | if(received>=0) 76 | { 77 | QByteArray qdata(buf, received); 78 | emit recAudio(qdata,sampleRate); 79 | } 80 | 81 | } 82 | 83 | if(subscriber)zmq_close(subscriber); 84 | if(context)zmq_ctx_destroy(context); 85 | subscriber=nullptr; 86 | context=nullptr; 87 | } 88 | 89 | ZMQAudioReceiver::ZMQAudioReceiver(QObject *parent): 90 | QObject(parent), 91 | running(false), 92 | context(nullptr), 93 | subscriber(nullptr) 94 | { 95 | 96 | } 97 | 98 | ZMQAudioReceiver::~ZMQAudioReceiver() 99 | { 100 | Stop(); 101 | } 102 | 103 | void ZMQAudioReceiver::setParameters(QString address, QString topic) 104 | { 105 | _address = address; 106 | _topic = topic; 107 | } 108 | 109 | 110 | -------------------------------------------------------------------------------- /JAERO/zmq_audioreceiver.h: -------------------------------------------------------------------------------- 1 | #ifndef ZMQ_AUDIORECEIVER_H 2 | #define ZMQ_AUDIORECEIVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class ZMQAudioReceiver : public QObject 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | 14 | explicit ZMQAudioReceiver(QObject *parent = 0); 15 | ~ZMQAudioReceiver(); 16 | 17 | public slots: 18 | 19 | void Stop(); 20 | void Start(QString address, QString topic); 21 | 22 | signals: 23 | 24 | void finished(); 25 | 26 | private: 27 | 28 | void setParameters(QString address, QString topic); 29 | volatile bool running; 30 | 31 | void process(); 32 | 33 | void * volatile context; 34 | void * volatile subscriber; 35 | 36 | int zmqStatus; 37 | 38 | QString _address; 39 | QString _topic; 40 | int _rate; 41 | 42 | QFuture future; 43 | 44 | signals: 45 | void recAudio(const QByteArray & audio,quint32 sampleRate); 46 | 47 | }; 48 | 49 | #endif // AUDIORECEIVER_H 50 | -------------------------------------------------------------------------------- /JAERO/zmq_audiosender.cpp: -------------------------------------------------------------------------------- 1 | #include "zmq_audiosender.h" 2 | #include "zmq.h" 3 | #include 4 | 5 | ZMQAudioSender::ZMQAudioSender(QObject *parent) : QObject(parent) 6 | { 7 | zmqStatus = -1; 8 | context = zmq_ctx_new(); 9 | publisher = zmq_socket(context, ZMQ_PUB); 10 | 11 | int keepalive = 1; 12 | int keepalivecnt = 10; 13 | int keepaliveidle = 1; 14 | int keepaliveintrv = 1; 15 | 16 | zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE,(void*)&keepalive, sizeof(ZMQ_TCP_KEEPALIVE)); 17 | zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_CNT,(void*)&keepalivecnt,sizeof(ZMQ_TCP_KEEPALIVE_CNT)); 18 | zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_IDLE,(void*)&keepaliveidle,sizeof(ZMQ_TCP_KEEPALIVE_IDLE)); 19 | zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_INTVL,(void*)&keepaliveintrv,sizeof(ZMQ_TCP_KEEPALIVE_INTVL)); 20 | } 21 | 22 | void ZMQAudioSender::Start(QString &address, QString &topic) 23 | { 24 | Stop(); 25 | // bind socket 26 | this->topic=topic; 27 | connected_url=address.toUtf8().constData(); 28 | zmqStatus=zmq_bind(publisher, connected_url.c_str() ); 29 | } 30 | 31 | void ZMQAudioSender::Stop() 32 | { 33 | if(zmqStatus == 0) 34 | { 35 | zmqStatus = zmq_disconnect(publisher, connected_url.c_str()); 36 | } 37 | } 38 | 39 | void ZMQAudioSender::Voiceslot(QByteArray &data, QString &hex) 40 | { 41 | std::string topic_text = topic.toUtf8().constData(); 42 | zmq_setsockopt(publisher, ZMQ_IDENTITY, topic_text.c_str(), topic_text.length()); 43 | 44 | if(data.length()!=0) 45 | { 46 | zmq_send(publisher, topic_text.c_str(), topic_text.length(), ZMQ_SNDMORE); 47 | zmq_send(publisher, data.data(), data.length(), 0 ); 48 | } 49 | zmq_send(publisher, topic_text.c_str(), 5, ZMQ_SNDMORE); 50 | zmq_send(publisher, hex.toStdString().c_str(), 6, 0 ); 51 | } 52 | -------------------------------------------------------------------------------- /JAERO/zmq_audiosender.h: -------------------------------------------------------------------------------- 1 | #ifndef ZMQ_AUDIOSENDER_H 2 | #define ZMQ_AUDIOSENDER_H 3 | 4 | #include 5 | 6 | class ZMQAudioSender : public QObject 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit ZMQAudioSender(QObject *parent = 0); 11 | void Start(QString &address,QString &topic); 12 | void Stop(); 13 | signals: 14 | public slots: 15 | void Voiceslot(QByteArray &data, QString &hex); 16 | private: 17 | void* context; 18 | void* publisher; 19 | int zmqStatus; 20 | std::string connected_url; 21 | QString topic; 22 | }; 23 | 24 | #endif // ZMQ_AUDIOSENDER_H 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JAERO 2 | 3 | [![build](https://github.com/jontio/JAERO/actions/workflows/ci-windows-build.yml/badge.svg)](https://github.com/jontio/JAERO/actions/workflows/ci-windows-build.yml) 4 | 5 | A SatCom ACARS demodulator and decoder for the Aero standard written in C++ Qt 6 | 7 | ![](images/screenshot-win-main.png) 8 | 9 | This program demodulates and decodes ACARS messages sent from satellites to Aeroplanes (SatCom ACARS) commonly used when Aeroplanes are beyond VHF range. Demodulation is performed using the soundcard. 10 | Such signals are typically around 1.5Ghz and can be received with a simple low gain antenna that can be home brewed in a few hours in conjunction with a cheap [RTL-SDR] dongle. 11 | 12 | The 600 and 1200 bps SatCom ACARS signals are basically MSK like so the demodulator was forked from [JMSK]. The demodulator implements a coherent MSK demodulator type as seen at http://jontio.zapto.org/hda1/msk-demodulation2.html. 13 | 14 | The 600 and 1200 bps demodulator uses the technique that treats the signal similar to [OQPSK] but with sine wave transitions rather than rectangular transitions. The BER (*Bit Error Rate*) versus EbNo (*Energy per bit to Noise power density*) performance in the presence of AWGN (*Additive White Gaussian Noise*) is the same as coherently demodulated differentially encoded [BPSK]. While designed for MSK it will also demodulate [GMSK] and some types of [BPSK]. The signal is supplied via the audio input of the computer’s soundcard. 15 | The software implements differential decoding hence the modulator must use differential encoding. The output of the demodulator can be directed to either a built-in console or to a [UDP] network port. 16 | 17 | An OQPSK demodulator was added and supports the faster 8400bps and 10.5k Aero signals. 18 | 19 | Both 1200 and 10.5k burst C-band signal demodulation (From plane to ground station) are supported. 20 | 21 | C-Channel signals at 8400bps that are for voice can be demodulated. 22 | 23 | ![](images/screenshot-win-planelog.png) 24 | 25 | ## Binaries 26 | 27 | Precompiled binaries can be downloaded from [Releases]. 28 | 29 | ## Directory structure 30 | 31 | The [JAERO](JAERO) directory is where the Qt pro file is for the main application. The [udptextserver](udptextserver) directory is a small demo application for receiving data sent from JAERO. 32 | 33 | ## Compiling JAERO 34 | 35 | Compiling JAERO requires the Qt framework. I would suggest using [MSYS2] to install the Qt framework and the rest of the development environment. Qt Creator can be used to compile JAERO and comes with the Qt framework. At least version 5 of the Qt framework is required. I only use MinGW and GCC for building so don't know if MSVC works. 36 | 37 | I've now added Windows and Linux build scripts. The Windows build script requires MSYS2, once installed run msys64 clone the repo then type `./ci-windows-build.sh`. The Linux build script is for Debian based distros and will need to be changed for others; I have only tested it on some of the Ubuntu family (Ubuntu, Kubuntu and Lubuntu). For Linux type `./ci-linux-build.sh`, it will install JAERO as a few packages so uninstalling should be clean. For Windows there is no fancy installer but rather just a folder with the dependencies and the exe file itself. The build will fail if any of the dependency folders already exist; so the scripts could still do with a bit more work. Currently the aim of the scripts is as a way of automatically building JAERO from a default system so I can easily make changes to the code and not have the hassle of build releases. 38 | 39 | I've added a continuous integration script [.github/workflows/ci-windows-build.yml](.github/workflows/ci-windows-build.yml) that will get Gihub to build JAERO for both Windows and Ubuntu. Currently the script is triggered manually in the [actions](https://github.com/jontio/JAERO/actions) tab. I suspect some older computers, say ones that don't support AVX instructions may now not run the new releases created in this manor and will need building on the intended computer itself. 40 | 41 | JAERO's dependencies will undoubtedly change over time, so I suspect eventually the build scripts will fail and will need fixing. Till then they work, but I have no idea how long they will work for. 42 | 43 | ## Thanks 44 | 45 | I'd like to thank everyone who has given their kind support for JAERO over the years. Thanks for Otti for getting the project started, John and Bev for setting up a worldwide large dish network, everyone who has donated, the people who have send feedback, people who use JAERO, Jeroen who done an excellent job programming new code for JAERO to bring some features that I’m sure will be appreciated by many, Tomasz for adding more ACARS message support, Corrosive for adding documentation, and the many other people who have written the libraries that JAERO uses. 46 | 47 | Jonti 2021 48 |
49 | https://jontio.zapto.org 50 | 51 | [OQPSK]: https://en.wikipedia.org/wiki/Phase-shift_keying#Offset_QPSK_.28OQPSK.29 52 | [GMSK]: https://en.wikipedia.org/wiki/Minimum-shift_keying#Gaussian_minimum-shift_keying 53 | [BPSK]: https://en.wikipedia.org/wiki/Phase-shift_keying#Binary_phase-shift_keying_.28BPSK.29 54 | [UDP]: https://en.wikipedia.org/wiki/User_Datagram_Protocol 55 | [SSB]: https://en.wikipedia.org/wiki/Single-sideband_modulation 56 | [Arduino]: https://www.arduino.cc/ 57 | [Varicode]: https://en.wikipedia.org/wiki/Varicode 58 | [Spectrum Lab]: http://www.qsl.net/dl4yhf/spectra1.html 59 | [JMSK]: https://github.com/jontio/JMSK 60 | [RTL-SDR]: http://www.rtl-sdr.com/about-rtl-sdr/ 61 | [Releases]: https://github.com/jontio/JAERO/releases 62 | [JAERO Wiki]: https://github.com/jontio/JAERO/wiki 63 | [MSYS2]: https://www.msys2.org/ 64 | -------------------------------------------------------------------------------- /basestationlinks: -------------------------------------------------------------------------------- 1 | https://jetvision.de/resources/sqb_databases/basestation.zip 2 | https://data.flightairmap.com/data/basestation/BaseStation.sqb.zip 3 | http://www.virtualradarserver.co.uk/Files/BaseStation.zip 4 | 5 | -------------------------------------------------------------------------------- /ci-create-basestation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #warning will delete all *.sqb files in output folder 4 | 5 | #input file of links and output folder where the downloading and uncompressing happens 6 | #relitive links are wrt to where this script is 7 | input="basestationlinks" 8 | outputdir="../basestation" 9 | save_sqb_file_as="basestation.sqb" 10 | 11 | echo "ci-create-basestation" 12 | 13 | #get script path 14 | SCRIPT=$(realpath $0) 15 | SCRIPTPATH=$(dirname "$SCRIPT") 16 | cd "$SCRIPTPATH" 17 | 18 | #create output path 19 | mkdir -p "$outputdir" 20 | 21 | #change to absolute paths 22 | outputdir=$(realpath "$outputdir") 23 | save_sqb_file_as=$(realpath "$outputdir/$save_sqb_file_as") 24 | 25 | #goto output path 26 | cd "$outputdir" 27 | 28 | #remove any sqb files in the output folder 29 | rm -f "$outputdir"/*.[sS][qQ][bB] 30 | 31 | #try and download one of the files and decompress it to the output folder 32 | filename="" 33 | while IFS= read -r line 34 | do 35 | line=$(echo "$line" | sed 's/^[ \t]*//;s/[ \t]*$//') 36 | if [ -z "$line" ]; then 37 | continue 38 | fi 39 | wget_output=$(wget -nv "$line" 2>&1 ) 40 | if [ $? -eq 0 ]; then 41 | filename=$(echo "$wget_output" |cut -d\" -f2) 42 | echo "downloaded $line ok as $filename" 43 | MIMETYPE=$(file --mime-type "$filename" |sed -n -e 's/^.*:\s//p') 44 | if echo "$MIMETYPE" | grep -q 'application/zip' ; then 45 | echo "file is a zip file" 46 | unzip "$filename" -d "$outputdir" 47 | rm "$filename" 48 | echo "saved uncompressed files to $outputdir" 49 | find "$outputdir"/*.[sS][qQ][bQ] -maxdepth 1 50 | if [ $? -ne 0 ]; then 51 | echo "error: sqb not one of in uncompressed files." 52 | continue 53 | fi 54 | break 55 | fi 56 | if echo "$MIMETYPE" | grep -q 'application/gzip' ; then 57 | echo "file is a gzip file" 58 | tar -zxf "$filename" -C "$outputdir" 59 | rm "$filename" 60 | echo "saved uncompressed files to $outputdir" 61 | find "$outputdir"/*.[sS][qQ][bQ] -maxdepth 1 62 | if [ $? -ne 0 ]; then 63 | echo "error: sqb not one of in uncompressed files." 64 | continue 65 | fi 66 | break 67 | fi 68 | echo "error: file has a mime type of $MIMETYPE and is not a zip/gzip compressed file" 69 | rm "$filename" 70 | else 71 | echo "failed to download $line" 72 | fi 73 | done < "$SCRIPTPATH/$input" 74 | #exit with a failure if we didn't compress anything 75 | if [ -z "$filename" ]; then 76 | exit 1 77 | fi 78 | #rename sqb file that should be in the download if not then fail 79 | outputfiles=$(find "$outputdir" -iname "*.sqb") 80 | if [ $? -ne 0 ]; then 81 | echo "error: sqb not one of in uncompressed files." 82 | exit 1 83 | else 84 | filename=$(echo "$outputfiles" |head -1) 85 | if [ "$filename" != "$save_sqb_file_as" ]; then 86 | echo "renaming $filename to $save_sqb_file_as" 87 | mv "$filename" "$save_sqb_file_as" 88 | fi 89 | fi 90 | 91 | -------------------------------------------------------------------------------- /images/screenshot-win-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/images/screenshot-win-main.png -------------------------------------------------------------------------------- /images/screenshot-win-planelog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/images/screenshot-win-planelog.png -------------------------------------------------------------------------------- /samples/10.5k_burst_sample.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/samples/10.5k_burst_sample.mp3 -------------------------------------------------------------------------------- /samples/10.5k_sample.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/samples/10.5k_sample.ogg -------------------------------------------------------------------------------- /samples/1200bps_burst_sample1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/samples/1200bps_burst_sample1.wav -------------------------------------------------------------------------------- /samples/1200bps_burst_sample2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/samples/1200bps_burst_sample2.wav -------------------------------------------------------------------------------- /samples/600bps_sample.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/samples/600bps_sample.ogg -------------------------------------------------------------------------------- /samples/8400bps_ambe_sample.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jontio/JAERO/1d4e515921244aec1d85a03f5f38b4e7818fdbe6/samples/8400bps_ambe_sample.ogg -------------------------------------------------------------------------------- /udptextserver/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /udptextserver/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /udptextserver/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | #include 4 | #include 5 | 6 | MainWindow::MainWindow(QWidget *parent) : 7 | QMainWindow(parent), 8 | ui(new Ui::MainWindow) 9 | { 10 | ui->setupUi(this); 11 | udpsocket = new QUdpSocket(this); 12 | connect(udpsocket,SIGNAL(readyRead()),this,SLOT(readyReadSlot())); 13 | udpsocket->bind(QHostAddress::Any,8765); 14 | 15 | //workaround for strange QUdpSocket bug where readyRead signal may not emit and never emit again filling up incoming buffer and the output seems to freeze. Can someone please do something about this? 16 | readtimer=new QTimer(this); 17 | connect(readtimer,SIGNAL(timeout()),this,SLOT(readyReadSlot())); 18 | readtimer->start(50); 19 | } 20 | 21 | void MainWindow::readyReadSlot() 22 | { 23 | readtimer->stop(); 24 | while (udpsocket->hasPendingDatagrams()) 25 | { 26 | //get packet 27 | QByteArray datagram; 28 | datagram.resize(udpsocket->pendingDatagramSize()); 29 | QHostAddress sender; 30 | quint16 senderPort; 31 | udpsocket->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort); 32 | 33 | //turn into hex 34 | QByteArray datagramhex;for(int i=0;iplainTextEdit->textCursor(); 38 | const int old_scrollbar_value = ui->plainTextEdit->verticalScrollBar()->value(); 39 | const bool is_scrolled_down = old_scrollbar_value == ui->plainTextEdit->verticalScrollBar()->maximum(); 40 | ui->plainTextEdit->moveCursor(QTextCursor::End); 41 | ui->plainTextEdit->textCursor().insertText(datagramhex); 42 | if (old_cursor.hasSelection() || !is_scrolled_down) 43 | { 44 | ui->plainTextEdit->setTextCursor(old_cursor); 45 | ui->plainTextEdit->verticalScrollBar()->setValue(old_scrollbar_value); 46 | } 47 | else 48 | { 49 | ui->plainTextEdit->moveCursor(QTextCursor::End); 50 | ui->plainTextEdit->verticalScrollBar()->setValue(ui->plainTextEdit->verticalScrollBar()->maximum()); 51 | } 52 | 53 | } 54 | readtimer->start(); 55 | } 56 | 57 | MainWindow::~MainWindow() 58 | { 59 | delete ui; 60 | } 61 | -------------------------------------------------------------------------------- /udptextserver/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Ui { 8 | class MainWindow; 9 | } 10 | 11 | class MainWindow : public QMainWindow 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit MainWindow(QWidget *parent = 0); 17 | ~MainWindow(); 18 | 19 | private: 20 | Ui::MainWindow *ui; 21 | QUdpSocket *udpsocket; 22 | QTimer *readtimer; 23 | private slots: 24 | void readyReadSlot(); 25 | 26 | }; 27 | 28 | #endif // MAINWINDOW_H 29 | -------------------------------------------------------------------------------- /udptextserver/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 577 10 | 461 11 | 12 | 13 | 14 | Udp Server Test 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 12 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 0 34 | 577 35 | 23 36 | 37 | 38 | 39 | 40 | 41 | TopToolBarArea 42 | 43 | 44 | false 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /udptextserver/udptextserver.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2015-08-04T10:16:22 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui network 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = udptextserver 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | mainwindow.cpp 17 | 18 | HEADERS += mainwindow.h 19 | 20 | FORMS += mainwindow.ui 21 | 22 | DISTFILES += \ 23 | license.txt 24 | --------------------------------------------------------------------------------