1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-03-30 19:55:52 -04:00

Merge branch 'f4exb:master' into acars

This commit is contained in:
srcejon 2026-01-25 16:43:30 +00:00 committed by GitHub
commit 139b366bfd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 602 additions and 43 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

View File

@ -2634,7 +2634,7 @@ int FT8::decode(const float ll174[], int a174[], FT8Params& _params, int use_osd
// apply (174, 91) generator mastrix to obtain the 83 parity bits
// append the 83 bits to the 91 bits message + crc to obbain the 174 bit payload
//
void FT8::encode(int a174[], int s77[])
void FT8::encode(int a174[], const int s77[])
{
int a91[91]; // msg + CRC
std::fill(a91, a91 + 91, 0);

View File

@ -273,7 +273,7 @@ public:
// adds the 14 bit CRC to obtain 91 bits
// apply (174, 91) generator mastrix to obtain the 83 parity bits
// append the 83 bits to the 91 bits message e+ crc to obtain the 174 bit payload
static void encode(int a174[], int s77[]);
static void encode(int a174[], const int s77[]);
//
// set ones and zero symbol indexes

View File

@ -396,7 +396,7 @@ void LDPC::ft8_crc(int msg1[], int msglen, int out[14])
}
}
for (int i = 0; i < msglen + 14; i++)
for (int i = 0; i < 14; i++)
{
out[i] = msg[msglen + i];
}

View File

@ -432,6 +432,14 @@ void ChirpChatDemod::applySettings(const ChirpChatDemodSettings& settings, bool
<< " m_sendViaUDP: " << settings.m_sendViaUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " m_decodeActive: " << settings.m_decodeActive
<< " m_eomSquelchTenths: " << settings.m_eomSquelchTenths
<< " m_nbSymbolsMax: " << settings.m_nbSymbolsMax
<< " m_preambleChirps: " << settings.m_preambleChirps
<< " m_streamIndex: " << settings.m_streamIndex
<< " m_useReverseAPI: " << settings.m_useReverseAPI
<< " m_fftWindow: " << settings.m_fftWindow
<< " m_invertRamps: " << settings.m_invertRamps
<< " m_rgbColor: " << settings.m_rgbColor
<< " m_title: " << settings.m_title
<< " force: " << force;
@ -533,6 +541,9 @@ void ChirpChatDemod::applySettings(const ChirpChatDemodSettings& settings, bool
if ((settings.m_autoNbSymbolsMax != m_settings.m_autoNbSymbolsMax) || force) {
reverseAPIKeys.append("autoNbSymbolsMax");
}
if ((settings.m_invertRamps != m_settings.m_invertRamps) || force) {
reverseAPIKeys.append("invertRamps");
}
if ((settings.m_udpAddress != m_settings.m_udpAddress) || force)
{
@ -694,6 +705,9 @@ void ChirpChatDemod::webapiUpdateChannelSettings(
uint16_t port = response.getChirpChatDemodSettings()->getUdpPort();
settings.m_udpPort = port < 1024 ? 1024 : port;
}
if (channelSettingsKeys.contains("invertRamps")) {
settings.m_invertRamps = response.getChirpChatDemodSettings()->getInvertRamps() != 0;
}
if (channelSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getChirpChatDemodSettings()->getRgbColor();
}
@ -757,6 +771,7 @@ void ChirpChatDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings
response.getChirpChatDemodSettings()->setHasCrc(settings.m_hasCRC ? 1 : 0);
response.getChirpChatDemodSettings()->setHasHeader(settings.m_hasHeader ? 1 : 0);
response.getChirpChatDemodSettings()->setSendViaUdp(settings.m_sendViaUDP ? 1 : 0);
response.getChirpChatDemodSettings()->setInvertRamps(settings.m_invertRamps ? 1 : 0);
if (response.getChirpChatDemodSettings()->getUdpAddress()) {
*response.getChirpChatDemodSettings()->getUdpAddress() = settings.m_udpAddress;
@ -978,6 +993,9 @@ void ChirpChatDemod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("updPort") || force) {
swgChirpChatDemodSettings->setUdpPort(settings.m_udpPort);
}
if (channelSettingsKeys.contains("invertRamps") || force) {
swgChirpChatDemodSettings->setInvertRamps(settings.m_invertRamps ? 1 : 0);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgChirpChatDemodSettings->setRgbColor(settings.m_rgbColor);
}

View File

@ -338,6 +338,12 @@ void ChirpChatDemodGUI::on_udpPort_editingFinished()
applySettings();
}
void ChirpChatDemodGUI::on_invertRamps_stateChanged(int state)
{
m_settings.m_invertRamps = (state == Qt::Checked);
applySettings();
}
void ChirpChatDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
@ -529,6 +535,7 @@ void ChirpChatDemodGUI::displaySettings()
}
ui->messageLengthAuto->setChecked(m_settings.m_autoNbSymbolsMax);
ui->invertRamps->setChecked(m_settings.m_invertRamps);
displaySquelch();
updateIndexLabel();
@ -854,6 +861,7 @@ void ChirpChatDemodGUI::makeUIConnections()
QObject::connect(ui->udpSend, &QCheckBox::stateChanged, this, &ChirpChatDemodGUI::on_udpSend_stateChanged);
QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &ChirpChatDemodGUI::on_udpAddress_editingFinished);
QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &ChirpChatDemodGUI::on_udpPort_editingFinished);
QObject::connect(ui->invertRamps, &QCheckBox::stateChanged, this, &ChirpChatDemodGUI::on_invertRamps_stateChanged);
}
void ChirpChatDemodGUI::updateAbsoluteCenterFrequency()

View File

@ -82,6 +82,7 @@ private slots:
void on_udpSend_stateChanged(int state);
void on_udpAddress_editingFinished();
void on_udpPort_editingFinished();
void on_invertRamps_stateChanged(int state);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void channelMarkerHighlightedByCursor();

View File

@ -526,6 +526,23 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_12">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="invertRamps">
<property name="toolTip">
<string>Invert preamble, SFD and payload ramps</string>
</property>
<property name="text">
<string>Inv</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">

View File

