Merge pull request #1664 from srcejon/ais_slot

AIS Demod: Calculate time slot used for messages.
This commit is contained in:
Edouard Griffiths 2023-04-18 16:45:24 +02:00 committed by GitHub
commit c09f404d27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 54 additions and 24 deletions

View File

@ -222,7 +222,8 @@ bool AISDemod::handleMessage(const Message& cmd)
<< QString("%1").arg(ais->m_mmsi, 9, 10, QChar('0')) << "," << QString("%1").arg(ais->m_mmsi, 9, 10, QChar('0')) << ","
<< ais->getType() << "," << ais->getType() << ","
<< "\"" << ais->toString() << "\"" << "," << "\"" << ais->toString() << "\"" << ","
<< "\"" << ais->toNMEA() << "\"" << "\n"; << "\"" << ais->toNMEA() << "\"" << ","
<< report.getSlot() << "\n";
delete ais; delete ais;
} }
@ -354,7 +355,7 @@ void AISDemod::applySettings(const AISDemodSettings& settings, bool force)
if (newFile) if (newFile)
{ {
// Write header // Write header
m_logStream << "Date,Time,Data,MMSI,Type,Message,NMEA\n"; m_logStream << "Date,Time,Data,MMSI,Type,Message,NMEA,Slot\n";
} }
} }
else else

View File

@ -72,20 +72,23 @@ public:
public: public:
QByteArray getMessage() const { return m_message; } QByteArray getMessage() const { return m_message; }
QDateTime getDateTime() const { return m_dateTime; } 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: private:
QByteArray m_message; QByteArray m_message;
QDateTime m_dateTime; QDateTime m_dateTime;
int m_slot;
MsgMessage(QByteArray message, QDateTime dateTime) : MsgMessage(QByteArray message, QDateTime dateTime, int slot) :
Message(), Message(),
m_message(message), m_message(message),
m_dateTime(dateTime) m_dateTime(dateTime),
m_slot(slot)
{ {
} }
}; };

View File

