From 7db8c3568244faf202b987775be3f984b654ab84 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 18 Apr 2023 10:49:14 +0100 Subject: [PATCH] AIS Demod: Calculate time slot used for messages. --- plugins/channelrx/demodais/aisdemod.cpp | 5 ++-- plugins/channelrx/demodais/aisdemod.h | 11 +++++--- plugins/channelrx/demodais/aisdemodgui.cpp | 16 ++++++++---- plugins/channelrx/demodais/aisdemodgui.h | 5 ++-- plugins/channelrx/demodais/aisdemodgui.ui | 26 ++++++++++++------- plugins/channelrx/demodais/aisdemodsettings.h | 2 +- plugins/channelrx/demodais/aisdemodsink.cpp | 12 ++++++++- plugins/channelrx/demodais/readme.md | 1 + 8 files changed, 54 insertions(+), 24 deletions(-) diff --git a/plugins/channelrx/demodais/aisdemod.cpp b/plugins/channelrx/demodais/aisdemod.cpp index d2fb61529..a165428fe 100644 --- a/plugins/channelrx/demodais/aisdemod.cpp +++ b/plugins/channelrx/demodais/aisdemod.cpp @@ -222,7 +222,8 @@ bool AISDemod::handleMessage(const Message& cmd) << QString("%1").arg(ais->m_mmsi, 9, 10, QChar('0')) << "," << ais->getType() << "," << "\"" << ais->toString() << "\"" << "," - << "\"" << ais->toNMEA() << "\"" << "\n"; + << "\"" << ais->toNMEA() << "\"" << "," + << report.getSlot() << "\n"; delete ais; } @@ -354,7 +355,7 @@ void AISDemod::applySettings(const AISDemodSettings& settings, bool force) if (newFile) { // Write header - m_logStream << "Date,Time,Data,MMSI,Type,Message,NMEA\n"; + m_logStream << "Date,Time,Data,MMSI,Type,Message,NMEA,Slot\n"; } } else diff --git a/plugins/channelrx/demodais/aisdemod.h b/plugins/channelrx/demodais/aisdemod.h index 3fbc1d0fa..ba7bd76bf 100644 --- a/plugins/channelrx/demodais/aisdemod.h +++ b/plugins/channelrx/demodais/aisdemod.h @@ -72,20 +72,23 @@ public: public: QByteArray getMessage() const { return m_message; } QDateTime getDateTime() const { return m_dateTime; } + int getSlot() const { return m_slot; } - static MsgMessage* create(QByteArray message) + static MsgMessage* create(QByteArray message, QDateTime dateTime, int slot) { - return new MsgMessage(message, QDateTime::currentDateTime()); + return new MsgMessage(message, dateTime, slot); } private: QByteArray m_message; QDateTime m_dateTime; + int m_slot; - MsgMessage(QByteArray message, QDateTime dateTime) : + MsgMessage(QByteArray message, QDateTime dateTime, int slot) : Message(), m_message(message), - m_dateTime(dateTime) + m_dateTime(dateTime), + m_slot(slot) { } }; diff --git a/plugins/channelrx/demodais/aisdemodgui.cpp b/plugins/channelrx/demodais/aisdemodgui.cpp index f9516aead..7b60ad873 100644 --- a/plugins/channelrx/demodais/aisdemodgui.cpp +++ b/plugins/channelrx/demodais/aisdemodgui.cpp @@ -68,6 +68,7 @@ void AISDemodGUI::resizeTable() ui->messages->setItem(row, MESSAGE_COL_DATA, new QTableWidgetItem("ABCEDGHIJKLMNOPQRSTUVWXYZ")); ui->messages->setItem(row, MESSAGE_COL_NMEA, new QTableWidgetItem("!AIVDM,1,1,,A,AAAAAAAAAAAAAAAAAAAAAAAAAAAA,0*00")); ui->messages->setItem(row, MESSAGE_COL_HEX, new QTableWidgetItem("04058804002000069a0760728d9e00000040000000")); + ui->messages->setItem(row, MESSAGE_COL_SLOT, new QTableWidgetItem("2450")); ui->messages->resizeColumnsToContents(); ui->messages->removeRow(row); } @@ -154,7 +155,7 @@ bool AISDemodGUI::deserialize(const QByteArray& data) } // Add row to table -void AISDemodGUI::messageReceived(const QByteArray& message, const QDateTime& dateTime) +void AISDemodGUI::messageReceived(const QByteArray& message, const QDateTime& dateTime, int slot) { AISMessage *ais; @@ -177,6 +178,7 @@ void AISDemodGUI::messageReceived(const QByteArray& message, const QDateTime& da QTableWidgetItem *dataItem = new QTableWidgetItem(); QTableWidgetItem *nmeaItem = new QTableWidgetItem(); QTableWidgetItem *hexItem = new QTableWidgetItem(); + QTableWidgetItem *slotItem = new QTableWidgetItem(); ui->messages->setItem(row, MESSAGE_COL_DATE, dateItem); ui->messages->setItem(row, MESSAGE_COL_TIME, timeItem); ui->messages->setItem(row, MESSAGE_COL_MMSI, mmsiItem); @@ -184,6 +186,7 @@ void AISDemodGUI::messageReceived(const QByteArray& message, const QDateTime& da ui->messages->setItem(row, MESSAGE_COL_DATA, dataItem); ui->messages->setItem(row, MESSAGE_COL_NMEA, nmeaItem); ui->messages->setItem(row, MESSAGE_COL_HEX, hexItem); + ui->messages->setItem(row, MESSAGE_COL_SLOT, slotItem); dateItem->setText(dateTime.date().toString()); timeItem->setText(dateTime.time().toString()); mmsiItem->setText(QString("%1").arg(ais->m_mmsi, 9, 10, QChar('0'))); @@ -191,6 +194,7 @@ void AISDemodGUI::messageReceived(const QByteArray& message, const QDateTime& da dataItem->setText(ais->toString()); nmeaItem->setText(ais->toNMEA()); hexItem->setText(ais->toHex()); + slotItem->setData(Qt::DisplayRole, slot); ui->messages->setSortingEnabled(true); if (scrollToBottom) { ui->messages->scrollToBottom(); @@ -217,7 +221,7 @@ bool AISDemodGUI::handleMessage(const Message& message) else if (AISDemod::MsgMessage::match(message)) { AISDemod::MsgMessage& report = (AISDemod::MsgMessage&) message; - messageReceived(report.getMessage(), report.getDateTime()); + messageReceived(report.getMessage(), report.getDateTime(), report.getSlot()); return true; } else if (DSPSignalNotification::match(message)) @@ -702,13 +706,14 @@ void AISDemodGUI::on_logOpen_clicked() { QTextStream in(&file); QString error; - QHash colIndexes = CSV::readHeader(in, {"Date", "Time", "Data"}, error); + QHash colIndexes = CSV::readHeader(in, {"Date", "Time", "Data", "Slot"}, error); if (error.isEmpty()) { int dateCol = colIndexes.value("Date"); int timeCol = colIndexes.value("Time"); int dataCol = colIndexes.value("Data"); - int maxCol = std::max({dateCol, timeCol, dataCol}); + int slotCol = colIndexes.value("Slot"); + int maxCol = std::max({dateCol, timeCol, dataCol, slotCol}); QMessageBox dialog(this); dialog.setText("Reading messages"); @@ -730,9 +735,10 @@ void AISDemodGUI::on_logOpen_clicked() QTime time = QTime::fromString(cols[timeCol]); QDateTime dateTime(date, time); QByteArray bytes = QByteArray::fromHex(cols[dataCol].toLatin1()); + int slot = cols[slotCol].toInt(); // Add to table - messageReceived(bytes, dateTime); + messageReceived(bytes, dateTime, slot); // Forward to AIS feature for (const auto& pipe : aisPipes) diff --git a/plugins/channelrx/demodais/aisdemodgui.h b/plugins/channelrx/demodais/aisdemodgui.h index e644ede36..252fbcf98 100644 --- a/plugins/channelrx/demodais/aisdemodgui.h +++ b/plugins/channelrx/demodais/aisdemodgui.h @@ -98,7 +98,7 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void messageReceived(const QByteArray& message, const QDateTime& dateTime); + void messageReceived(const QByteArray& message, const QDateTime& dateTime, int slot); bool handleMessage(const Message& message); void makeUIConnections(); void updateAbsoluteCenterFrequency(); @@ -116,7 +116,8 @@ private: MESSAGE_COL_TYPE, MESSAGE_COL_DATA, MESSAGE_COL_NMEA, - MESSAGE_COL_HEX + MESSAGE_COL_HEX, + MESSAGE_COL_SLOT }; private slots: diff --git a/plugins/channelrx/demodais/aisdemodgui.ui b/plugins/channelrx/demodais/aisdemodgui.ui index 4fbfb0ab5..b2eced5b8 100644 --- a/plugins/channelrx/demodais/aisdemodgui.ui +++ b/plugins/channelrx/demodais/aisdemodgui.ui @@ -712,6 +712,14 @@ Packet data as hex + + + Slot + + + Time slot + + @@ -917,6 +925,11 @@ + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
RollupContents QWidget @@ -924,9 +937,10 @@ 1 - ButtonSwitch - QToolButton -
gui/buttonswitch.h
+ ValueDialZ + QWidget +
gui/valuedialz.h
+ 1
LevelMeterSignalDB @@ -934,12 +948,6 @@
gui/levelmeter.h
1
- - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 -
GLScope QWidget diff --git a/plugins/channelrx/demodais/aisdemodsettings.h b/plugins/channelrx/demodais/aisdemodsettings.h index 2d22273cc..9e0ca9b86 100644 --- a/plugins/channelrx/demodais/aisdemodsettings.h +++ b/plugins/channelrx/demodais/aisdemodsettings.h @@ -27,7 +27,7 @@ class Serializable; // Number of columns in the tables -#define AISDEMOD_MESSAGE_COLUMNS 7 +#define AISDEMOD_MESSAGE_COLUMNS 8 struct AISDemodSettings { diff --git a/plugins/channelrx/demodais/aisdemodsink.cpp b/plugins/channelrx/demodais/aisdemodsink.cpp index 32716bb08..bd567290e 100644 --- a/plugins/channelrx/demodais/aisdemodsink.cpp +++ b/plugins/channelrx/demodais/aisdemodsink.cpp @@ -181,6 +181,7 @@ void AISDemodSink::processOneSample(Complex &ci) int onesCount = 0; int byteCount = 0; int symbolPrev = 0; + int totalBitCount = 0; // Count of bits after start flag, before bit stuffing removal, including stop flag for (int sampleIdx = 0; sampleIdx < m_rxBufLength; sampleIdx += m_samplesPerSymbol) { // Sum and slice @@ -247,7 +248,14 @@ void AISDemodSink::processOneSample(Complex &ci) //qDebug() << "RX: " << rxPacket.toHex(); if (getMessageQueueToChannel()) { - AISDemod::MsgMessage *msg = AISDemod::MsgMessage::create(rxPacket); + // Calculate slot number based on time of start of transmission + // This is unlikely to be accurate in absolute terms, given we don't know latency from SDR or buffering within SDRangel + // But can be used to get an idea of congestion + QDateTime currentTime = QDateTime::currentDateTime(); + QDateTime startDateTime = currentTime.addMSecs(-(totalBitCount + 8 + 24 + 8) * (1000.0 / m_settings.m_baud)); // Add ramp up, preamble and start-flag + int ms = startDateTime.time().second() * 1000 + startDateTime.time().msec(); + int slot = ms / 26.67; // 2250 slots per minute, 26ms per slot + AISDemod::MsgMessage *msg = AISDemod::MsgMessage::create(rxPacket, currentTime, slot); getMessageQueueToChannel()->push(msg); } @@ -273,6 +281,7 @@ void AISDemodSink::processOneSample(Complex &ci) bits = 0; bitCount = 0; byteCount = 0; + totalBitCount = 0; } } onesCount = 0; @@ -280,6 +289,7 @@ void AISDemodSink::processOneSample(Complex &ci) if (gotSOP) { + totalBitCount++; if (bitCount == 8) { // Could also check count according to message ID as that varies diff --git a/plugins/channelrx/demodais/readme.md b/plugins/channelrx/demodais/readme.md index 010527f98..fba594552 100644 --- a/plugins/channelrx/demodais/readme.md +++ b/plugins/channelrx/demodais/readme.md @@ -95,5 +95,6 @@ The received messages table displays information about each AIS message received * Data - A textual decode of the message displaying the most interesting fields. * NMEA - The message in NMEA format. * Hex - The message in hex format. +* Slot - Time slot (0-2249). Due to SDR to SDRangel latency being unknown, this is likely to have some offset. Right clicking on the table header allows you to select which columns to show. The columns can be reorderd by left clicking and dragging the column header. Right clicking on an item in the table allows you to copy the value to the clipboard.