@ -80,6 +80,7 @@ void ChirpChatDemodSettings::resetToDefaults()
m_hasCRC = true;
m_hasHeader = true;
m_sendViaUDP = false;
m_invertRamps = false;
m_udpAddress = "127.0.0.1";
m_udpPort = 9999;
m_rgbColor = QColor(255, 0, 255).rgb();
@ -121,6 +122,7 @@ QByteArray ChirpChatDemodSettings::serialize() const
s.writeBool(15, m_hasHeader);
s.writeU32(17, m_preambleChirps);
s.writeS32(18, (int) m_fftWindow);
s.writeBool(19, m_invertRamps);
s.writeBool(20, m_useReverseAPI);
s.writeString(21, m_reverseAPIAddress);
s.writeU32(22, m_reverseAPIPort);
@ -188,6 +190,7 @@ bool ChirpChatDemodSettings::deserialize(const QByteArray& data)
d.readU32(17, &m_preambleChirps, 8);
d.readS32(18, &tmp, (int) FFTWindow::Rectangle);
m_fftWindow = (FFTWindow::Function) tmp;
d.readBool(19, &m_invertRamps, false);
d.readBool(20, &m_useReverseAPI, false);
d.readString(21, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(22, &utmp, 0);
@ -232,6 +235,113 @@ bool ChirpChatDemodSettings::deserialize(const QByteArray& data)
}
}
void ChirpChatDemodSettings::applySettings(const QStringList& settingsKeys, const ChirpChatDemodSettings& settings)
{
if (settingsKeys.contains("inputFrequencyOffset"))
m_inputFrequencyOffset = settings.m_inputFrequencyOffset;
if (settingsKeys.contains("bandwidthIndex"))
m_bandwidthIndex = settings.m_bandwidthIndex;
if (settingsKeys.contains("spreadFactor"))
m_spreadFactor = settings.m_spreadFactor;
if (settingsKeys.contains("deBits"))
m_deBits = settings.m_deBits;
if (settingsKeys.contains("fftWindow"))
m_fftWindow = settings.m_fftWindow;
if (settingsKeys.contains("codingScheme"))
m_codingScheme = settings.m_codingScheme;
if (settingsKeys.contains("decodeActive"))
m_decodeActive = settings.m_decodeActive;
if (settingsKeys.contains("eomSquelchTenths"))
m_eomSquelchTenths = settings.m_eomSquelchTenths;
if (settingsKeys.contains("nbSymbolsMax"))
m_nbSymbolsMax = settings.m_nbSymbolsMax;
if (settingsKeys.contains("preambleChirps"))
m_preambleChirps = settings.m_preambleChirps;
if (settingsKeys.contains("nbParityBits"))
m_nbParityBits = settings.m_nbParityBits;
if (settingsKeys.contains("packetLength"))
m_packetLength = settings.m_packetLength;
if (settingsKeys.contains("hasCRC"))
m_hasCRC = settings.m_hasCRC;
if (settingsKeys.contains("hasHeader"))
m_hasHeader = settings.m_hasHeader;
if (settingsKeys.contains("sendViaUDP"))
m_sendViaUDP = settings.m_sendViaUDP;
if (settingsKeys.contains("invertRamps"))
m_invertRamps = settings.m_invertRamps;
if (settingsKeys.contains("udpAddress"))
m_udpAddress = settings.m_udpAddress;
if (settingsKeys.contains("udpPort"))
m_udpPort = settings.m_udpPort;
if (settingsKeys.contains("useReverseAPI"))
m_useReverseAPI = settings.m_useReverseAPI;
if (settingsKeys.contains("reverseAPIAddress"))
m_reverseAPIAddress = settings.m_reverseAPIAddress;
if (settingsKeys.contains("reverseAPIPort"))
m_reverseAPIPort = settings.m_reverseAPIPort;
if (settingsKeys.contains("reverseAPIDeviceIndex"))
m_reverseAPIDeviceIndex = settings.m_reverseAPIDeviceIndex;
if (settingsKeys.contains("reverseAPIChannelIndex"))
m_reverseAPIChannelIndex = settings.m_reverseAPIChannelIndex;
if (settingsKeys.contains("streamIndex"))
m_streamIndex = settings.m_streamIndex;
}
QString ChirpChatDemodSettings::getDebugString(const QStringList& settingsKeys, bool force) const
{
QString debug;
if (force || settingsKeys.contains("inputFrequencyOffset"))
debug += QString("InputFrequencyOffset: %1 ").arg(m_inputFrequencyOffset);
if (force || settingsKeys.contains("bandwidthIndex"))
debug += QString("BandwidthIndex: %1 ").arg(m_bandwidthIndex);
if (force || settingsKeys.contains("spreadFactor"))
debug += QString("SpreadFactor: %1 ").arg(m_spreadFactor);
if (force || settingsKeys.contains("deBits"))
debug += QString("DEBits: %1 ").arg(m_deBits);
if (force || settingsKeys.contains("fftWindow"))
debug += QString("FFTWindow: %1 ").arg((int) m_fftWindow);
if (force || settingsKeys.contains("codingScheme"))
debug += QString("CodingScheme: %1 ").arg((int) m_codingScheme);
if (force || settingsKeys.contains("decodeActive"))
debug += QString("DecodeActive: %1 ").arg(m_decodeActive);
if (force || settingsKeys.contains("eomSquelchTenths"))
debug += QString("EOMSquelchTenths: %1 ").arg(m_eomSquelchTenths);
if (force || settingsKeys.contains("nbSymbolsMax"))
debug += QString("NbSymbolsMax: %1 ").arg(m_nbSymbolsMax);
if (force || settingsKeys.contains("preambleChirps"))
debug += QString("PreambleChirps: %1 ").arg(m_preambleChirps);
if (force || settingsKeys.contains("nbParityBits"))
debug += QString("NbParityBits: %1 ").arg(m_nbParityBits);
if (force || settingsKeys.contains("packetLength"))
debug += QString("PacketLength: %1 ").arg(m_packetLength);
if (force || settingsKeys.contains("hasCRC"))
debug += QString("HasCRC: %1 ").arg(m_hasCRC);
if (force || settingsKeys.contains("hasHeader"))
debug += QString("HasHeader: %1 ").arg(m_hasHeader);
if (force || settingsKeys.contains("sendViaUDP"))
debug += QString("SendViaUDP: %1 ").arg(m_sendViaUDP);
if (force || settingsKeys.contains("invertRamps"))
debug += QString("InvertRamps: %1 ").arg(m_invertRamps);
if (force || settingsKeys.contains("udpAddress"))
debug += QString("UDPAddress: %1 ").arg(m_udpAddress);
if (force || settingsKeys.contains("udpPort"))
debug += QString("UDPPort: %1 ").arg(m_udpPort);
if (force || settingsKeys.contains("useReverseAPI"))
debug += QString("UseReverseAPI: %1 ").arg(m_useReverseAPI);
if (force || settingsKeys.contains("reverseAPIAddress"))
debug += QString("ReverseAPIAddress: %1 ").arg(m_reverseAPIAddress);
if (force || settingsKeys.contains("reverseAPIPort"))
debug += QString("ReverseAPIPort: %1 ").arg(m_reverseAPIPort);
if (force || settingsKeys.contains("reverseAPIDeviceIndex"))
debug += QString("ReverseAPIDeviceIndex: %1 ").arg(m_reverseAPIDeviceIndex);
if (force || settingsKeys.contains("reverseAPIChannelIndex"))
debug += QString("ReverseAPIChannelIndex: %1 ").arg(m_reverseAPIChannelIndex);
if (force || settingsKeys.contains("streamIndex"))
debug += QString("StreamIndex: %1 ").arg(m_streamIndex);
return debug;
}
unsigned int ChirpChatDemodSettings::getNbSFDFourths() const
{
switch (m_codingScheme)

View File

@ -65,6 +65,7 @@ struct ChirpChatDemodSettings
bool m_hasCRC; //!< Payload has CRC (LoRa)
bool m_hasHeader; //!< Header present before actual payload (LoRa)
bool m_sendViaUDP; //!< Send decoded message via UDP
bool m_invertRamps; //!< Invert chirp ramps vs standard LoRa (up/down/up is standard)
QString m_udpAddress; //!< UDP address where to send message
uint16_t m_udpPort; //!< UDP port where to send message
uint32_t m_rgbColor;
@ -96,6 +97,8 @@ struct ChirpChatDemodSettings
bool hasSyncWord() const; //!< Only LoRa has a syncword (for the moment)
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
void applySettings(const QStringList& settingsKeys, const ChirpChatDemodSettings& settings);
QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
};

