1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-15 21:01:45 -05:00

Merge pull request #966 from srcejon/pager_charset

Add support for character set mapping in Pager demod
This commit is contained in:
Edouard Griffiths 2021-07-22 08:22:10 +02:00 committed by GitHub
commit 904c1f6add
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 469 additions and 6 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -27,10 +27,13 @@ if(NOT SERVER_MODE)
${demodpager_SOURCES} ${demodpager_SOURCES}
pagerdemodgui.cpp pagerdemodgui.cpp
pagerdemodgui.ui pagerdemodgui.ui
pagerdemodcharsetdialog.cpp
pagerdemodcharsetdialog.ui
) )
set(demodpager_HEADERS set(demodpager_HEADERS
${demodpager_HEADERS} ${demodpager_HEADERS}
pagerdemodgui.h pagerdemodgui.h
pagerdemodcharsetdialog.h
) )
set(TARGET_NAME demodpager) set(TARGET_NAME demodpager)

View File

@ -0,0 +1,118 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021 Jon Beniston, M7RCE //
// //
// 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 <QDebug>
#include "pagerdemodcharsetdialog.h"
PagerDemodCharsetDialog::PagerDemodCharsetDialog(PagerDemodSettings *settings,
QWidget* parent) :
QDialog(parent),
m_settings(settings),
ui(new Ui::PagerDemodCharsetDialog)
{
ui->setupUi(this);
if (settings->m_sevenbit.size() > 0) {
ui->preset->setCurrentIndex(2); // User
}
ui->readingOrder->setCurrentIndex(settings->m_rightToLeft ? 1 : 0);
for (int i = 0; i < settings->m_sevenbit.size(); i++) {
addRow(settings->m_sevenbit[i], settings->m_unicode[i]);
}
connect(ui->table, &QTableWidget::cellChanged, this, &PagerDemodCharsetDialog::on_table_cellChanged);
}
PagerDemodCharsetDialog::~PagerDemodCharsetDialog()
{
delete ui;
}
void PagerDemodCharsetDialog::accept()
{
m_settings->m_sevenbit.clear();
m_settings->m_unicode.clear();
for (int i = 0; i < ui->table->rowCount(); i++)
{
int sevenbit = ui->table->item(i, SEVENBIT_COL)->data(Qt::DisplayRole).toString().toInt(nullptr, 16);
int unicode = ui->table->item(i, UNICODE_COL)->data(Qt::DisplayRole).toString().toInt(nullptr, 16);
m_settings->m_sevenbit.append(sevenbit);
m_settings->m_unicode.append(unicode);
}
m_settings->m_rightToLeft = ui->readingOrder->currentIndex() == 1;
QDialog::accept();
}
void PagerDemodCharsetDialog::on_add_clicked()
{
addRow(0, 0);
}
void PagerDemodCharsetDialog::on_remove_clicked()
{
QModelIndexList indexList = ui->table->selectionModel()->selectedRows();
if (!indexList.isEmpty())
{
int row = indexList.at(0).row();
ui->table->removeRow(row);
}
}
void PagerDemodCharsetDialog::on_preset_currentIndexChanged(int index)
{
ui->table->setRowCount(0);
ui->readingOrder->setCurrentIndex(0);
if (index == 1)
{
// Hebrew
for (int i = 0; i < 22; i++) {
addRow(96 + i, 0x05D0 + i);
}
ui->readingOrder->setCurrentIndex(1);
}
}
void PagerDemodCharsetDialog::addRow(int sevenBit, int unicode)
{
ui->table->setSortingEnabled(false);
ui->table->blockSignals(true);
int row = ui->table->rowCount();
ui->table->setRowCount(row + 1);
QTableWidgetItem *sevenbitItem = new QTableWidgetItem();
QTableWidgetItem *unicodeItem = new QTableWidgetItem();
QTableWidgetItem *glyphItem = new QTableWidgetItem();
ui->table->setItem(row, SEVENBIT_COL, sevenbitItem);
ui->table->setItem(row, UNICODE_COL, unicodeItem);
ui->table->setItem(row, GLYPH_COL, glyphItem);
sevenbitItem->setFlags(Qt::ItemIsEditable | sevenbitItem->flags());
sevenbitItem->setData(Qt::DisplayRole, QString::number(sevenBit, 16));
unicodeItem->setFlags(Qt::ItemIsEditable | unicodeItem->flags());
unicodeItem->setData(Qt::DisplayRole, QString::number(unicode, 16));
glyphItem->setFlags(glyphItem->flags() & ~Qt::ItemIsEditable);
glyphItem->setData(Qt::DisplayRole, QChar(unicode));
ui->table->blockSignals(false);
ui->table->setSortingEnabled(true);
}
void PagerDemodCharsetDialog::on_table_cellChanged(int row, int column)
{
if (column == UNICODE_COL)
{
// Update glyph to match entered unicode code point
int unicode = ui->table->item(row, UNICODE_COL)->data(Qt::DisplayRole).toString().toInt(nullptr, 16);
ui->table->item(row, GLYPH_COL)->setData(Qt::DisplayRole, QChar(unicode));
}
}

View File

@ -0,0 +1,55 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_PAGERDEMODCHARSETDIALOG_H
#define INCLUDE_PAGERDEMODCHARSETDIALOG_H
#include <QHash>
#include <QNetworkRequest>
#include "ui_pagerdemodcharsetdialog.h"
#include "pagerdemodsettings.h"
class PagerDemodCharsetDialog : public QDialog {
Q_OBJECT
public:
explicit PagerDemodCharsetDialog(PagerDemodSettings* settings, QWidget* parent = 0);
~PagerDemodCharsetDialog();
PagerDemodSettings *m_settings;
private slots:
void accept();
void on_add_clicked();
void on_remove_clicked();
void on_preset_currentIndexChanged(int index);
void on_table_cellChanged(int row, int column);
private:
Ui::PagerDemodCharsetDialog* ui;
enum Columns {
SEVENBIT_COL,
UNICODE_COL,
GLYPH_COL
};
void addRow(int sevenBit, int unicode);
};
#endif // INCLUDE_PAGERDEMODCHARSETDIALOG_H

View File

@ -0,0 +1,208 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PagerDemodCharsetDialog</class>
<widget class="QDialog" name="PagerDemodCharsetDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>403</width>
<height>561</height>
</rect>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Set chararcter encoding</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="presetLayout">
<item>
<widget class="QLabel" name="presetLabel">
<property name="text">
<string>Preset</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="preset">
<property name="toolTip">
<string>Select a pre-defined character encoding</string>
</property>
<item>
<property name="text">
<string>Latin</string>
</property>
</item>
<item>
<property name="text">
<string>Hebrew</string>
</property>
</item>
<item>
<property name="text">
<string>User</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="presetlSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="readingOrderLabel">
<property name="text">
<string>Reading Order</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="readingOrder">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Specify the order in which characters should be displayed</string>
</property>
<item>
<property name="text">
<string>Left-to-right</string>
</property>
</item>
<item>
<property name="text">
<string>Right-to-left</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="tableLayout">
<item>
<widget class="QTableWidget" name="table">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<column>
<property name="text">
<string>7-bit</string>
</property>
</column>
<column>
<property name="text">
<string>Unicode</string>
</property>
</column>
<column>
<property name="text">
<string>Glyph</string>
</property>
</column>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="buttonLayout">
<item>
<widget class="QPushButton" name="add">
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remove">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item>
<spacer name="buttonSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PagerDemodCharsetDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PagerDemodCharsetDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -41,6 +41,7 @@
#include "maincore.h" #include "maincore.h"
#include "pagerdemod.h" #include "pagerdemod.h"
#include "pagerdemodcharsetdialog.h"
void PagerDemodGUI::resizeTable() void PagerDemodGUI::resizeTable()
{ {
@ -659,3 +660,12 @@ void PagerDemodGUI::tick()
m_tickCount++; m_tickCount++;
} }
void PagerDemodGUI::on_charset_clicked()
{
PagerDemodCharsetDialog dialog(&m_settings);
if (dialog.exec() == QDialog::Accepted)
{
applySettings();
}
}

View File

@ -105,6 +105,7 @@ private slots:
void on_fmDev_valueChanged(int value); void on_fmDev_valueChanged(int value);
void on_baud_currentIndexChanged(int index); void on_baud_currentIndexChanged(int index);
void on_decode_currentIndexChanged(int index); void on_decode_currentIndexChanged(int index);
void on_charset_clicked();
void on_filterAddress_editingFinished(); void on_filterAddress_editingFinished();
void on_clearTable_clicked(); void on_clearTable_clicked();
void on_udpEnabled_clicked(bool checked); void on_udpEnabled_clicked(bool checked);