@ -68,6 +68,7 @@ void AISDemodGUI::resizeTable()
ui->messages->setItem(row, MESSAGE_COL_DATA, new QTableWidgetItem("ABCEDGHIJKLMNOPQRSTUVWXYZ")); 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_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_HEX, new QTableWidgetItem("04058804002000069a0760728d9e00000040000000"));
ui->messages->setItem(row, MESSAGE_COL_SLOT, new QTableWidgetItem("2450"));
ui->messages->resizeColumnsToContents(); ui->messages->resizeColumnsToContents();
ui->messages->removeRow(row); ui->messages->removeRow(row);
} }
@ -154,7 +155,7 @@ bool AISDemodGUI::deserialize(const QByteArray& data)
} }
// Add row to table // 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; AISMessage *ais;
@ -177,6 +178,7 @@ void AISDemodGUI::messageReceived(const QByteArray& message, const QDateTime& da
QTableWidgetItem *dataItem = new QTableWidgetItem(); QTableWidgetItem *dataItem = new QTableWidgetItem();
QTableWidgetItem *nmeaItem = new QTableWidgetItem(); QTableWidgetItem *nmeaItem = new QTableWidgetItem();
QTableWidgetItem *hexItem = new QTableWidgetItem(); QTableWidgetItem *hexItem = new QTableWidgetItem();
QTableWidgetItem *slotItem = new QTableWidgetItem();
ui->messages->setItem(row, MESSAGE_COL_DATE, dateItem); ui->messages->setItem(row, MESSAGE_COL_DATE, dateItem);
ui->messages->setItem(row, MESSAGE_COL_TIME, timeItem); ui->messages->setItem(row, MESSAGE_COL_TIME, timeItem);
ui->messages->setItem(row, MESSAGE_COL_MMSI, mmsiItem); 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_DATA, dataItem);
ui->messages->setItem(row, MESSAGE_COL_NMEA, nmeaItem); ui->messages->setItem(row, MESSAGE_COL_NMEA, nmeaItem);
ui->messages->setItem(row, MESSAGE_COL_HEX, hexItem); ui->messages->setItem(row, MESSAGE_COL_HEX, hexItem);
ui->messages->setItem(row, MESSAGE_COL_SLOT, slotItem);
dateItem->setText(dateTime.date().toString()); dateItem->setText(dateTime.date().toString());
timeItem->setText(dateTime.time().toString()); timeItem->setText(dateTime.time().toString());
mmsiItem->setText(QString("%1").arg(ais->m_mmsi, 9, 10, QChar('0'))); 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()); dataItem->setText(ais->toString());
nmeaItem->setText(ais->toNMEA()); nmeaItem->setText(ais->toNMEA());
hexItem->setText(ais->toHex()); hexItem->setText(ais->toHex());
slotItem->setData(Qt::DisplayRole, slot);
ui->messages->setSortingEnabled(true); ui->messages->setSortingEnabled(true);
if (scrollToBottom) { if (scrollToBottom) {
ui->messages->scrollToBottom(); ui->messages->scrollToBottom();
@ -217,7 +221,7 @@ bool AISDemodGUI::handleMessage(const Message& message)
else if (AISDemod::MsgMessage::match(message)) else if (AISDemod::MsgMessage::match(message))
{ {
AISDemod::MsgMessage& report = (AISDemod::MsgMessage&) message; AISDemod::MsgMessage& report = (AISDemod::MsgMessage&) message;
messageReceived(report.getMessage(), report.getDateTime()); messageReceived(report.getMessage(), report.getDateTime(), report.getSlot());
return true; return true;
} }
else if (DSPSignalNotification::match(message)) else if (DSPSignalNotification::match(message))
@ -702,13 +706,14 @@ void AISDemodGUI::on_logOpen_clicked()
{ {
QTextStream in(&file); QTextStream in(&file);
QString error; QString error;
QHash<QString, int> colIndexes = CSV::readHeader(in, {"Date", "Time", "Data"}, error); QHash<QString, int> colIndexes = CSV::readHeader(in, {"Date", "Time", "Data", "Slot"}, error);
if (error.isEmpty()) if (error.isEmpty())
{ {
int dateCol = colIndexes.value("Date"); int dateCol = colIndexes.value("Date");
int timeCol = colIndexes.value("Time"); int timeCol = colIndexes.value("Time");
int dataCol = colIndexes.value("Data"); 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); QMessageBox dialog(this);
dialog.setText("Reading messages"); dialog.setText("Reading messages");
@ -730,9 +735,10 @@ void AISDemodGUI::on_logOpen_clicked()
QTime time = QTime::fromString(cols[timeCol]); QTime time = QTime::fromString(cols[timeCol]);
QDateTime dateTime(date, time); QDateTime dateTime(date, time);
QByteArray bytes = QByteArray::fromHex(cols[dataCol].toLatin1()); QByteArray bytes = QByteArray::fromHex(cols[dataCol].toLatin1());
int slot = cols[slotCol].toInt();
// Add to table // Add to table
messageReceived(bytes, dateTime); messageReceived(bytes, dateTime, slot);
// Forward to AIS feature // Forward to AIS feature
for (const auto& pipe : aisPipes) for (const auto& pipe : aisPipes)

View File

@ -98,7 +98,7 @@ private:
void blockApplySettings(bool block); void blockApplySettings(bool block);
void applySettings(bool force = false); void applySettings(bool force = false);
void displaySettings(); 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); bool handleMessage(const Message& message);
void makeUIConnections(); void makeUIConnections();
void updateAbsoluteCenterFrequency(); void updateAbsoluteCenterFrequency();
@ -116,7 +116,8 @@ private:
MESSAGE_COL_TYPE, MESSAGE_COL_TYPE,
MESSAGE_COL_DATA, MESSAGE_COL_DATA,
MESSAGE_COL_NMEA, MESSAGE_COL_NMEA,
MESSAGE_COL_HEX MESSAGE_COL_HEX,
MESSAGE_COL_SLOT
}; };
private slots: private slots:

View File

@ -712,6 +712,14 @@
<string>Packet data as hex</string> <string>Packet data as hex</string>
</property> </property>
</column> </column>
<column>
<property name="text">
<string>Slot</string>
</property>
<property name="toolTip">
<string>Time slot</string>
</property>
</column>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -917,6 +925,11 @@
</widget> </widget>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget> <customwidget>
<class>RollupContents</class> <class>RollupContents</class>
<extends>QWidget</extends> <extends>QWidget</extends>
@ -924,9 +937,10 @@
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget> <customwidget>
<class>ButtonSwitch</class> <class>ValueDialZ</class>
<extends>QToolButton</extends> <extends>QWidget</extends>
<header>gui/buttonswitch.h</header> <header>gui/valuedialz.h</header>
<container>1</container>
</customwidget> </customwidget>
<customwidget> <customwidget>
<class>LevelMeterSignalDB</class> <class>LevelMeterSignalDB</class>
@ -934,12 +948,6 @@
<header>gui/levelmeter.h</header> <header>gui/levelmeter.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>ValueDialZ</class>
<extends>QWidget</extends>
<header>gui/valuedialz.h</header>
<container>1</container>
</customwidget>
<customwidget> <customwidget>
<class>GLScope</class> <class>GLScope</class>
<extends>QWidget</extends> <extends>QWidget</extends>

View File

@ -27,7 +27,7 @@
class Serializable; class Serializable;
// Number of columns in the tables // Number of columns in the tables
#define AISDEMOD_MESSAGE_COLUMNS 7 #define AISDEMOD_MESSAGE_COLUMNS 8
struct AISDemodSettings struct AISDemodSettings
{ {

View File

@ -181,6 +181,7 @@ void AISDemodSink::processOneSample(Complex &ci)
int onesCount = 0; int onesCount = 0;
int byteCount = 0; int byteCount = 0;
int symbolPrev = 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) for (int sampleIdx = 0; sampleIdx < m_rxBufLength; sampleIdx += m_samplesPerSymbol)
{ {
// Sum and slice // Sum and slice
@ -247,7 +248,14 @@ void AISDemodSink::processOneSample(Complex &ci)
//qDebug() << "RX: " << rxPacket.toHex(); //qDebug() << "RX: " << rxPacket.toHex();
if (getMessageQueueToChannel()) 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); getMessageQueueToChannel()->push(msg);
} }
@ -273,6 +281,7 @@ void AISDemodSink::processOneSample(Complex &ci)
bits = 0; bits = 0;
bitCount = 0; bitCount = 0;
byteCount = 0; byteCount = 0;
totalBitCount = 0;
} }
} }
onesCount = 0; onesCount = 0;
@ -280,6 +289,7 @@ void AISDemodSink::processOneSample(Complex &ci)
if (gotSOP) if (gotSOP)
{ {
totalBitCount++;
if (bitCount == 8) if (bitCount == 8)
{ {
// Could also check count according to message ID as that varies // Could also check count according to message ID as that varies

View File

@ -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. * Data - A textual decode of the message displaying the most interesting fields.
* NMEA - The message in NMEA format. * NMEA - The message in NMEA format.
* Hex - The message in hex 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. 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.