View File

@ -158,7 +158,7 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
}
else if (m_state == ChirpChatStateDetectPreamble) // look for preamble
{
m_fft->in()[m_fftCounter++] = ci * m_downChirps[m_chirp]; // de-chirp the up ramp
m_fft->in()[m_fftCounter++] = ci * (m_settings.m_invertRamps ? m_upChirps[m_chirp] : m_downChirps[m_chirp]); // de-chirp the preamble ramp
if (m_fftCounter == m_fftLength)
{
@ -178,6 +178,11 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
m_fftInterpolation
) / m_fftInterpolation;
// When ramps are inverted, FFT output interpretation is reversed
if (m_settings.m_invertRamps) {
imax = (m_nbSymbols - imax) % m_nbSymbols;
}
if (m_magsqQueue.size() > m_settings.m_preambleChirps) {
m_magsqQueue.pop();
}
@ -246,8 +251,8 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
}
else if (m_state == ChirpChatStatePreamble) // preamble found look for SFD start
{
m_fft->in()[m_fftCounter] = ci * m_downChirps[m_chirp]; // de-chirp the up ramp
m_fftSFD->in()[m_fftCounter] = ci * m_upChirps[m_chirp]; // de-chirp the down ramp
m_fft->in()[m_fftCounter] = ci * (m_settings.m_invertRamps ? m_upChirps[m_chirp] : m_downChirps[m_chirp]); // de-chirp the preamble ramp
m_fftSFD->in()[m_fftCounter] = ci * (m_settings.m_invertRamps ? m_downChirps[m_chirp] : m_upChirps[m_chirp]); // de-chirp the SFD ramp
m_fftCounter++;
if (m_fftCounter == m_fftLength)
@ -284,6 +289,11 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
m_fftInterpolation
) / m_fftInterpolation;
// When ramps are inverted, FFT output interpretation is reversed
if (m_settings.m_invertRamps) {
imax = (m_nbSymbols - imax) % m_nbSymbols;
}
m_preambleHistory[m_chirpCount] = imax;
m_chirpCount++;
double preDrop = magsqPre - magsqSFD;
@ -374,7 +384,7 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
}
else if (m_state == ChirpChatStateReadPayload)
{
m_fft->in()[m_fftCounter] = ci * m_downChirps[m_chirp]; // de-chirp the up ramp
m_fft->in()[m_fftCounter] = ci * (m_settings.m_invertRamps ? m_upChirps[m_chirp] : m_downChirps[m_chirp]); // de-chirp the payload ramp
m_fftCounter++;
if (m_fftCounter == m_fftLength)
@ -438,6 +448,11 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
);
}
// When ramps are inverted, FFT output interpretation is reversed
if (m_settings.m_invertRamps) {
imax = (m_nbSymbols * m_fftInterpolation - imax) % (m_nbSymbols * m_fftInterpolation);
}
symbol = evalSymbol(imax) % m_nbSymbolsEff;
m_decodeMsg->pushBackSymbol(symbol);
}

View File

@ -120,6 +120,12 @@ In practice it is difficult to make correct decodes if only one FFT bin is used
This is the number of chirps expected in the preamble and has to be agreed between the transmitter and receiver.
<h3>15: Invert chirp ramps</h3>
The LoRa standard is up-chirps for the preamble, down-chirps for the SFD and up-chirps for the payload.
When you check this option it inverts the direction of the chirps thus becoming down-chirps for the preamble, up-chirps for the SFD and down-chirps for the payload.
<h3>A: Payload controls and indicators</h3>
![ChirpChat Demodulator payload controls](../../../doc/img/ChirpChatDemod_payload.png)
@ -165,6 +171,8 @@ LoRa mode only. This is the number of parity bits in the Hamming code used in th
When a header is expected this control is disabled because the value used is the one found in the header.
In FT8 mode there is no FEC as FEC is handled within the FT payload (with LDPC)
<h4>A.9: Payload CRC presence</h4>
LoRa mode: Use this checkbox to tell if you expect a 2 byte CRC at the end of the payload. FT mode: there is always a CRC.
@ -284,3 +292,43 @@ Controls are the usual controls of spectrum displays with the following restrict
- The window type is non operating because the FFT window is chosen by (7)
- The FFT size can be changed however it is set to 2<sup>SF</sup> where SF is the spread factor and thus displays correctly
<h2>Common LoRa settings</h2>
CR is the code rate and translates to FEC according to the following table
| CR | FEC |
| --- | --- |
| 4/5 | 1 |
| 4/6 | 2 |
| 4/7 | 3 |
| 4/8 | 4 |
When DE is on set DE to 2 else 0
<h3>Generic</h3>
| Use Case | SF | CR | BW (kHz) | DE Enabled? | Notes |
| --------------------- | --------- | ------- | -------- | ----------- | ----------------------------------------------------------- |
| High rate/short range | SF7 | 4/5 | 500 | Off | Fastest, urban/close devices |
| Balanced/general IoT | SF7SF9 | 4/54/6 | 125250 | Off | TTN default, good for gateways |
| Long range/rural | SF10SF12 | 4/64/8 | 125 | On | Max sensitivity (-137 dBm), slow airtime |
| Extreme range | SF12 | 4/8 | 125 | On | Best for weak signals, long packets |
<h3>Meshtastic</h3>
<h4>Quick facts</h4>
- Uses 0x2B sync byte
- In Europe the default channel is centered on 869.525 MHz
<h4>Presets table</h4>
| Preset | SF | CR | BW (kHz) | DE? | Use Case |
| ------------------- | -- | ---- | -------- | --- | ---------------------------------------------------- |
| LONG_FAST (default) | 11 | 4/8 | 250 | On | Long range, moderate speed |
| MEDIUM_SLOW | 10 | 4/7 | 250 | On | Balanced range/reliability |
| SHORT_FAST | 9 | 4/7 | 250 | Off | Urban/short hops, faster |
| SHORT_TURBO | 7 | 4/5 | 500 | Off | Max speed, shortest range (region-limited) |
| LONG_SLOW | 12 | 4/8 | 125 | On | Extreme range, slowest meshtastic |

View File

