mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-21 15:51:47 -05:00
ChirpChat demod: implemented FT decoding
This commit is contained in:
parent
a02d1839ef
commit
3c9f74aeb5
10
ft8/ft8.cpp
10
ft8/ft8.cpp
@ -2566,8 +2566,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)
|
||||
{
|
||||
@ -2582,6 +2588,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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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})
|
||||
|
@ -318,6 +318,29 @@ bool ChirpChatDemod::handleMessage(const Message& cmd)
|
||||
|
||||
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, ...)
|
||||
|
||||
if (m_settings.m_sendViaUDP)
|
||||
{
|
||||
const QByteArray& byteArray = m_lastMsgString.toUtf8();
|
||||
const uint8_t *bytes = reinterpret_cast<const uint8_t*>(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))
|
||||
{
|
||||
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "chirpchatdemoddecodertty.h"
|
||||
#include "chirpchatdemoddecoderascii.h"
|
||||
#include "chirpchatdemoddecoderlora.h"
|
||||
#include "chirpchatdemoddecoderft.h"
|
||||
#include "chirpchatdemodmsg.h"
|
||||
|
||||
ChirpChatDemodDecoder::ChirpChatDemodDecoder() :
|
||||
@ -60,7 +61,7 @@ void ChirpChatDemodDecoder::decodeSymbols(const std::vector<unsigned short>& sym
|
||||
}
|
||||
break;
|
||||
case ChirpChatDemodSettings::CodingASCII:
|
||||
if (m_nbSymbolBits == 5) {
|
||||
if (m_nbSymbolBits == 7) {
|
||||
ChirpChatDemodDecoderASCII::decodeSymbols(symbols, str);
|
||||
}
|
||||
break;
|
||||
@ -106,6 +107,33 @@ void ChirpChatDemodDecoder::decodeSymbols(const std::vector<unsigned short>& sym
|
||||
}
|
||||
}
|
||||
|
||||
void ChirpChatDemodDecoder::decodeSymbols( //!< For FT coding scheme
|
||||
const std::vector<std::vector<float>>& 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))
|
||||
@ -145,7 +173,34 @@ bool ChirpChatDemodDecoder::handleMessage(const Message& cmd)
|
||||
}
|
||||
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
|
||||
{
|
||||
|
@ -40,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<unsigned short>& symbols, QString& str); //!< For ASCII and TTY
|
||||
void decodeSymbols(const std::vector<unsigned short>& symbols, QByteArray& bytes); //!< For raw bytes (original LoRa)
|
||||
void decodeSymbols( //!< For FT coding scheme
|
||||
const std::vector<std::vector<float>>& 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; }
|
||||
@ -52,11 +66,6 @@ public:
|
||||
bool getHeaderCRCStatus() const { return m_headerCRCStatus; }
|
||||
int getPayloadParityStatus() const { return m_payloadParityStatus; }
|
||||
bool getPayloadCRCStatus() const { return m_payloadCRCStatus; }
|
||||
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||
void setOutputMessageQueue(MessageQueue *messageQueue) { m_outputMessageQueue = messageQueue; }
|
||||
|
||||
private:
|
||||
bool handleMessage(const Message& cmd);
|
||||
|
||||
ChirpChatDemodSettings::CodingScheme m_codingScheme;
|
||||
unsigned int m_spreadFactor;
|
||||
|
111
plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.cpp
Normal file
111
plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2024 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// 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 <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "chirpchatdemodsettings.h"
|
||||
#include "chirpchatdemoddecoderft.h"
|
||||
|
||||
#ifndef HAS_FT8
|
||||
void ChirpChatDemodDecoderFT::decodeSymbols(
|
||||
const std::vector<std::vector<float>>& 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<std::vector<float>>& 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;
|
||||
|
||||
if (FT8::FT8::decode(lls, r174, params, 0, comments) == 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;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAS_FT8
|
49
plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.h
Normal file
49
plugins/channelrx/demodchirpchat/chirpchatdemoddecoderft.h
Normal file
@ -0,0 +1,49 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2024 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// 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 <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_CHIRPCHATDEMODDECODERFT_H
|
||||
#define INCLUDE_CHIRPCHATDEMODDECODERFT_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class ChirpChatDemodDecoderFT
|
||||
{
|
||||
public:
|
||||
enum ParityStatus
|
||||
{
|
||||
ParityUndefined,
|
||||
ParityError,
|
||||
ParityCorrected,
|
||||
ParityOK
|
||||
};
|
||||
|
||||
static void decodeSymbols(
|
||||
const std::vector<std::vector<float>>& 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
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#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:
|
||||
|
@ -26,14 +26,6 @@
|
||||
class ChirpChatDemodDecoderLoRa
|
||||
{
|
||||
public:
|
||||
enum ParityStatus
|
||||
{
|
||||
ParityUndefined,
|
||||
ParityError,
|
||||
ParityCorrected,
|
||||
ParityOK
|
||||
};
|
||||
|
||||
static void decodeBytes(
|
||||
QByteArray& bytes,
|
||||
const std::vector<unsigned short>& inSymbols,
|
||||
|
@ -115,8 +115,16 @@ bool ChirpChatDemodGUI::handleMessage(const Message& 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;
|
||||
@ -544,11 +552,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); }");
|
||||
@ -562,11 +570,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); }");
|
||||
@ -589,6 +597,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;
|
||||
@ -644,7 +671,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
|
||||
@ -694,6 +721,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();
|
||||
@ -754,11 +802,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";
|
||||
|
@ -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);
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include <QObject>
|
||||
#include "util/message.h"
|
||||
|
||||
#include "chirpchatdemodsettings.h"
|
||||
|
||||
namespace ChirpChatDemodMsg
|
||||
{
|
||||
class MsgDecodeSymbols : public Message {
|
||||
@ -178,7 +180,7 @@ namespace ChirpChatDemodMsg
|
||||
m_earlyEOM(false),
|
||||
m_headerParityStatus(false),
|
||||
m_headerCRCStatus(false),
|
||||
m_payloadParityStatus(false),
|
||||
m_payloadParityStatus((int) ChirpChatDemodSettings::ParityUndefined),
|
||||
m_payloadCRCStatus(false)
|
||||
{ }
|
||||
};
|
||||
@ -240,6 +242,8 @@ namespace ChirpChatDemodMsg
|
||||
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()
|
||||
{
|
||||
@ -275,6 +279,12 @@ namespace ChirpChatDemodMsg
|
||||
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;
|
||||
@ -287,6 +297,8 @@ namespace ChirpChatDemodMsg
|
||||
float m_signalDb;
|
||||
float m_noiseDb;
|
||||
QString m_msgTimestamp;
|
||||
int m_payloadParityStatus;
|
||||
bool m_payloadCRCStatus;
|
||||
|
||||
MsgReportDecodeFT() :
|
||||
Message(),
|
||||
@ -294,7 +306,9 @@ namespace ChirpChatDemodMsg
|
||||
m_freeText(false),
|
||||
m_syncWord(0),
|
||||
m_signalDb(0.0),
|
||||
m_noiseDb(0.0)
|
||||
m_noiseDb(0.0),
|
||||
m_payloadParityStatus((int) ChirpChatDemodSettings::ParityUndefined),
|
||||
m_payloadCRCStatus(false)
|
||||
{ }
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -96,7 +96,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 +109,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 +143,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 +177,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 +205,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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user