/////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2023 Jon Beniston, M7RCE // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation as version 3 of the License, or // // (at your option) any later version. // // // // This program is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY; without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License V3 for more details. // // // // You should have received a copy of the GNU General Public License // // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// #ifndef INCLUDE_UTIL_DSC_H #define INCLUDE_UTIL_DSC_H #include "export.h" #include #include #include // 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 m_formatSpecifierStrings; static QMap m_formatSpecifierShortStrings; static QMap m_categoryStrings; static QMap m_categoryShortStrings; static QMap m_telecommand1Strings; static QMap m_telecommand1ShortStrings; static QMap m_telecommand2Strings; static QMap m_telecommand2ShortStrings; static QMap m_distressNatureStrings; static QMap m_endOfSignalStrings; static QMap 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 */