@ -186,6 +186,21 @@ void ChirpChatMod::applySettings(const ChirpChatModSettings& settings, bool forc
<< " m_73message: " << settings.m_73Message
<< " m_qsoTextMessage: " << settings.m_qsoTextMessage
<< " m_textMessage: " << settings.m_textMessage
<< " m_bytesMessage: " << settings.m_bytesMessage.toHex()
<< " m_spreadFactor: " << settings.m_spreadFactor
<< " m_deBits: " << settings.m_deBits
<< " m_codingScheme: " << settings.m_codingScheme
<< " m_nbParityBits: " << settings.m_nbParityBits
<< " m_hasCRC: " << settings.m_hasCRC
<< " m_hasHeader: " << settings.m_hasHeader
<< " m_messageType: " << settings.m_messageType
<< " m_preambleChirps: " << settings.m_preambleChirps
<< " m_quietMillis: " << settings.m_quietMillis
<< " m_messageRepeat: " << settings.m_messageRepeat
<< " m_udpEnabled: " << settings.m_udpEnabled
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " m_invertRamps: " << settings.m_invertRamps
<< " m_useReverseAPI: " << settings.m_useReverseAPI
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< " m_reverseAPIAddress: " << settings.m_reverseAPIPort
@ -216,6 +231,17 @@ void ChirpChatMod::applySettings(const ChirpChatModSettings& settings, bool forc
m_encoder.setNbSymbolBits(settings.m_spreadFactor, settings.m_deBits);
}
if ((settings.m_spreadFactor != m_settings.m_spreadFactor)
|| (settings.m_bandwidthIndex != m_settings.m_bandwidthIndex) || force)
{
if (getMessageQueueToGUI())
{
m_currentPayloadTime = (m_symbols.size()*(1<<settings.m_spreadFactor)*1000.0) / ChirpChatModSettings::bandwidths[settings.m_bandwidthIndex];
MsgReportPayloadTime *rpt = MsgReportPayloadTime::create(m_currentPayloadTime, m_symbols.size());
getMessageQueueToGUI()->push(rpt);
}
}
if ((settings.m_codingScheme != m_settings.m_codingScheme) || force)
{
reverseAPIKeys.append("codingScheme");
@ -273,9 +299,17 @@ void ChirpChatMod::applySettings(const ChirpChatModSettings& settings, bool forc
if ((settings.m_bytesMessage != m_settings.m_bytesMessage) || force) {
reverseAPIKeys.append("bytesMessage");
}
if ((settings.m_preambleChirps != m_settings.m_preambleChirps) || force) {
reverseAPIKeys.append("preambleChirps");
}
if ((settings.m_quietMillis != m_settings.m_quietMillis) || force) {
reverseAPIKeys.append("quietMillis");
}
if ((settings.m_invertRamps != m_settings.m_invertRamps) || force) {
reverseAPIKeys.append("invertRamps");
}
ChirpChatModBaseband::MsgConfigureChirpChatModPayload *payloadMsg = nullptr;
std::vector<unsigned short> symbols;
if ((settings.m_messageType == ChirpChatModSettings::MessageNone)
&& ((settings.m_messageType != m_settings.m_messageType) || force))
@ -294,18 +328,19 @@ void ChirpChatMod::applySettings(const ChirpChatModSettings& settings, bool forc
|| (settings.m_textMessage != m_settings.m_textMessage)
|| (settings.m_bytesMessage != m_settings.m_bytesMessage) || force)
{
m_encoder.encode(settings, symbols);
payloadMsg = ChirpChatModBaseband::MsgConfigureChirpChatModPayload::create(symbols);
m_symbols.clear();
m_encoder.encode(settings, m_symbols);
payloadMsg = ChirpChatModBaseband::MsgConfigureChirpChatModPayload::create(m_symbols);
}
if (payloadMsg)
{
m_basebandSource->getInputMessageQueue()->push(payloadMsg);
m_currentPayloadTime = (symbols.size()*(1<<settings.m_spreadFactor)*1000.0) / ChirpChatModSettings::bandwidths[settings.m_bandwidthIndex];
m_currentPayloadTime = (m_symbols.size()*(1<<settings.m_spreadFactor)*1000.0) / ChirpChatModSettings::bandwidths[settings.m_bandwidthIndex];
if (getMessageQueueToGUI())
{
MsgReportPayloadTime *rpt = MsgReportPayloadTime::create(m_currentPayloadTime, symbols.size());
MsgReportPayloadTime *rpt = MsgReportPayloadTime::create(m_currentPayloadTime, m_symbols.size());
getMessageQueueToGUI()->push(rpt);
}
}
@ -552,6 +587,9 @@ void ChirpChatMod::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("udpPort")) {
settings.m_udpPort = response.getChirpChatModSettings()->getUdpPort();
}
if (channelSettingsKeys.contains("invertRamps")) {
settings.m_invertRamps = response.getChirpChatModSettings()->getInvertRamps();
}
if (channelSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getChirpChatModSettings()->getRgbColor();
}
@ -703,6 +741,7 @@ void ChirpChatMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings&
response.getChirpChatModSettings()->setUdpEnabled(settings.m_udpEnabled);
response.getChirpChatModSettings()->setUdpAddress(new QString(settings.m_udpAddress));
response.getChirpChatModSettings()->setUdpPort(settings.m_udpPort);
response.getChirpChatModSettings()->setInvertRamps(settings.m_invertRamps ? 1 : 0);
response.getChirpChatModSettings()->setRgbColor(settings.m_rgbColor);
@ -935,6 +974,9 @@ void ChirpChatMod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("udpPort") || force) {
swgChirpChatModSettings->setUdpPort(settings.m_udpPort);
}
if (channelSettingsKeys.contains("invertRamps") || force) {
swgChirpChatModSettings->setInvertRamps(settings.m_invertRamps ? 1 : 0);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgChirpChatModSettings->setRgbColor(settings.m_rgbColor);

View File

@ -167,6 +167,7 @@ private:
ChirpChatModEncoder m_encoder; // TODO: check if it needs to be on its own thread
ChirpChatModSettings m_settings;
float m_currentPayloadTime;
std::vector<unsigned short> m_symbols;
SampleVector m_sampleBuffer;
QRecursiveMutex m_settingsMutex;

View File

@ -359,6 +359,12 @@ void ChirpChatModGUI::on_udpPort_editingFinished()
applySettings();
}
void ChirpChatModGUI::on_invertRamps_stateChanged(int state)
{
m_settings.m_invertRamps = (state == Qt::Checked);
applySettings();
}
void ChirpChatModGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
@ -541,6 +547,7 @@ void ChirpChatModGUI::displaySettings()
ui->udpEnabled->setChecked(m_settings.m_udpEnabled);
ui->udpAddress->setText(m_settings.m_udpAddress);
ui->udpPort->setText(QString::number(m_settings.m_udpPort));
ui->invertRamps->setChecked(m_settings.m_invertRamps);
getRollupContents()->restoreState(m_rollupState);
updateAbsoluteCenterFrequency();
blockApplySettings(false);
@ -658,6 +665,7 @@ void ChirpChatModGUI::makeUIConnections()
QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &ChirpChatModGUI::on_udpEnabled_clicked);
QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_udpAddress_editingFinished);
QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_udpPort_editingFinished);
QObject::connect(ui->invertRamps, &QCheckBox::stateChanged, this, &ChirpChatModGUI::on_invertRamps_stateChanged);
}
void ChirpChatModGUI::updateAbsoluteCenterFrequency()

