diff --git a/plugins/channelrx/demodlora/CMakeLists.txt b/plugins/channelrx/demodlora/CMakeLists.txt
index 66e487f71..6d9ad7a37 100644
--- a/plugins/channelrx/demodlora/CMakeLists.txt
+++ b/plugins/channelrx/demodlora/CMakeLists.txt
@@ -7,6 +7,7 @@ set(lora_SOURCES
lorademodsink.cpp
lorademodbaseband.cpp
loraplugin.cpp
+ lorademoddecoder.cpp
lorademodgui.ui
)
@@ -16,6 +17,7 @@ set(lora_HEADERS
lorademodsettings.h
lorademodsink.h
lorademodbaseband.h
+ lorademoddecoder.h
loraplugin.h
)
diff --git a/plugins/channelrx/demodlora/lorademoddecoder.cpp b/plugins/channelrx/demodlora/lorademoddecoder.cpp
new file mode 100644
index 000000000..160469be0
--- /dev/null
+++ b/plugins/channelrx/demodlora/lorademoddecoder.cpp
@@ -0,0 +1,113 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2020 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 "lorademoddecoder.h"
+
+const char LoRaDemodDecoder::ttyLetters[32] = {
+ '\0', 'E', '\n', 'A', ' ', 'S', 'I', 'U',
+ '\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K',
+ 'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q',
+ 'O', 'B', 'G', ' ', 'M', 'X', 'V', ' '
+};
+
+const char LoRaDemodDecoder::ttyFigures[32] = { // U.S. standard
+ '\0', '3', '\n', '-', ' ', '\a', '8', '7',
+ '\r', '$', '4', '\'', ',', '!', ':', '(',
+ '5', '"', ')', '2', '#', '6', '0', '1',
+ '9', '?', '&', ' ', '.', '/', ';', ' '
+};
+
+
+LoRaDemodDecoder::LoRaDemodDecoder() :
+ m_codingScheme(LoRaDemodSettings::CodingTTY),
+ m_nbSymbolBits(5)
+{}
+
+LoRaDemodDecoder::~LoRaDemodDecoder()
+{}
+
+void LoRaDemodDecoder::decodeSymbols(const std::vector& symbols, QString& str)
+{
+ switch(m_codingScheme)
+ {
+ case LoRaDemodSettings::CodingTTY:
+ decodeSymbolsTTY(symbols, str);
+ break;
+ case LoRaDemodSettings::CodingASCII:
+ decodeSymbolsASCII(symbols, str);
+ break;
+ }
+}
+
+void LoRaDemodDecoder::decodeSymbols(const std::vector& symbols, QByteArray& bytes)
+{
+
+}
+
+void LoRaDemodDecoder::decodeSymbolsASCII(const std::vector& symbols, QString& str)
+{
+ if (m_nbSymbolBits != 7) {
+ return;
+ }
+
+ std::vector::const_iterator it = symbols.begin();
+ QByteArray bytes;
+
+ for (; it != symbols.end(); ++it) {
+ bytes.push_back(*it & 0x7F);
+ }
+
+ str = QString(bytes.toStdString().c_str());
+}
+
+void LoRaDemodDecoder::decodeSymbolsTTY(const std::vector& symbols, QString& str)
+{
+ if (m_nbSymbolBits != 5) {
+ return;
+ }
+
+ std::vector::const_iterator it = symbols.begin();
+ QByteArray bytes;
+ TTYState ttyState = TTYLetters;
+
+ for (; it != symbols.end(); ++it)
+ {
+ char ttyChar = *it & 0x1F;
+
+ if (ttyChar == lettersTag) {
+ ttyState = TTYLetters;
+ } else if (ttyChar == figuresTag) {
+ ttyState = TTYFigures;
+ }
+ else
+ {
+ char asciiChar = -1;
+
+ if (ttyState == TTYLetters) {
+ asciiChar = ttyLetters[ttyChar];
+ } else if (ttyState == TTYLetters) {
+ asciiChar = ttyFigures[ttyChar];
+ }
+
+ if (asciiChar >= 0) {
+ bytes.push_back(asciiChar);
+ }
+ }
+ }
+
+ str = QString(bytes.toStdString().c_str());
+}
diff --git a/plugins/channelrx/demodlora/lorademoddecoder.h b/plugins/channelrx/demodlora/lorademoddecoder.h
new file mode 100644
index 000000000..4a86c6c07
--- /dev/null
+++ b/plugins/channelrx/demodlora/lorademoddecoder.h
@@ -0,0 +1,54 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2020 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_LORADEMODDECODER_H
+#define INCLUDE_LORADEMODDECODER_H
+
+#include
+#include "lorademodsettings.h"
+
+class LoRaDemodDecoder
+{
+public:
+ LoRaDemodDecoder();
+ ~LoRaDemodDecoder();
+
+ void setCodingScheme(LoRaDemodSettings::CodingScheme codingScheme) { m_codingScheme = codingScheme; }
+ void setNbSymbolBits(unsigned int symbolBits) { m_nbSymbolBits = symbolBits; }
+ 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)
+
+private:
+ enum TTYState
+ {
+ TTYLetters,
+ TTYFigures
+ };
+
+ void decodeSymbolsASCII(const std::vector& symbols, QString& str);
+ void decodeSymbolsTTY(const std::vector& symbols, QString& str);
+
+ LoRaDemodSettings::CodingScheme m_codingScheme;
+ unsigned int m_nbSymbolBits;
+
+ static const char ttyLetters[32];
+ static const char ttyFigures[32];
+ static const char lettersTag = 0x1f;
+ static const char figuresTag = 0x1b;
+};
+
+#endif // INCLUDE_LORADEMODDECODER_H
diff --git a/plugins/channelrx/demodlora/lorademodsettings.h b/plugins/channelrx/demodlora/lorademodsettings.h
index 475c36114..639235a13 100644
--- a/plugins/channelrx/demodlora/lorademodsettings.h
+++ b/plugins/channelrx/demodlora/lorademodsettings.h
@@ -28,10 +28,18 @@ class Serializable;
struct LoRaDemodSettings
{
+ enum CodingScheme
+ {
+ CodingTTY, //!< plain TTY (5 bits)
+ CodingASCII, //!< plain ASCII (7 bits)
+ CodingLoRa //!< Standard LoRa
+ };
+
int m_inputFrequencyOffset;
int m_bandwidthIndex;
int m_spreadFactor;
int m_deBits; //!< Low data rate optmize (DE) bits
+ CodingScheme m_codingScheme;
uint32_t m_rgbColor;
QString m_title;
diff --git a/plugins/channeltx/modlora/CMakeLists.txt b/plugins/channeltx/modlora/CMakeLists.txt
index 9936be9a0..f3225c707 100644
--- a/plugins/channeltx/modlora/CMakeLists.txt
+++ b/plugins/channeltx/modlora/CMakeLists.txt
@@ -6,6 +6,7 @@ set(modlora_SOURCES
loramodsource.cpp
loramodbaseband.cpp
loramodplugin.cpp
+ loramodencoder.cpp
loramodwebapiadapter.cpp
)
@@ -15,6 +16,7 @@ set(modlora_HEADERS
loramodsource.h
loramodbaseband.h
loramodplugin.h
+ loramodencoder.h
loramodwebapiadapter.h
)
diff --git a/plugins/channeltx/modlora/loramodencoder.cpp b/plugins/channeltx/modlora/loramodencoder.cpp
new file mode 100644
index 000000000..85f37faa2
--- /dev/null
+++ b/plugins/channeltx/modlora/loramodencoder.cpp
@@ -0,0 +1,174 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2020 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 "loramodencoder.h"
+
+const char LoRaModEncoder::asciiToTTYLetters[128] = {
+// '\x00' '\x01' '\x02' '\x03' '\x04' '\x05' '\x06' '\x07'
+ 0x00, -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// '\x08' '\t' '\n' '\x0b' '\x0c' '\r' '\x0e' '\x0f'
+ -1 , -1 , 0x02, -1 , -1 , 0x08, -1 , -1 ,
+// '\x10' '\x11' '\x12' '\x13' '\x14' '\x15' '\x16' '\x17'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// '\x18' '\x19' '\x1a' '\x1b' '\x1c' '\x1d' '\x1e' '\x1f'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// ' ' '!' '"' '#' '$' '%' '&' "'"
+ 0x04, -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// '(' ')' '*' '+' ',' '-' '.' '/'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// '0' '1' '2' '3' '4' '5' '6' '7'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// '8' '9' ':' ';' '<' '=' '>' '?'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G'
+ -1 , 0x03, 0x19, 0x0e, 0x09, 0x01, 0x0d, 0x1a,
+// 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O'
+ 0x14, 0x06, 0x0b, 0x0f, 0x12, 0x1c, 0x0c, 0x18,
+// 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W'
+ 0x16, 0x17, 0x0a, 0x05, 0x10, 0x07, 0x1e, 0x13,
+// 'X' 'Y' 'Z' '[' '\\' ']' '^' '_'
+ 0x1d, 0x15, 0x11, -1 , -1 , -1 , -1 , -1 ,
+// '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g'
+ -1 , 0x03, 0x19, 0x0e, 0x09, 0x01, 0x0d, 0x1a,
+// 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'
+ 0x14, 0x06, 0x0b, 0x0f, 0x12, 0x1c, 0x0c, 0x18,
+// 'p' 'q' 'r' 's' 't' 'u' 'v' 'w'
+ 0x16, 0x17, 0x0a, 0x05, 0x10, 0x07, 0x1e, 0x13,
+// 'x' 'y' 'z' '{' '|' '}' '~' '\x7f'
+ 0x1d, 0x15, 0x11, -1 , -1 , -1 , -1 , -1
+ };
+
+const char LoRaModEncoder::asciiToTTYFigures[128] = {
+// '\x00' '\x01' '\x02' '\x03' '\x04' '\x05' '\x06' '\x07'
+ 0x00, -1 , -1 , -1 , -1 , -1 , -1 , 0x05,
+// '\x08' '\t' '\n' '\x0b' '\x0c' '\r' '\x0e' '\x0f'
+ -1 , -1 , 0x02, -1 , -1 , 0x08, -1 , -1 ,
+// '\x10' '\x11' '\x12' '\x13' '\x14' '\x15' '\x16' '\x17'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// '\x18' '\x19' '\x1a' '\x1b' '\x1c' '\x1d' '\x1e' '\x1f'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// ' ' '!' '"' '#' '$' '%' '&' "'"
+ 0x04, 0x0d, 0x11, 0x14, 0x09, -1 , 0x1a, -1 ,
+// '(' ')' '*' '+' ',' '-' '.' '/'
+ 0x0f, 0x12, -1 , -1 , 0x0c, 0x03, 0x1c, 0x1d,
+// '0' '1' '2' '3' '4' '5' '6' '7'
+ 0x16, 0x17, 0x13, 0x01, 0x0a, 0x10, 0x15, 0x07,
+// '8' '9' ':' ';' '<' '=' '>' '?'
+ 0x06, 0x18, 0x0e, 0x1e, -1 , -1 , -1 , 0x19,
+// '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// 'X' 'Y' 'Z' '[' '\\' ']' '^' '_'
+ -1 , -1 , -1 , -1 , 0x0b, -1 , -1 , -1 ,
+// '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// 'p' 'q' 'r' 's' 't' 'u' 'v' 'w'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
+// 'x' 'y' 'z' '{' '|' '}' '~' '\x7f'
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1
+ };
+
+LoRaModEncoder::LoRaModEncoder() :
+ m_codingScheme(LoRaModSettings::CodingTTY),
+ m_nbSymbolBits(5)
+{}
+
+LoRaModEncoder::~LoRaModEncoder()
+{}
+
+void LoRaModEncoder::encodeString(const QString& str, std::vector& symbols)
+{
+ switch (m_codingScheme)
+ {
+ case LoRaModSettings::CodingTTY:
+ encodeStringTTY(str, symbols);
+ break;
+ case LoRaModSettings::CodingASCII:
+ encodeStringASCII(str, symbols);
+ break;
+ default:
+ break;
+ }
+}
+
+void LoRaModEncoder::encodeStringASCII(const QString& str, std::vector& symbols)
+{
+ if (m_nbSymbolBits != 7) {
+ return;
+ }
+
+ QByteArray asciiStr = str.toUtf8();
+ QByteArray::const_iterator it = asciiStr.begin();
+
+ for (; it != asciiStr.end(); ++it) {
+ symbols.push_back(*it & 0x7F);
+ }
+}
+
+void LoRaModEncoder::encodeStringTTY(const QString& str, std::vector& symbols)
+{
+ if (m_nbSymbolBits != 5) {
+ return;
+ }
+
+ TTYState ttyState = TTYLetters;
+ QByteArray asciiStr = str.toUtf8();
+ QByteArray::const_iterator it = asciiStr.begin();
+
+ for (; it != asciiStr.end(); ++it)
+ {
+ char asciiChar = *it & 0x7F;
+ int ttyLetter = asciiToTTYLetters[asciiChar];
+ int ttyFigure = asciiToTTYFigures[asciiChar];
+
+ if (ttyLetter < 0)
+ {
+ if (ttyFigure >= 0)
+ {
+ if (ttyState != TTYFigures)
+ {
+ symbols.push_back(ttyFigures);
+ ttyState = TTYFigures;
+ }
+
+ symbols.push_back(ttyFigure);
+ } // else skip
+ }
+ else
+ {
+ if (ttyFigure >= 0)
+ {
+ symbols.push_back(ttyFigure); // same TTY character no state change
+ }
+ else
+ {
+ if (ttyState != TTYLetters)
+ {
+ symbols.push_back(ttyLetters);
+ ttyState = TTYLetters;
+ }
+
+ symbols.push_back(ttyLetter);
+ }
+ }
+ }
+}
diff --git a/plugins/channeltx/modlora/loramodencoder.h b/plugins/channeltx/modlora/loramodencoder.h
new file mode 100644
index 000000000..8cad06a54
--- /dev/null
+++ b/plugins/channeltx/modlora/loramodencoder.h
@@ -0,0 +1,54 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2020 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 PLUGINS_CHANNELTX_MODLORA_LORAMODENCODER_H_
+#define PLUGINS_CHANNELTX_MODLORA_LORAMODENCODER_H_
+
+#include
+#include "loramodsettings.h"
+
+class LoRaModEncoder
+{
+public:
+ LoRaModEncoder();
+ ~LoRaModEncoder();
+
+ void setCodingScheme(LoRaModSettings::CodingScheme codingScheme) { m_codingScheme = codingScheme; }
+ void setNbSymbolBits(unsigned int symbolBits) { m_nbSymbolBits = symbolBits; }
+ void encodeString(const QString& str, std::vector& symbols);
+
+private:
+ enum TTYState
+ {
+ TTYLetters,
+ TTYFigures
+ };
+
+ void encodeStringASCII(const QString& str, std::vector& symbols);
+ void encodeStringTTY(const QString& str, std::vector& symbols);
+
+ LoRaModSettings::CodingScheme m_codingScheme;
+ unsigned int m_nbSymbolBits;
+
+ static const char asciiToTTYLetters[128];
+ static const char asciiToTTYFigures[128];
+ static const char ttyLetters = 0x1f;
+ static const char ttyFigures = 0x1b;
+};
+
+#endif // PLUGINS_CHANNELTX_MODLORA_LORAMODENCODER_H_
+
diff --git a/plugins/channeltx/modlora/loramodsettings.cpp b/plugins/channeltx/modlora/loramodsettings.cpp
index 324da1eef..03bafd0ea 100644
--- a/plugins/channeltx/modlora/loramodsettings.cpp
+++ b/plugins/channeltx/modlora/loramodsettings.cpp
@@ -42,7 +42,7 @@ void LoRaModSettings::resetToDefaults()
m_deBits = 0;
m_preambleChirps = 8;
m_quietMillis = 1000;
- m_message = "LoRa beacon";
+ m_message = "Hello LoRa";
m_syncWord = 0x34;
m_channelMute = false;
m_rgbColor = QColor(255, 0, 255).rgb();
@@ -101,7 +101,7 @@ bool LoRaModSettings::deserialize(const QByteArray& data)
d.readS32(1, &m_inputFrequencyOffset, 0);
d.readS32(2, &m_bandwidthIndex, 0);
d.readS32(3, &m_spreadFactor, 0);
- d.readString(4, &m_message, "LoRa beacon");
+ d.readString(4, &m_message, "Hello LoRa");
if (m_channelMarker)
{
diff --git a/plugins/channeltx/modlora/loramodsettings.h b/plugins/channeltx/modlora/loramodsettings.h
index a92461880..ed70983e1 100644
--- a/plugins/channeltx/modlora/loramodsettings.h
+++ b/plugins/channeltx/modlora/loramodsettings.h
@@ -27,6 +27,13 @@ class Serializable;
struct LoRaModSettings
{
+ enum CodingScheme
+ {
+ CodingTTY, //!< plain TTY (5 bits)
+ CodingASCII, //!< plain ASCII (7 bits)
+ CodingLoRa //!< Standard LoRa
+ };
+
int m_inputFrequencyOffset;
int m_bandwidthIndex;
int m_spreadFactor;
@@ -35,7 +42,12 @@ struct LoRaModSettings
int m_quietMillis; //!< Number of milliseconds to pause between transmissions
unsigned char m_syncWord;
bool m_channelMute;
- QString m_message;
+ CodingScheme m_codingScheme;
+ QString m_message; //!< Freeflow message
+ QString m_myCall; //!< QSO mode: my callsign
+ QString m_urCall; //!< QSO mode: your callsign
+ QString m_myLoc; //!< QSO mode: my locator
+ QString m_myRpt; //!< QSO mode: my report
uint32_t m_rgbColor;
QString m_title;
int m_streamIndex;