mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-04-24 00:14:03 -04:00
LoRa modulator: implement LoRa
This commit is contained in:
parent
09a980de70
commit
c6f8ac2ca4
@ -7,6 +7,9 @@ set(modlora_SOURCES
|
||||
loramodbaseband.cpp
|
||||
loramodplugin.cpp
|
||||
loramodencoder.cpp
|
||||
loramodencodertty.cpp
|
||||
loramodencoderascii.cpp
|
||||
loramodencoderlora.cpp
|
||||
loramodwebapiadapter.cpp
|
||||
)
|
||||
|
||||
@ -17,6 +20,9 @@ set(modlora_HEADERS
|
||||
loramodbaseband.h
|
||||
loramodplugin.h
|
||||
loramodencoder.h
|
||||
loramodencodertty.h
|
||||
loramodencoderascii.h
|
||||
loramodencoderlora.h
|
||||
loramodwebapiadapter.h
|
||||
)
|
||||
|
||||
|
||||
@ -157,15 +157,27 @@ void LoRaMod::applySettings(const LoRaModSettings& settings, bool force)
|
||||
|
||||
if ((settings.m_spreadFactor != m_settings.m_spreadFactor)
|
||||
|| (settings.m_deBits != m_settings.m_deBits) || force) {
|
||||
m_encoder.setNbSymbolBits(settings.m_spreadFactor - settings.m_deBits);
|
||||
m_encoder.setNbSymbolBits(settings.m_spreadFactor, settings.m_deBits);
|
||||
}
|
||||
|
||||
if ((settings.m_codingScheme != m_settings.m_codingScheme) || force) {
|
||||
m_encoder.setCodingScheme(settings.m_codingScheme);
|
||||
}
|
||||
|
||||
if ((settings.m_nbParityBits != m_settings.m_nbParityBits || force)) {
|
||||
m_encoder.setLoRaParityBits(settings.m_nbParityBits);
|
||||
}
|
||||
|
||||
if ((settings.m_hasCRC != m_settings.m_hasCRC) || force) {
|
||||
m_encoder.setLoRaHasCRC(settings.m_hasCRC);
|
||||
}
|
||||
|
||||
if ((settings.m_hasHeader != m_settings.m_hasHeader) || force) {
|
||||
m_encoder.setLoRaHasHeader(settings.m_hasHeader);
|
||||
}
|
||||
|
||||
LoRaModBaseband::MsgConfigureLoRaModPayload *payloadMsg = nullptr;
|
||||
std::vector<unsigned int> symbols;
|
||||
std::vector<unsigned short> symbols;
|
||||
|
||||
if ((settings.m_messageType == LoRaModSettings::MessageNone)
|
||||
&& ((settings.m_messageType != m_settings.m_messageType) || force))
|
||||
|
||||
@ -60,22 +60,22 @@ public:
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
const std::vector<unsigned int>& getPayload() const { return m_payload; }
|
||||
const std::vector<unsigned short>& getPayload() const { return m_payload; }
|
||||
|
||||
static MsgConfigureLoRaModPayload* create() {
|
||||
return new MsgConfigureLoRaModPayload();
|
||||
}
|
||||
static MsgConfigureLoRaModPayload* create(const std::vector<unsigned int>& payload) {
|
||||
static MsgConfigureLoRaModPayload* create(const std::vector<unsigned short>& payload) {
|
||||
return new MsgConfigureLoRaModPayload(payload);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<unsigned int> m_payload;
|
||||
std::vector<unsigned short> m_payload;
|
||||
|
||||
MsgConfigureLoRaModPayload() : // This is empty payload notification
|
||||
Message()
|
||||
{}
|
||||
MsgConfigureLoRaModPayload(const std::vector<unsigned int>& payload) :
|
||||
MsgConfigureLoRaModPayload(const std::vector<unsigned short>& payload) :
|
||||
Message()
|
||||
{ m_payload = payload; }
|
||||
};
|
||||
|
||||
@ -16,174 +16,79 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#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
|
||||
};
|
||||
#include "loramodencodertty.h"
|
||||
#include "loramodencoderascii.h"
|
||||
#include "loramodencoderlora.h"
|
||||
|
||||
LoRaModEncoder::LoRaModEncoder() :
|
||||
m_codingScheme(LoRaModSettings::CodingTTY),
|
||||
m_nbSymbolBits(5)
|
||||
m_nbSymbolBits(5),
|
||||
m_nbParityBits(1),
|
||||
m_hasCRC(true),
|
||||
m_hasHeader(true)
|
||||
{}
|
||||
|
||||
LoRaModEncoder::~LoRaModEncoder()
|
||||
{}
|
||||
|
||||
void LoRaModEncoder::encodeString(const QString& str, std::vector<unsigned int>& symbols)
|
||||
void LoRaModEncoder::setNbSymbolBits(unsigned int spreadFactor, unsigned int deBits)
|
||||
{
|
||||
m_spreadFactor = spreadFactor;
|
||||
|
||||
if (deBits >= spreadFactor) {
|
||||
m_deBits = m_spreadFactor - 1;
|
||||
} else {
|
||||
m_deBits = deBits;
|
||||
}
|
||||
|
||||
m_nbSymbolBits = m_spreadFactor - m_deBits;
|
||||
}
|
||||
|
||||
void LoRaModEncoder::encodeString(const QString& str, std::vector<unsigned short>& symbols)
|
||||
{
|
||||
switch (m_codingScheme)
|
||||
{
|
||||
case LoRaModSettings::CodingTTY:
|
||||
encodeStringTTY(str, symbols);
|
||||
if (m_nbSymbolBits == 5) {
|
||||
LoRaModEncoderTTY::encodeString(str, symbols);
|
||||
}
|
||||
break;
|
||||
case LoRaModSettings::CodingASCII:
|
||||
encodeStringASCII(str, symbols);
|
||||
if (m_nbSymbolBits == 7) {
|
||||
LoRaModEncoderASCII::encodeString(str, symbols);
|
||||
}
|
||||
break;
|
||||
case LoRaModSettings::CodingLoRa:
|
||||
// TODO
|
||||
if (m_nbSymbolBits >= 5)
|
||||
{
|
||||
QByteArray bytes = str.toUtf8();
|
||||
encodeBytesLoRa(bytes, symbols);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaModEncoder::encodeBytes(const QByteArray& bytes, std::vector<unsigned int>& symbols)
|
||||
void LoRaModEncoder::encodeBytes(const QByteArray& bytes, std::vector<unsigned short>& symbols)
|
||||
{
|
||||
switch (m_codingScheme)
|
||||
{
|
||||
case LoRaModSettings::CodingLoRa:
|
||||
// TODO
|
||||
encodeBytesLoRa(bytes, symbols);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void LoRaModEncoder::encodeStringASCII(const QString& str, std::vector<unsigned int>& symbols)
|
||||
void LoRaModEncoder::encodeBytesLoRa(const QByteArray& bytes, std::vector<unsigned short>& symbols)
|
||||
{
|
||||
if (m_nbSymbolBits != 7) {
|
||||
return;
|
||||
QByteArray payload(bytes);
|
||||
|
||||
if (m_hasCRC) {
|
||||
LoRaModEncoderLoRa::addChecksum(payload);
|
||||
}
|
||||
|
||||
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<unsigned int>& 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LoRaModEncoderLoRa::encodeBytes(payload, symbols, m_nbSymbolBits, m_hasHeader, m_hasCRC, m_nbParityBits);
|
||||
}
|
||||
@ -28,27 +28,26 @@ public:
|
||||
~LoRaModEncoder();
|
||||
|
||||
void setCodingScheme(LoRaModSettings::CodingScheme codingScheme) { m_codingScheme = codingScheme; }
|
||||
void setNbSymbolBits(unsigned int symbolBits) { m_nbSymbolBits = symbolBits; }
|
||||
void encodeString(const QString& str, std::vector<unsigned int>& symbols);
|
||||
void encodeBytes(const QByteArray& bytes, std::vector<unsigned int>& symbols);
|
||||
void setNbSymbolBits(unsigned int spreadFactor, unsigned int deBits);
|
||||
void setLoRaParityBits(unsigned int parityBits) { m_nbParityBits = parityBits; }
|
||||
void setLoRaHasHeader(bool hasHeader) { m_hasHeader = hasHeader; }
|
||||
void setLoRaHasCRC(bool hasCRC) { m_hasCRC = hasCRC; }
|
||||
void encodeString(const QString& str, std::vector<unsigned short>& symbols);
|
||||
void encodeBytes(const QByteArray& bytes, std::vector<unsigned short>& symbols);
|
||||
|
||||
private:
|
||||
enum TTYState
|
||||
{
|
||||
TTYLetters,
|
||||
TTYFigures
|
||||
};
|
||||
|
||||
void encodeStringASCII(const QString& str, std::vector<unsigned int>& symbols);
|
||||
void encodeStringTTY(const QString& str, std::vector<unsigned int>& symbols);
|
||||
// LoRa functions
|
||||
void encodeBytesLoRa(const QByteArray& bytes, std::vector<unsigned short>& symbols);
|
||||
|
||||
// General attributes
|
||||
LoRaModSettings::CodingScheme m_codingScheme;
|
||||
unsigned int m_spreadFactor;
|
||||
unsigned int m_deBits;
|
||||
unsigned int m_nbSymbolBits;
|
||||
|
||||
static const char asciiToTTYLetters[128];
|
||||
static const char asciiToTTYFigures[128];
|
||||
static const char ttyLetters = 0x1f;
|
||||
static const char ttyFigures = 0x1b;
|
||||
// LoRa attributes
|
||||
unsigned int m_nbParityBits; //!< 1 to 4 Hamming FEC bits for 4 payload bits
|
||||
bool m_hasCRC;
|
||||
bool m_hasHeader;
|
||||
};
|
||||
|
||||
#endif // PLUGINS_CHANNELTX_MODLORA_LORAMODENCODER_H_
|
||||
|
||||
28
plugins/channeltx/modlora/loramodencoderascii.cpp
Normal file
28
plugins/channeltx/modlora/loramodencoderascii.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "loramodencoderascii.h"
|
||||
|
||||
void LoRaModEncoderASCII::encodeString(const QString& str, std::vector<unsigned short>& symbols)
|
||||
{
|
||||
QByteArray asciiStr = str.toUtf8();
|
||||
QByteArray::const_iterator it = asciiStr.begin();
|
||||
|
||||
for (; it != asciiStr.end(); ++it) {
|
||||
symbols.push_back(*it & 0x7F);
|
||||
}
|
||||
}
|
||||
30
plugins/channeltx/modlora/loramodencoderascii.h
Normal file
30
plugins/channeltx/modlora/loramodencoderascii.h
Normal file
@ -0,0 +1,30 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERASCII_H_
|
||||
#define PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERASCII_H_
|
||||
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
|
||||
class LoRaModEncoderASCII
|
||||
{
|
||||
public:
|
||||
static void encodeString(const QString& str, std::vector<unsigned short>& symbols);
|
||||
};
|
||||
|
||||
#endif // PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERASCII_H_
|
||||
147
plugins/channeltx/modlora/loramodencoderlora.cpp
Normal file
147
plugins/channeltx/modlora/loramodencoderlora.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
|
||||
// //
|
||||
// Inspired by: https://github.com/myriadrf/LoRa-SDR //
|
||||
// //
|
||||
// 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 "loramodencoderlora.h"
|
||||
|
||||
void LoRaModEncoderLoRa::addChecksum(QByteArray& bytes)
|
||||
{
|
||||
uint16_t crc = sx1272DataChecksum(reinterpret_cast<const uint8_t*>(bytes.data()), bytes.size());
|
||||
bytes.append(crc & 0xff);
|
||||
bytes.append((crc >> 8) & 0xff);
|
||||
}
|
||||
|
||||
void LoRaModEncoderLoRa::encodeBytes(
|
||||
const QByteArray& bytes,
|
||||
std::vector<unsigned short>& symbols,
|
||||
unsigned int nbSymbolBits,
|
||||
bool hasHeader,
|
||||
bool hasCRC,
|
||||
unsigned int nbParityBits
|
||||
)
|
||||
{
|
||||
if (nbSymbolBits < 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int payloadSize = bytes.size();
|
||||
const unsigned int numCodewords = roundUp(bytes.size()*2 + (hasHeader ? 5 : 0), nbSymbolBits);
|
||||
unsigned int cOfs = 0;
|
||||
unsigned int dOfs = 0;
|
||||
|
||||
std::vector<uint8_t> codewords(numCodewords);
|
||||
|
||||
if (hasHeader)
|
||||
{
|
||||
std::vector<uint8_t> hdr(3);
|
||||
hdr[0] = payloadSize % 256;
|
||||
hdr[1] = (hasCRC ? 1 : 0) | (nbParityBits << 1);
|
||||
hdr[2] = headerChecksum(hdr.data());
|
||||
|
||||
// Nibble decomposition and parity bit(s) addition. LSNibble first.
|
||||
codewords[cOfs++] = encodeHamming84sx(hdr[0] >> 4);
|
||||
codewords[cOfs++] = encodeHamming84sx(hdr[0] & 0xf); // length
|
||||
codewords[cOfs++] = encodeHamming84sx(hdr[1] & 0xf); // crc / fec info
|
||||
codewords[cOfs++] = encodeHamming84sx(hdr[2] >> 4); // checksum
|
||||
codewords[cOfs++] = encodeHamming84sx(hdr[2] & 0xf);
|
||||
}
|
||||
|
||||
unsigned int headerSize = cOfs;
|
||||
|
||||
// fill nbSymbolBits codewords with 8 bit codewords using payload data (ecode and whiten)
|
||||
encodeFec(codewords, 4, cOfs, dOfs, reinterpret_cast<const uint8_t*>(bytes.data()), nbSymbolBits - headerSize);
|
||||
Sx1272ComputeWhitening(codewords.data() + headerSize, nbSymbolBits - headerSize, 0, 4);
|
||||
|
||||
// encode and whiten the rest of the payload with 4 + nbParityBits bits codewords
|
||||
if (numCodewords > nbSymbolBits)
|
||||
{
|
||||
unsigned int cOfs2 = cOfs;
|
||||
encodeFec(codewords, nbParityBits, cOfs, dOfs, reinterpret_cast<const uint8_t*>(bytes.data()), numCodewords - nbSymbolBits);
|
||||
Sx1272ComputeWhitening(codewords.data() + cOfs2, numCodewords - nbSymbolBits, nbSymbolBits - headerSize, nbParityBits);
|
||||
}
|
||||
|
||||
const unsigned int numSymbols = 8 + (numCodewords / nbSymbolBits - 1) * (4 + nbParityBits); // header is always coded with 8 bits
|
||||
|
||||
// interleave the codewords into symbols
|
||||
symbols.clear();
|
||||
symbols.resize(numSymbols);
|
||||
diagonalInterleaveSx(codewords.data(), nbSymbolBits, symbols.data(), nbSymbolBits, 4);
|
||||
|
||||
if (numCodewords > nbSymbolBits) {
|
||||
diagonalInterleaveSx(codewords.data() + nbSymbolBits, numCodewords - nbSymbolBits, symbols.data() + 8, nbSymbolBits, nbParityBits);
|
||||
}
|
||||
|
||||
// gray decode
|
||||
for (auto &sym : symbols) {
|
||||
sym = grayToBinary16(sym);
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaModEncoderLoRa::encodeFec(
|
||||
std::vector<uint8_t> &codewords,
|
||||
unsigned int nbParityBits,
|
||||
unsigned int& cOfs,
|
||||
unsigned int& dOfs,
|
||||
const uint8_t *bytes,
|
||||
const unsigned int codewordCount
|
||||
)
|
||||
{
|
||||
for (unsigned int i = 0; i < codewordCount; i++, dOfs++)
|
||||
{
|
||||
if (nbParityBits == 1)
|
||||
{
|
||||
if (dOfs % 2 == 1) {
|
||||
codewords[cOfs++] = encodeParity54(bytes[dOfs/2] >> 4);
|
||||
} else {
|
||||
codewords[cOfs++] = encodeParity54(bytes[dOfs/2] & 0xf);
|
||||
}
|
||||
}
|
||||
else if (nbParityBits == 2)
|
||||
{
|
||||
if (dOfs % 2 == 1) {
|
||||
codewords[cOfs++] = encodeParity64(bytes[dOfs/2] >> 4);
|
||||
} else {
|
||||
codewords[cOfs++] = encodeParity64(bytes[dOfs/2] & 0xf);
|
||||
}
|
||||
}
|
||||
else if (nbParityBits == 3)
|
||||
{
|
||||
if (dOfs % 2 == 1) {
|
||||
codewords[cOfs++] = encodeHamming74sx(bytes[dOfs/2] >> 4);
|
||||
} else {
|
||||
codewords[cOfs++] = encodeHamming74sx(bytes[dOfs/2] & 0xf);
|
||||
}
|
||||
}
|
||||
else if (nbParityBits == 4)
|
||||
{
|
||||
if (dOfs % 2 == 1) {
|
||||
codewords[cOfs++] = encodeHamming84sx(bytes[dOfs/2] >> 4);
|
||||
} else {
|
||||
codewords[cOfs++] = encodeHamming84sx(bytes[dOfs/2] & 0xf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dOfs % 2 == 1) {
|
||||
codewords[cOfs++] = bytes[dOfs/2] >> 4;
|
||||
} else {
|
||||
codewords[cOfs++] = bytes[dOfs/2] & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
270
plugins/channeltx/modlora/loramodencoderlora.h
Normal file
270
plugins/channeltx/modlora/loramodencoderlora.h
Normal file
@ -0,0 +1,270 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
|
||||
// //
|
||||
// Inspired by: https://github.com/myriadrf/LoRa-SDR //
|
||||
// //
|
||||
// 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 PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERLORA_H_
|
||||
#define PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERLORA_H_
|
||||
|
||||
#include <vector>
|
||||
#include <QByteArray>
|
||||
|
||||
class LoRaModEncoderLoRa
|
||||
{
|
||||
public:
|
||||
static void addChecksum(QByteArray& bytes);
|
||||
static void encodeBytes(
|
||||
const QByteArray& bytes,
|
||||
std::vector<unsigned short>& symbols,
|
||||
unsigned int nbSymbolBits,
|
||||
bool hasHeader,
|
||||
bool hasCRC,
|
||||
unsigned int nbParityBits
|
||||
);
|
||||
|
||||
private:
|
||||
static void encodeFec(
|
||||
std::vector<uint8_t> &codewords,
|
||||
unsigned int nbParityBits,
|
||||
unsigned int& cOfs,
|
||||
unsigned int& dOfs,
|
||||
const uint8_t *bytes,
|
||||
const unsigned int codewordCount
|
||||
);
|
||||
|
||||
/***********************************************************************
|
||||
* Round functions
|
||||
**********************************************************************/
|
||||
static inline unsigned roundUp(unsigned num, unsigned factor)
|
||||
{
|
||||
return ((num + factor - 1) / factor) * factor;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Encode a 4 bit word into a 8 bits with parity
|
||||
* Non standard version used in sx1272.
|
||||
* https://en.wikipedia.org/wiki/Hamming_code
|
||||
**********************************************************************/
|
||||
static inline unsigned char encodeHamming84sx(const unsigned char x)
|
||||
{
|
||||
auto d0 = (x >> 0) & 0x1;
|
||||
auto d1 = (x >> 1) & 0x1;
|
||||
auto d2 = (x >> 2) & 0x1;
|
||||
auto d3 = (x >> 3) & 0x1;
|
||||
|
||||
unsigned char b = x & 0xf;
|
||||
b |= (d0 ^ d1 ^ d2) << 4;
|
||||
b |= (d1 ^ d2 ^ d3) << 5;
|
||||
b |= (d0 ^ d1 ^ d3) << 6;
|
||||
b |= (d0 ^ d2 ^ d3) << 7;
|
||||
return b;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Encode a 4 bit word into a 7 bits with parity.
|
||||
* Non standard version used in sx1272.
|
||||
**********************************************************************/
|
||||
static inline unsigned char encodeHamming74sx(const unsigned char x)
|
||||
{
|
||||
auto d0 = (x >> 0) & 0x1;
|
||||
auto d1 = (x >> 1) & 0x1;
|
||||
auto d2 = (x >> 2) & 0x1;
|
||||
auto d3 = (x >> 3) & 0x1;
|
||||
|
||||
unsigned char b = x & 0xf;
|
||||
b |= (d0 ^ d1 ^ d2) << 4;
|
||||
b |= (d1 ^ d2 ^ d3) << 5;
|
||||
b |= (d0 ^ d1 ^ d3) << 6;
|
||||
return b;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Encode a 4 bit word into a 6 bits with parity.
|
||||
**********************************************************************/
|
||||
static inline unsigned char encodeParity64(const unsigned char b)
|
||||
{
|
||||
auto x = b ^ (b >> 1) ^ (b >> 2);
|
||||
auto y = x ^ b ^ (b >> 3);
|
||||
return ((x & 1) << 4) | ((y & 1) << 5) | (b & 0xf);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Encode a 4 bit word into a 5 bits with parity.
|
||||
**********************************************************************/
|
||||
static inline unsigned char encodeParity54(const unsigned char b)
|
||||
{
|
||||
auto x = b ^ (b >> 2);
|
||||
x = x ^ (x >> 1);
|
||||
return (b & 0xf) | ((x << 4) & 0x10);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* CRC reverse engineered from Sx1272 data stream.
|
||||
* Modified CCITT crc with masking of the output with an 8bit lfsr
|
||||
**********************************************************************/
|
||||
static inline uint16_t crc16sx(uint16_t crc, const uint16_t poly)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (crc & 0x8000) {
|
||||
crc = (crc << 1) ^ poly;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
static inline uint8_t xsum8(uint8_t t)
|
||||
{
|
||||
t ^= t >> 4;
|
||||
t ^= t >> 2;
|
||||
t ^= t >> 1;
|
||||
|
||||
return (t & 1);
|
||||
}
|
||||
|
||||
static inline uint16_t sx1272DataChecksum(const uint8_t *data, int length)
|
||||
{
|
||||
uint16_t res = 0;
|
||||
uint8_t v = 0xff;
|
||||
uint16_t crc = 0;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
crc = crc16sx(res, 0x1021);
|
||||
v = xsum8(v & 0xB8) | (v << 1);
|
||||
res = crc ^ data[i];
|
||||
}
|
||||
|
||||
res ^= v;
|
||||
v = xsum8(v & 0xB8) | (v << 1);
|
||||
res ^= v << 8;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Specific checksum for header
|
||||
**********************************************************************/
|
||||
static inline uint8_t headerChecksum(const uint8_t *h)
|
||||
{
|
||||
auto a0 = (h[0] >> 4) & 0x1;
|
||||
auto a1 = (h[0] >> 5) & 0x1;
|
||||
auto a2 = (h[0] >> 6) & 0x1;
|
||||
auto a3 = (h[0] >> 7) & 0x1;
|
||||
|
||||
auto b0 = (h[0] >> 0) & 0x1;
|
||||
auto b1 = (h[0] >> 1) & 0x1;
|
||||
auto b2 = (h[0] >> 2) & 0x1;
|
||||
auto b3 = (h[0] >> 3) & 0x1;
|
||||
|
||||
auto c0 = (h[1] >> 0) & 0x1;
|
||||
auto c1 = (h[1] >> 1) & 0x1;
|
||||
auto c2 = (h[1] >> 2) & 0x1;
|
||||
auto c3 = (h[1] >> 3) & 0x1;
|
||||
|
||||
uint8_t res;
|
||||
res = (a0 ^ a1 ^ a2 ^ a3) << 4;
|
||||
res |= (a3 ^ b1 ^ b2 ^ b3 ^ c0) << 3;
|
||||
res |= (a2 ^ b0 ^ b3 ^ c1 ^ c3) << 2;
|
||||
res |= (a1 ^ b0 ^ b2 ^ c0 ^ c1 ^ c2) << 1;
|
||||
res |= a0 ^ b1 ^ c0 ^ c1 ^ c2 ^ c3;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Whitening generator reverse engineered from Sx1272 data stream.
|
||||
* Each bit of a codeword is combined with the output from a different position in the whitening sequence.
|
||||
**********************************************************************/
|
||||
static inline void Sx1272ComputeWhitening(uint8_t *buffer, uint16_t bufferSize, const int bitOfs, const int nbParityBits)
|
||||
{
|
||||
static const int ofs0[8] = {6,4,2,0,-112,-114,-302,-34 }; // offset into sequence for each bit
|
||||
static const int ofs1[5] = {6,4,2,0,-360 }; // different offsets used for single parity mode (1 == nbParityBits)
|
||||
static const int whiten_len = 510; // length of whitening sequence
|
||||
static const uint64_t whiten_seq[8] = { // whitening sequence
|
||||
0x0102291EA751AAFFL,0xD24B050A8D643A17L,0x5B279B671120B8F4L,0x032B37B9F6FB55A2L,
|
||||
0x994E0F87E95E2D16L,0x7CBCFC7631984C26L,0x281C8E4F0DAEF7F9L,0x1741886EB7733B15L
|
||||
};
|
||||
const int *ofs = (1 == nbParityBits) ? ofs1 : ofs0;
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < bufferSize; j++)
|
||||
{
|
||||
uint8_t x = 0;
|
||||
|
||||
for (i = 0; i < 4 + nbParityBits; i++)
|
||||
{
|
||||
int t = (ofs[i] + j + bitOfs + whiten_len) % whiten_len;
|
||||
|
||||
if (whiten_seq[t >> 6] & ((uint64_t)1 << (t & 0x3F))) {
|
||||
x |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[j] ^= x;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Diagonal interleaver + deinterleaver
|
||||
**********************************************************************/
|
||||
static inline void diagonalInterleaveSx(
|
||||
const uint8_t *codewords,
|
||||
const size_t numCodewords,
|
||||
uint16_t *symbols,
|
||||
const size_t nbSymbolBits,
|
||||
const size_t nbParityBits
|
||||
)
|
||||
{
|
||||
for (size_t x = 0; x < numCodewords / nbSymbolBits; x++)
|
||||
{
|
||||
const size_t cwOff = x*nbSymbolBits;
|
||||
const size_t symOff = x*(4 + nbParityBits);
|
||||
|
||||
for (size_t k = 0; k < 4 + nbParityBits; k++)
|
||||
{
|
||||
for (size_t m = 0; m < nbSymbolBits; m++)
|
||||
{
|
||||
const size_t i = (m + k + nbSymbolBits) % nbSymbolBits;
|
||||
const auto bit = (codewords[cwOff + i] >> k) & 0x1;
|
||||
symbols[symOff + k] |= (bit << m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* https://en.wikipedia.org/wiki/Gray_code
|
||||
**********************************************************************/
|
||||
|
||||
/*
|
||||
* A more efficient version, for Gray codes of 16 or fewer bits.
|
||||
*/
|
||||
static inline unsigned short grayToBinary16(unsigned short num)
|
||||
{
|
||||
num = num ^ (num >> 8);
|
||||
num = num ^ (num >> 4);
|
||||
num = num ^ (num >> 2);
|
||||
num = num ^ (num >> 1);
|
||||
return num;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERLORA_H_
|
||||
133
plugins/channeltx/modlora/loramodencodertty.cpp
Normal file
133
plugins/channeltx/modlora/loramodencodertty.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "loramodencodertty.h"
|
||||
|
||||
const char LoRaModEncoderTTY::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 LoRaModEncoderTTY::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
|
||||
};
|
||||
|
||||
void LoRaModEncoderTTY::encodeString(const QString& str, std::vector<unsigned short>& symbols)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
plugins/channeltx/modlora/loramodencodertty.h
Normal file
42
plugins/channeltx/modlora/loramodencodertty.h
Normal file
@ -0,0 +1,42 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERTTY_H_
|
||||
#define PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERTTY_H_
|
||||
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
|
||||
class LoRaModEncoderTTY
|
||||
{
|
||||
public:
|
||||
static void encodeString(const QString& str, std::vector<unsigned short>& symbols);
|
||||
|
||||
private:
|
||||
enum TTYState
|
||||
{
|
||||
TTYLetters,
|
||||
TTYFigures
|
||||
};
|
||||
|
||||
static const char asciiToTTYLetters[128];
|
||||
static const char asciiToTTYFigures[128];
|
||||
static const char ttyLetters = 0x1f;
|
||||
static const char ttyFigures = 0x1b;
|
||||
};
|
||||
|
||||
#endif // PLUGINS_CHANNELTX_MODLORA_LORAMODENCODERTTY_H_
|
||||
@ -108,7 +108,10 @@ bool LoRaModGUI::handleMessage(const Message& message)
|
||||
else if (LoRaMod::MsgReportPayloadTime::match(message))
|
||||
{
|
||||
const LoRaMod::MsgReportPayloadTime& rpt = (LoRaMod::MsgReportPayloadTime&) message;
|
||||
ui->msgTimeText->setText(tr("%1").arg(rpt.getPayloadTimeMs()));
|
||||
unsigned int fourthsMs = ((1<<m_settings.m_spreadFactor)*250) / LoRaModSettings::bandwidths[m_settings.m_bandwidthIndex];
|
||||
unsigned int controlMs = (4*(m_settings.m_preambleChirps)+8+9)*fourthsMs; // preamble + sync word + SFD
|
||||
ui->msgTimeText->setText(tr("%1 ms").arg(rpt.getPayloadTimeMs()));
|
||||
ui->msgTotalTimeText->setText(tr("%1 ms").arg(rpt.getPayloadTimeMs()+controlMs));
|
||||
return true;
|
||||
}
|
||||
else if (DSPSignalNotification::match(message))
|
||||
@ -225,9 +228,31 @@ void LoRaModGUI::on_syncWord_editingFinished()
|
||||
void LoRaModGUI::on_scheme_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_codingScheme = (LoRaModSettings::CodingScheme) index;
|
||||
ui->fecParity->setEnabled(m_settings.m_codingScheme == LoRaModSettings::CodingLoRa);
|
||||
ui->crc->setEnabled(m_settings.m_codingScheme == LoRaModSettings::CodingLoRa);
|
||||
ui->header->setEnabled(m_settings.m_codingScheme == LoRaModSettings::CodingLoRa);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void LoRaModGUI::on_fecParity_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_nbParityBits = value;
|
||||
ui->fecParityText->setText(tr("%1").arg(m_settings.m_nbParityBits));
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void LoRaModGUI::on_crc_stateChanged(int state)
|
||||
{
|
||||
m_settings.m_hasCRC = (state == Qt::Checked);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void LoRaModGUI::on_header_stateChanged(int state)
|
||||
{
|
||||
m_settings.m_hasHeader = (state == Qt::Checked);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void LoRaModGUI::on_myCall_editingFinished()
|
||||
{
|
||||
m_settings.m_myCall = ui->myCall->text();
|
||||
@ -460,6 +485,10 @@ void LoRaModGUI::displaySettings()
|
||||
displayStreamIndex();
|
||||
displayCurrentPayloadMessage();
|
||||
|
||||
ui->fecParity->setEnabled(m_settings.m_codingScheme == LoRaModSettings::CodingLoRa);
|
||||
ui->crc->setEnabled(m_settings.m_codingScheme == LoRaModSettings::CodingLoRa);
|
||||
ui->header->setEnabled(m_settings.m_codingScheme == LoRaModSettings::CodingLoRa);
|
||||
|
||||
blockApplySettings(true);
|
||||
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
|
||||
ui->bwText->setText(QString("%1 Hz").arg(thisBW));
|
||||
@ -475,6 +504,10 @@ void LoRaModGUI::displaySettings()
|
||||
ui->syncWord->setText((tr("%1").arg(m_settings.m_syncWord, 2, 16)));
|
||||
ui->channelMute->setChecked(m_settings.m_channelMute);
|
||||
ui->scheme->setCurrentIndex((int) m_settings.m_codingScheme);
|
||||
ui->fecParity->setValue(m_settings.m_nbParityBits);
|
||||
ui->fecParityText->setText(tr("%1").arg(m_settings.m_nbParityBits));
|
||||
ui->crc->setChecked(m_settings.m_hasCRC);
|
||||
ui->header->setChecked(m_settings.m_hasHeader);
|
||||
ui->myCall->setText(m_settings.m_myCall);
|
||||
ui->urCall->setText(m_settings.m_urCall);
|
||||
ui->myLocator->setText(m_settings.m_myLoc);
|
||||
|
||||
@ -95,6 +95,9 @@ private slots:
|
||||
void on_syncWord_editingFinished();
|
||||
void on_channelMute_toggled(bool checked);
|
||||
void on_scheme_currentIndexChanged(int index);
|
||||
void on_fecParity_valueChanged(int value);
|
||||
void on_crc_stateChanged(int state);
|
||||
void on_header_stateChanged(int state);
|
||||
void on_myCall_editingFinished();
|
||||
void on_urCall_editingFinished();
|
||||
void on_myLocator_editingFinished();
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>380</width>
|
||||
<height>411</height>
|
||||
<height>376</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
@ -31,17 +31,17 @@
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>370</width>
|
||||
<height>150</height>
|
||||
<height>125</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>150</height>
|
||||
<height>125</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>RF/demod Settings</string>
|
||||
<string>RF/mod/coder Settings</string>
|
||||
</property>
|
||||
<widget class="QLabel" name="bwLabel">
|
||||
<property name="geometry">
|
||||
@ -102,7 +102,7 @@
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>70</y>
|
||||
<width>81</width>
|
||||
<width>61</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -131,7 +131,7 @@
|
||||
<widget class="QLabel" name="spreadText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>130</x>
|
||||
<x>110</x>
|
||||
<y>70</y>
|
||||
<width>30</width>
|
||||
<height>16</height>
|
||||
@ -175,7 +175,7 @@
|
||||
<widget class="QLabel" name="deBitsLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>180</x>
|
||||
<x>160</x>
|
||||
<y>70</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
@ -188,15 +188,15 @@
|
||||
<widget class="QLabel" name="deBitsText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>320</x>
|
||||
<x>250</x>
|
||||
<y>70</y>
|
||||
<width>30</width>
|
||||
<width>10</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<width>10</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -210,9 +210,9 @@
|
||||
<widget class="QSlider" name="deBits">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>220</x>
|
||||
<x>200</x>
|
||||
<y>70</y>
|
||||
<width>81</width>
|
||||
<width>41</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -496,8 +496,8 @@
|
||||
<widget class="QLabel" name="syncLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>2</x>
|
||||
<y>114</y>
|
||||
<x>280</x>
|
||||
<y>70</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -509,8 +509,8 @@
|
||||
<widget class="QLineEdit" name="syncWord">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>112</y>
|
||||
<x>320</x>
|
||||
<y>68</y>
|
||||
<width>30</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
@ -528,58 +528,20 @@
|
||||
<string>00</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="schemeLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>114</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scheme</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="scheme">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>140</x>
|
||||
<y>112</y>
|
||||
<width>86</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>LoRa</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ASCII</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>TTY</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="messageContainer" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>180</y>
|
||||
<y>150</y>
|
||||
<width>370</width>
|
||||
<height>210</height>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>210</height>
|
||||
<height>220</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -589,7 +551,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>2</x>
|
||||
<y>10</y>
|
||||
<y>40</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -602,7 +564,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>10</y>
|
||||
<y>40</y>
|
||||
<width>40</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -615,7 +577,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>10</y>
|
||||
<y>40</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -628,7 +590,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>10</y>
|
||||
<y>40</y>
|
||||
<width>90</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -650,7 +612,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
<y>10</y>
|
||||
<y>40</y>
|
||||
<width>90</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -672,7 +634,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>30</y>
|
||||
<y>60</y>
|
||||
<width>40</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -685,7 +647,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>30</y>
|
||||
<y>60</y>
|
||||
<width>90</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -707,7 +669,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>30</y>
|
||||
<y>60</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -720,7 +682,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
<y>30</y>
|
||||
<y>60</y>
|
||||
<width>90</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -742,7 +704,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>310</x>
|
||||
<y>58</y>
|
||||
<y>80</y>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
@ -758,7 +720,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>58</y>
|
||||
<y>80</y>
|
||||
<width>90</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
@ -831,7 +793,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>2</x>
|
||||
<y>60</y>
|
||||
<y>110</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -844,7 +806,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>90</y>
|
||||
<y>110</y>
|
||||
<width>311</width>
|
||||
<height>60</height>
|
||||
</rect>
|
||||
@ -854,7 +816,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>2</x>
|
||||
<y>160</y>
|
||||
<y>175</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -867,7 +829,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>160</y>
|
||||
<y>175</y>
|
||||
<width>311</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
@ -877,7 +839,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>140</x>
|
||||
<y>58</y>
|
||||
<y>80</y>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
@ -897,7 +859,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>170</x>
|
||||
<y>58</y>
|
||||
<y>80</y>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
@ -920,7 +882,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>60</y>
|
||||
<y>82</y>
|
||||
<width>51</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -933,7 +895,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>250</x>
|
||||
<y>56</y>
|
||||
<y>78</y>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
@ -955,7 +917,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>280</x>
|
||||
<y>60</y>
|
||||
<y>82</y>
|
||||
<width>22</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -971,7 +933,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>2</x>
|
||||
<y>190</y>
|
||||
<y>200</y>
|
||||
<width>40</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -984,8 +946,8 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>190</y>
|
||||
<width>50</width>
|
||||
<y>200</y>
|
||||
<width>65</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -993,23 +955,166 @@
|
||||
<string>Payload time in milliseconds</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00000</string>
|
||||
<string>00000 ms</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="msgTimeUnits">
|
||||
<widget class="QLabel" name="msgTotalTimeLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>95</x>
|
||||
<y>190</y>
|
||||
<width>20</width>
|
||||
<x>119</x>
|
||||
<y>200</y>
|
||||
<width>35</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ms</string>
|
||||
<string>Total</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="msgTotalTimeText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>150</x>
|
||||
<y>200</y>
|
||||
<width>65</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Total transmission time in milliseconds</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00000 ms</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="schemeLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>2</x>
|
||||
<y>10</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scheme</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="scheme">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>8</y>
|
||||
<width>86</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>LoRa</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ASCII</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>TTY</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="header">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>300</x>
|
||||
<y>10</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Header (explicit)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>HDR</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="crc">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>240</x>
|
||||
<y>10</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Append CRC to payload</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>CRC</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="fecParityLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>160</x>
|
||||
<y>10</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FEC</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QDial" name="fecParity">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>190</x>
|
||||
<y>5</y>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Number of FEC parity bits (0 to 4) for Hamming code</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="fecParityText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>220</x>
|
||||
<y>10</y>
|
||||
<width>12</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
@ -43,6 +43,9 @@ void LoRaModSettings::resetToDefaults()
|
||||
m_preambleChirps = 8;
|
||||
m_quietMillis = 1000;
|
||||
m_codingScheme = CodingLoRa;
|
||||
m_nbParityBits = 1;
|
||||
m_hasCRC = true;
|
||||
m_hasHeader = true;
|
||||
m_textMessage = "Hello LoRa";
|
||||
m_myCall = "MYCALL";
|
||||
m_urCall = "URCALL";
|
||||
@ -129,6 +132,9 @@ QByteArray LoRaModSettings::serialize() const
|
||||
s.writeString(28, m_textMessage);
|
||||
s.writeBlob(29, m_bytesMessage);
|
||||
s.writeS32(30, (int) m_messageType);
|
||||
s.writeS32(31, m_nbParityBits);
|
||||
s.writeBool(32, m_hasCRC);
|
||||
s.writeBool(33, m_hasHeader);
|
||||
s.writeString(40, m_myCall);
|
||||
s.writeString(41, m_urCall);
|
||||
s.writeString(42, m_myLoc);
|
||||
@ -199,6 +205,9 @@ bool LoRaModSettings::deserialize(const QByteArray& data)
|
||||
d.readBlob(29, &m_bytesMessage);
|
||||
d.readS32(30, &tmp, 0);
|
||||
m_messageType = (MessageType) tmp;
|
||||
d.readS32(31, &m_nbParityBits, 1);
|
||||
d.readBool(32, &m_hasCRC, true);
|
||||
d.readBool(33, &m_hasHeader, true);
|
||||
d.readString(40, &m_myCall, "MYCALL");
|
||||
d.readString(41, &m_urCall, "URCALL");
|
||||
d.readString(42, &m_myLoc, "AA00AA");
|
||||
|
||||
@ -56,6 +56,9 @@ struct LoRaModSettings
|
||||
int m_deBits; //!< Low data rate optmize (DE) bits
|
||||
int m_preambleChirps; //!< Number of preamble chirps
|
||||
int m_quietMillis; //!< Number of milliseconds to pause between transmissions
|
||||
int m_nbParityBits; //!< Hamming parity bits (LoRa)
|
||||
bool m_hasCRC; //!< Payload has CRC (LoRa)
|
||||
bool m_hasHeader; //!< Header present before actual payload (LoRa)
|
||||
unsigned char m_syncWord;
|
||||
bool m_channelMute;
|
||||
CodingScheme m_codingScheme;
|
||||
|
||||
@ -332,7 +332,7 @@ void LoRaModSource::modulateSample()
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int LoRaModSource::encodeSymbol(unsigned int symbol)
|
||||
unsigned short LoRaModSource::encodeSymbol(unsigned short symbol)
|
||||
{
|
||||
if (m_settings.m_deBits == 0) {
|
||||
return symbol;
|
||||
@ -421,7 +421,7 @@ void LoRaModSource::applyChannelSettings(int channelSampleRate, int bandwidth, i
|
||||
reset();
|
||||
}
|
||||
|
||||
void LoRaModSource::setSymbols(const std::vector<unsigned int>& symbols)
|
||||
void LoRaModSource::setSymbols(const std::vector<unsigned short>& symbols)
|
||||
{
|
||||
m_symbols = symbols;
|
||||
qDebug("LoRaModSource::setSymbols: m_symbols: %lu", m_symbols.size());
|
||||
|
||||
@ -47,7 +47,7 @@ public:
|
||||
}
|
||||
void applySettings(const LoRaModSettings& settings, bool force = false);
|
||||
void applyChannelSettings(int channelSampleRate, int bandwidth, int channelFrequencyOffset, bool force = false);
|
||||
void setSymbols(const std::vector<unsigned int>& symbols);
|
||||
void setSymbols(const std::vector<unsigned short>& symbols);
|
||||
bool getActive() const { return m_active; }
|
||||
|
||||
private:
|
||||
@ -76,7 +76,7 @@ private:
|
||||
Complex *m_downChirps;
|
||||
Complex *m_upChirps;
|
||||
double *m_phaseIncrements;
|
||||
std::vector<unsigned int> m_symbols;
|
||||
std::vector<unsigned short> m_symbols;
|
||||
unsigned int m_fftLength; //!< chirp length in samples
|
||||
unsigned int m_chirp; //!< actual chirp index in chirps table
|
||||
unsigned int m_chirp0; //!< half index of chirp start in chirps table
|
||||
@ -116,7 +116,7 @@ private:
|
||||
void processOneSample(Complex& ci);
|
||||
void calculateLevel(Real& sample);
|
||||
void modulateSample();
|
||||
unsigned int encodeSymbol(unsigned int symbol); //!< Encodes symbol with possible DE bits spacing
|
||||
unsigned short encodeSymbol(unsigned short symbol); //!< Encodes symbol with possible DE bits spacing
|
||||
};
|
||||
|
||||
#endif // INCLUDE_LORAMODSOURCE_H
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user