ChirpChat demod: implemented FT decoding

This commit is contained in:
f4exb 2024-04-05 01:03:24 +02:00
parent a02d1839ef
commit 3c9f74aeb5
16 changed files with 406 additions and 71 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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})

View File

@ -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;

View File

@ -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
{

View File

@ -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;

View 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

View 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

View File

@ -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:

View File

@ -26,14 +26,6 @@
class ChirpChatDemodDecoderLoRa
{
public:
enum ParityStatus
{
ParityUndefined,
ParityError,
ParityCorrected,
ParityOK
};
static void decodeBytes(
QByteArray& bytes,
const std::vector<unsigned short>& inSymbols,

View File

@ -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";

View File

@ -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);

View File

@ -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)
{ }
};
}

View File

@ -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;

View File

@ -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;
}