View File

@ -123,6 +123,7 @@ private slots:
void on_udpEnabled_clicked(bool checked);
void on_udpAddress_editingFinished();
void on_udpPort_editingFinished();
void on_invertRamps_stateChanged(int state);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void tick();

View File

@ -215,6 +215,23 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="invertRamps">
<property name="toolTip">
<string>Invert preamble, SFD and payload ramps</string>
</property>
<property name="text">
<string>Inv</string>
</property>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -88,6 +88,7 @@ void ChirpChatModSettings::resetToDefaults()
m_udpEnabled = false;
m_udpAddress = "127.0.0.1";
m_udpPort = 9998;
m_invertRamps = false;
m_rgbColor = QColor(255, 0, 255).rgb();
m_title = "ChirpChat Modulator";
m_streamIndex = 0;
@ -169,11 +170,7 @@ QByteArray ChirpChatModSettings::serialize() const
s.writeU32(9, m_syncWord);
s.writeU32(10, m_preambleChirps);
s.writeS32(11, m_quietMillis);
s.writeBool(12, m_useReverseAPI);
s.writeString(13, m_reverseAPIAddress);
s.writeU32(14, m_reverseAPIPort);
s.writeU32(15, m_reverseAPIDeviceIndex);
s.writeU32(16, m_reverseAPIChannelIndex);
s.writeBool(12, m_invertRamps);
s.writeString(20, m_beaconMessage);
s.writeString(21, m_cqMessage);
s.writeString(22, m_replyMessage);
@ -250,19 +247,7 @@ bool ChirpChatModSettings::deserialize(const QByteArray& data)
d.readU32(10, &m_preambleChirps, 8);
d.readS32(11, &m_quietMillis, 1000);
d.readBool(11, &m_useReverseAPI, false);
d.readString(12, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(13, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_reverseAPIPort = utmp;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(14, &utmp, 0);
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
d.readU32(15, &utmp, 0);
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
d.readBool(12, &m_invertRamps, false);
d.readString(20, &m_beaconMessage, "VVV DE %1 %2");
d.readString(21, &m_cqMessage, "CQ DE %1 %2");
d.readString(22, &m_replyMessage, "%2 %1 %3");
@ -327,3 +312,181 @@ bool ChirpChatModSettings::deserialize(const QByteArray& data)
return false;
}
}
void ChirpChatModSettings::applySettings(const QStringList& settingsKeys, const ChirpChatModSettings& settings)
{
if (settingsKeys.contains("inputFrequencyOffset"))
m_inputFrequencyOffset = settings.m_inputFrequencyOffset;
if (settingsKeys.contains("bandwidthIndex"))
m_bandwidthIndex = settings.m_bandwidthIndex;
if (settingsKeys.contains("spreadFactor"))
m_spreadFactor = settings.m_spreadFactor;
if (settingsKeys.contains("deBits"))
m_deBits = settings.m_deBits;
if (settingsKeys.contains("codingScheme"))
m_codingScheme = settings.m_codingScheme;
if (settingsKeys.contains("preambleChirps"))
m_preambleChirps = settings.m_preambleChirps;
if (settingsKeys.contains("quietMillis"))
m_quietMillis = settings.m_quietMillis;
if (settingsKeys.contains("invertRamps"))
m_invertRamps = settings.m_invertRamps;
if (settingsKeys.contains("syncWord"))
m_syncWord = settings.m_syncWord;
if (settingsKeys.contains("channelMute"))
m_channelMute = settings.m_channelMute;
if (settingsKeys.contains("title"))
m_title = settings.m_title;
if (settingsKeys.contains("udpEnabled"))
m_udpEnabled = settings.m_udpEnabled;
if (settingsKeys.contains("udpAddress"))
m_udpAddress = settings.m_udpAddress;
if (settingsKeys.contains("udpPort"))
m_udpPort = settings.m_udpPort;
if (settingsKeys.contains("streamIndex"))
m_streamIndex = settings.m_streamIndex;
if (settingsKeys.contains("useReverseAPI"))
m_useReverseAPI = settings.m_useReverseAPI;
if (settingsKeys.contains("reverseAPIAddress"))
m_reverseAPIAddress = settings.m_reverseAPIAddress;
if (settingsKeys.contains("reverseAPIPort"))
m_reverseAPIPort = settings.m_reverseAPIPort;
if (settingsKeys.contains("reverseAPIDeviceIndex"))
m_reverseAPIDeviceIndex = settings.m_reverseAPIDeviceIndex;
if (settingsKeys.contains("reverseAPIChannelIndex"))
m_reverseAPIChannelIndex = settings.m_reverseAPIChannelIndex;
if (settingsKeys.contains("workspaceIndex"))
m_workspaceIndex = settings.m_workspaceIndex;
if (settingsKeys.contains("geometryBytes"))
m_geometryBytes = settings.m_geometryBytes;
if (settingsKeys.contains("hidden"))
m_hidden = settings.m_hidden;
if (settingsKeys.contains("channelMarker") && m_channelMarker && settings.m_channelMarker)
m_channelMarker->deserialize(settings.m_channelMarker->serialize());
if (settingsKeys.contains("rollupState") && m_rollupState && settings.m_rollupState)
m_rollupState->deserialize(settings.m_rollupState->serialize());
if (settingsKeys.contains("beaconMessage"))
m_beaconMessage = settings.m_beaconMessage;
if (settingsKeys.contains("cqMessage"))
m_cqMessage = settings.m_cqMessage;
if (settingsKeys.contains("replyMessage"))
m_replyMessage = settings.m_replyMessage;
if (settingsKeys.contains("reportMessage"))
m_reportMessage = settings.m_reportMessage;
if (settingsKeys.contains("replyReportMessage"))
m_replyReportMessage = settings.m_replyReportMessage;
if (settingsKeys.contains("rrrMessage"))
m_rrrMessage = settings.m_rrrMessage;
if (settingsKeys.contains("73Message"))
m_73Message = settings.m_73Message;
if (settingsKeys.contains("qsoTextMessage"))
m_qsoTextMessage = settings.m_qsoTextMessage;
if (settingsKeys.contains("textMessage"))
m_textMessage = settings.m_textMessage;
if (settingsKeys.contains("bytesMessage"))
m_bytesMessage = settings.m_bytesMessage;
if (settingsKeys.contains("messageType"))
m_messageType = settings.m_messageType;
if (settingsKeys.contains("nbParityBits"))
m_nbParityBits = settings.m_nbParityBits;
if (settingsKeys.contains("hasCRC"))
m_hasCRC = settings.m_hasCRC;
if (settingsKeys.contains("hasHeader"))
m_hasHeader = settings.m_hasHeader;
if (settingsKeys.contains("myCall"))
m_myCall = settings.m_myCall;
if (settingsKeys.contains("urCall"))
m_urCall = settings.m_urCall;
if (settingsKeys.contains("myLoc"))
m_myLoc = settings.m_myLoc;
if (settingsKeys.contains("myRpt"))
m_myRpt = settings.m_myRpt;
if (settingsKeys.contains("messageRepeat"))
m_messageRepeat = settings.m_messageRepeat;
}
QString ChirpChatModSettings::getDebugString(const QStringList& settingsKeys, bool force) const
{
QString debug;
if (settingsKeys.contains("inputFrequencyOffset") || force)
debug += QString("Input Frequency Offset: %1\n").arg(m_inputFrequencyOffset);
if (settingsKeys.contains("bandwidthIndex") || force)
debug += QString("Bandwidth Index: %1\n").arg(m_bandwidthIndex);
if (settingsKeys.contains("spreadFactor") || force)
debug += QString("Spread Factor: %1\n").arg(m_spreadFactor);
if (settingsKeys.contains("deBits") || force)
debug += QString("DE Bits: %1\n").arg(m_deBits);
if (settingsKeys.contains("codingScheme") || force)
debug += QString("Coding Scheme: %1\n").arg(m_codingScheme);
if (settingsKeys.contains("preambleChirps") || force)
debug += QString("Preamble Chirps: %1\n").arg(m_preambleChirps);
if (settingsKeys.contains("quietMillis") || force)
debug += QString("Quiet Millis: %1\n").arg(m_quietMillis);
if (settingsKeys.contains("invertRamps") || force)
debug += QString("Invert Ramps: %1\n").arg(m_invertRamps);
if (settingsKeys.contains("syncWord") || force)
debug += QString("Sync Word: %1\n").arg(m_syncWord);
if (settingsKeys.contains("channelMute") || force)
debug += QString("Channel Mute: %1\n").arg(m_channelMute);
if (settingsKeys.contains("title") || force)
debug += QString("Title: %1\n").arg(m_title);
if (settingsKeys.contains("udpEnabled") || force)
debug += QString("UDP Enabled: %1\n").arg(m_udpEnabled);
if (settingsKeys.contains("udpAddress") || force)
debug += QString("UDP Address: %1\n").arg(m_udpAddress);
if (settingsKeys.contains("udpPort") || force)
debug += QString("UDP Port: %1\n").arg(m_udpPort);
if (settingsKeys.contains("streamIndex") || force)
debug += QString("Stream Index: %1\n").arg(m_streamIndex);
if (settingsKeys.contains("useReverseAPI") || force)
debug += QString("Use Reverse API: %1\n").arg(m_useReverseAPI);
if (settingsKeys.contains("reverseAPIAddress") || force)
debug += QString("Reverse API Address: %1\n").arg(m_reverseAPIAddress);
if (settingsKeys.contains("reverseAPIPort") || force)
debug += QString("Reverse API Port: %1\n").arg(m_reverseAPIPort);
if (settingsKeys.contains("reverseAPIDeviceIndex") || force)
debug += QString("Reverse API Device Index: %1\n").arg(m_reverseAPIDeviceIndex);
if (settingsKeys.contains("reverseAPIChannelIndex") || force)
debug += QString("Reverse API Channel Index: %1\n").arg(m_reverseAPIChannelIndex);
if (settingsKeys.contains("workspaceIndex") || force)
debug += QString("Workspace Index: %1\n").arg(m_workspaceIndex);
if (settingsKeys.contains("hidden") || force)
debug += QString("Hidden: %1\n").arg(m_hidden);
if (settingsKeys.contains("beaconMessage") || force)
debug += QString("Beacon Message: %1\n").arg(m_beaconMessage);
if (settingsKeys.contains("cqMessage") || force)
debug += QString("CQ Message: %1\n").arg(m_cqMessage);
if (settingsKeys.contains("replyMessage") || force)
debug += QString("Reply Message: %1\n").arg(m_replyMessage);
if (settingsKeys.contains("reportMessage") || force)
debug += QString("Report Message: %1\n").arg(m_reportMessage);
if (settingsKeys.contains("replyReportMessage") || force)
debug += QString("Reply Report Message: %1\n").arg(m_replyReportMessage);
if (settingsKeys.contains("rrrMessage") || force)
debug += QString("RRR Message: %1\n").arg(m_rrrMessage);
if (settingsKeys.contains("73Message") || force)
debug += QString("73 Message: %1\n").arg(m_73Message);
if (settingsKeys.contains("qsoTextMessage") || force)
debug += QString("QSO Text Message: %1\n").arg(m_qsoTextMessage);
if (settingsKeys.contains("textMessage") || force)
debug += QString("Text Message: %1\n").arg(m_textMessage);
if (settingsKeys.contains("messageType") || force)
debug += QString("Message Type: %1\n").arg(m_messageType);
if (settingsKeys.contains("nbParityBits") || force)
debug += QString("Number of Parity Bits: %1\n").arg(m_nbParityBits);
if (settingsKeys.contains("hasCRC") || force)
debug += QString("Has CRC: %1\n").arg(m_hasCRC);
if (settingsKeys.contains("hasHeader") || force)
debug += QString("Has Header: %1\n").arg(m_hasHeader);
if (settingsKeys.contains("myCall") || force)
debug += QString("My Call: %1\n").arg(m_myCall);
if (settingsKeys.contains("urCall") || force)
debug += QString("UR Call: %1\n").arg(m_urCall);
if (settingsKeys.contains("myLoc") || force)
debug += QString("My Loc: %1\n").arg(m_myLoc);
if (settingsKeys.contains("myRpt") || force)
debug += QString("My Rpt: %1\n").arg(m_myRpt);
if (settingsKeys.contains("messageRepeat") || force)
debug += QString("Message Repeat: %1\n").arg(m_messageRepeat);
return debug;
}

