| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							| 
									
										
										
										
											2023-11-19 06:43:20 +01:00
										 |  |  | // Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com>                //
 | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 17:17:10 +00:00
										 |  |  | #include <QDebug>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | #include "ais.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISMessage::AISMessage(const QByteArray ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // All AIS messages have these 3 fields in common
 | 
					
						
							|  |  |  |     m_id = (ba[0] & 0xff) >> 2 & 0x3f; | 
					
						
							|  |  |  |     m_repeatIndicator = ba[0] & 0x3; | 
					
						
							|  |  |  |     m_mmsi = ((ba[1] & 0xff) << 22) | ((ba[2] & 0xff) << 14) | ((ba[3] & 0xff) << 6) | ((ba[4] & 0xff) >> 2); | 
					
						
							|  |  |  |     m_bytes = ba; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISMessage::toHex() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_bytes.toHex(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See: https://gpsd.gitlab.io/gpsd/AIVDM.html
 | 
					
						
							| 
									
										
										
										
											2021-05-18 09:02:38 +01:00
										 |  |  | QString AISMessage::toNMEA(const QByteArray bytes) | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     QStringList nmeaSentences; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Max payload is ~61 chars  -> 366 bits
 | 
					
						
							|  |  |  |     int sentences = bytes.size() / 45 + 1; | 
					
						
							|  |  |  |     int sentence = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int bits = 8; | 
					
						
							|  |  |  |     int i = 0; | 
					
						
							|  |  |  |     while (i < bytes.size()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QStringList nmeaSentence; | 
					
						
							|  |  |  |         QStringList nmea; | 
					
						
							|  |  |  |         QStringList payload; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         nmea.append(QString("AIVDM,%1,%2,%3,,").arg(sentences).arg(sentence).arg(sentences > 1 ? "1" : "")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int maxPayload = 80 - 1 - nmea[0].length() - 5; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Encode message data in 6-bit ASCII
 | 
					
						
							|  |  |  |         while ((payload.size() < maxPayload) && (i < bytes.size())) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             int c = 0; | 
					
						
							|  |  |  |             for (int j = 0; j < 6; j++) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-07-17 13:15:17 +01:00
										 |  |  |                 if (i < bytes.size()) { | 
					
						
							|  |  |  |                     c = (c << 1) | ((bytes[i] >> (bits - 1)) & 0x1); | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     c = (c << 1); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |                 bits--; | 
					
						
							|  |  |  |                 if (bits == 0) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     i++; | 
					
						
							|  |  |  |                     bits = 8; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (c >= 40) { | 
					
						
							|  |  |  |                 c += 56; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 c += 48; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             payload.append(QChar(c)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         nmea.append(payload); | 
					
						
							|  |  |  |         nmea.append(QString(",%1").arg((i == bytes.size()) ? (8 - bits) : 0)); // Number of filler bits to ignore
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Calculate checksum
 | 
					
						
							|  |  |  |         QString nmeaProtected = nmea.join(""); | 
					
						
							|  |  |  |         int checksum = AISMessage::nmeaChecksum(nmeaProtected); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Construct complete sentence with leading ! and trailing checksum
 | 
					
						
							|  |  |  |         nmeaSentence.append("!"); | 
					
						
							|  |  |  |         nmeaSentence.append(nmeaProtected); | 
					
						
							|  |  |  |         nmeaSentence.append(QString("*%1").arg(checksum, 2, 16, QChar('0'))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         nmeaSentences.append(nmeaSentence.join("")); | 
					
						
							|  |  |  |         sentence++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-17 13:15:17 +01:00
										 |  |  |     return nmeaSentences.join("\r\n").append("\r\n");   // NMEA-0183 requires CR and LF
 | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISMessage::toNMEA() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return AISMessage::toNMEA(m_bytes); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | qint8 AISMessage::nmeaChecksum(QString string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qint8 checksum = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < string.length(); i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qint8 c = (qint8)string[i].toLatin1(); | 
					
						
							|  |  |  |         checksum ^= c; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return checksum; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Type as in message 5 and 19
 | 
					
						
							|  |  |  | QString AISMessage::typeToString(quint8 type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (type == 0) { | 
					
						
							|  |  |  |         return "N/A"; | 
					
						
							|  |  |  |     } else if ((type >= 100) && (type < 199)) { | 
					
						
							|  |  |  |         return "Preserved for regional use"; | 
					
						
							| 
									
										
										
										
											2021-05-07 22:06:51 +01:00
										 |  |  |     } else if (type >= 200) { | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |         return "Preserved for future use"; | 
					
						
							|  |  |  |     } else if ((type >= 50) && (type <= 59)) { | 
					
						
							|  |  |  |         const QStringList specialCrafts = { | 
					
						
							|  |  |  |             "Pilot vessel", | 
					
						
							|  |  |  |             "Search and rescue vessel", | 
					
						
							|  |  |  |             "Tug", | 
					
						
							|  |  |  |             "Port tender", | 
					
						
							|  |  |  |             "Anti-pollution vessel", | 
					
						
							|  |  |  |             "Law enforcement vessel", | 
					
						
							|  |  |  |             "Spare (56)", | 
					
						
							|  |  |  |             "Spare (57)", | 
					
						
							|  |  |  |             "Medical transport", | 
					
						
							|  |  |  |             "Ships and aircraft of States not parties to an armed conflict" | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         return specialCrafts[type-50]; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         int firstDigit = type / 10; | 
					
						
							|  |  |  |         int secondDigit = type % 10; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const QStringList shipType = { | 
					
						
							|  |  |  |             "0", | 
					
						
							|  |  |  |             "Reserved (1)", | 
					
						
							|  |  |  |             "WIG", | 
					
						
							|  |  |  |             "Vessel", | 
					
						
							|  |  |  |             "HSC", | 
					
						
							|  |  |  |             "5", | 
					
						
							|  |  |  |             "Passenger", | 
					
						
							|  |  |  |             "Cargo", | 
					
						
							|  |  |  |             "Tanker", | 
					
						
							|  |  |  |             "Other" | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         const QStringList activity = { | 
					
						
							|  |  |  |             "Fishing", | 
					
						
							|  |  |  |             "Towing", | 
					
						
							|  |  |  |             "Towing", | 
					
						
							|  |  |  |             "Dredging or underwater operations", | 
					
						
							|  |  |  |             "Diving operations", | 
					
						
							|  |  |  |             "Military operations", | 
					
						
							|  |  |  |             "Sailing", | 
					
						
							|  |  |  |             "Pleasure craft", | 
					
						
							|  |  |  |             "Reserved (8)", | 
					
						
							|  |  |  |             "Reserved (9)" | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (firstDigit == 3) { | 
					
						
							|  |  |  |             return shipType[firstDigit] + " - " + activity[secondDigit]; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return shipType[firstDigit]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISMessage* AISMessage::decode(const QByteArray ba) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-06-20 22:00:15 +01:00
										 |  |  |     if (ba.size() < 1) { | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     int id = (ba[0] >> 2) & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((id == 1) || (id == 2) || (id == 3)) { | 
					
						
							|  |  |  |         return new AISPositionReport(ba); | 
					
						
							|  |  |  |     } else if ((id == 4) || (id == 11)) { | 
					
						
							|  |  |  |         return new AISBaseStationReport(ba); | 
					
						
							|  |  |  |     } else if (id == 5) { | 
					
						
							|  |  |  |         return new AISShipStaticAndVoyageData(ba); | 
					
						
							|  |  |  |     } else if (id == 6) { | 
					
						
							|  |  |  |         return new AISBinaryMessage(ba); | 
					
						
							|  |  |  |     } else if (id == 7) { | 
					
						
							|  |  |  |         return new AISBinaryAck(ba); | 
					
						
							|  |  |  |     } else if (id == 8) { | 
					
						
							|  |  |  |         return new AISBinaryBroadcast(ba); | 
					
						
							|  |  |  |     } else if (id == 9) { | 
					
						
							|  |  |  |         return new AISSARAircraftPositionReport(ba); | 
					
						
							|  |  |  |     } else if (id == 10) { | 
					
						
							|  |  |  |         return new AISUTCInquiry(ba); | 
					
						
							|  |  |  |     } else if (id == 12) { | 
					
						
							|  |  |  |         return new AISSafetyMessage(ba); | 
					
						
							|  |  |  |     } else if (id == 13) { | 
					
						
							|  |  |  |         return new AISSafetyAck(ba); | 
					
						
							|  |  |  |     } else if (id == 14) { | 
					
						
							|  |  |  |         return new AISSafetyBroadcast(ba); | 
					
						
							|  |  |  |     } else if (id == 15) { | 
					
						
							|  |  |  |         return new AISInterrogation(ba); | 
					
						
							|  |  |  |     } else if (id == 16) { | 
					
						
							|  |  |  |         return new AISAssignedModeCommand(ba); | 
					
						
							|  |  |  |     } else if (id == 17) { | 
					
						
							|  |  |  |         return new AISGNSSBroadcast(ba); | 
					
						
							|  |  |  |     } else if (id == 18) { | 
					
						
							|  |  |  |         return new AISStandardClassBPositionReport(ba); | 
					
						
							|  |  |  |     } else if (id == 19) { | 
					
						
							|  |  |  |         return new AISExtendedClassBPositionReport(ba); | 
					
						
							|  |  |  |     } else if (id == 20) { | 
					
						
							|  |  |  |         return new AISDatalinkManagement(ba); | 
					
						
							|  |  |  |     } else if (id == 21) { | 
					
						
							|  |  |  |         return new AISAidsToNavigationReport(ba); | 
					
						
							|  |  |  |     } else if (id == 22) { | 
					
						
							|  |  |  |         return new AISChannelManagement(ba); | 
					
						
							|  |  |  |     } else if (id == 23) { | 
					
						
							|  |  |  |         return new AISGroupAssignment(ba); | 
					
						
							|  |  |  |     } else if (id == 24) { | 
					
						
							|  |  |  |         return new AISStaticDataReport(ba); | 
					
						
							|  |  |  |     } else if (id == 25) { | 
					
						
							|  |  |  |         return new AISSingleSlotBinaryMessage(ba); | 
					
						
							|  |  |  |     } else if (id == 26) { | 
					
						
							|  |  |  |         return new AISMultipleSlotBinaryMessage(ba); | 
					
						
							|  |  |  |     } else if (id == 27) { | 
					
						
							|  |  |  |         return new AISLongRangePositionReport(ba); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return new AISUnknownMessageID(ba); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Extract 6-bit ASCII string
 | 
					
						
							|  |  |  | QString AISMessage::getString(const QByteArray ba, int byteIdx, int bitsLeft, int chars) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QString s; | 
					
						
							|  |  |  |     for (int i = 0; i < chars; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Extract 6-bits
 | 
					
						
							|  |  |  |         int c = 0; | 
					
						
							|  |  |  |         for (int j = 0; j < 6; j++) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             c = (c << 1) | ((ba[byteIdx] >> (bitsLeft - 1)) & 0x1); | 
					
						
							|  |  |  |             bitsLeft--; | 
					
						
							|  |  |  |             if (bitsLeft == 0) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 byteIdx++; | 
					
						
							|  |  |  |                 bitsLeft = 8; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Map from 6-bit to 8-bit ASCII
 | 
					
						
							|  |  |  |         if (c < 32) { | 
					
						
							|  |  |  |             c |= 0x40; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-11-17 14:41:55 +00:00
										 |  |  |         s.append(QChar(c)); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     // Remove leading/trailing spaces
 | 
					
						
							|  |  |  |     s = s.trimmed(); | 
					
						
							|  |  |  |     // Remave @s, which indiciate no character
 | 
					
						
							|  |  |  |     while (s.endsWith("@")) { | 
					
						
							|  |  |  |         s = s.left(s.length() - 1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     while (s.startsWith("@")) { | 
					
						
							|  |  |  |         s = s.mid(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISPositionReport::AISPositionReport(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-05-07 22:06:51 +01:00
										 |  |  |     m_status = ((ba[4] & 0x3) << 2) | ((ba[5] >> 6) & 0x3); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     int rateOfTurn = ((ba[5] << 2) & 0xfc) | ((ba[6] >> 6) & 0x3); | 
					
						
							|  |  |  |     if (rateOfTurn == 127) { | 
					
						
							|  |  |  |         m_rateOfTurn = 720.0f; | 
					
						
							|  |  |  |     } else if (rateOfTurn == -127) { | 
					
						
							|  |  |  |         m_rateOfTurn = -720.0f; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         m_rateOfTurn = (rateOfTurn / 4.733f) * (rateOfTurn / 4.733f); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     m_rateOfTurnAvailable = rateOfTurn != 0x80; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int sog = ((ba[6] & 0x3f) << 4) | ((ba[7] >> 4) & 0xf); | 
					
						
							|  |  |  |     m_speedOverGroundAvailable = sog != 1023; | 
					
						
							|  |  |  |     m_speedOverGround = sog * 0.1f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_positionAccuracy = (ba[7] >> 3) & 0x1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t longitude = ((ba[7] & 0x7) << 25) | ((ba[8] & 0xff) << 17) | ((ba[9] & 0xff) << 9) | ((ba[10] & 0xff) << 1) | ((ba[11] >> 7) & 1); | 
					
						
							|  |  |  |     longitude = (longitude << 4) >> 4; | 
					
						
							|  |  |  |     m_longitudeAvailable = longitude != 0x6791ac0; | 
					
						
							|  |  |  |     m_longitude = longitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t latitude = ((ba[11] & 0x7f) << 20) | ((ba[12] & 0xff) << 12) | ((ba[13] & 0xff) << 4) | ((ba[14] >> 4) & 0x4); | 
					
						
							|  |  |  |     latitude = (latitude << 5) >> 5; | 
					
						
							|  |  |  |     m_latitudeAvailable = latitude != 0x3412140; | 
					
						
							|  |  |  |     m_latitude = latitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int cog = ((ba[14] & 0xf) << 8) | (ba[15] & 0xff); | 
					
						
							|  |  |  |     m_courseAvailable = cog != 3600; | 
					
						
							|  |  |  |     m_course = cog * 0.1f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_heading = ((ba[16] & 0xff) << 1) | ((ba[17] >> 7) & 0x1); | 
					
						
							|  |  |  |     m_headingAvailable = m_heading != 511; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_timeStamp = (ba[17] >> 1) & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_specialManoeuvre = ((ba[17] & 0x1) << 1) | ((ba[18] >> 7) & 0x1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISPositionReport::getStatusString(int status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QStringList statuses = { | 
					
						
							|  |  |  |         "Under way using engine", | 
					
						
							|  |  |  |         "At anchor", | 
					
						
							|  |  |  |         "Not under command", | 
					
						
							|  |  |  |         "Restricted manoeuvrability", | 
					
						
							|  |  |  |         "Constrained by her draught", | 
					
						
							|  |  |  |         "Moored", | 
					
						
							|  |  |  |         "Aground", | 
					
						
							|  |  |  |         "Engaged in fishing", | 
					
						
							|  |  |  |         "Under way sailing", | 
					
						
							|  |  |  |         "Reserved for future amendment of navigational status for ships carrying DG, HS, or MP, or IMO hazard or pollutant category C (HSC)", | 
					
						
							|  |  |  |         "Reserved for future amendment of navigational status for carrying DG, HS or MP, or IMO hazard or pollutant category A (WIG)", | 
					
						
							|  |  |  |         "Reserved for future use", | 
					
						
							|  |  |  |         "Reserved for future use", | 
					
						
							|  |  |  |         "Reserved for future use", | 
					
						
							|  |  |  |         "Reserved for future use", | 
					
						
							|  |  |  |         "Not defined" | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |    return statuses[status]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  | QString AISPositionReport::getType() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_id == 1) { | 
					
						
							|  |  |  |         return "Position report (Scheduled)"; | 
					
						
							|  |  |  |     } else if (m_id == 2) { | 
					
						
							|  |  |  |         return "Position report (Assigned)"; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return "Position report (Interrogated)"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | QString AISPositionReport::toString() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  |     QString speed = m_speedOverGround == 1022 ? ">102.2" : QString::number(m_speedOverGround); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     return QString("Lat: %1%6 Lon: %2%6 Speed: %3 knts Course: %4%6 Status: %5") | 
					
						
							|  |  |  |                 .arg(m_latitude) | 
					
						
							|  |  |  |                 .arg(m_longitude) | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  |                 .arg(speed) | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |                 .arg(m_course) | 
					
						
							|  |  |  |                 .arg(AISPositionReport::getStatusString(m_status)) | 
					
						
							|  |  |  |                 .arg(QChar(0xb0)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISBaseStationReport::AISBaseStationReport(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int year = ((ba[4] & 0x3) << 12) | ((ba[5] & 0xff) << 4) | ((ba[6] >> 4) & 0xf); | 
					
						
							|  |  |  |     int month = ba[6] & 0xf; | 
					
						
							|  |  |  |     int day = ((ba[7] >> 3) & 0x1f); | 
					
						
							|  |  |  |     int hour = ((ba[7] & 0x7) << 2) | ((ba[8] >> 6) & 0x3); | 
					
						
							|  |  |  |     int minute = ba[8] & 0x3f; | 
					
						
							|  |  |  |     int second = (ba[9] >> 2) & 0x3f; | 
					
						
							|  |  |  |     m_utc = QDateTime(QDate(year, month, day), QTime(hour, minute, second), Qt::UTC); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_positionAccuracy = (ba[9] >> 1) & 0x1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t longitude = ((ba[9] & 0x1) << 27) | ((ba[10] & 0xff) << 19) | ((ba[11] & 0xff) << 11) | ((ba[12] & 0xff) << 3) | ((ba[13] >> 5) & 0x7); | 
					
						
							|  |  |  |     longitude = (longitude << 4) >> 4; | 
					
						
							|  |  |  |     m_longitudeAvailable = longitude != 0x6791ac0; | 
					
						
							|  |  |  |     m_longitude = longitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t latitude = ((ba[13] & 0x1f) << 22) | ((ba[14] & 0xff) << 14) | ((ba[15] & 0xff) << 6) | ((ba[16] >> 2) & 0x3f); | 
					
						
							|  |  |  |     latitude = (latitude << 5) >> 5; | 
					
						
							|  |  |  |     m_latitudeAvailable = latitude != 0x3412140; | 
					
						
							|  |  |  |     m_latitude = latitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISBaseStationReport::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QString("Lat: %1%3 Lon: %2%3 %4") | 
					
						
							|  |  |  |                 .arg(m_latitude) | 
					
						
							|  |  |  |                 .arg(m_longitude) | 
					
						
							|  |  |  |                 .arg(QChar(0xb0)) | 
					
						
							|  |  |  |                 .arg(m_utc.toString()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISShipStaticAndVoyageData::AISShipStaticAndVoyageData(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_version = ba[4] & 0x3; | 
					
						
							|  |  |  |     m_imo = ((ba[5] & 0xff) << 22) | ((ba[6] & 0xff) << 14) | ((ba[7] & 0xff) << 6) | ((ba[8] >> 2) & 0x3f); | 
					
						
							|  |  |  |     m_callsign = AISMessage::getString(ba, 8, 2, 7); | 
					
						
							|  |  |  |     m_name = AISMessage::getString(ba, 14, 8, 20); | 
					
						
							|  |  |  |     m_type = ba[29] & 0xff; | 
					
						
							|  |  |  |     m_dimension = ((ba[30] & 0xff) << 22) | ((ba[31] & 0xff) << 14) | ((ba[32] & 0xff) << 6) | ((ba[33] >> 2) & 0x3f); | 
					
						
							| 
									
										
										
										
											2022-02-04 17:17:10 +00:00
										 |  |  |     m_a = (m_dimension >> 21) & 0x1ff; | 
					
						
							|  |  |  |     m_b = (m_dimension >> 12) & 0x1ff; | 
					
						
							|  |  |  |     m_c = (m_dimension >> 6) & 0x3f; | 
					
						
							|  |  |  |     m_d = m_dimension & 0x3f; | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     m_positionFixing = ((ba[33] & 0x3) << 2) | ((ba[34] >> 6) & 0x3); | 
					
						
							|  |  |  |     m_eta = ((ba[34] & 0x3f) << 14) | ((ba[35] & 0xff) << 6) | ((ba[36] >> 2) & 0x3f); | 
					
						
							|  |  |  |     m_draught = ((ba[36] & 0x3) << 6) | ((ba[37] >> 2) & 0x3f); | 
					
						
							|  |  |  |     m_destination = AISMessage::getString(ba, 37, 2, 20); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISShipStaticAndVoyageData::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QString("IMO: %1 Callsign: %2 Name: %3 Type: %4 Destination: %5") | 
					
						
							|  |  |  |                 .arg(m_imo == 0 ? "N/A" : QString::number(m_imo)) | 
					
						
							|  |  |  |                 .arg(m_callsign) | 
					
						
							|  |  |  |                 .arg(m_name) | 
					
						
							|  |  |  |                 .arg(AISMessage::typeToString(m_type)) | 
					
						
							|  |  |  |                 .arg(m_destination); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISBinaryMessage::AISBinaryMessage(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_sequenceNumber = ba[4] & 0x3; | 
					
						
							|  |  |  |     m_destinationId = ((ba[5] & 0xff) << 22) | ((ba[6] & 0xff) << 14) | ((ba[7] & 0xff) << 6) | ((ba[8] >> 2) & 0x3f); | 
					
						
							|  |  |  |     m_retransmitFlag = (ba[8] >> 1) & 0x1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISBinaryMessage::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QString("Seq No: %1 Destination: %2 Retransmit: %3") | 
					
						
							|  |  |  |                 .arg(m_sequenceNumber) | 
					
						
							|  |  |  |                 .arg(m_destinationId) | 
					
						
							|  |  |  |                 .arg(m_retransmitFlag); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISBinaryAck::AISBinaryAck(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISBinaryBroadcast::AISBinaryBroadcast(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISSARAircraftPositionReport::AISSARAircraftPositionReport(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_altitude = ((ba[4] & 0x3) << 10) | ((ba[5] & 0xff) << 2) | ((ba[6] >> 6) & 0x3); | 
					
						
							|  |  |  |     m_altitudeAvailable = m_altitude != 4095; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int sog = ((ba[6] & 0x3f) << 4) | ((ba[7] >> 4) & 0xf); | 
					
						
							|  |  |  |     m_speedOverGroundAvailable = sog != 1023; | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  |     m_speedOverGround = sog; | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     m_positionAccuracy = (ba[7] >> 3) & 0x1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t longitude = ((ba[7] & 0x7) << 25) | ((ba[8] & 0xff) << 17) | ((ba[9] & 0xff) << 9) | ((ba[10] & 0xff) << 1) | ((ba[11] >> 7) & 1); | 
					
						
							|  |  |  |     longitude = (longitude << 4) >> 4; | 
					
						
							|  |  |  |     m_longitudeAvailable = longitude != 0x6791ac0; | 
					
						
							|  |  |  |     m_longitude = longitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t latitude = ((ba[11] & 0x7f) << 20) | ((ba[12] & 0xff) << 12) | ((ba[13] & 0xff) << 4) | ((ba[14] >> 4) & 0x4); | 
					
						
							|  |  |  |     latitude = (latitude << 5) >> 5; | 
					
						
							|  |  |  |     m_latitudeAvailable = latitude != 0x3412140; | 
					
						
							|  |  |  |     m_latitude = latitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int cog = ((ba[14] & 0xf) << 8) | (ba[15] & 0xff); | 
					
						
							|  |  |  |     m_courseAvailable = cog != 3600; | 
					
						
							|  |  |  |     m_course = cog * 0.1f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_timeStamp = (ba[16] >> 2) & 0x3f; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISSARAircraftPositionReport::toString() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  |     QString altitude = m_altitude == 4094 ? ">4094" : QString::number(m_altitude); | 
					
						
							|  |  |  |     QString speed = m_speedOverGround == 1022 ? ">1022" : QString::number(m_speedOverGround); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     return QString("Lat: %1%6 Lon: %2%6 Speed: %3 knts Course: %4%6 Alt: %5 m") | 
					
						
							|  |  |  |                 .arg(m_latitude) | 
					
						
							|  |  |  |                 .arg(m_longitude) | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  |                 .arg(speed) | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |                 .arg(m_course) | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  |                 .arg(altitude) | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |                 .arg(QChar(0xb0)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISUTCInquiry::AISUTCInquiry(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISSafetyMessage::AISSafetyMessage(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_sequenceNumber = ba[4] & 0x3; | 
					
						
							|  |  |  |     m_destinationId = ((ba[5] & 0xff) << 22) | ((ba[6] & 0xff) << 14) | ((ba[7] & 0xff) << 6) | ((ba[8] >> 2) & 0x3f); | 
					
						
							|  |  |  |     m_retransmitFlag = (ba[8] >> 1) & 0x1; | 
					
						
							| 
									
										
										
										
											2024-04-30 09:32:22 +01:00
										 |  |  |     m_safetyRelatedText = AISMessage::getString(ba, 9, 8, (ba.size() - 9) * 8 / 6); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISSafetyMessage::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QString("To %1: Safety message: %2").arg(m_destinationId).arg(m_safetyRelatedText); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISSafetyAck::AISSafetyAck(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISSafetyBroadcast::AISSafetyBroadcast(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-30 09:32:22 +01:00
										 |  |  |     m_safetyRelatedText = AISMessage::getString(ba, 5, 8, (ba.size() - 5) * 8 / 6); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISSafetyBroadcast::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QString("Safety message: %1").arg(m_safetyRelatedText); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISInterrogation::AISInterrogation(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISAssignedModeCommand::AISAssignedModeCommand(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  |     m_destinationIdA = ((ba[5] & 0xff) << 22) | ((ba[6] & 0xff) << 14) | ((ba[7] & 0xff) << 6) | ((ba[8] >> 2) & 0x3f); | 
					
						
							|  |  |  |     m_offsetA = ((ba[8] & 0x3) << 10) | ((ba[9] & 0xff) << 2) | ((ba[10] >> 6) & 0x3); | 
					
						
							|  |  |  |     m_incrementA = ((ba[10] & 0x3f) << 4) | ((ba[11] >> 4) & 0xf); | 
					
						
							|  |  |  |     m_bAvailable = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISAssignedModeCommand::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QString("Dest A: %1 Offset A: %2 Inc A: %3") | 
					
						
							|  |  |  |                 .arg(m_destinationIdA) | 
					
						
							|  |  |  |                 .arg(m_offsetA) | 
					
						
							|  |  |  |                 .arg(m_incrementA); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISGNSSBroadcast::AISGNSSBroadcast(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISStandardClassBPositionReport::AISStandardClassBPositionReport(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int sog = ((ba[5] & 0x3) << 8) | (ba[6] & 0xff); | 
					
						
							|  |  |  |     m_speedOverGroundAvailable = sog != 1023; | 
					
						
							|  |  |  |     m_speedOverGround = sog * 0.1f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_positionAccuracy = (ba[7] >> 7) & 0x1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t longitude = ((ba[7] & 0x7f) << 21) | ((ba[8] & 0xff) << 13) | ((ba[9] & 0xff) << 5) | ((ba[10] >> 3) & 0x1f); | 
					
						
							|  |  |  |     longitude = (longitude << 4) >> 4; | 
					
						
							|  |  |  |     m_longitudeAvailable = longitude != 0x6791ac0; | 
					
						
							|  |  |  |     m_longitude = longitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |     int32_t latitude = ((ba[10] & 0x7) << 24) | ((ba[11] & 0xff) << 16) | ((ba[12] & 0xff) << 8) | (ba[13] & 0xff); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     latitude = (latitude << 5) >> 5; | 
					
						
							|  |  |  |     m_latitudeAvailable = latitude != 0x3412140; | 
					
						
							|  |  |  |     m_latitude = latitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int cog = ((ba[14] & 0xff) << 4) | ((ba[15] >> 4) & 0xf); | 
					
						
							|  |  |  |     m_courseAvailable = cog != 3600; | 
					
						
							|  |  |  |     m_course = cog * 0.1f; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |     m_heading = ((ba[15] & 0xf) << 5) | ((ba[16] >> 3) & 0x1f); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     m_headingAvailable = m_heading != 511; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |     m_timeStamp = ((ba[16] & 0x7) << 3) | ((ba[17] >> 5) & 0x7); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISStandardClassBPositionReport::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QString("Lat: %1%5 Lon: %2%5 Speed: %3 knts Course: %4%5") | 
					
						
							|  |  |  |                 .arg(m_latitude) | 
					
						
							|  |  |  |                 .arg(m_longitude) | 
					
						
							|  |  |  |                 .arg(m_speedOverGround) | 
					
						
							|  |  |  |                 .arg(m_course) | 
					
						
							|  |  |  |                 .arg(QChar(0xb0)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISExtendedClassBPositionReport::AISExtendedClassBPositionReport(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int sog = ((ba[5] & 0x3) << 8) | (ba[6] & 0xff); | 
					
						
							|  |  |  |     m_speedOverGroundAvailable = sog != 1023; | 
					
						
							|  |  |  |     m_speedOverGround = sog * 0.1f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_positionAccuracy = (ba[7] >> 7) & 0x1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t longitude = ((ba[7] & 0x7f) << 21) | ((ba[8] & 0xff) << 13) | ((ba[9] & 0xff) << 5) | ((ba[10] >> 3) & 0x1f); | 
					
						
							|  |  |  |     longitude = (longitude << 4) >> 4; | 
					
						
							|  |  |  |     m_longitudeAvailable = longitude != 0x6791ac0; | 
					
						
							|  |  |  |     m_longitude = longitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |     int32_t latitude = ((ba[10] & 0x7) << 24) | ((ba[11] & 0xff) << 16) | ((ba[12] & 0xff) << 8) | (ba[13] & 0xff); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     latitude = (latitude << 5) >> 5; | 
					
						
							|  |  |  |     m_latitudeAvailable = latitude != 0x3412140; | 
					
						
							|  |  |  |     m_latitude = latitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int cog = ((ba[14] & 0xff) << 4) | ((ba[15] >> 4) & 0xf); | 
					
						
							|  |  |  |     m_courseAvailable = cog != 3600; | 
					
						
							|  |  |  |     m_course = cog * 0.1f; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |     m_heading = ((ba[15] & 0xf) << 5) | ((ba[16] >> 3) & 0x1f); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     m_headingAvailable = m_heading != 511; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |     m_timeStamp = ((ba[16] & 0x7) << 3) | ((ba[17] >> 5) & 0x7); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |     m_name = AISMessage::getString(ba, 17, 1, 20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_type = ((ba[32] & 1) << 7) | ((ba[33] >> 1) & 0x3f); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISExtendedClassBPositionReport::toString() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |     return QString("Lat: %1%5 Lon: %2%5 Speed: %3 knts Course: %4%5 Name: %6 Type: %7") | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |                 .arg(m_latitude) | 
					
						
							|  |  |  |                 .arg(m_longitude) | 
					
						
							|  |  |  |                 .arg(m_speedOverGround) | 
					
						
							|  |  |  |                 .arg(m_course) | 
					
						
							|  |  |  |                 .arg(QChar(0xb0)) | 
					
						
							| 
									
										
										
										
											2021-05-11 10:04:58 +01:00
										 |  |  |                 .arg(m_name) | 
					
						
							|  |  |  |                 .arg(typeToString(m_type)); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISDatalinkManagement::AISDatalinkManagement(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISAidsToNavigationReport::AISAidsToNavigationReport(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_type = ((ba[4] & 0x3) << 3) | ((ba[5] >> 5) & 0x7); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_name = AISMessage::getString(ba, 5, 5, 20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_positionAccuracy = (ba[20] >> 4) & 0x1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t longitude = ((ba[20] & 0xf) << 24) | ((ba[21] & 0xff) << 16) | ((ba[22] & 0xff) << 8) | (ba[23] & 0xff); | 
					
						
							|  |  |  |     longitude = (longitude << 4) >> 4; | 
					
						
							|  |  |  |     m_longitudeAvailable = longitude != 0x6791ac0; | 
					
						
							|  |  |  |     m_longitude = longitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t latitude = ((ba[24] & 0xff) << 19) | ((ba[25] & 0xff) << 11) | ((ba[26] & 0xff) << 3) | ((ba[27] >> 5) & 0x7); | 
					
						
							|  |  |  |     latitude = (latitude << 5) >> 5; | 
					
						
							|  |  |  |     m_latitudeAvailable = latitude != 0x3412140; | 
					
						
							|  |  |  |     m_latitude = latitude / 60.0f / 10000.0f; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISAidsToNavigationReport::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QStringList types = { | 
					
						
							|  |  |  |         "N/A", | 
					
						
							|  |  |  |         "Reference point", | 
					
						
							|  |  |  |         "RACON", | 
					
						
							|  |  |  |         "Fixed structure off short", | 
					
						
							|  |  |  |         "Emergency wreck marking buoy", | 
					
						
							|  |  |  |         "Light, without sectors", | 
					
						
							|  |  |  |         "Light, with sectors", | 
					
						
							|  |  |  |         "Leading light front", | 
					
						
							|  |  |  |         "Leading light rear", | 
					
						
							|  |  |  |         "Beacon, Cardinal N", | 
					
						
							|  |  |  |         "Beacon, Cardinal E", | 
					
						
							|  |  |  |         "Beacon, Cardinal S", | 
					
						
							|  |  |  |         "Beacon, Cardianl W", | 
					
						
							|  |  |  |         "Beacon, Port hand", | 
					
						
							|  |  |  |         "Beacon, Starboard hand", | 
					
						
							|  |  |  |         "Beacon, Preferred channel port hand", | 
					
						
							|  |  |  |         "Beacon, Preferred channel starboard hand", | 
					
						
							|  |  |  |         "Beacon, Isolated danger", | 
					
						
							|  |  |  |         "Beacon, Safe water", | 
					
						
							|  |  |  |         "Beacon, Special mark" | 
					
						
							|  |  |  |         "Cardinal mark N", | 
					
						
							|  |  |  |         "Cardinal mark E", | 
					
						
							|  |  |  |         "Cardinal mark S", | 
					
						
							|  |  |  |         "Cardinal mark W", | 
					
						
							|  |  |  |         "Port hand mark", | 
					
						
							|  |  |  |         "Starboard hand mark", | 
					
						
							|  |  |  |         "Preferred channel port hand", | 
					
						
							|  |  |  |         "Preferred channel starboard hand", | 
					
						
							|  |  |  |         "Isolated danger", | 
					
						
							|  |  |  |         "Safe water", | 
					
						
							|  |  |  |         "Special mark", | 
					
						
							|  |  |  |         "Light vessel/LANBY/Rigs" | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |     return QString("Lat: %1%5 Lon: %2%5 Name: %3 Type: %4") | 
					
						
							|  |  |  |                 .arg(m_latitude) | 
					
						
							|  |  |  |                 .arg(m_longitude) | 
					
						
							|  |  |  |                 .arg(m_name) | 
					
						
							|  |  |  |                 .arg(types[m_type]) | 
					
						
							|  |  |  |                 .arg(QChar(0xb0)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISChannelManagement::AISChannelManagement(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISGroupAssignment::AISGroupAssignment(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISStaticDataReport::AISStaticDataReport(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_partNumber = ba[4] & 0x3; | 
					
						
							|  |  |  |     if (m_partNumber == 0) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-11 10:56:06 +01:00
										 |  |  |         m_name = AISMessage::getString(ba, 5, 8, 20); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     else if (m_partNumber == 1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_type = ba[5] & 0xff; | 
					
						
							| 
									
										
										
										
											2021-05-11 10:56:06 +01:00
										 |  |  |         m_vendorId = AISMessage::getString(ba, 6, 8, 7); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  |         m_callsign = AISMessage::getString(ba, 11, 6, 7); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISStaticDataReport::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_partNumber == 0) { | 
					
						
							|  |  |  |         return QString("Name: %1").arg(m_name); | 
					
						
							|  |  |  |     } else if (m_partNumber == 1) { | 
					
						
							|  |  |  |         return QString("Type: %1 Vendor ID: %2 Callsign: %3").arg(typeToString(m_type)).arg(m_vendorId).arg(m_callsign); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return ""; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISSingleSlotBinaryMessage::AISSingleSlotBinaryMessage(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-16 10:17:17 +01:00
										 |  |  |     m_destinationIndicator = (ba[4] >> 1) & 1; | 
					
						
							|  |  |  |     m_binaryDataFlag = ba[4] & 1; | 
					
						
							|  |  |  |     if (m_destinationIndicator) { | 
					
						
							|  |  |  |         m_destinationId = ((ba[5] & 0xff) << 22) | ((ba[6] & 0xff) << 14) | ((ba[7] & 0xff) << 6) | ((ba[8] >> 2) & 0x3f); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     m_destinationIdAvailable = m_destinationIndicator; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISSingleSlotBinaryMessage::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QStringList s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s.append(QString("Destination: %1").arg(m_destinationIndicator ? "Broadcast" : "Addressed")); | 
					
						
							|  |  |  |     s.append(QString("Flag: %1").arg(m_binaryDataFlag ? "Unstructured" : "Structured")); | 
					
						
							|  |  |  |     if (m_destinationIdAvailable) { | 
					
						
							|  |  |  |         s.append(QString("Destination Id: %1").arg(m_destinationId)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return s.join(" "); | 
					
						
							| 
									
										
										
										
											2021-05-07 21:50:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISMultipleSlotBinaryMessage::AISMultipleSlotBinaryMessage(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISLongRangePositionReport::AISLongRangePositionReport(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_positionAccuracy = (ba[4] >> 1) & 0x1; | 
					
						
							|  |  |  |     m_raim = ba[4] & 0x1; | 
					
						
							|  |  |  |     m_status = (ba[5] >> 4) & 0xf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t longitude = ((ba[5] & 0xf) << 14) | ((ba[6] & 0xff) << 6) | ((ba[7] >> 2) & 0x3f); | 
					
						
							|  |  |  |     longitude = (longitude << 14) >> 14; | 
					
						
							|  |  |  |     m_longitudeAvailable = longitude != 0x1a838; | 
					
						
							|  |  |  |     m_longitude = longitude / 60.0f / 10.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int32_t latitude = ((ba[7] & 0x3) << 15) | ((ba[8] & 0xff) << 7) | ((ba[9] >> 1) & 0x7f); | 
					
						
							|  |  |  |     latitude = (latitude << 15) >> 15; | 
					
						
							|  |  |  |     m_latitudeAvailable = latitude != 0xd548; | 
					
						
							|  |  |  |     m_latitude = latitude / 60.0f / 10.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_speedOverGround = ((ba[9] & 0x1) << 5) | ((ba[10] >> 3) & 0x1f); | 
					
						
							|  |  |  |     m_speedOverGroundAvailable = m_speedOverGround != 63; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_course = ((ba[10] & 0x7) << 6) | ((ba[11] >> 2) & 0x3f); | 
					
						
							|  |  |  |     m_courseAvailable = m_course != 512; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString AISLongRangePositionReport::toString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QString("Lat: %1%6 Lon: %2%6 Speed: %3 knts Course: %4%6 Status: %5") | 
					
						
							|  |  |  |                 .arg(m_latitude) | 
					
						
							|  |  |  |                 .arg(m_longitude) | 
					
						
							|  |  |  |                 .arg(m_speedOverGround) | 
					
						
							|  |  |  |                 .arg(m_course) | 
					
						
							|  |  |  |                 .arg(AISPositionReport::getStatusString(m_status)) | 
					
						
							|  |  |  |                 .arg(QChar(0xb0)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AISUnknownMessageID::AISUnknownMessageID(QByteArray ba) : | 
					
						
							|  |  |  |     AISMessage(ba) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |