| 
									
										
										
										
											2023-05-15 16:40:43 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							| 
									
										
										
										
											2023-11-19 06:43:20 +01:00
										 |  |  | // Copyright (C) 2023 Jon Beniston, M7RCE <jon@beniston.com>                     //
 | 
					
						
							| 
									
										
										
										
											2023-05-15 16:40:43 +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/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef INCLUDE_UTIL_DSC_H
 | 
					
						
							|  |  |  | #define INCLUDE_UTIL_DSC_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "export.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QByteArray>
 | 
					
						
							|  |  |  | #include <QString>
 | 
					
						
							|  |  |  | #include <QDateTime>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Digital Select Calling
 | 
					
						
							|  |  |  | // https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.493-15-201901-I!!PDF-E.pdf
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SDRBASE_API DSCDecoder { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void init(int offset); | 
					
						
							|  |  |  |     bool decodeBits(int bits); | 
					
						
							|  |  |  |     QByteArray getMessage() const { return m_bytes; } | 
					
						
							|  |  |  |     int getErrors() const { return m_errors; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static int m_maxBytes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static const int BUFFER_SIZE = 3; | 
					
						
							|  |  |  |     signed char m_buf[3]; | 
					
						
							|  |  |  |     enum State { | 
					
						
							|  |  |  |         PHASING, | 
					
						
							|  |  |  |         FILL_DX, | 
					
						
							|  |  |  |         FILL_RX, | 
					
						
							|  |  |  |         DX, | 
					
						
							|  |  |  |         RX, | 
					
						
							|  |  |  |         DX_EOS, | 
					
						
							|  |  |  |         RX_EOS, | 
					
						
							|  |  |  |         DONE, | 
					
						
							|  |  |  |         NO_EOS | 
					
						
							|  |  |  |     } m_state; | 
					
						
							|  |  |  |     int m_idx; | 
					
						
							|  |  |  |     int m_errors; | 
					
						
							|  |  |  |     int m_phaseIdx; | 
					
						
							|  |  |  |     bool m_eos; | 
					
						
							|  |  |  |     static const signed char m_expectedSymbols[]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QByteArray m_bytes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool decodeSymbol(signed char symbol); | 
					
						
							|  |  |  |     static signed char bitsToSymbol(unsigned int bits); | 
					
						
							|  |  |  |     static unsigned char reverse(unsigned char b); | 
					
						
							|  |  |  |     signed char selectSymbol(signed char dx, signed char rx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SDRBASE_API DSCMessage { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum FormatSpecifier { | 
					
						
							|  |  |  |         GEOGRAPHIC_CALL = 102, | 
					
						
							|  |  |  |         DISTRESS_ALERT = 112, | 
					
						
							|  |  |  |         GROUP_CALL = 114, | 
					
						
							|  |  |  |         ALL_SHIPS = 116, | 
					
						
							|  |  |  |         SELECTIVE_CALL = 120, | 
					
						
							|  |  |  |         AUTOMATIC_CALL = 123 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum Category { | 
					
						
							|  |  |  |         ROUTINE = 100, | 
					
						
							|  |  |  |         SAFETY = 108, | 
					
						
							|  |  |  |         URGENCY = 110, | 
					
						
							|  |  |  |         DISTRESS = 112 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum FirstTelecommand { | 
					
						
							|  |  |  |         F3E_G3E_ALL_MODES_TP = 100, | 
					
						
							|  |  |  |         F3E_G3E_DUPLEX_TP = 101, | 
					
						
							|  |  |  |         POLLING = 103, | 
					
						
							|  |  |  |         UNABLE_TO_COMPLY = 104, | 
					
						
							|  |  |  |         END_OF_CALL = 105, | 
					
						
							|  |  |  |         DATA = 106, | 
					
						
							|  |  |  |         J3E_TP = 109, | 
					
						
							|  |  |  |         DISTRESS_ACKNOWLEDGEMENT = 110, | 
					
						
							|  |  |  |         DISTRESS_ALERT_RELAY = 112, | 
					
						
							|  |  |  |         F1B_J2B_TTY_FEC = 113, | 
					
						
							|  |  |  |         F1B_J2B_TTY_AQR = 115, | 
					
						
							|  |  |  |         TEST = 118, | 
					
						
							|  |  |  |         POSITION_UPDATE = 121, | 
					
						
							|  |  |  |         NO_INFORMATION = 126 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum SecondTelecommand { | 
					
						
							|  |  |  |         NO_REASON = 100, | 
					
						
							|  |  |  |         CONGESTION = 101, | 
					
						
							|  |  |  |         BUSY = 102, | 
					
						
							|  |  |  |         QUEUE = 103, | 
					
						
							|  |  |  |         BARRED = 104, | 
					
						
							|  |  |  |         NO_OPERATOR = 105, | 
					
						
							|  |  |  |         OPERATOR_UNAVAILABLE = 106, | 
					
						
							|  |  |  |         EQUIPMENT_DISABLED = 107, | 
					
						
							|  |  |  |         UNABLE_TO_USE_CHANNEL = 108, | 
					
						
							|  |  |  |         UNABLE_TO_USE_MODE = 109, | 
					
						
							|  |  |  |         NOT_PARTIES_TO_CONFLICT = 110, | 
					
						
							|  |  |  |         MEDICAL_TRANSPORTS = 111, | 
					
						
							|  |  |  |         PAY_PHONE = 112, | 
					
						
							|  |  |  |         FAX = 113, | 
					
						
							|  |  |  |         NO_INFORMATION_2 = 126 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum DistressNature { | 
					
						
							|  |  |  |         FIRE = 100, | 
					
						
							|  |  |  |         FLOODING = 101, | 
					
						
							|  |  |  |         COLLISION = 102, | 
					
						
							|  |  |  |         GROUNDING = 103, | 
					
						
							|  |  |  |         LISTING = 104, | 
					
						
							|  |  |  |         SINKING = 105, | 
					
						
							|  |  |  |         ADRIFT = 106, | 
					
						
							|  |  |  |         UNDESIGNATED = 107, | 
					
						
							|  |  |  |         ABANDONING_SHIP = 108, | 
					
						
							|  |  |  |         PIRACY = 109, | 
					
						
							|  |  |  |         MAN_OVERBOARD = 110, | 
					
						
							|  |  |  |         EPIRB = 112 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum EndOfSignal { | 
					
						
							|  |  |  |         REQ = 117, | 
					
						
							|  |  |  |         ACK = 122, | 
					
						
							|  |  |  |         EOS = 127 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static QMap<FormatSpecifier, QString> m_formatSpecifierStrings; | 
					
						
							|  |  |  |     static QMap<FormatSpecifier, QString> m_formatSpecifierShortStrings; | 
					
						
							|  |  |  |     static QMap<Category, QString> m_categoryStrings; | 
					
						
							|  |  |  |     static QMap<Category, QString> m_categoryShortStrings; | 
					
						
							|  |  |  |     static QMap<FirstTelecommand, QString> m_telecommand1Strings; | 
					
						
							|  |  |  |     static QMap<FirstTelecommand, QString> m_telecommand1ShortStrings; | 
					
						
							|  |  |  |     static QMap<SecondTelecommand, QString> m_telecommand2Strings; | 
					
						
							|  |  |  |     static QMap<SecondTelecommand, QString> m_telecommand2ShortStrings; | 
					
						
							|  |  |  |     static QMap<DistressNature, QString> m_distressNatureStrings; | 
					
						
							|  |  |  |     static QMap<EndOfSignal, QString> m_endOfSignalStrings; | 
					
						
							|  |  |  |     static QMap<EndOfSignal, QString> m_endOfSignalShortStrings; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FormatSpecifier m_formatSpecifier; | 
					
						
							|  |  |  |     bool m_formatSpecifierMatch; | 
					
						
							|  |  |  |     QString m_address; | 
					
						
							|  |  |  |     bool m_hasAddress; | 
					
						
							|  |  |  |     int m_addressLatitude;      // For GEOGRAPHIC_CALL
 | 
					
						
							|  |  |  |     int m_addressLongitude; | 
					
						
							|  |  |  |     int m_addressLatAngle; | 
					
						
							|  |  |  |     int m_addressLonAngle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Category m_category; | 
					
						
							|  |  |  |     bool m_hasCategory; | 
					
						
							|  |  |  |     QString m_selfId; | 
					
						
							|  |  |  |     FirstTelecommand m_telecommand1; | 
					
						
							|  |  |  |     bool m_hasTelecommand1; | 
					
						
							|  |  |  |     SecondTelecommand m_telecommand2; | 
					
						
							|  |  |  |     bool m_hasTelecommand2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString m_distressId; | 
					
						
							|  |  |  |     bool m_hasDistressId; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DistressNature m_distressNature; | 
					
						
							|  |  |  |     bool m_hasDistressNature; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString m_position; | 
					
						
							|  |  |  |     bool m_hasPosition; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int m_frequency1;  // Rx
 | 
					
						
							|  |  |  |     bool m_hasFrequency1; | 
					
						
							|  |  |  |     QString m_channel1; | 
					
						
							|  |  |  |     bool m_hasChannel1; | 
					
						
							|  |  |  |     int m_frequency2;   // Tx
 | 
					
						
							|  |  |  |     bool m_hasFrequency2; | 
					
						
							|  |  |  |     QString m_channel2; | 
					
						
							|  |  |  |     bool m_hasChannel2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString m_number; // Phone number
 | 
					
						
							|  |  |  |     bool m_hasNumber; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTime m_time; | 
					
						
							|  |  |  |     bool m_hasTime; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FirstTelecommand m_subsequenceComms; | 
					
						
							|  |  |  |     bool m_hasSubsequenceComms; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EndOfSignal m_eos; | 
					
						
							|  |  |  |     signed char m_ecc; // Error checking code (parity)
 | 
					
						
							|  |  |  |     signed char m_calculatedECC; | 
					
						
							|  |  |  |     bool m_eccOk; | 
					
						
							|  |  |  |     bool m_valid; // Data is within defined values
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QDateTime m_dateTime; // Date/time when received
 | 
					
						
							|  |  |  |     QByteArray m_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DSCMessage(const QByteArray& data, QDateTime dateTime); | 
					
						
							|  |  |  |     QString toString(const QString separator = " ") const; | 
					
						
							|  |  |  |     QString toYaddNetFormat(const QString& id, qint64 frequency) const; | 
					
						
							|  |  |  |     QString formatSpecifier(bool shortString=false) const; | 
					
						
							|  |  |  |     QString category(bool shortString=false) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static QString telecommand1(FirstTelecommand telecommand, bool shortString=false); | 
					
						
							|  |  |  |     static QString telecommand2(SecondTelecommand telecommand, bool shortString=false); | 
					
						
							|  |  |  |     static QString distressNature(DistressNature nature); | 
					
						
							|  |  |  |     static QString endOfSignal(EndOfSignal eos, bool shortString=false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString symbolsToDigits(const QByteArray data, int startIdx, int length); | 
					
						
							|  |  |  |     QString formatCoordinates(int latitude, int longitude); | 
					
						
							|  |  |  |     void decode(const QByteArray& data); | 
					
						
							|  |  |  |     void checkECC(const QByteArray& data); | 
					
						
							|  |  |  |     void decodeFrequency(const QByteArray& data, int& idx, int& frequency, QString& channel); | 
					
						
							|  |  |  |     QString formatAddress(const QString &address) const; | 
					
						
							|  |  |  |     QString formatCoordinates(const QString& coords); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* INCLUDE_UTIL_DSC_H */
 |