View File

@ -84,6 +84,7 @@ struct ChirpChatModSettings
bool m_udpEnabled;
QString m_udpAddress;
uint16_t m_udpPort;
bool m_invertRamps; //!< Invert chirp ramps vs standard LoRa (up/down/up is standard)
uint32_t m_rgbColor;
QString m_title;
int m_streamIndex;
@ -113,6 +114,8 @@ struct ChirpChatModSettings
void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
void applySettings(const QStringList& settingsKeys, const ChirpChatModSettings& settings);
QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
};

View File

@ -197,7 +197,7 @@ void ChirpChatModSource::modulateSample()
}
else if (m_state == ChirpChatStatePreamble)
{
m_modPhasor += m_phaseIncrements[m_chirp]; // up chirps
m_modPhasor += (m_settings.m_invertRamps ? -1 : 1) * m_phaseIncrements[m_chirp]; // preamble chirps
m_modSample = Complex(std::polar(0.891235351562 * SDR_TX_SCALED, m_modPhasor));
m_fftCounter++;
@ -228,7 +228,7 @@ void ChirpChatModSource::modulateSample()
}
else if (m_state == ChirpChatStateSyncWord)
{
m_modPhasor += m_phaseIncrements[m_chirp]; // up chirps
m_modPhasor += (m_settings.m_invertRamps ? -1 : 1) * m_phaseIncrements[m_chirp]; // sync chirps same orientation as preamble
m_modSample = Complex(std::polar(0.891235351562 * SDR_TX_SCALED, m_modPhasor));
m_fftCounter++;
@ -251,7 +251,7 @@ void ChirpChatModSource::modulateSample()
}
else if (m_state == ChirpChatStateSFD)
{
m_modPhasor -= m_phaseIncrements[m_chirp]; // down chirps
m_modPhasor -= (m_settings.m_invertRamps ? -1 : 1) * m_phaseIncrements[m_chirp]; // SFD chirps
m_modSample = Complex(std::polar(0.891235351562 * SDR_TX_SCALED, m_modPhasor));
m_fftCounter++;
m_sampleCounter++;
@ -280,7 +280,7 @@ void ChirpChatModSource::modulateSample()
}
else if (m_state == ChirpChatStatePayload)
{
m_modPhasor += m_phaseIncrements[m_chirp]; // up chirps
m_modPhasor += (m_settings.m_invertRamps ? -1 : 1) * m_phaseIncrements[m_chirp]; // payload chirps
m_modSample = Complex(std::polar(0.891235351562 * SDR_TX_SCALED, m_modPhasor));
m_fftCounter++;

View File

@ -72,6 +72,12 @@ Thus available bandwidths are:
The ChirpChat signal is oversampled by four therefore it needs a baseband of at least four times the bandwidth. This drives the maximum value on the slider automatically.
<h3>16: Invert chirp ramps</h3>
The LoRa standard is up-chirps for the preamble, down-chirps for the SFD and up-chirps for the payload.
When you check this option it inverts the direction of the chirps thus becoming down-chirps for the preamble, up-chirps for the SFD and down-chirps for the payload.
<h3>5: Spread Factor</h3>
This is the Spread Factor parameter of the ChirpChat signal. This is the log2 of the possible frequency shifts used over the bandwidth (3). The number of symbols is 2<sup>SF-DE</sup> where SF is the spread factor and DE the Distance Enhancement factor (6).
@ -107,7 +113,7 @@ To populate messages you can specify your callsign (10.5), the other party calls
- **LoRa**: LoRa compatible
- **ASCII**: 7 bit plain ASCII without FEC and CRC. Requires exactly 7 bit effective samples thus SF-DE = 7 where SF is the spreading factor (5) and DE the distance enhancement factor (6)
- **TTY**: 5 bit Baudot (Teletype) without FEC and CRC. Requires exactly 5 bit effective samples thus SF-DE = 5 where SF is the spreading factor (5) and DE the distance enhancement factor (6)
- **FT**: FT8/FT4 coding is applied using data in (10.5) to (10.8) to encode the 174 bit message payload with CRC and FEC as per FT8/FT4 protocol using a type 1 (standard) type of message. Note that the report (10.8) must comply with the FT rule (coded "-35" to "+99" with a leading 0 for the number) and would usually represent the integer part of the S/N ratio in the ChirpChat demodulator receiver. Calls should not be prefixed nor suffixed and the first 4 characters of the locator must represent a valid 4 character grid square. Plain text messages (13 characters) are also supported with the 0.0 type of message using the text entered in the message box (11). These 174 bits are packed into (SF - DE) bits symbols padded with zero bits if necessary. For the details of the FT protocol see: https://wsjt.sourceforge.io/FT4_FT8_QEX.pdf
- **FT**: FT8/FT4 coding is applied using data in (10.5) to (10.8) to encode the 174 bit message payload with CRC and FEC as per FT8/FT4 protocol using a type 1 (standard) type of message. Note that the report (10.8) must comply with the FT rule (coded "-35" to "+99" with a leading 0 for the number) and would usually represent the integer part of the S/N ratio in the ChirpChat demodulator receiver. Calls should not be prefixed nor suffixed and the first 4 characters of the locator must represent a valid 4 character grid square. Plain text messages (13 characters) are also supported with the 0.0 type of message using the text entered in the message box (11). These 174 bits are packed into (SF - DE) bits symbols padded with zero bits if necessary. For the details of the FT protocol see: https://wsjt.sourceforge.io/FT4_FT8_QEX.pdf For example for SF=9 and DE=3 we have 6 bits per symbols so the 174 bits are packed in exactly 29 symbols this should appear in the message length ML (13)
<h4>10.2: Number of FEC parity bits (LoRa)</h4>
@ -229,9 +235,9 @@ This window lets you edit the message selected in (10.9). You can use `%n` place
Use this line editor to specify the hex string used as the bytes message.
<h3>13: Symbol time</h3>
<h3>13: Symbol time and message length</h3>
This is the duration of a symbol or chirp in milliseconds
This is the duration of a symbol or chirp in milliseconds followed by the message length in the number of symbols
<h3>14: Payload time</h3>

View File

@ -4457,7 +4457,11 @@ margin-bottom: 20px;
},
"udpPort" : {
"type" : "integer",
"description" : "UDP destination properties"
"description" : "UDP destination port"
},
"invertRamps" : {
"type" : "integer",
"description" : "Invert chirp ramps\n * 0 - Normal chirp ramps (upchirps for preamble and payload)\n * 1 - Inverted chirp ramps (downchirps for preamble and payload)\n"
},
"rgbColor" : {
"type" : "integer"
@ -4657,6 +4661,10 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "UDP port to listen for messages to transmit on"
},
"invertRamps" : {
"type" : "integer",
"description" : "Invert chirp ramps\n * 0 - Normal chirp ramps (upchirps for preamble and payload)\n * 1 - Inverted chirp ramps (downchirps for preamble and payload)\n"
},
"rgbColor" : {
"type" : "integer"
},
@ -59832,7 +59840,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2026-01-10T11:16:10.140+01:00
Generated 2026-01-24T10:44:52.632+01:00
</div>
</div>
</div>