View File

@ -465,6 +465,20 @@
</item> </item>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="charset">
<property name="toolTip">
<string>Select character encoding</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/keyboard.png</normaloff>:/keyboard.png</iconset>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer_2"> <spacer name="horizontalSpacer_2">
<property name="orientation"> <property name="orientation">
@ -614,7 +628,7 @@
</spacer> </spacer>
</item> </item>
<item> <item>
<widget class="QPushButton" name="clearTable"> <widget class="QToolButton" name="clearTable">
<property name="toolTip"> <property name="toolTip">
<string>Clear messages from table</string> <string>Clear messages from table</string>
</property> </property>

View File

@ -17,6 +17,7 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include <QColor> #include <QColor>
#include <QDataStream>
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "util/simpleserializer.h" #include "util/simpleserializer.h"
@ -51,6 +52,7 @@ void PagerDemodSettings::resetToDefaults()
m_reverseAPIPort = 8888; m_reverseAPIPort = 8888;
m_reverseAPIDeviceIndex = 0; m_reverseAPIDeviceIndex = 0;
m_reverseAPIChannelIndex = 0; m_reverseAPIChannelIndex = 0;
m_rightToLeft = 0;
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++)
{ {
@ -86,6 +88,9 @@ QByteArray PagerDemodSettings::serialize() const
s.writeU32(19, m_reverseAPIDeviceIndex); s.writeU32(19, m_reverseAPIDeviceIndex);
s.writeU32(20, m_reverseAPIChannelIndex); s.writeU32(20, m_reverseAPIChannelIndex);
s.writeBlob(21, m_scopeGUI->serialize()); s.writeBlob(21, m_scopeGUI->serialize());
s.writeBool(22, m_rightToLeft);
s.writeBlob(23, serializeIntList(m_sevenbit));
s.writeBlob(24, serializeIntList(m_unicode));
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) { for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) {
s.writeS32(100 + i, m_messageColumnIndexes[i]); s.writeS32(100 + i, m_messageColumnIndexes[i]);
@ -112,6 +117,7 @@ bool PagerDemodSettings::deserialize(const QByteArray& data)
QByteArray bytetmp; QByteArray bytetmp;
uint32_t utmp; uint32_t utmp;
QString strtmp; QString strtmp;
QByteArray blob;
d.readS32(1, &m_inputFrequencyOffset, 0); d.readS32(1, &m_inputFrequencyOffset, 0);
d.readFloat(2, &m_rfBandwidth, 20000.0f); d.readFloat(2, &m_rfBandwidth, 20000.0f);
@ -154,6 +160,11 @@ bool PagerDemodSettings::deserialize(const QByteArray& data)
d.readBlob(21, &bytetmp); d.readBlob(21, &bytetmp);
m_scopeGUI->deserialize(bytetmp); m_scopeGUI->deserialize(bytetmp);
} }
d.readBool(22, &m_rightToLeft, false);
d.readBlob(23, &blob);
deserializeIntList(blob, m_sevenbit);
d.readBlob(24, &blob);
deserializeIntList(blob, m_unicode);
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) { for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) {
d.readS32(100 + i, &m_messageColumnIndexes[i], i); d.readS32(100 + i, &m_messageColumnIndexes[i], i);
@ -171,4 +182,18 @@ bool PagerDemodSettings::deserialize(const QByteArray& data)
} }
} }
QByteArray PagerDemodSettings::serializeIntList(const QList<qint32>& ints) const
{
QByteArray data;
QDataStream *stream = new QDataStream(&data, QIODevice::WriteOnly);
(*stream) << ints;
delete stream;
return data;
}
void PagerDemodSettings::deserializeIntList(const QByteArray& data, QList<qint32>& ints)
{
QDataStream *stream = new QDataStream(data);
(*stream) >> ints;
delete stream;
}

View File

