diff --git a/ft8/ft8.cpp b/ft8/ft8.cpp index 617f97bf3..a3c6a8397 100644 --- a/ft8/ft8.cpp +++ b/ft8/ft8.cpp @@ -1233,6 +1233,32 @@ std::vector> FT8::un_gray_code_r(const std::vector> FT8::un_gray_code_r_gen(const std::vector> &mags) +{ + if (mags.size() == 0) { + return mags; + } + + std::vector> magsa(mags.size()); + int nsyms = mags.front().size(); + + for (unsigned int si = 0; si < mags.size(); si++) + { + magsa[si].resize(nsyms); + + for (int bini = 0; bini < nsyms; bini++) + { + int grayi = bini ^ (bini >> 1); + magsa[si][bini] = mags[si][grayi]; + } + } + + return magsa; +} + // // normalize levels by windowed median. // this helps, but why? @@ -1807,6 +1833,52 @@ void FT8::soft_decode(const FFTEngine::ffts_t &c79, float ll174[]) m79 = un_gray_code_r(m79); int lli = 0; + // tone numbers that make second index bit zero or one. + int zeroi[4][3]; + int onei[4][3]; + + for (int biti = 0; biti < 3; biti++) + { + if (biti == 0) + { + // high bit + zeroi[0][0] = 0; + zeroi[1][0] = 1; + zeroi[2][0] = 2; + zeroi[3][0] = 3; + onei[0][0] = 4; + onei[1][0] = 5; + onei[2][0] = 6; + onei[3][0] = 7; + } + + if (biti == 1) + { + // middle bit + zeroi[0][1] = 0; + zeroi[1][1] = 1; + zeroi[2][1] = 4; + zeroi[3][1] = 5; + onei[0][1] = 2; + onei[1][1] = 3; + onei[2][1] = 6; + onei[3][1] = 7; + } + + if (biti == 2) + { + // low bit + zeroi[0][2] = 0; + zeroi[1][2] = 2; + zeroi[2][2] = 4; + zeroi[3][2] = 6; + onei[0][2] = 1; + onei[1][2] = 3; + onei[2][2] = 5; + onei[3][2] = 7; + } + } + for (int i79 = 0; i79 < 79; i79++) { if (i79 < 7 || (i79 >= 36 && i79 < 36 + 7) || i79 >= 72) { @@ -1823,56 +1895,13 @@ void FT8::soft_decode(const FFTEngine::ffts_t &c79, float ll174[]) for (int biti = 0; biti < 3; biti++) { - // tone numbers that make this bit zero or one. - int zeroi[4]; - int onei[4]; - - if (biti == 0) - { - // high bit - zeroi[0] = 0; - zeroi[1] = 1; - zeroi[2] = 2; - zeroi[3] = 3; - onei[0] = 4; - onei[1] = 5; - onei[2] = 6; - onei[3] = 7; - } - - if (biti == 1) - { - // middle bit - zeroi[0] = 0; - zeroi[1] = 1; - zeroi[2] = 4; - zeroi[3] = 5; - onei[0] = 2; - onei[1] = 3; - onei[2] = 6; - onei[3] = 7; - } - - if (biti == 2) - { - // low bit - zeroi[0] = 0; - zeroi[1] = 2; - zeroi[2] = 4; - zeroi[3] = 6; - onei[0] = 1; - onei[1] = 3; - onei[2] = 5; - onei[3] = 7; - } - // strongest tone that would make this bit be zero. int got_best_zero = 0; float best_zero = 0; for (int i = 0; i < 4; i++) { - float x = m79[i79][zeroi[i]]; + float x = m79[i79][zeroi[i][biti]]; if (got_best_zero == 0 || x > best_zero) { @@ -1887,7 +1916,7 @@ void FT8::soft_decode(const FFTEngine::ffts_t &c79, float ll174[]) for (int i = 0; i < 4; i++) { - float x = m79[i79][onei[i]]; + float x = m79[i79][onei[i][biti]]; if (got_best_one == 0 || x > best_one) { got_best_one = 1; @@ -1916,6 +1945,7 @@ void FT8::soft_decode_mags(FT8Params& params, const std::vector= 36 && i79 < 36 + 7) || i79 >= 72) { @@ -2089,56 +2165,13 @@ void FT8::c_soft_decode(const FFTEngine::ffts_t &c79x, float ll174[]) for (int biti = 0; biti < 3; biti++) { - // tone numbers that make this bit zero or one. - int zeroi[4]; - int onei[4]; - - if (biti == 0) - { - // high bit - zeroi[0] = 0; - zeroi[1] = 1; - zeroi[2] = 2; - zeroi[3] = 3; - onei[0] = 4; - onei[1] = 5; - onei[2] = 6; - onei[3] = 7; - } - - if (biti == 1) - { - // middle bit - zeroi[0] = 0; - zeroi[1] = 1; - zeroi[2] = 4; - zeroi[3] = 5; - onei[0] = 2; - onei[1] = 3; - onei[2] = 6; - onei[3] = 7; - } - - if (biti == 2) - { - // low bit - zeroi[0] = 0; - zeroi[1] = 2; - zeroi[2] = 4; - zeroi[3] = 6; - onei[0] = 1; - onei[1] = 3; - onei[2] = 5; - onei[3] = 7; - } - // strongest tone that would make this bit be zero. int got_best_zero = 0; float best_zero = 0; for (int i = 0; i < 4; i++) { - float x = m79[i79][zeroi[i]]; + float x = m79[i79][zeroi[i][biti]]; if (got_best_zero == 0 || x > best_zero) { @@ -2153,7 +2186,7 @@ void FT8::c_soft_decode(const FFTEngine::ffts_t &c79x, float ll174[]) for (int i = 0; i < 4; i++) { - float x = m79[i79][onei[i]]; + float x = m79[i79][onei[i][biti]]; if (got_best_one == 0 || x > best_one) { @@ -2560,8 +2593,14 @@ int FT8::decode(const float ll174[], int a174[], FT8Params& _params, int use_osd if (OSD::check_crc(a174)) { // success! return 1; + } else { + comment = "CRC fail"; } } + else + { + comment = "LDPC fail"; + } if (use_osd && _params.osd_depth >= 0 && ldpc_ok >= _params.osd_ldpc_thresh) { @@ -2576,6 +2615,10 @@ int FT8::decode(const float ll174[], int a174[], FT8Params& _params, int use_osd OSD::ldpc_encode(oplain, a174); return 1; } + else + { + comment = "OSD fail"; + } } return 0; @@ -3172,7 +3215,7 @@ int FT8::one_iter1( hz1_for_cb, params.use_osd, "", - m79 + m79 ); if (ret) { diff --git a/ft8/ft8.h b/ft8/ft8.h index 004e411ea..d381d6d0c 100644 --- a/ft8/ft8.h +++ b/ft8/ft8.h @@ -286,6 +286,11 @@ public: // static void soft_decode_mags(FT8Params& params, const std::vector>& mags, int nbSymbolBits, float ll174[]); + // + // Generic Gray decoding for magnitudes (floats) + // + static std::vector> un_gray_code_r_gen(const std::vector> &mags); + private: // // reduce the sample rate from arate to brate. diff --git a/ft8/packing.cpp b/ft8/packing.cpp index aa5eac1aa..84585792e 100644 --- a/ft8/packing.cpp +++ b/ft8/packing.cpp @@ -934,11 +934,11 @@ bool Packing::packfree(int a77[], const std::string& msg) return true; } -void Packing::pack1(int a77[], int c28_1, int c28_2, int g15, int report) +void Packing::pack1(int a77[], int c28_1, int c28_2, int g15, int reply) { pa64(a77, 0, 28, c28_1); pa64(a77, 28+1, 28, c28_2); - a77[28+1+28+1] = report; + a77[28+1+28+1] = reply; pa64(a77, 28+1+28+2, 15, g15); pa64(a77, 28+1+28+2+15, 3, 1); } diff --git a/ft8/packing.h b/ft8/packing.h index c3caa9775..f828c183e 100644 --- a/ft8/packing.h +++ b/ft8/packing.h @@ -40,7 +40,7 @@ public: static bool packcall_std(int& c28, const std::string& callstr); static bool packgrid(int& g15, const std::string& locstr); static bool packfree(int a77[], const std::string& msg); - static void pack1(int a77[], int c28_1, int c28_2, int g15, int report); + static void pack1(int a77[], int c28_1, int c28_2, int g15, int reply); private: static int ihashcall(std::string call, int m); diff --git a/plugins/channelrx/demodadsb/readme.md b/plugins/channelrx/demodadsb/readme.md index 2cf77bf4d..e19dfa913 100644 --- a/plugins/channelrx/demodadsb/readme.md +++ b/plugins/channelrx/demodadsb/readme.md @@ -86,7 +86,7 @@ Clicking the Display Settings button will open the Display Settings dialog, whic * The font used for the table. * Whether demodulator statistics are displayed (primarily an option for developers). * Whether the columns in the table are automatically resized after an aircraft is added to it. If unchecked, columns can be resized manually and should be saved with presets. -* The transistion altitude in feet for use in ATC mode. Below the TA, altitude will be displayed. Above the TA flight levels will be displayed. +* The transition altitude in feet for use in ATC mode. Below the TA, altitude will be displayed. Above the TA flight levels will be displayed. You can also enter an [aviationstack](https://aviationstack.com/product) API key, needed to download flight information (such as departure and arrival airports and times). diff --git a/plugins/channelrx/demodchirpchat/CMakeLists.txt b/plugins/channelrx/demodchirpchat/CMakeLists.txt index f312b65e4..aafc386d1 100644 --- a/plugins/channelrx/demodchirpchat/CMakeLists.txt +++ b/plugins/channelrx/demodchirpchat/CMakeLists.txt @@ -1,5 +1,10 @@ project(chirpchat) +if (FT8_SUPPORT) + set(chirpchatmod_FT8_LIB ft8) + set(chirpchatmod_FT8_INCLUDE ${CMAKE_SOURCE_DIR}/ft8) +endif() + set(chirpchat_SOURCES chirpchatdemod.cpp chirpchatdemodsettings.cpp @@ -10,6 +15,7 @@ set(chirpchat_SOURCES chirpchatdemoddecodertty.cpp chirpchatdemoddecoderascii.cpp chirpchatdemoddecoderlora.cpp + chirpchatdemoddecoderft.cpp chirpchatdemodmsg.cpp ) @@ -22,12 +28,14 @@ set(chirpchat_HEADERS chirpchatdemoddecodertty.h chirpchatdemoddecoderascii.h chirpchatdemoddecoderlora.h + chirpchatdemoddecoderft.h chirpchatdemodmsg.h chirpchatplugin.h ) include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${chirpchatmod_FT8_INCLUDE} ) if(NOT SERVER_MODE) @@ -61,6 +69,7 @@ target_link_libraries(${TARGET_NAME} sdrbase ${TARGET_LIB_GUI} swagger + ${chirpchatmod_FT8_LIB} ) install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp index cdb916d50..387cb0601 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp @@ -44,11 +44,10 @@ #include "maincore.h" #include "chirpchatdemodmsg.h" +#include "chirpchatdemoddecoder.h" #include "chirpchatdemod.h" MESSAGE_CLASS_DEFINITION(ChirpChatDemod::MsgConfigureChirpChatDemod, Message) -MESSAGE_CLASS_DEFINITION(ChirpChatDemod::MsgReportDecodeBytes, Message) -MESSAGE_CLASS_DEFINITION(ChirpChatDemod::MsgReportDecodeString, Message) const char* const ChirpChatDemod::m_channelIdURI = "sdrangel.channel.chirpchatdemod"; const char* const ChirpChatDemod::m_channelId = "ChirpChatDemod"; @@ -57,7 +56,9 @@ ChirpChatDemod::ChirpChatDemod(DeviceAPI* deviceAPI) : ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink), m_deviceAPI(deviceAPI), m_thread(nullptr), + m_decoderThread(nullptr), m_basebandSink(nullptr), + m_decoder(nullptr), m_running(false), m_spectrumVis(SDR_RX_SCALEF), m_basebandSampleRate(0), @@ -122,7 +123,7 @@ void ChirpChatDemod::feed(const SampleVector::const_iterator& begin, const Sampl (void) pO; if (m_running) { - m_basebandSink->feed(begin, end); + m_basebandSink->feed(begin, end); } } @@ -133,10 +134,25 @@ void ChirpChatDemod::start() } qDebug() << "ChirpChatDemod::start"; + m_decoderThread = new QThread(this); + m_decoder = new ChirpChatDemodDecoder(); + m_decoder->setOutputMessageQueue(getInputMessageQueue()); + m_decoder->setNbSymbolBits(m_settings.m_spreadFactor, m_settings.m_deBits); + m_decoder->setCodingScheme(m_settings.m_codingScheme); + m_decoder->setLoRaHasHeader(m_settings.m_hasHeader); + m_decoder->setLoRaHasCRC(m_settings.m_hasCRC); + m_decoder->setLoRaParityBits(m_settings.m_nbParityBits); + m_decoder->setLoRaPacketLength(m_settings.m_packetLength); + m_decoder->moveToThread(m_decoderThread); + + QObject::connect(m_decoderThread, &QThread::finished, m_decoder, &QObject::deleteLater); + QObject::connect(m_decoderThread, &QThread::finished, m_decoderThread, &QThread::deleteLater); + m_decoderThread->start(); + m_thread = new QThread(this); m_basebandSink = new ChirpChatDemodBaseband(); m_basebandSink->setSpectrumSink(&m_spectrumVis); - m_basebandSink->setDecoderMessageQueue(getInputMessageQueue()); // Decoder held on the main thread + m_basebandSink->setDecoderMessageQueue(m_decoder->getInputMessageQueue()); m_basebandSink->moveToThread(m_thread); QObject::connect(m_thread, &QThread::finished, m_basebandSink, &QObject::deleteLater); @@ -167,6 +183,9 @@ void ChirpChatDemod::stop() m_running = false; m_thread->exit(); m_thread->wait(); + m_decoderThread->exit(); + m_decoderThread->wait(); + m_decoderThread = nullptr; } bool ChirpChatDemod::handleMessage(const Message& cmd) @@ -180,29 +199,28 @@ bool ChirpChatDemod::handleMessage(const Message& cmd) return true; } - else if (ChirpChatDemodMsg::MsgDecodeSymbols::match(cmd)) + else if (ChirpChatDemodMsg::MsgReportDecodeBytes::match(cmd)) { - qDebug() << "ChirpChatDemod::handleMessage: MsgDecodeSymbols"; - ChirpChatDemodMsg::MsgDecodeSymbols& msg = (ChirpChatDemodMsg::MsgDecodeSymbols&) cmd; + qDebug() << "ChirpChatDemod::handleMessage: MsgReportDecodeBytes"; + ChirpChatDemodMsg::MsgReportDecodeBytes& msg = (ChirpChatDemodMsg::MsgReportDecodeBytes&) cmd; m_lastMsgSignalDb = msg.getSingalDb(); m_lastMsgNoiseDb = msg.getNoiseDb(); m_lastMsgSyncWord = msg.getSyncWord(); + m_lastMsgTimestamp = msg.getMsgTimestamp(); if (m_settings.m_codingScheme == ChirpChatDemodSettings::CodingLoRa) { - m_decoder.decodeSymbols(msg.getSymbols(), m_lastMsgBytes); - QDateTime dt = QDateTime::currentDateTime(); - m_lastMsgTimestamp = dt.toString(Qt::ISODateWithMs); - m_lastMsgPacketLength = m_decoder.getPacketLength(); - m_lastMsgNbParityBits = m_decoder.getNbParityBits(); - m_lastMsgHasCRC = m_decoder.getHasCRC(); - m_lastMsgNbSymbols = m_decoder.getNbSymbols(); - m_lastMsgNbCodewords = m_decoder.getNbCodewords(); - m_lastMsgEarlyEOM = m_decoder.getEarlyEOM(); - m_lastMsgHeaderCRC = m_decoder.getHeaderCRCStatus(); - m_lastMsgHeaderParityStatus = m_decoder.getHeaderParityStatus(); - m_lastMsgPayloadCRC = m_decoder.getPayloadCRCStatus(); - m_lastMsgPayloadParityStatus = m_decoder.getPayloadParityStatus(); + m_lastMsgBytes = msg.getBytes(); + m_lastMsgPacketLength = msg.getPacketSize(); + m_lastMsgNbParityBits = msg.getNbParityBits(); + m_lastMsgHasCRC = msg.getHasCRC(); + m_lastMsgNbSymbols = msg.getNbSymbols(); + m_lastMsgNbCodewords = msg.getNbCodewords(); + m_lastMsgEarlyEOM = msg.getEarlyEOM(); + m_lastMsgHeaderCRC = msg.getHeaderCRCStatus(); + m_lastMsgHeaderParityStatus = msg.getHeaderParityStatus(); + m_lastMsgPayloadCRC = msg.getPayloadCRCStatus(); + m_lastMsgPayloadParityStatus = msg.getPayloadParityStatus(); QByteArray bytesCopy(m_lastMsgBytes); bytesCopy.truncate(m_lastMsgPacketLength); @@ -215,23 +233,8 @@ bool ChirpChatDemod::handleMessage(const Message& cmd) m_udpSink.writeUnbuffered(bytes, m_lastMsgPacketLength); } - if (getMessageQueueToGUI()) - { - MsgReportDecodeBytes *msgToGUI = MsgReportDecodeBytes::create(m_lastMsgBytes); - msgToGUI->setSyncWord(m_lastMsgSyncWord); - msgToGUI->setSignalDb(m_lastMsgSignalDb); - msgToGUI->setNoiseDb(m_lastMsgNoiseDb); - msgToGUI->setPacketSize(m_lastMsgPacketLength); - msgToGUI->setNbParityBits(m_lastMsgNbParityBits); - msgToGUI->setHasCRC(m_lastMsgHasCRC); - msgToGUI->setNbSymbols(m_lastMsgNbSymbols); - msgToGUI->setNbCodewords(m_lastMsgNbCodewords); - msgToGUI->setEarlyEOM(m_lastMsgEarlyEOM); - msgToGUI->setHeaderParityStatus(m_lastMsgHeaderParityStatus); - msgToGUI->setHeaderCRCStatus(m_lastMsgHeaderCRC); - msgToGUI->setPayloadParityStatus(m_lastMsgPayloadParityStatus); - msgToGUI->setPayloadCRCStatus(m_lastMsgPayloadCRC); - getMessageQueueToGUI()->push(msgToGUI); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new ChirpChatDemodMsg::MsgReportDecodeBytes(msg)); // make a copy } // Is this an APRS packet? @@ -243,7 +246,7 @@ bool ChirpChatDemod::handleMessage(const Message& cmd) && (greaterThanIdx != -1) && (colonIdx != -1) && ((m_lastMsgHasCRC && m_lastMsgPayloadCRC) || !m_lastMsgHasCRC) - ) + ) { QByteArray packet; @@ -289,29 +292,68 @@ bool ChirpChatDemod::handleMessage(const Message& cmd) } } } - else + + return true; + } + else if (ChirpChatDemodMsg::MsgReportDecodeString::match(cmd)) + { + qDebug() << "ChirpChatDemod::handleMessage: MsgReportDecodeString"; + ChirpChatDemodMsg::MsgReportDecodeString& msg = (ChirpChatDemodMsg::MsgReportDecodeString&) cmd; + m_lastMsgSignalDb = msg.getSingalDb(); + m_lastMsgNoiseDb = msg.getNoiseDb(); + m_lastMsgSyncWord = msg.getSyncWord(); + m_lastMsgTimestamp = msg.getMsgTimestamp(); + m_lastMsgString = msg.getString(); + + if (m_settings.m_sendViaUDP) { - m_decoder.decodeSymbols(msg.getSymbols(), m_lastMsgString); - QDateTime dt = QDateTime::currentDateTime(); - m_lastMsgTimestamp = dt.toString(Qt::ISODateWithMs); + const QByteArray& byteArray = m_lastMsgString.toUtf8(); + const uint8_t *bytes = reinterpret_cast(byteArray.data()); + m_udpSink.writeUnbuffered(bytes, byteArray.size()); + } - if (m_settings.m_sendViaUDP) - { - const QByteArray& byteArray = m_lastMsgString.toUtf8(); - const uint8_t *bytes = reinterpret_cast(byteArray.data()); - m_udpSink.writeUnbuffered(bytes, byteArray.size()); - } + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new ChirpChatDemodMsg::MsgReportDecodeString(msg)); // make a copy + } - if (getMessageQueueToGUI()) + return true; + } + else if (ChirpChatDemodMsg::MsgReportDecodeFT::match(cmd)) + { + qDebug() << "ChirpChatDemod::handleMessage: MsgReportDecodeFT"; + ChirpChatDemodMsg::MsgReportDecodeFT& msg = (ChirpChatDemodMsg::MsgReportDecodeFT&) cmd; + m_lastMsgSignalDb = msg.getSingalDb(); + m_lastMsgNoiseDb = msg.getNoiseDb(); + m_lastMsgSyncWord = msg.getSyncWord(); + m_lastMsgTimestamp = msg.getMsgTimestamp(); + m_lastMsgString = msg.getMessage(); // for now we do not handle message components (call1, ...) + int nbSymbolBits = m_settings.m_spreadFactor - m_settings.m_deBits; + m_lastMsgNbSymbols = (174 / nbSymbolBits) + ((174 % nbSymbolBits) == 0 ? 0 : 1); + + if (m_settings.m_autoNbSymbolsMax) + { + ChirpChatDemodSettings settings = m_settings; + settings.m_nbSymbolsMax = m_lastMsgNbSymbols; + applySettings(settings); + + if (getMessageQueueToGUI()) // forward to GUI if any { - MsgReportDecodeString *msgToGUI = MsgReportDecodeString::create(m_lastMsgString); - msgToGUI->setSyncWord(m_lastMsgSyncWord); - msgToGUI->setSignalDb(m_lastMsgSignalDb); - msgToGUI->setNoiseDb(m_lastMsgNoiseDb); + MsgConfigureChirpChatDemod *msgToGUI = MsgConfigureChirpChatDemod::create(settings, false); getMessageQueueToGUI()->push(msgToGUI); } } + if (m_settings.m_sendViaUDP) + { + const QByteArray& byteArray = m_lastMsgString.toUtf8(); + const uint8_t *bytes = reinterpret_cast(byteArray.data()); + m_udpSink.writeUnbuffered(bytes, byteArray.size()); + } + + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new ChirpChatDemodMsg::MsgReportDecodeFT(msg)); // make a copy + } + return true; } else if (DSPSignalNotification::match(cmd)) @@ -420,38 +462,51 @@ void ChirpChatDemod::applySettings(const ChirpChatDemodSettings& settings, bool } if ((settings.m_spreadFactor != m_settings.m_spreadFactor) - || (settings.m_deBits != m_settings.m_deBits) || force) { - m_decoder.setNbSymbolBits(settings.m_spreadFactor, settings.m_deBits); + || (settings.m_deBits != m_settings.m_deBits) || force) + { + if (m_decoder) { + m_decoder->setNbSymbolBits(settings.m_spreadFactor, settings.m_deBits); + } } if ((settings.m_codingScheme != m_settings.m_codingScheme) || force) { reverseAPIKeys.append("codingScheme"); - m_decoder.setCodingScheme(settings.m_codingScheme); + if (m_decoder) { + m_decoder->setCodingScheme(settings.m_codingScheme); + } } if ((settings.m_hasHeader != m_settings.m_hasHeader) || force) { reverseAPIKeys.append("hasHeader"); - m_decoder.setLoRaHasHeader(settings.m_hasHeader); + if (m_decoder) { + m_decoder->setLoRaHasHeader(settings.m_hasHeader); + } } if ((settings.m_hasCRC != m_settings.m_hasCRC) || force) { reverseAPIKeys.append("hasCRC"); - m_decoder.setLoRaHasCRC(settings.m_hasCRC); + if (m_decoder) { + m_decoder->setLoRaHasCRC(settings.m_hasCRC); + } } if ((settings.m_nbParityBits != m_settings.m_nbParityBits) || force) { reverseAPIKeys.append("nbParityBits"); - m_decoder.setLoRaParityBits(settings.m_nbParityBits); + if (m_decoder) { + m_decoder->setLoRaParityBits(settings.m_nbParityBits); + } } if ((settings.m_packetLength != m_settings.m_packetLength) || force) { reverseAPIKeys.append("packetLength"); - m_decoder.setLoRaPacketLength(settings.m_packetLength); + if (m_decoder) { + m_decoder->setLoRaPacketLength(settings.m_packetLength); + } } if ((settings.m_decodeActive != m_settings.m_decodeActive) || force) { diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemod.h b/plugins/channelrx/demodchirpchat/chirpchatdemod.h index f1432f4f4..5bc815d2b 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemod.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemod.h @@ -35,13 +35,13 @@ #include "util/udpsinkutil.h" #include "chirpchatdemodbaseband.h" -#include "chirpchatdemoddecoder.h" class QNetworkAccessManager; class QNetworkReply; class DeviceAPI; class QThread; class ObjectPipe; +class ChirpChatDemodDecoder; class ChirpChatDemod : public BasebandSampleSink, public ChannelAPI { public: @@ -68,141 +68,6 @@ public: { } }; - class MsgReportDecodeBytes : public Message { - MESSAGE_CLASS_DECLARATION - - public: - const QByteArray& getBytes() const { return m_bytes; } - unsigned int getSyncWord() const { return m_syncWord; } - float getSingalDb() const { return m_signalDb; } - float getNoiseDb() const { return m_noiseDb; } - unsigned int getPacketSize() const { return m_packetSize; } - unsigned int getNbParityBits() const { return m_nbParityBits; } - unsigned int getNbSymbols() const { return m_nbSymbols; } - unsigned int getNbCodewords() const { return m_nbCodewords; } - bool getHasCRC() const { return m_hasCRC; } - bool getEarlyEOM() const { return m_earlyEOM; } - int getHeaderParityStatus() const { return m_headerParityStatus; } - bool getHeaderCRCStatus() const { return m_headerCRCStatus; } - int getPayloadParityStatus() const { return m_payloadParityStatus; } - bool getPayloadCRCStatus() const { return m_payloadCRCStatus; } - - static MsgReportDecodeBytes* create(const QByteArray& bytes) { - return new MsgReportDecodeBytes(bytes); - } - void setSyncWord(unsigned int syncWord) { - m_syncWord = syncWord; - } - void setSignalDb(float db) { - m_signalDb = db; - } - void setNoiseDb(float db) { - m_noiseDb = db; - } - void setPacketSize(unsigned int packetSize) { - m_packetSize = packetSize; - } - void setNbParityBits(unsigned int nbParityBits) { - m_nbParityBits = nbParityBits; - } - void setNbSymbols(unsigned int nbSymbols) { - m_nbSymbols = nbSymbols; - } - void setNbCodewords(unsigned int nbCodewords) { - m_nbCodewords = nbCodewords; - } - void setHasCRC(bool hasCRC) { - m_hasCRC = hasCRC; - } - void setEarlyEOM(bool earlyEOM) { - m_earlyEOM = earlyEOM; - } - void setHeaderParityStatus(int headerParityStatus) { - m_headerParityStatus = headerParityStatus; - } - void setHeaderCRCStatus(bool headerCRCStatus) { - m_headerCRCStatus = headerCRCStatus; - } - void setPayloadParityStatus(int payloadParityStatus) { - m_payloadParityStatus = payloadParityStatus; - } - void setPayloadCRCStatus(bool payloadCRCStatus) { - m_payloadCRCStatus = payloadCRCStatus; - } - - private: - QByteArray m_bytes; - unsigned int m_syncWord; - float m_signalDb; - float m_noiseDb; - unsigned int m_packetSize; - unsigned int m_nbParityBits; - unsigned int m_nbSymbols; - unsigned int m_nbCodewords; - bool m_hasCRC; - bool m_earlyEOM; - int m_headerParityStatus; - bool m_headerCRCStatus; - int m_payloadParityStatus; - bool m_payloadCRCStatus; - - MsgReportDecodeBytes(const QByteArray& bytes) : - Message(), - m_bytes(bytes), - m_syncWord(0), - m_signalDb(0.0), - m_noiseDb(0.0), - m_packetSize(0), - m_nbParityBits(0), - m_nbSymbols(0), - m_nbCodewords(0), - m_hasCRC(false), - m_earlyEOM(false), - m_headerParityStatus(false), - m_headerCRCStatus(false), - m_payloadParityStatus(false), - m_payloadCRCStatus(false) - { } - }; - - class MsgReportDecodeString : public Message { - MESSAGE_CLASS_DECLARATION - - public: - const QString& getString() const { return m_str; } - unsigned int getSyncWord() const { return m_syncWord; } - float getSingalDb() const { return m_signalDb; } - float getNoiseDb() const { return m_noiseDb; } - - static MsgReportDecodeString* create(const QString& str) - { - return new MsgReportDecodeString(str); - } - void setSyncWord(unsigned int syncWord) { - m_syncWord = syncWord; - } - void setSignalDb(float db) { - m_signalDb = db; - } - void setNoiseDb(float db) { - m_noiseDb = db; - } - - private: - QString m_str; - unsigned int m_syncWord; - float m_signalDb; - float m_noiseDb; - - MsgReportDecodeString(const QString& str) : - Message(), - m_str(str), - m_syncWord(0), - m_signalDb(0.0), - m_noiseDb(0.0) - { } - }; - ChirpChatDemod(DeviceAPI* deviceAPI); virtual ~ChirpChatDemod(); virtual void destroy() { delete this; } @@ -276,9 +141,10 @@ public: private: DeviceAPI *m_deviceAPI; QThread *m_thread; + QThread *m_decoderThread; ChirpChatDemodBaseband *m_basebandSink; + ChirpChatDemodDecoder *m_decoder; bool m_running; - ChirpChatDemodDecoder m_decoder; ChirpChatDemodSettings m_settings; SpectrumVis m_spectrumVis; int m_basebandSampleRate; //!< stored from device message used when starting baseband sink diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoder.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoder.cpp index 09e79f584..3a4b77970 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoder.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoder.cpp @@ -15,18 +15,25 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + #include "chirpchatdemoddecoder.h" #include "chirpchatdemoddecodertty.h" #include "chirpchatdemoddecoderascii.h" #include "chirpchatdemoddecoderlora.h" +#include "chirpchatdemoddecoderft.h" +#include "chirpchatdemodmsg.h" ChirpChatDemodDecoder::ChirpChatDemodDecoder() : m_codingScheme(ChirpChatDemodSettings::CodingTTY), m_nbSymbolBits(5), m_nbParityBits(1), m_hasCRC(true), - m_hasHeader(true) -{} + m_hasHeader(true), + m_outputMessageQueue(nullptr) +{ + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); +} ChirpChatDemodDecoder::~ChirpChatDemodDecoder() {} @@ -54,7 +61,7 @@ void ChirpChatDemodDecoder::decodeSymbols(const std::vector& sym } break; case ChirpChatDemodSettings::CodingASCII: - if (m_nbSymbolBits == 5) { + if (m_nbSymbolBits == 7) { ChirpChatDemodDecoderASCII::decodeSymbols(symbols, str); } break; @@ -99,3 +106,132 @@ void ChirpChatDemodDecoder::decodeSymbols(const std::vector& sym break; } } + +void ChirpChatDemodDecoder::decodeSymbols( //!< For FT coding scheme + const std::vector>& mags, // vector of symbols magnitudes + int nbSymbolBits, //!< number of bits per symbol + std::string& msg, //!< formatted message + std::string& call1, //!< 1st callsign or shorthand + std::string& call2, //!< 2nd callsign + std::string& loc, //!< locator, report or shorthand + bool& reply //!< true if message is a reply report +) +{ + if (m_codingScheme != ChirpChatDemodSettings::CodingFT) { + return; + } + + ChirpChatDemodDecoderFT::decodeSymbols( + mags, + nbSymbolBits, + msg, + call1, + call2, + loc, + reply, + m_payloadParityStatus, + m_payloadCRCStatus + ); +} + +bool ChirpChatDemodDecoder::handleMessage(const Message& cmd) +{ + if (ChirpChatDemodMsg::MsgDecodeSymbols::match(cmd)) + { + qDebug("ChirpChatDemodDecoder::handleMessage: MsgDecodeSymbols"); + ChirpChatDemodMsg::MsgDecodeSymbols& msg = (ChirpChatDemodMsg::MsgDecodeSymbols&) cmd; + float msgSignalDb = msg.getSingalDb(); + float msgNoiseDb = msg.getNoiseDb(); + unsigned int msgSyncWord = msg.getSyncWord(); + QDateTime dt = QDateTime::currentDateTime(); + QString msgTimestamp = dt.toString(Qt::ISODateWithMs); + + if (m_codingScheme == ChirpChatDemodSettings::CodingLoRa) + { + QByteArray msgBytes; + decodeSymbols(msg.getSymbols(), msgBytes); + + if (m_outputMessageQueue) + { + ChirpChatDemodMsg::MsgReportDecodeBytes *outputMsg = ChirpChatDemodMsg::MsgReportDecodeBytes::create(msgBytes); + outputMsg->setSyncWord(msgSyncWord); + outputMsg->setSignalDb(msgSignalDb); + outputMsg->setNoiseDb(msgNoiseDb); + outputMsg->setMsgTimestamp(msgTimestamp); + outputMsg->setPacketSize(getPacketLength()); + outputMsg->setNbParityBits(getNbParityBits()); + outputMsg->setHasCRC(getHasCRC()); + outputMsg->setNbSymbols(getNbSymbols()); + outputMsg->setNbCodewords(getNbCodewords()); + outputMsg->setEarlyEOM(getEarlyEOM()); + outputMsg->setHeaderParityStatus(getHeaderParityStatus()); + outputMsg->setHeaderCRCStatus(getHeaderCRCStatus()); + outputMsg->setPayloadParityStatus(getPayloadParityStatus()); + outputMsg->setPayloadCRCStatus(getPayloadCRCStatus()); + m_outputMessageQueue->push(outputMsg); + } + } + else if (m_codingScheme == ChirpChatDemodSettings::CodingFT) + { + std::string fmsg, call1, call2, loc; + bool reply; + decodeSymbols( + msg.getMagnitudes(), + m_nbSymbolBits, + fmsg, + call1, + call2, + loc, + reply + ); + + if (m_outputMessageQueue) + { + ChirpChatDemodMsg::MsgReportDecodeFT *outputMsg = ChirpChatDemodMsg::MsgReportDecodeFT::create(); + outputMsg->setSyncWord(msgSyncWord); + outputMsg->setSignalDb(msgSignalDb); + outputMsg->setNoiseDb(msgNoiseDb); + outputMsg->setMsgTimestamp(msgTimestamp); + outputMsg->setMessage(QString(fmsg.c_str())); + outputMsg->setCall1(QString(call1.c_str())); + outputMsg->setCall2(QString(call2.c_str())); + outputMsg->setLoc(QString(loc.c_str())); + outputMsg->setReply(reply); + outputMsg->setPayloadParityStatus(getPayloadParityStatus()); + outputMsg->setPayloadCRCStatus(getPayloadCRCStatus()); + m_outputMessageQueue->push(outputMsg); + } + } + else + { + QString msgString; + decodeSymbols(msg.getSymbols(), msgString); + + if (m_outputMessageQueue) + { + ChirpChatDemodMsg::MsgReportDecodeString *outputMsg = ChirpChatDemodMsg::MsgReportDecodeString::create(msgString); + outputMsg->setSyncWord(msgSyncWord); + outputMsg->setSignalDb(msgSignalDb); + outputMsg->setNoiseDb(msgNoiseDb); + outputMsg->setMsgTimestamp(msgTimestamp); + m_outputMessageQueue->push(outputMsg); + } + } + + return true; + } + + return false; +} + +void ChirpChatDemodDecoder::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoder.h b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoder.h index e0566316a..3abcc8cd5 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoder.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoder.h @@ -21,10 +21,15 @@ #define INCLUDE_CHIRPCHATDEMODDECODER_H #include + +#include + +#include "util/messagequeue.h" #include "chirpchatdemodsettings.h" -class ChirpChatDemodDecoder +class ChirpChatDemodDecoder : public QObject { + Q_OBJECT public: ChirpChatDemodDecoder(); ~ChirpChatDemodDecoder(); @@ -35,8 +40,22 @@ public: void setLoRaHasHeader(bool hasHeader) { m_hasHeader = hasHeader; } void setLoRaHasCRC(bool hasCRC) { m_hasCRC = hasCRC; } void setLoRaPacketLength(unsigned int packetLength) { m_packetLength = packetLength; } + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + void setOutputMessageQueue(MessageQueue *messageQueue) { m_outputMessageQueue = messageQueue; } + +private: + bool handleMessage(const Message& cmd); void decodeSymbols(const std::vector& symbols, QString& str); //!< For ASCII and TTY void decodeSymbols(const std::vector& symbols, QByteArray& bytes); //!< For raw bytes (original LoRa) + void decodeSymbols( //!< For FT coding scheme + const std::vector>& mags, // vector of symbols magnitudes + int nbSymbolBits, //!< number of bits per symbol + std::string& msg, //!< formatted message + std::string& call1, //!< 1st callsign or shorthand + std::string& call2, //!< 2nd callsign + std::string& loc, //!< locator, report or shorthand + bool& reply //!< true if message is a reply report + ); unsigned int getNbParityBits() const { return m_nbParityBits; } unsigned int getPacketLength() const { return m_packetLength; } bool getHasCRC() const { return m_hasCRC; } @@ -48,7 +67,6 @@ public: int getPayloadParityStatus() const { return m_payloadParityStatus; } bool getPayloadCRCStatus() const { return m_payloadCRCStatus; } -private: ChirpChatDemodSettings::CodingScheme m_codingScheme; unsigned int m_spreadFactor; unsigned int m_deBits; @@ -65,6 +83,11 @@ private: bool m_headerCRCStatus; int m_payloadParityStatus; bool m_payloadCRCStatus; + MessageQueue m_inputMessageQueue; + MessageQueue *m_outputMessageQueue; + +private slots: + void handleInputMessages(); }; #endif // INCLUDE_CHIRPCHATDEMODDECODER_H diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.cpp new file mode 100644 index 000000000..dbfcbc285 --- /dev/null +++ b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.cpp @@ -0,0 +1,176 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2024 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "chirpchatdemodsettings.h" +#include "chirpchatdemoddecoderft.h" + +#ifndef HAS_FT8 +void ChirpChatDemodDecoderFT::decodeSymbols( + const std::vector>& mags, // vector of symbols magnitudes + int nbSymbolBits, //!< number of bits per symbol + QString& msg, //!< formatted message + QString& call1, //!< 1st callsign or shorthand + QString& call2, //!< 2nd callsign + QString& loc, //!< locator, report or shorthand + bool& reply //!< true if message is a reply report +) +{ + qWarning("ChirpChatDemodDecoderFT::decodeSymbols: not implemented"); +} +#else + +#include "ft8.h" +#include "packing.h" + +void ChirpChatDemodDecoderFT::decodeSymbols( + const std::vector>& mags, // vector of symbols magnitudes + int nbSymbolBits, //!< number of bits per symbol + std::string& msg, //!< formatted message + std::string& call1, //!< 1st callsign or shorthand + std::string& call2, //!< 2nd callsign + std::string& loc, //!< locator, report or shorthand + bool& reply, //!< true if message is a reply report + int& payloadParityStatus, + bool& payloadCRCStatus +) +{ + if (mags.size()*nbSymbolBits < 174) + { + qWarning("ChirpChatDemodDecoderFT::decodeSymbols: insufficient number of symbols for FT payload"); + return; + } + + // float *lls = new float[mags.size()*nbSymbolBits]; // bits log likelihoods (>0 for 0, <0 for 1) + // std::fill(lls, lls+mags.size()*nbSymbolBits, 0.0); + FT8::FT8Params params; + // FT8::FT8::soft_decode_mags(params, mags, nbSymbolBits, lls); + int r174[174]; + std::string comments; + payloadParityStatus = (int) ChirpChatDemodSettings::ParityOK; + payloadCRCStatus = false; + std::vector> magsp = mags; + + qDebug("ChirpChatDemodDecoderFT::decodeSymbols: try decode with symbol shift 0"); + int res = decodeWithShift(params, magsp, nbSymbolBits, r174, comments); + + if (res == 0) + { + std::vector> magsn = mags; + int shiftcount = 0; + + while ((res == 0) && (shiftcount < 7)) + { + qDebug("ChirpChatDemodDecoderFT::decodeSymbols: try decode with symbol shift %d", shiftcount + 1); + res = decodeWithShift(params, magsp, nbSymbolBits, r174, comments, 1); + + if (res == 0) + { + qDebug("ChirpChatDemodDecoderFT::decodeSymbols: try decode with symbol shift -%d", shiftcount + 1); + res = decodeWithShift(params, magsn, nbSymbolBits, r174, comments, -1); + } + + shiftcount++; + } + } + + if (res == 0) + { + if (comments == "LDPC fail") + { + qWarning("ChirpChatDemodDecoderFT::decodeSymbols: LDPC failed"); + payloadParityStatus = (int) ChirpChatDemodSettings::ParityError; + } + else if (comments == "OSD fail") + { + qWarning("ChirpChatDemodDecoderFT::decodeSymbols: OSD failed"); + payloadParityStatus = (int) ChirpChatDemodSettings::ParityError; + } + else if (comments == "CRC fail") + { + qWarning("ChirpChatDemodDecoderFT::decodeSymbols: CRC failed"); + } + else + { + qWarning("ChirpChatDemodDecoderFT::decodeSymbols: decode failed for unknown reason"); + payloadParityStatus = (int) ChirpChatDemodSettings::ParityUndefined; + } + + return; + } + + payloadCRCStatus = true; + FT8::Packing packing; + std::string msgType; + msg = packing.unpack(r174, call1, call2, loc, msgType); + reply = false; + + if ((msgType == "0.3") || (msgType == "0.3")) { + reply = r174[56] != 0; + } + if ((msgType == "1") || (msgType == "2")) { + reply = r174[58] != 0; + } + if ((msgType == "3")) { + reply = r174[57] != 0; + } + if ((msgType == "5")) { + reply = r174[34] != 0; + } +} + +int ChirpChatDemodDecoderFT::decodeWithShift( + FT8::FT8Params& params, + std::vector>& mags, + int nbSymbolBits, + int *r174, + std::string& comments, + int shift +) +{ + if (shift > 0) + { + for (unsigned int si = 0; si < mags.size(); si++) + { + for (int bini = (1< 0; bini--) + { + float x = mags[si][bini - 1]; + mags[si][bini - 1] = mags[si][bini]; + mags[si][bini] = x; + } + } + } + + if (shift < 0) + { + for (unsigned int si = 0; si < mags.size(); si++) + { + for (int bini = 0; bini < (1<0 for 0, <0 for 1) + std::fill(lls, lls+mags.size()*nbSymbolBits, 0.0); + FT8::FT8::soft_decode_mags(params, mags, nbSymbolBits, lls); + return FT8::FT8::decode(lls, r174, params, 0, comments); +} + +#endif // HAS_FT8 diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.h b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.h new file mode 100644 index 000000000..f921cf815 --- /dev/null +++ b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.h @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2024 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_CHIRPCHATDEMODDECODERFT_H +#define INCLUDE_CHIRPCHATDEMODDECODERFT_H + +#include +#include + +namespace FT8 { + class FT8Params; +} + +class ChirpChatDemodDecoderFT +{ +public: + enum ParityStatus + { + ParityUndefined, + ParityError, + ParityCorrected, + ParityOK + }; + + static void decodeSymbols( + const std::vector>& mags, // vector of symbols magnitudes + int nbSymbolBits, //!< number of bits per symbol + std::string& msg, //!< formatted message + std::string& call1, //!< 1st callsign or shorthand + std::string& call2, //!< 2nd callsign + std::string& loc, //!< locator, report or shorthand + bool& reply, //!< true if message is a reply report + int& payloadParityStatus, + bool& payloadCRCStatus + ); + +private: + static int decodeWithShift( + FT8::FT8Params& params, + std::vector>& mags, + int nbSymbolBits, + int *r174, + std::string& comments, + int shift = 0 + ); +}; + + +#endif diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderlora.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderlora.cpp index 3bf878414..684c637c0 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderlora.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderlora.cpp @@ -17,6 +17,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include "chirpchatdemodsettings.h" #include "chirpchatdemoddecoderlora.h" void ChirpChatDemodDecoderLoRa::decodeHeader( @@ -71,14 +72,14 @@ void ChirpChatDemodDecoderLoRa::decodeHeader( if (bad) { - headerParityStatus = (int) ParityError; + headerParityStatus = (int) ChirpChatDemodSettings::ParityError; } else { if (error) { - headerParityStatus = (int) ParityCorrected; + headerParityStatus = (int) ChirpChatDemodSettings::ParityCorrected; } else { - headerParityStatus = (int) ParityOK; + headerParityStatus = (int) ChirpChatDemodSettings::ParityOK; } if (bytes[2] != 0) { @@ -300,11 +301,11 @@ void ChirpChatDemodDecoderLoRa::decodeBytes( } if (bad) { - payloadParityStatus = (int) ParityError; + payloadParityStatus = (int) ChirpChatDemodSettings::ParityError; } else if (error) { - payloadParityStatus = (int) ParityCorrected; + payloadParityStatus = (int) ChirpChatDemodSettings::ParityCorrected; } else { - payloadParityStatus = (int) ParityOK; + payloadParityStatus = (int) ChirpChatDemodSettings::ParityOK; } // finalization: diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderlora.h b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderlora.h index e9fb63e5a..6459ee2bb 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderlora.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemoddecoderlora.h @@ -26,14 +26,6 @@ class ChirpChatDemodDecoderLoRa { public: - enum ParityStatus - { - ParityUndefined, - ParityError, - ParityCorrected, - ParityOK - }; - static void decodeBytes( QByteArray& bytes, const std::vector& inSymbols, diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.cpp index 84f689ebf..25f99edc7 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.cpp @@ -40,6 +40,7 @@ #include "maincore.h" #include "chirpchatdemod.h" +#include "chirpchatdemodmsg.h" #include "chirpchatdemodgui.h" ChirpChatDemodGUI* ChirpChatDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) @@ -103,7 +104,7 @@ bool ChirpChatDemodGUI::handleMessage(const Message& message) return true; } - else if (ChirpChatDemod::MsgReportDecodeBytes::match(message)) + else if (ChirpChatDemodMsg::MsgReportDecodeBytes::match(message)) { if (m_settings.m_codingScheme == ChirpChatDemodSettings::CodingLoRa) { showLoRaMessage(message); @@ -111,11 +112,19 @@ bool ChirpChatDemodGUI::handleMessage(const Message& message) return true; } - else if (ChirpChatDemod::MsgReportDecodeString::match(message)) + else if (ChirpChatDemodMsg::MsgReportDecodeString::match(message)) { if ((m_settings.m_codingScheme == ChirpChatDemodSettings::CodingASCII) - || (m_settings.m_codingScheme == ChirpChatDemodSettings::CodingTTY)) { - showTextMessage(message); + || (m_settings.m_codingScheme == ChirpChatDemodSettings::CodingTTY)) { + showTextMessage(message); + } + + return true; + } + else if (ChirpChatDemodMsg::MsgReportDecodeFT::match(message)) + { + if (m_settings.m_codingScheme == ChirpChatDemodSettings::CodingFT) { + showFTMessage(message); } return true; @@ -280,6 +289,7 @@ void ChirpChatDemodGUI::on_header_stateChanged(int state) ui->fecParity->setEnabled(state != Qt::Checked); ui->crc->setEnabled(state != Qt::Checked); + ui->packetLength->setEnabled(state != Qt::Checked); applySettings(); } @@ -543,11 +553,11 @@ void ChirpChatDemodGUI::displaySquelch() void ChirpChatDemodGUI::displayLoRaStatus(int headerParityStatus, bool headerCRCStatus, int payloadParityStatus, bool payloadCRCStatus) { - if (m_settings.m_hasHeader && (headerParityStatus == (int) ParityOK)) { + if (m_settings.m_hasHeader && (headerParityStatus == (int) ChirpChatDemodSettings::ParityOK)) { ui->headerHammingStatus->setStyleSheet("QLabel { background-color : green; }"); - } else if (m_settings.m_hasHeader && (headerParityStatus == (int) ParityError)) { + } else if (m_settings.m_hasHeader && (headerParityStatus == (int) ChirpChatDemodSettings::ParityError)) { ui->headerHammingStatus->setStyleSheet("QLabel { background-color : red; }"); - } else if (m_settings.m_hasHeader && (headerParityStatus == (int) ParityCorrected)) { + } else if (m_settings.m_hasHeader && (headerParityStatus == (int) ChirpChatDemodSettings::ParityCorrected)) { ui->headerHammingStatus->setStyleSheet("QLabel { background-color : blue; }"); } else { ui->headerHammingStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }"); @@ -561,11 +571,11 @@ void ChirpChatDemodGUI::displayLoRaStatus(int headerParityStatus, bool headerCRC ui->headerCRCStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }"); } - if (payloadParityStatus == (int) ParityOK) { + if (payloadParityStatus == (int) ChirpChatDemodSettings::ParityOK) { ui->payloadFECStatus->setStyleSheet("QLabel { background-color : green; }"); - } else if (payloadParityStatus == (int) ParityError) { + } else if (payloadParityStatus == (int) ChirpChatDemodSettings::ParityError) { ui->payloadFECStatus->setStyleSheet("QLabel { background-color : red; }"); - } else if (payloadParityStatus == (int) ParityCorrected) { + } else if (payloadParityStatus == (int) ChirpChatDemodSettings::ParityCorrected) { ui->payloadFECStatus->setStyleSheet("QLabel { background-color : blue; }"); } else { ui->payloadFECStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }"); @@ -588,6 +598,25 @@ void ChirpChatDemodGUI::resetLoRaStatus() ui->nbCodewordsText->setText("---"); } +void ChirpChatDemodGUI::displayFTStatus(int payloadParityStatus, bool payloadCRCStatus) +{ + if (payloadParityStatus == (int) ChirpChatDemodSettings::ParityOK) { + ui->payloadFECStatus->setStyleSheet("QLabel { background-color : green; }"); + } else if (payloadParityStatus == (int) ChirpChatDemodSettings::ParityError) { + ui->payloadFECStatus->setStyleSheet("QLabel { background-color : red; }"); + } else if (payloadParityStatus == (int) ChirpChatDemodSettings::ParityCorrected) { + ui->payloadFECStatus->setStyleSheet("QLabel { background-color : blue; }"); + } else { + ui->payloadFECStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }"); + } + + if (payloadCRCStatus) { + ui->payloadCRCStatus->setStyleSheet("QLabel { background-color : green; }"); + } else { + ui->payloadCRCStatus->setStyleSheet("QLabel { background-color : red; }"); + } +} + void ChirpChatDemodGUI::setBandwidths() { int maxBandwidth = m_basebandSampleRate/ChirpChatDemodSettings::oversampling; @@ -607,7 +636,7 @@ void ChirpChatDemodGUI::setBandwidths() void ChirpChatDemodGUI::showLoRaMessage(const Message& message) { - const ChirpChatDemod::MsgReportDecodeBytes& msg = (ChirpChatDemod::MsgReportDecodeBytes&) message; + const ChirpChatDemodMsg::MsgReportDecodeBytes& msg = (ChirpChatDemodMsg::MsgReportDecodeBytes&) message; QByteArray bytes = msg.getBytes(); QString syncWordStr((tr("%1").arg(msg.getSyncWord(), 2, 16, QChar('0')))); @@ -643,7 +672,7 @@ void ChirpChatDemodGUI::showLoRaMessage(const Message& message) .arg(msg.getHeaderCRCStatus() ? "ok" : "err"); displayStatus(loRaStatus); - displayLoRaStatus(msg.getHeaderParityStatus(), msg.getHeaderCRCStatus(), (int) ParityUndefined, true); + displayLoRaStatus(msg.getHeaderParityStatus(), msg.getHeaderCRCStatus(), (int) ChirpChatDemodSettings::ParityUndefined, true); ui->payloadCRCStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }"); // reset payload CRC } else @@ -677,7 +706,7 @@ void ChirpChatDemodGUI::showLoRaMessage(const Message& message) void ChirpChatDemodGUI::showTextMessage(const Message& message) { - const ChirpChatDemod::MsgReportDecodeString& msg = (ChirpChatDemod::MsgReportDecodeString&) message; + const ChirpChatDemodMsg::MsgReportDecodeString& msg = (ChirpChatDemodMsg::MsgReportDecodeString&) message; QDateTime dt = QDateTime::currentDateTime(); QString dateStr = dt.toString("HH:mm:ss"); @@ -693,6 +722,27 @@ void ChirpChatDemodGUI::showTextMessage(const Message& message) displayText(msg.getString()); } +void ChirpChatDemodGUI::showFTMessage(const Message& message) +{ + const ChirpChatDemodMsg::MsgReportDecodeFT& msg = (ChirpChatDemodMsg::MsgReportDecodeFT&) message; + + QDateTime dt = QDateTime::currentDateTime(); + QString dateStr = dt.toString("HH:mm:ss"); + ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1)); + ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1)); + + QString status = tr("%1 S:%2 SN:%3 FEC:%4 CRC:%5") + .arg(dateStr) + .arg(msg.getSingalDb(), 0, 'f', 1) + .arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1) + .arg(getParityStr(msg.getPayloadParityStatus())) + .arg(msg.getPayloadCRCStatus() ? "ok" : "err"); + + displayStatus(status); + displayText(msg.getMessage()); // We do not show constituents of the message (call1, ...) + displayFTStatus(msg.getPayloadParityStatus(), msg.getPayloadCRCStatus()); +} + void ChirpChatDemodGUI::displayText(const QString& text) { QTextCursor cursor = ui->messageText->textCursor(); @@ -753,11 +803,11 @@ void ChirpChatDemodGUI::displayStatus(const QString& status) QString ChirpChatDemodGUI::getParityStr(int parityStatus) { - if (parityStatus == (int) ParityError) { + if (parityStatus == (int) ChirpChatDemodSettings::ParityError) { return "err"; - } else if (parityStatus == (int) ParityCorrected) { + } else if (parityStatus == (int) ChirpChatDemodSettings::ParityCorrected) { return "fix"; - } else if (parityStatus == (int) ParityOK) { + } else if (parityStatus == (int) ChirpChatDemodSettings::ParityOK) { return "ok"; } else { return "n/a"; diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.h b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.h index 8ce74aa30..277ae430c 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.h @@ -89,14 +89,6 @@ private slots: void tick(); private: - enum ParityStatus // matches decoder status - { - ParityUndefined, - ParityError, - ParityCorrected, - ParityOK - }; - Ui::ChirpChatDemodGUI* ui; PluginAPI* m_pluginAPI; DeviceUISet* m_deviceUISet; @@ -120,12 +112,14 @@ private: void displaySettings(); void displaySquelch(); void setBandwidths(); - void showLoRaMessage(const Message& message); + void showLoRaMessage(const Message& message); //!< For LoRa coding scheme void showTextMessage(const Message& message); //!< For TTY and ASCII + void showFTMessage(const Message& message); //!< For FT coding scheme void displayText(const QString& text); void displayBytes(const QByteArray& bytes); void displayStatus(const QString& status); void displayLoRaStatus(int headerParityStatus, bool headerCRCStatus, int payloadParityStatus, bool payloadCRCStatus); + void displayFTStatus(int payloadParityStatus, bool payloadCRCStatus); QString getParityStr(int parityStatus); void resetLoRaStatus(); bool handleMessage(const Message& message); diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.ui b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.ui index 39d5ba3d3..b127dc8c4 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.ui +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.ui @@ -723,7 +723,7 @@ - Set message length in symbols automatically to provided message length (LoRa only) + Set message length in symbols automatically to provided message length (LoRa and FT only) Auto diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodmsg.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemodmsg.cpp index bae47764a..2939f4488 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodmsg.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodmsg.cpp @@ -20,3 +20,6 @@ #include "chirpchatdemodmsg.h" MESSAGE_CLASS_DEFINITION(ChirpChatDemodMsg::MsgDecodeSymbols, Message) +MESSAGE_CLASS_DEFINITION(ChirpChatDemodMsg::MsgReportDecodeBytes, Message) +MESSAGE_CLASS_DEFINITION(ChirpChatDemodMsg::MsgReportDecodeString, Message) +MESSAGE_CLASS_DEFINITION(ChirpChatDemodMsg::MsgReportDecodeFT, Message) diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodmsg.h b/plugins/channelrx/demodchirpchat/chirpchatdemodmsg.h index 58ee3da20..2969916e1 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodmsg.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodmsg.h @@ -21,6 +21,8 @@ #include #include "util/message.h" +#include "chirpchatdemodsettings.h" + namespace ChirpChatDemodMsg { class MsgDecodeSymbols : public Message { @@ -80,6 +82,235 @@ namespace ChirpChatDemodMsg m_noiseDb(0.0) { m_symbols = symbols; } }; + + class MsgReportDecodeBytes : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const QByteArray& getBytes() const { return m_bytes; } + unsigned int getSyncWord() const { return m_syncWord; } + float getSingalDb() const { return m_signalDb; } + float getNoiseDb() const { return m_noiseDb; } + const QString& getMsgTimestamp() const { return m_msgTimestamp; } + unsigned int getPacketSize() const { return m_packetSize; } + unsigned int getNbParityBits() const { return m_nbParityBits; } + unsigned int getNbSymbols() const { return m_nbSymbols; } + unsigned int getNbCodewords() const { return m_nbCodewords; } + bool getHasCRC() const { return m_hasCRC; } + bool getEarlyEOM() const { return m_earlyEOM; } + int getHeaderParityStatus() const { return m_headerParityStatus; } + bool getHeaderCRCStatus() const { return m_headerCRCStatus; } + int getPayloadParityStatus() const { return m_payloadParityStatus; } + bool getPayloadCRCStatus() const { return m_payloadCRCStatus; } + + static MsgReportDecodeBytes* create(const QByteArray& bytes) { + return new MsgReportDecodeBytes(bytes); + } + void setSyncWord(unsigned int syncWord) { + m_syncWord = syncWord; + } + void setSignalDb(float db) { + m_signalDb = db; + } + void setNoiseDb(float db) { + m_noiseDb = db; + } + void setMsgTimestamp(const QString& ts) { + m_msgTimestamp = ts; + } + void setPacketSize(unsigned int packetSize) { + m_packetSize = packetSize; + } + void setNbParityBits(unsigned int nbParityBits) { + m_nbParityBits = nbParityBits; + } + void setNbSymbols(unsigned int nbSymbols) { + m_nbSymbols = nbSymbols; + } + void setNbCodewords(unsigned int nbCodewords) { + m_nbCodewords = nbCodewords; + } + void setHasCRC(bool hasCRC) { + m_hasCRC = hasCRC; + } + void setEarlyEOM(bool earlyEOM) { + m_earlyEOM = earlyEOM; + } + void setHeaderParityStatus(int headerParityStatus) { + m_headerParityStatus = headerParityStatus; + } + void setHeaderCRCStatus(bool headerCRCStatus) { + m_headerCRCStatus = headerCRCStatus; + } + void setPayloadParityStatus(int payloadParityStatus) { + m_payloadParityStatus = payloadParityStatus; + } + void setPayloadCRCStatus(bool payloadCRCStatus) { + m_payloadCRCStatus = payloadCRCStatus; + } + + private: + QByteArray m_bytes; + unsigned int m_syncWord; + float m_signalDb; + float m_noiseDb; + QString m_msgTimestamp; + unsigned int m_packetSize; + unsigned int m_nbParityBits; + unsigned int m_nbSymbols; + unsigned int m_nbCodewords; + bool m_hasCRC; + bool m_earlyEOM; + int m_headerParityStatus; + bool m_headerCRCStatus; + int m_payloadParityStatus; + bool m_payloadCRCStatus; + + MsgReportDecodeBytes(const QByteArray& bytes) : + Message(), + m_bytes(bytes), + m_syncWord(0), + m_signalDb(0.0), + m_noiseDb(0.0), + m_packetSize(0), + m_nbParityBits(0), + m_nbSymbols(0), + m_nbCodewords(0), + m_hasCRC(false), + m_earlyEOM(false), + m_headerParityStatus(false), + m_headerCRCStatus(false), + m_payloadParityStatus((int) ChirpChatDemodSettings::ParityUndefined), + m_payloadCRCStatus(false) + { } + }; + + class MsgReportDecodeString : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const QString& getString() const { return m_str; } + unsigned int getSyncWord() const { return m_syncWord; } + float getSingalDb() const { return m_signalDb; } + float getNoiseDb() const { return m_noiseDb; } + const QString& getMsgTimestamp() const { return m_msgTimestamp; } + + static MsgReportDecodeString* create(const QString& str) + { + return new MsgReportDecodeString(str); + } + void setSyncWord(unsigned int syncWord) { + m_syncWord = syncWord; + } + void setSignalDb(float db) { + m_signalDb = db; + } + void setNoiseDb(float db) { + m_noiseDb = db; + } + void setMsgTimestamp(const QString& ts) { + m_msgTimestamp = ts; + } + + private: + QString m_str; + unsigned int m_syncWord; + float m_signalDb; + float m_noiseDb; + QString m_msgTimestamp; + + MsgReportDecodeString(const QString& str) : + Message(), + m_str(str), + m_syncWord(0), + m_signalDb(0.0), + m_noiseDb(0.0) + { } + }; + + class MsgReportDecodeFT : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const QString& getMessage() const { return m_message; } + const QString& getCall1() const { return m_call1; } + const QString& getCall2() const { return m_call2; } + const QString& getLoc() const { return m_loc; } + bool isReply() const { return m_reply; } + bool isFreeText() const { return m_freeText; } + unsigned int getSyncWord() const { return m_syncWord; } + float getSingalDb() const { return m_signalDb; } + float getNoiseDb() const { return m_noiseDb; } + const QString& getMsgTimestamp() const { return m_msgTimestamp; } + int getPayloadParityStatus() const { return m_payloadParityStatus; } + bool getPayloadCRCStatus() const { return m_payloadCRCStatus; } + + static MsgReportDecodeFT* create() + { + return new MsgReportDecodeFT(); + } + void setMessage(const QString& message) { + m_message = message; + } + void setCall1(const QString& call1) { + m_call1 = call1; + } + void setCall2(const QString& call2) { + m_call2 = call2; + } + void setLoc(const QString& loc) { + m_loc = loc; + } + void setReply(bool reply) { + m_reply = reply; + } + void setFreeText(bool freeText) { + m_freeText = freeText; + } + void setSyncWord(unsigned int syncWord) { + m_syncWord = syncWord; + } + void setSignalDb(float db) { + m_signalDb = db; + } + void setNoiseDb(float db) { + m_noiseDb = db; + } + void setMsgTimestamp(const QString& ts) { + m_msgTimestamp = ts; + } + void setPayloadParityStatus(int payloadParityStatus) { + m_payloadParityStatus = payloadParityStatus; + } + void setPayloadCRCStatus(bool payloadCRCStatus) { + m_payloadCRCStatus = payloadCRCStatus; + } + + private: + QString m_message; + QString m_call1; + QString m_call2; + QString m_loc; + bool m_reply; + bool m_freeText; + unsigned int m_syncWord; + float m_signalDb; + float m_noiseDb; + QString m_msgTimestamp; + int m_payloadParityStatus; + bool m_payloadCRCStatus; + + MsgReportDecodeFT() : + Message(), + m_reply(false), + m_freeText(false), + m_syncWord(0), + m_signalDb(0.0), + m_noiseDb(0.0), + m_payloadParityStatus((int) ChirpChatDemodSettings::ParityUndefined), + m_payloadCRCStatus(false) + { } + }; } #endif // INCLUDE_CHIRPCHATDEMODMSG_H diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.cpp index 518d61717..4643aecdc 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.cpp @@ -26,6 +26,7 @@ const int ChirpChatDemodSettings::bandwidths[] = { 325, // 384k / 1024 + 488, // 500k / 1024 750, // 384k / 512 1500, // 384k / 256 2604, // 333k / 128 @@ -53,7 +54,7 @@ const int ChirpChatDemodSettings::bandwidths[] = { 400000, // 400k / 1 500000 // 500k / 1 }; -const int ChirpChatDemodSettings::nbBandwidths = 3*8 + 3; +const int ChirpChatDemodSettings::nbBandwidths = 3*8 + 4; const int ChirpChatDemodSettings::oversampling = 2; ChirpChatDemodSettings::ChirpChatDemodSettings() : diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.h b/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.h index 051312d9c..f66f1ef58 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.h @@ -41,6 +41,14 @@ struct ChirpChatDemodSettings CodingFT //!< FT8/4 scheme (payload 174 bits LDPC) }; + enum ParityStatus + { + ParityUndefined, + ParityError, + ParityCorrected, + ParityOK + }; + int m_inputFrequencyOffset; int m_bandwidthIndex; int m_spreadFactor; diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodsink.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemodsink.cpp index 3fe3f8fd2..0c7c1ab85 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodsink.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodsink.cpp @@ -286,8 +286,10 @@ void ChirpChatDemodSink::processSample(const Complex& ci) m_preambleHistory[m_chirpCount] = imax; m_chirpCount++; + double preDrop = magsqPre - magsqSFD; + double dropRatio = -preDrop / magsqSFD; - if (magsqPre < magsqSFD) // preamble drop + if ((preDrop < 0.0) && (dropRatio > 0.5)) // preamble drop { m_magsqTotalAvg(magsqSFDTotal); @@ -455,19 +457,12 @@ void ChirpChatDemodSink::processSample(const Complex& ci) || ((m_settings.m_eomSquelchTenths*magsq)/10.0 > m_magsqMax)) { qDebug("ChirpChatDemodSink::processSample: symbol %02u: %4u|%11.6f", m_chirpCount, symbol, magsq); - // const std::vector& magnitudes = m_decodeMsg->getMagnitudes().back(); - // int i = 0; - // for (auto magnitude : magnitudes) - // { - // qDebug("ChirpChatDemodSink::processSample: mag[%02d] = %11.6f", i, magnitude); - // i++; - // } m_magsqOnAvg(magsq); m_chirpCount++; if (m_chirpCount > m_settings.m_nbSymbolsMax) { - qDebug("ChirpChatDemodSink::processSample: message length exceeded"); + qDebug("ChirpChatDemodSink::processSample: message length reached"); m_state = ChirpChatStateReset; m_decodeMsg->setSignalDb(CalcDb::dbPower(m_magsqOnAvg.asDouble() / (1<setNoiseDb(CalcDb::dbPower(m_magsqOffAvg.asDouble() / (1<A.2: Start/Stop decoder @@ -145,7 +147,7 @@ This is the expected number of symbols in a message. When a header is present in

A.5: Auto message length

-LoRa mode only. Set message length (A.4) equal to the number of symbols specified in the message just received. When messages are sent repeatedly this helps adjusting in possible message length changes automatically. +LoRa and DT modes only. Set message length (A.4) equal to the number of symbols specified (or implied for FT) in the message just received. When messages are sent repeatedly this helps adjusting in possible message length changes automatically.

A.6: Sync word

@@ -163,21 +165,21 @@ When a header is expected this control is disabled because the value used is the

A.9: Payload CRC presence

-Use this checkbox to tell if you expect a 2 byte CRC at the end of the payload. +LoRa mode: Use this checkbox to tell if you expect a 2 byte CRC at the end of the payload. FT mode: there is always a CRC. -When a header is expected this control is disabled because the value used is the one found in the header. +LoRa: When a header is expected this control is disabled because the value used is the one found in the header.

A.10: Packet length

-This is the expected packet length in bytes without header and CRC. +This is the expected packet length in bytes without header and CRC. For FT this is the number of symbols. -When a header is expected this control is disabled because the value used is the one found in the header. +LoRa: When a header is expected this control is disabled because the value used is the one found in the header.

A.11: Number of symbols and codewords

This is the number of symbols (left of slash) and codewords (right of slash) used for the payload including header and CRC. -

A.12: Header FEC indicator

+

A.12: Header FEC indicator (LoRa)

Header uses a H(4,8) FEC. The color of the indicator gives the status of header parity checks: @@ -186,27 +188,27 @@ Header uses a H(4,8) FEC. The color of the indicator gives the status of header - **Blue**: recovered error - **Green**: no errors -

A.13: Header CRC indicator

+

A.13: Header CRC indicator (LoRa)

The header has a one byte CRC. The color of this indicator gives the CRC status: - **Green**: CRC OK - **Red**: CRC error -

A.14: Payload FEC indicator

+

A.14: Payload FEC indicator (LoRa and FT)

The color of the indicator gives the status of payload parity checks: - **Grey**: undefined - - **Red**: unrecoverable error. H(4,7) cannot distinguish between recoverable and unrecoverable error. Therefore this is never displayed for H(4,7) - - **Blue**: recovered error + - **Red**: unrecoverable error. H(4,7) cannot distinguish between recoverable and unrecoverable error. Therefore this is never displayed for H(4,7). For FT it means that LDPC decoding failed. + - **Blue**: recovered error (LoRa only) - **Green**: no errors -

A.15: Payload CRC indicator

+

A.15: Payload CRC indicator (LoRa and FT)

The payload can have a two byte CRC. The color of this indicator gives the CRC status: - - **Grey**: No CRC + - **Grey**: No CRC (LoRa) - **Green**: CRC OK - **Red**: CRC error @@ -216,7 +218,7 @@ Use this push button to clear the message window (12)

12: Message window

-This is where the message and status data are displayed. The display varies if the coding scheme is purely text based (TTY, ASCII) or text/binary mixed based (LoRa). The text vs binary consideration concerns the content of the message not the way it is transmitted on air that is by itself binary. +This is where the message and status data are displayed. The display varies if the coding scheme is purely text based (TTY, ASCII, FT) or text/binary mixed based (LoRa). The text vs binary consideration concerns the content of the message not the way it is transmitted on air that is by itself binary.

12.a: Text messages

diff --git a/plugins/channelrx/demoddatv/readme.md b/plugins/channelrx/demoddatv/readme.md index 960641bc9..957c51a25 100644 --- a/plugins/channelrx/demoddatv/readme.md +++ b/plugins/channelrx/demoddatv/readme.md @@ -114,7 +114,7 @@ Use this dial to flip through standard DATV symbol rates: 25, 33, 66, 125, 250,
B.2a.4: FEC rate
-Dpends on the standard and modulation +Depends on the standard and modulation - DVB-S with all modulations: 1/2 , 2/3 , 3/4, 5/6 and 7/8. - DVB-S2 and QPSK: 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 5/6, 8/9, 9/10 diff --git a/plugins/channelrx/demodendoftrain/endoftraindemodgui.ui b/plugins/channelrx/demodendoftrain/endoftraindemodgui.ui index 7630fb32b..87091f2d8 100644 --- a/plugins/channelrx/demodendoftrain/endoftraindemodgui.ui +++ b/plugins/channelrx/demodendoftrain/endoftraindemodgui.ui @@ -736,7 +736,7 @@ Light Batt
- Market light battery condtion + Market light battery condition diff --git a/plugins/channelrx/demodendoftrain/readme.md b/plugins/channelrx/demodendoftrain/readme.md index d952fa279..22fb78306 100644 --- a/plugins/channelrx/demodendoftrain/readme.md +++ b/plugins/channelrx/demodendoftrain/readme.md @@ -4,7 +4,7 @@ This plugin can be used to demodulate End-of-Train packets. These are packets transmitted by an [End-of-Train Device](https://en.wikipedia.org/wiki/End-of-train_device), that can be found on some trains. -It transmits information about whether motion is detected, brake pressue, whether the marker light is on and battery information. +It transmits information about whether motion is detected, brake pressure, whether the marker light is on and battery information. * Frequency: 457.9375 MHz (North America, India), 477.7 MHz (Australia) and 450.2625 MHz (New Zealand). * Modulation: FSK, 1800Hz space, 1200 mark, +-3kHz deviation. @@ -93,7 +93,7 @@ The received packets table displays the contents of the packets that have been r * Disc - Discretionary bit that is used for varying data by different vendors. * Valve - Valve circuit status (Ok or Fail). * Conf - Confirmation indicator. -* Turbine - Air tubine equiped. +* Turbine - Air turbine equipped. * Motion - Whether motion is detected (i.e. is the rear of the train is moving). * Light Batt - Marker light battery condition (Ok or Low). * Light - Marker light status (On or off). diff --git a/plugins/channelrx/demodssb/readme.md b/plugins/channelrx/demodssb/readme.md index 9694a378a..c7ec86423 100644 --- a/plugins/channelrx/demodssb/readme.md +++ b/plugins/channelrx/demodssb/readme.md @@ -159,7 +159,7 @@ Use this button to toggle noise reduction on/off. Right click on this button to

13.4.1: Noise reduction scheme

-Use this combo box to choose the noise reduction scheme among the follwing: +Use this combo box to choose the noise reduction scheme among the following: - **Average**: calculates the average of magnitudes of the FFT (PSD) and sets the magnitude threshold to this average multiplied by a factor that can be set with the control next (13.4.2). diff --git a/plugins/channelrx/freqscanner/readme.md b/plugins/channelrx/freqscanner/readme.md index 4995c09be..0636c0683 100644 --- a/plugins/channelrx/freqscanner/readme.md +++ b/plugins/channelrx/freqscanner/readme.md @@ -18,7 +18,7 @@ Specifies the channel (such as an AM, NFM or DSD Demod), by device set and chann

2: Minimum frequency shift from center frequency of reception for channel

-Use the wheels of keyboard to adjust the minimim frequency shift in Hz from the center frequency of reception for the channel (1). +Use the wheels of keyboard to adjust the minimum frequency shift in Hz from the center frequency of reception for the channel (1). This setting is typically used to avoid having the channel (1) centered at DC, which can be problematic for some demodulators used with SDRs with a DC spike. @@ -34,7 +34,7 @@ Power threshold in dB that determines whether a frequency is active or not. Specifies the time in milliseconds that the Frequency Scanner should wait after adjusting the device center frequency, before starting a measurement. This time should take in to account PLL settle time and the device to host transfer latency, so that the measurement only starts when IQ data -that corresponds to the set frequency is being recieved. +that corresponds to the set frequency is being received.

6: t_s - Scan time

@@ -93,7 +93,7 @@ The frequency table contains the list of frequencies to be scanned, along with r - Freq (Hz): Specifies the channel center frequencies to be scanned. Values should be entered in Hertz. - Annotation: An annotation (description) for the frequency, that is obtained from the closest matching [annotation marker](../../../sdrgui/gui/spectrummarkers.md) in the Main Spectrum. -- Enable: Determines whether the frequency will be scanned. This can be used to temporaily disable frequencies you aren't interested in. +- Enable: Determines whether the frequency will be scanned. This can be used to temporarily disable frequencies you aren't interested in. - Power (dB): Displays the measured power in decibels from the last scan. The cell will have a green background if the power was above the threshold (4). - Active Count: Displays the number of scans in which the power for this frequency was above the threshold (4). This allows you to see which frequencies are commonly in use. - Notes: Available for user-entry of notes/information about this frequency. diff --git a/plugins/channeltx/modchirpchat/chirpchatmodencoderft.cpp b/plugins/channeltx/modchirpchat/chirpchatmodencoderft.cpp index c874fc350..b36511add 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmodencoderft.cpp +++ b/plugins/channeltx/modchirpchat/chirpchatmodencoderft.cpp @@ -84,6 +84,7 @@ void ChirpChatModEncoderFT::encodeMsg( if ((i % nbSymbolBits) == (nbSymbolBits - 1)) { + symbol = symbol ^ (symbol >> 1); // Gray code symbols.push_back(symbol); symbol = 0; } @@ -96,7 +97,7 @@ void ChirpChatModEncoderFT::encodeTextMsg(const QString& text, int a174[]) std::fill(a77, a77 + 77, 0); QString sentMsg = text.rightJustified(13, ' ', true); - if (!FT8::Packing::packfree(a77, sentMsg.toStdString())) + if (!FT8::Packing::packfree(a77, sentMsg.toUpper().toStdString())) { qDebug("ChirpChatModEncoderFT::encodeTextMsg: failed to encode free text message (%s)", qPrintable(sentMsg)); return; @@ -109,21 +110,27 @@ void ChirpChatModEncoderFT::encodeMsgBeaconOrCQ(const QString& myCall, const QSt { int c28_1, c28_2, g15; - if (!FT8::Packing::packcall_std(c28_1, shorthand.toStdString())) // + if (!FT8::Packing::packcall_std(c28_1, shorthand.toUpper().toStdString())) // { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode call1 (%s)", qPrintable(shorthand)); + qDebug("ChirpChatModEncoderFT::encodeMsgBeaconOrCQ: failed to encode call1 (%s)", qPrintable(shorthand)); return; } - if (!FT8::Packing::packcall_std(c28_2, myCall.toStdString())) + if (!FT8::Packing::packcall_std(c28_2, myCall.toUpper().toStdString())) { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode call2 (%s)", qPrintable(myCall)); + qDebug("ChirpChatModEncoderFT::encodeMsgBeaconOrCQ: failed to encode call2 (%s)", qPrintable(myCall)); return; } - if (!FT8::Packing::packgrid(g15, myLocator.toStdString())) + if (myLocator.size() < 4) { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode locator (%s)", qPrintable(myLocator)); + qDebug("ChirpChatModEncoderFT::encodeMsgBeaconOrCQ: locator invalid (%s)", qPrintable(myLocator)); + return; + } + + if (!FT8::Packing::packgrid(g15, myLocator.left(4).toUpper().toStdString())) + { + qDebug("ChirpChatModEncoderFT::encodeMsgBeaconOrCQ: failed to encode locator (%s)", qPrintable(myLocator)); return; } @@ -137,21 +144,27 @@ void ChirpChatModEncoderFT::encodeMsgReply(const QString& myCall, const QString& { int c28_1, c28_2, g15; - if (!FT8::Packing::packcall_std(c28_1, urCall.toStdString())) // + if (!FT8::Packing::packcall_std(c28_1, urCall.toUpper().toStdString())) // { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode call1 (%s)", qPrintable(urCall)); + qDebug("ChirpChatModEncoderFT::encodeMsgReply: failed to encode call1 (%s)", qPrintable(urCall)); return; } - if (!FT8::Packing::packcall_std(c28_2, myCall.toStdString())) + if (!FT8::Packing::packcall_std(c28_2, myCall.toUpper().toStdString())) { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode call2 (%s)", qPrintable(myCall)); + qDebug("ChirpChatModEncoderFT::encodeMsgReply: failed to encode call2 (%s)", qPrintable(myCall)); return; } - if (!FT8::Packing::packgrid(g15, myLocator.toStdString())) + if (myLocator.size() < 4) { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode locator (%s)", qPrintable(myLocator)); + qDebug("ChirpChatModEncoderFT::encodeMsgReply: locator invalid (%s)", qPrintable(myLocator)); + return; + } + + if (!FT8::Packing::packgrid(g15, myLocator.left(4).toUpper().toStdString())) + { + qDebug("ChirpChatModEncoderFT::encodeMsgReply: failed to encode locator (%s)", qPrintable(myLocator)); return; } @@ -165,21 +178,21 @@ void ChirpChatModEncoderFT::encodeMsgReport(const QString& myCall, const QString { int c28_1, c28_2, g15; - if (!FT8::Packing::packcall_std(c28_1, urCall.toStdString())) // + if (!FT8::Packing::packcall_std(c28_1, urCall.toUpper().toStdString())) // { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode call1 (%s)", qPrintable(urCall)); + qDebug("ChirpChatModEncoderFT::encodeMsgReport: failed to encode call1 (%s)", qPrintable(urCall)); return; } - if (!FT8::Packing::packcall_std(c28_2, myCall.toStdString())) + if (!FT8::Packing::packcall_std(c28_2, myCall.toUpper().toStdString())) { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode call2 (%s)", qPrintable(myCall)); + qDebug("ChirpChatModEncoderFT::encodeMsgReport: failed to encode call2 (%s)", qPrintable(myCall)); return; } - if (!FT8::Packing::packgrid(g15, myReport.toStdString())) + if (!FT8::Packing::packgrid(g15, myReport.toUpper().toStdString())) { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode report (%s)", qPrintable(myReport)); + qDebug("ChirpChatModEncoderFT::encodeMsgReport: failed to encode report (%s)", qPrintable(myReport)); return; } @@ -193,21 +206,21 @@ void ChirpChatModEncoderFT::encodeMsgFinish(const QString& myCall, const QString { int c28_1, c28_2, g15; - if (!FT8::Packing::packcall_std(c28_1, urCall.toStdString())) // + if (!FT8::Packing::packcall_std(c28_1, urCall.toUpper().toStdString())) // { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode call1 (%s)", qPrintable(urCall)); + qDebug("ChirpChatModEncoderFT::encodeMsgFinish: failed to encode call1 (%s)", qPrintable(urCall)); return; } - if (!FT8::Packing::packcall_std(c28_2, myCall.toStdString())) + if (!FT8::Packing::packcall_std(c28_2, myCall.toUpper().toStdString())) { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode call2 (%s)", qPrintable(myCall)); + qDebug("ChirpChatModEncoderFT::encodeMsgFinish: failed to encode call2 (%s)", qPrintable(myCall)); return; } - if (!FT8::Packing::packgrid(g15, shorthand.toStdString())) + if (!FT8::Packing::packgrid(g15, shorthand.toUpper().toStdString())) { - qDebug("ChirpChatModEncoderFT::encodeMsgBeacon: failed to encode shorthand (%s)", qPrintable(shorthand)); + qDebug("ChirpChatModEncoderFT::encodeMsgFinish: failed to encode shorthand (%s)", qPrintable(shorthand)); return; } diff --git a/plugins/channeltx/modchirpchat/chirpchatmodsettings.cpp b/plugins/channeltx/modchirpchat/chirpchatmodsettings.cpp index 2592f4676..03d2f65b3 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmodsettings.cpp +++ b/plugins/channeltx/modchirpchat/chirpchatmodsettings.cpp @@ -28,6 +28,7 @@ const int ChirpChatModSettings::bandwidths[] = { 325, // 384k / 1024 + 488, // 500k / 1024 750, // 384k / 512 1500, // 384k / 256 2604, // 333k / 128 @@ -55,7 +56,7 @@ const int ChirpChatModSettings::bandwidths[] = { 400000, // 400k / 1 500000 // 500k / 1 }; -const int ChirpChatModSettings::nbBandwidths = 3*8 + 3; +const int ChirpChatModSettings::nbBandwidths = 3*8 + 4; const int ChirpChatModSettings::oversampling = 4; ChirpChatModSettings::ChirpChatModSettings() : diff --git a/plugins/channeltx/modchirpchat/readme.md b/plugins/channeltx/modchirpchat/readme.md index 8a631b4e4..085b40d54 100644 --- a/plugins/channeltx/modchirpchat/readme.md +++ b/plugins/channeltx/modchirpchat/readme.md @@ -67,6 +67,7 @@ Thus available bandwidths are: - **2604** (333333 / 128) Hz not in LoRa standard - **1500** (384000 / 256) Hz not in LoRa standard - **750** (384000 / 512) Hz not in LoRa standard + - **488** (500000 / 1024) Hz not in LoRa standard - **375** (384000 / 1024) Hz not in LoRa standard The ChirpChat signal is oversampled by four therefore it needs a baseband of at least four times the bandwidth. This drives the maximum value on the slider automatically. diff --git a/plugins/channeltx/modpsk31/readme.md b/plugins/channeltx/modpsk31/readme.md index 31fa1eecb..fb0e5bd90 100644 --- a/plugins/channeltx/modpsk31/readme.md +++ b/plugins/channeltx/modpsk31/readme.md @@ -80,7 +80,7 @@ The substitutions are applied when the Transmit Settings dialog is closed.

14: Transmitted Text

-The trasnmitted text area shows characters as they are transmitted. +The transmitted text area shows characters as they are transmitted. Holding the cursor over an acronym may show a tooltip with the decoded acronym. diff --git a/plugins/channeltx/modrtty/readme.md b/plugins/channeltx/modrtty/readme.md index cf267e4bd..2e9be4b4c 100644 --- a/plugins/channeltx/modrtty/readme.md +++ b/plugins/channeltx/modrtty/readme.md @@ -117,7 +117,7 @@ The substitutions are applied when the Transmit Settings dialog is closed.

21: Transmitted Text

-The trasnmitted text area shows characters as they are transmitted. +The transmitted text area shows characters as they are transmitted. Holding the cursor over an acronym may show a tooltip with the decoded acronym. diff --git a/plugins/feature/map/readme.md b/plugins/feature/map/readme.md index a1de95cd4..17d052ac8 100644 --- a/plugins/feature/map/readme.md +++ b/plugins/feature/map/readme.md @@ -144,14 +144,14 @@ This is only supported on 2D raster maps and the 3D map.

11: Display MUF Contours

When checked, contours will be downloaded and displayed on the 3D map, showing the MUF (Maximum Usable Frequency) for a 3000km path that reflects off the ionosphere. -The contours will be updated every 15 minutes. MUF contour data is available for the preceeding 5 days. +The contours will be updated every 15 minutes. MUF contour data is available for the preceding 5 days. ![MUF contours](../../../doc/img/Map_plugin_muf.png)

12: Display coF2 Contours

When checked, contours will be downloaded and displayed on the 3D map, showing coF2 (F2 layer critical frequency), the maximum frequency at which radio waves will be reflected vertically from the F2 region of the ionosphere. -The contours will be updated every 15 minutes. coF2 contour data is available for the preceeding 5 days. +The contours will be updated every 15 minutes. coF2 contour data is available for the preceding 5 days.

13: Display NASA GIBS Data

@@ -159,7 +159,7 @@ When checked, enables overlay of data from NASA GIBS (Global Imagery Browse Serv such as land and sea temperatures, atmospheric conditions, flux measurements and the like. Details of available data products can be found [here](https://nasa-gibs.github.io/gibs-api-docs/available-visualizations/#visualization-product-catalog). -For some data sets, GIBS has data spanning many decades. The data period may be hours, days or months. The 3D map will attemp to show data from the closest time set in the 3D map's timescale. +For some data sets, GIBS has data spanning many decades. The data period may be hours, days or months. The 3D map will attempt to show data from the closest time set in the 3D map's timescale. The 2D map will only show data from the default date (which is displayed in the table at the bottom). ![NASA GIBS](../../../doc/img/Map_plugin_GIBS.png) @@ -221,7 +221,7 @@ For the 3D map, the settings include: For ECI (Earth Centred Inertial) the camera is fixed in space and the globe will rotate under it. The "Download 3D Models" button will download the 3D models of aircraft, ships and satellites that are required for the 3D map. -These are not included with the SDRangel distribution, so must be downloaded. It is recommeded to restart SDRangel after downloading the models. +These are not included with the SDRangel distribution, so must be downloaded. It is recommended to restart SDRangel after downloading the models. ![Map Display Settings Dialog Items Tab](../../../doc/img/Map_plugin_display_settings_items.png) @@ -265,7 +265,7 @@ To the right of the timeline is the fullscreen toggle button, which allows the 3

SDRs

-The map can display KiwiSDRs and Spy Servers that are publically accessible via the internet. A URL is displayed in the info box. +The map can display KiwiSDRs and Spy Servers that are publicly accessible via the internet. A URL is displayed in the info box. Clicking on the URL will open a new KiwiSDR or RemoteTCPInput device which will connect to the corresponding SDR. Before connecting, you should check the whether the number of users is below the maximum. Server data is updated every 2 minutes. diff --git a/plugins/feature/satellitetracker/satellitetrackergui.ui b/plugins/feature/satellitetracker/satellitetrackergui.ui index 7bedad157..55bb4bbdb 100644 --- a/plugins/feature/satellitetracker/satellitetrackergui.ui +++ b/plugins/feature/satellitetracker/satellitetrackergui.ui @@ -713,7 +713,7 @@ Norad ID - Norad catalog idenfitier for the satellite + Norad catalog identifier for the satellite
diff --git a/plugins/feature/sid/readme.md b/plugins/feature/sid/readme.md index caea10b17..a7433502d 100644 --- a/plugins/feature/sid/readme.md +++ b/plugins/feature/sid/readme.md @@ -18,7 +18,7 @@ The SID chart can plot multiple series, allowing different signals from differen This can be useful as SIDs can be localized to specific regions in the atmosphere, thus not all signals may be affected. Data can come from multiple [Channel Power](../../channelrx/channelpower/readme.md) plugins within a single device, or separate devices. -To help determine the cause of a SID, addtional data can be plotted from a variety of sources: +To help determine the cause of a SID, additional data can be plotted from a variety of sources: * the chart can plot X-ray data from the GOES satellites, to allow visual correlation of spikes in the X-ray flux measurement with spikes in the VLF power measurements, * it can display images and video from the Solar Dynamics Observatory at EUV wavelengths, which may visually show the solar flare, @@ -63,9 +63,9 @@ Number of samples to use in a moving average filter that can be applied to the d Check to display long wavelength (0.1-0.8nm) X-Ray data from the primary GOES satellite (Currently GOES 16) on the chart. -This is probably the most useful data in order to see when a solar flare has occured, as there will typically be a sharp peak. +This is probably the most useful data in order to see when a solar flare has occurred, as there will typically be a sharp peak. The GOES satellites are in a geostationary orbit around the Earth, so the measured increase in X-ray flux from a flare will be approximately 8 minutes -after it has occured. +after it has occurred. The Y-axis indicates the flare classification. M and X class flares are those most likely to have a measurable impact on the ionosphere. ![X-Ray data showing M class flare](../../../doc/img/SID_plugin_xray.png) @@ -150,7 +150,7 @@ When checked, displays imagary from NASA's SDO (Solar Dynamic Observatory) and E SDOs images the Sun in a variety of UV and EUV wavelengths. SOHO shows images of the solar corona. The images are near real-time, updated every 15 minutes. -Solar flares are particularly visible in the AIA 131 Å images. +Solar flares are particularly visible in the AIA 131 Ã… images.

19: Image or Video Selection

@@ -160,24 +160,24 @@ Selects whether to display images (unchecked) or video (checked). Selects which image / wavelength to view. -* AIA 94 Å to 1700 Å - The AIA (Atmospheric Imaging Assembly) images the solar atmosphere at multiple EUV (Extreme Ultraviolet) and UV (Ultraviolet) wavelengths: +* AIA 94 Ã… to 1700 Ã… - The AIA (Atmospheric Imaging Assembly) images the solar atmosphere at multiple EUV (Extreme Ultraviolet) and UV (Ultraviolet) wavelengths: | Band | Region | |---------|-----------------------------------------| -| 94 Å | Flaring | -| 131 Å | Flaring | -| 171 Å | Quiet corona, upper transition region | -| 193 Å | Corona and hot flare plasma | -| 211 Å | Active corona | -| 304 Å | Chromosphere, transition region | -| 335 Å | Active corona | -| 1600 Å | Transition region, upper photoshere | -| 1700 Å | Temperature minimum, photosphere | +| 94 Ã… | Flaring | +| 131 Ã… | Flaring | +| 171 Ã… | Quiet corona, upper transition region | +| 193 Ã… | Corona and hot flare plasma | +| 211 Ã… | Active corona | +| 304 Ã… | Chromosphere, transition region | +| 335 Ã… | Active corona | +| 1600 Ã… | Transition region, upper photoshere | +| 1700 Ã… | Temperature minimum, photosphere | [Ref](https://sdo.gsfc.nasa.gov/data/channels.php) * MHI Magnetogram - HMI (Helioseismic and Magnetic Imager) Magnetogram shows the magnetic field in the photosphere, with black and white indicating opposite polarities. -* MHI Intensitygram - Brightness in a visible light band (6173 Å - Red - Iron spectral line), useful for observing sun spots. +* MHI Intensitygram - Brightness in a visible light band (6173 Ã… - Red - Iron spectral line), useful for observing sun spots. * Dopplergram - Shows velocities along the line-of-sight. * LASCO (Large Angle Spectrometric Coronagraph) shows solar corona. C2 shows corona up to 8.4Mkm. C3 shows corona up to 23Mkm. @@ -211,11 +211,11 @@ When clicked, the X-axis is set 1 day later than the current setting, at the sam

27: Start Time

-Displays/sets the current start time of the chart (X-axis minimum). It's possible to scroll through hours/days/months by clicking on the relevent segment and using the mouse scroll wheel. +Displays/sets the current start time of the chart (X-axis minimum). It's possible to scroll through hours/days/months by clicking on the relevant segment and using the mouse scroll wheel.

28: End Time

-Displays/sets the current end time of the chart (X-axis maximum). It's possible to scroll through hours/days/months by clicking on the relevent segment and using the mouse scroll wheel. +Displays/sets the current end time of the chart (X-axis maximum). It's possible to scroll through hours/days/months by clicking on the relevant segment and using the mouse scroll wheel.

29: Min

@@ -258,7 +258,7 @@ In order to check that a peak in the spectrum is a real VLF signal, you can: * Check that the signal has diurnal variation (it should vary with the time of day, due to the changes in the ionosphere). * Check with online lists of VLF signals (E.g. https://sidstation.loudet.org/stations-list-en.xhtml or https://www.mwlist.org/vlf.php). A number of these are plotted on the [Map](../../feature/map/readme.md) feature. -Occasionally, the X-ray flux data may drop to 0. This is typically when the GOES satellite is in eclipse (The Earth or moon is inbetween the satellite and the Sun). +Occasionally, the X-ray flux data may drop to 0. This is typically when the GOES satellite is in eclipse (The Earth or Moon is in between the satellite and the Sun). SIDs are most likely to be detected when it's day time in the path between the signal source and receiver, as at night, the atmosphere is shielded from the X-rays by the Earth. Also, as the D layer in the ionosphere essentially disappears at night, the received power is not as constant as during the day. diff --git a/plugins/feature/skymap/readme.md b/plugins/feature/skymap/readme.md index 11430978b..5c26e1e8b 100644 --- a/plugins/feature/skymap/readme.md +++ b/plugins/feature/skymap/readme.md @@ -82,7 +82,7 @@ For WWT, when checked, displays names of constellations and Ecliptic text (when For WWT, this option enables the display of constellations. How the constellations are drawn can be customised in the Display Settings dialog (12). -

7: Display gird

+

7: Display grid

When checked, displays a coordinate grid. @@ -113,7 +113,7 @@ Select a Star Tracker, Rotator Controller, Satellite Tracker or Map plugin to re When clicked, opens the Display Settings dialog. The Display Settings dialog allows the user to set: -* Observation location (latitude and longitude in degreees). +* Observation location (latitude and longitude in degrees). * Antenna beamwidth in degrees. * Settings for WWT, such as how the constellations are drawn, what grids are displayed and how the Solar System view appears. diff --git a/plugins/samplesource/androidsdrdriverinput/readme.md b/plugins/samplesource/androidsdrdriverinput/readme.md index aacaeeb6d..b133caf67 100644 --- a/plugins/samplesource/androidsdrdriverinput/readme.md +++ b/plugins/samplesource/androidsdrdriverinput/readme.md @@ -15,7 +15,7 @@ Device start / stop button. - Blue triangle icon: device is ready and can be started - Green square icon: device is running and can be stopped - - Red square icon: an error has occured with the connection to the device. The plugin will continually try to reconnect. + - Red square icon: an error has occurred with the connection to the device. The plugin will continually try to reconnect.

2: Center frequency

diff --git a/sdrbase/audio/audiodevicemanager.cpp b/sdrbase/audio/audiodevicemanager.cpp index f845ef615..a94e8c5e4 100644 --- a/sdrbase/audio/audiodevicemanager.cpp +++ b/sdrbase/audio/audiodevicemanager.cpp @@ -339,11 +339,17 @@ void AudioDeviceManager::addAudioSink(AudioFifo* audioFifo, MessageQueue *sample if (audioOutputDeviceIndex != outputDeviceIndex) // change of audio device { - removeAudioSink(audioFifo); // remove from current + // remove from current + m_audioOutputs[audioOutputDeviceIndex]->removeFifo(audioFifo); + if ((audioOutputDeviceIndex != -1) && (m_audioOutputs[audioOutputDeviceIndex]->getNbFifos() == 0)) { + stopAudioOutput(audioOutputDeviceIndex); + } + m_audioOutputs[outputDeviceIndex]->addFifo(audioFifo); // add to new m_audioSinkFifos[audioFifo] = outputDeviceIndex; // new index - m_outputDeviceSinkMessageQueues[audioOutputDeviceIndex].removeOne(sampleSinkMessageQueue); + m_outputDeviceSinkMessageQueues[audioOutputDeviceIndex].removeOne(m_audioFifoToSinkMessageQueues[audioFifo]); m_outputDeviceSinkMessageQueues[outputDeviceIndex].append(sampleSinkMessageQueue); + m_audioFifoToSinkMessageQueues[audioFifo] = sampleSinkMessageQueue; } } } @@ -416,6 +422,9 @@ void AudioDeviceManager::addAudioSource(AudioFifo* audioFifo, MessageQueue *samp if (m_audioSourceFifos.find(audioFifo) == m_audioSourceFifos.end()) // new FIFO { m_audioInputs[inputDeviceIndex]->addFifo(audioFifo); + m_audioSourceFifos[audioFifo] = inputDeviceIndex; // register audio FIFO + m_audioFifoToSourceMessageQueues[audioFifo] = sampleSourceMessageQueue; + m_inputDeviceSourceMessageQueues[inputDeviceIndex].append(sampleSourceMessageQueue); } else { @@ -423,14 +432,19 @@ void AudioDeviceManager::addAudioSource(AudioFifo* audioFifo, MessageQueue *samp if (audioInputDeviceIndex != inputDeviceIndex) // change of audio device { - removeAudioSource(audioFifo); // remove from current + // remove from current + m_audioInputs[audioInputDeviceIndex]->removeFifo(audioFifo); + if ((audioInputDeviceIndex != -1) && (m_audioInputs[audioInputDeviceIndex]->getNbFifos() == 0)) { + stopAudioInput(audioInputDeviceIndex); + } + m_audioInputs[inputDeviceIndex]->addFifo(audioFifo); // add to new + m_audioSourceFifos[audioFifo] = inputDeviceIndex; // new index + m_outputDeviceSinkMessageQueues[audioInputDeviceIndex].removeOne(m_audioFifoToSourceMessageQueues[audioFifo]); + m_inputDeviceSourceMessageQueues[inputDeviceIndex].append(sampleSourceMessageQueue); + m_audioFifoToSourceMessageQueues[audioFifo] = sampleSourceMessageQueue; } } - - m_audioSourceFifos[audioFifo] = inputDeviceIndex; // register audio FIFO - m_audioFifoToSourceMessageQueues[audioFifo] = sampleSourceMessageQueue; - m_outputDeviceSinkMessageQueues[inputDeviceIndex].append(sampleSourceMessageQueue); } void AudioDeviceManager::removeAudioSource(AudioFifo* audioFifo) diff --git a/sdrbench/test_ft8protocols.cpp b/sdrbench/test_ft8protocols.cpp index b5cdc4d41..573259c75 100644 --- a/sdrbench/test_ft8protocols.cpp +++ b/sdrbench/test_ft8protocols.cpp @@ -322,7 +322,8 @@ void TestFT8Protocols::testSoftDecode(const QStringList& argElements) } symbol = symbol % symbolSize; - magSymbols[symbol] += 0.01; + symbol = symbol ^(symbol >> 1); // Gray code + magSymbols[symbol] += 0.015; mags.push_back(magSymbols); }