View File

@ -100,8 +100,14 @@ ChirpChatDemodSettings:
description: UDP destination udpAddress
type: string
udpPort:
description: UDP destination properties
description: UDP destination port
type: integer
invertRamps:
type: integer
description: >
Invert chirp ramps
* 0 - Normal chirp ramps (upchirps for preamble and payload)
* 1 - Inverted chirp ramps (downchirps for preamble and payload)
rgbColor:
type: integer
title:

View File

@ -139,6 +139,12 @@ ChirpChatModSettings:
udpPort:
description: UDP port to listen for messages to transmit on
type: integer
invertRamps:
type: integer
description: >
Invert chirp ramps
* 0 - Normal chirp ramps (upchirps for preamble and payload)
* 1 - Inverted chirp ramps (downchirps for preamble and payload)
rgbColor:
type: integer
title:

View File

@ -100,8 +100,14 @@ ChirpChatDemodSettings:
description: UDP destination udpAddress
type: string
udpPort:
description: UDP destination properties
description: UDP destination port
type: integer
invertRamps:
type: integer
description: >
Invert chirp ramps
* 0 - Normal chirp ramps (upchirps for preamble and payload)
* 1 - Inverted chirp ramps (downchirps for preamble and payload)
rgbColor:
type: integer
title:

View File