@ -60,6 +60,10 @@ struct PagerDemodSettings
uint16_t m_reverseAPIChannelIndex; uint16_t m_reverseAPIChannelIndex;
Serializable *m_scopeGUI; Serializable *m_scopeGUI;
bool m_rightToLeft; //!< Whether characters are right to left or left to right
QList<qint32> m_sevenbit;
QList<qint32> m_unicode;
int m_messageColumnIndexes[PAGERDEMOD_MESSAGE_COLUMNS];//!< How the columns are ordered in the table int m_messageColumnIndexes[PAGERDEMOD_MESSAGE_COLUMNS];//!< How the columns are ordered in the table
int m_messageColumnSizes[PAGERDEMOD_MESSAGE_COLUMNS]; //!< Size of the columns in the table int m_messageColumnSizes[PAGERDEMOD_MESSAGE_COLUMNS]; //!< Size of the columns in the table
@ -71,6 +75,8 @@ struct PagerDemodSettings
void setScopeGUI(Serializable *scopeGUI) { m_scopeGUI = scopeGUI; } void setScopeGUI(Serializable *scopeGUI) { m_scopeGUI = scopeGUI; }
QByteArray serialize() const; QByteArray serialize() const;
bool deserialize(const QByteArray& data); bool deserialize(const QByteArray& data);
QByteArray serializeIntList(const QList<qint32>& ints) const;
void deserializeIntList(const QByteArray& data, QList<qint32>& ints);
}; };
#endif /* INCLUDE_PAGERDEMODSETTINGS_H */ #endif /* INCLUDE_PAGERDEMODSETTINGS_H */

View File

@ -273,6 +273,21 @@ void PagerDemodSink::decodeBatch()
m_numericMessage = m_numericMessage.trimmed(); // Remove trailing spaces m_numericMessage = m_numericMessage.trimmed(); // Remove trailing spaces
if (getMessageQueueToChannel()) if (getMessageQueueToChannel())
{ {
// Convert from 7-bit to UTF-8 using user specified encoding
for (int i = 0; i < m_alphaMessage; i++)
{
QChar c = m_alphaMessage[i];
int idx = m_settings.m_sevenbit.indexOf(c.toLatin1());
if (idx >= 0) {
c = m_settings.m_unicode[idx];
}
m_alphaMessage[i] = c;
}
// Reverse reading order, if required
if (m_settings.m_rightToLeft) {
std::reverse(m_alphaMessage.begin(), m_alphaMessage.end());
}
// Send to channel and GUI
PagerDemod::MsgPagerMessage *msg = PagerDemod::MsgPagerMessage::create(m_address, m_functionBits, m_alphaMessage, m_numericMessage, m_parityErrors, m_bchErrors); PagerDemod::MsgPagerMessage *msg = PagerDemod::MsgPagerMessage::create(m_address, m_functionBits, m_alphaMessage, m_numericMessage, m_parityErrors, m_bchErrors);
getMessageQueueToChannel()->push(msg); getMessageQueueToChannel()->push(msg);
} }

View File

@ -54,25 +54,33 @@ Specifies how messages are decoded in the Message column in the table:
The table has Numeric and Alphanumeric columns which always display the corresponding decode. The table has Numeric and Alphanumeric columns which always display the corresponding decode.
<h3>9: Find</h3> <h3>9: Character encoding</h3>
Click to open the character encoding dialog, which allows a mapping from the received 7-bit alphanumeric characters to Unicode.
![Character encoding dialog](../../../doc/img/PagerDemod_plugin_charset.png)
Each row contains a mapping from a 7-bit value to a Unicode code point. Values should be entered in hexideicmal
<h3>10: Find</h3>
Entering a regular expression in the Find field displays only messages where the address matches the given regular expression. Entering a regular expression in the Find field displays only messages where the address matches the given regular expression.
<h3>10: Clear Messages from table</h3> <h3>11: Clear Messages from table</h3>
Pressing this button clears all messages from the table. Pressing this button clears all messages from the table.
<h3>11: UDP</h3> <h3>12: UDP</h3>
When checked, received messages are forwarded to the specified UDP address (12) and port (13). When checked, received messages are forwarded to the specified UDP address (12) and port (13).
The messages are forwarded as null terminated ASCII strings, in the format: data time address function alpha numeric The messages are forwarded as null terminated ASCII strings, in the format: data time address function alpha numeric
<h3>12: UDP address</h3> <h3>13: UDP address</h3>
IP address of the host to forward received messages to via UDP. IP address of the host to forward received messages to via UDP.
<h3>13: UDP port</h3> <h3>14: UDP port</h3>
UDP port number to forward received messages to. UDP port number to forward received messages to.