@ -139,6 +139,12 @@ ChirpChatModSettings:
udpPort:
description: UDP port to listen for messages to transmit on
type: integer
invertRamps:
type: integer
description: >
Invert chirp ramps
* 0 - Normal chirp ramps (upchirps for preamble and payload)
* 1 - Inverted chirp ramps (downchirps for preamble and payload)
rgbColor:
type: integer
title:

View File

@ -4457,7 +4457,11 @@ margin-bottom: 20px;
},
"udpPort" : {
"type" : "integer",
"description" : "UDP destination properties"
"description" : "UDP destination port"
},
"invertRamps" : {
"type" : "integer",
"description" : "Invert chirp ramps\n * 0 - Normal chirp ramps (upchirps for preamble and payload)\n * 1 - Inverted chirp ramps (downchirps for preamble and payload)\n"
},
"rgbColor" : {
"type" : "integer"
@ -4657,6 +4661,10 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "UDP port to listen for messages to transmit on"
},
"invertRamps" : {
"type" : "integer",
"description" : "Invert chirp ramps\n * 0 - Normal chirp ramps (upchirps for preamble and payload)\n * 1 - Inverted chirp ramps (downchirps for preamble and payload)\n"
},
"rgbColor" : {
"type" : "integer"
},
@ -59832,7 +59840,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2026-01-10T11:16:10.140+01:00
Generated 2026-01-24T10:44:52.632+01:00
</div>
</div>
</div>

View File

@ -66,6 +66,8 @@ SWGChirpChatDemodSettings::SWGChirpChatDemodSettings() {
m_udp_address_isSet = false;
udp_port = 0;
m_udp_port_isSet = false;
invert_ramps = 0;
m_invert_ramps_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
title = nullptr;
@ -134,6 +136,8 @@ SWGChirpChatDemodSettings::init() {
m_udp_address_isSet = false;
udp_port = 0;
m_udp_port_isSet = false;
invert_ramps = 0;
m_invert_ramps_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
title = new QString("");
@ -182,6 +186,7 @@ SWGChirpChatDemodSettings::cleanup() {
}
if(title != nullptr) {
delete title;
}
@ -253,6 +258,8 @@ SWGChirpChatDemodSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&udp_port, pJson["udpPort"], "qint32", "");
::SWGSDRangel::setValue(&invert_ramps, pJson["invertRamps"], "qint32", "");
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
@ -348,6 +355,9 @@ SWGChirpChatDemodSettings::asJsonObject() {
if(m_udp_port_isSet){
obj->insert("udpPort", QJsonValue(udp_port));
}
if(m_invert_ramps_isSet){
obj->insert("invertRamps", QJsonValue(invert_ramps));
}
if(m_rgb_color_isSet){
obj->insert("rgbColor", QJsonValue(rgb_color));
}
@ -575,6 +585,16 @@ SWGChirpChatDemodSettings::setUdpPort(qint32 udp_port) {
this->m_udp_port_isSet = true;
}
qint32
SWGChirpChatDemodSettings::getInvertRamps() {
return invert_ramps;
}
void
SWGChirpChatDemodSettings::setInvertRamps(qint32 invert_ramps) {
this->invert_ramps = invert_ramps;
this->m_invert_ramps_isSet = true;
}
qint32
SWGChirpChatDemodSettings::getRgbColor() {
return rgb_color;
@ -747,6 +767,9 @@ SWGChirpChatDemodSettings::isSet(){
if(m_udp_port_isSet){
isObjectUpdated = true; break;
}
if(m_invert_ramps_isSet){
isObjectUpdated = true; break;
}
if(m_rgb_color_isSet){
isObjectUpdated = true; break;
}

View File

@ -102,6 +102,9 @@ public:
qint32 getUdpPort();
void setUdpPort(qint32 udp_port);
qint32 getInvertRamps();
void setInvertRamps(qint32 invert_ramps);
qint32 getRgbColor();
void setRgbColor(qint32 rgb_color);
@ -196,6 +199,9 @@ private:
qint32 udp_port;
bool m_udp_port_isSet;
qint32 invert_ramps;
bool m_invert_ramps_isSet;
qint32 rgb_color;
bool m_rgb_color_isSet;

View File

@ -90,6 +90,8 @@ SWGChirpChatModSettings::SWGChirpChatModSettings() {
m_udp_address_isSet = false;
udp_port = 0;
m_udp_port_isSet = false;
invert_ramps = 0;
m_invert_ramps_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
title = nullptr;
@ -180,6 +182,8 @@ SWGChirpChatModSettings::init() {
m_udp_address_isSet = false;
udp_port = 0;
m_udp_port_isSet = false;
invert_ramps = 0;
m_invert_ramps_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
title = new QString("");
@ -270,6 +274,7 @@ SWGChirpChatModSettings::cleanup() {
}
if(title != nullptr) {
delete title;
}
@ -362,6 +367,8 @@ SWGChirpChatModSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&udp_port, pJson["udpPort"], "qint32", "");
::SWGSDRangel::setValue(&invert_ramps, pJson["invertRamps"], "qint32", "");
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
@ -491,6 +498,9 @@ SWGChirpChatModSettings::asJsonObject() {
if(m_udp_port_isSet){
obj->insert("udpPort", QJsonValue(udp_port));
}
if(m_invert_ramps_isSet){
obj->insert("invertRamps", QJsonValue(invert_ramps));
}
if(m_rgb_color_isSet){
obj->insert("rgbColor", QJsonValue(rgb_color));
}
@ -835,6 +845,16 @@ SWGChirpChatModSettings::setUdpPort(qint32 udp_port) {
this->m_udp_port_isSet = true;
}
qint32
SWGChirpChatModSettings::getInvertRamps() {
return invert_ramps;
}
void
SWGChirpChatModSettings::setInvertRamps(qint32 invert_ramps) {
this->invert_ramps = invert_ramps;
this->m_invert_ramps_isSet = true;
}
qint32
SWGChirpChatModSettings::getRgbColor() {
return rgb_color;
@ -1033,6 +1053,9 @@ SWGChirpChatModSettings::isSet(){
if(m_udp_port_isSet){
isObjectUpdated = true; break;
}
if(m_invert_ramps_isSet){
isObjectUpdated = true; break;
}
if(m_rgb_color_isSet){
isObjectUpdated = true; break;
}

View File

@ -138,6 +138,9 @@ public:
qint32 getUdpPort();
void setUdpPort(qint32 udp_port);
qint32 getInvertRamps();
void setInvertRamps(qint32 invert_ramps);
qint32 getRgbColor();
void setRgbColor(qint32 rgb_color);
@ -265,6 +268,9 @@ private:
qint32 udp_port;
bool m_udp_port_isSet;
qint32 invert_ramps;
bool m_invert_ramps_isSet;
qint32 rgb_color;
bool m_rgb_color_isSet;