From 51e74c6182b75aa00d47f90f677b351ae3dd01c6 Mon Sep 17 00:00:00 2001 From: SASANO Takayoshi Date: Wed, 10 Mar 2021 21:09:58 +0900 Subject: [PATCH 01/23] revise UserDB display setting on OLED To display UserDB on OLED, either Slot1=0/Slot2=1 or Slot1=1/Slot2=0 of [DMR Network] in MMDVM.ini was required. Other displays such as LCDproc, HD44180 and TFTSurenoo uses duplex value of [General], OLED also uses same entry from now. --- Display.cpp | 2 +- OLED.cpp | 10 +++++----- OLED.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Display.cpp b/Display.cpp index 39b0a09..516d76d 100644 --- a/Display.cpp +++ b/Display.cpp @@ -642,7 +642,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) bool rotate = conf.getOLEDRotate(); bool logosaver = conf.getOLEDLogoScreensaver(); - display = new COLED(type, brightness, invert, scroll, rotate, logosaver, conf.getDMRNetworkSlot1(), conf.getDMRNetworkSlot2()); + display = new COLED(type, brightness, invert, scroll, rotate, logosaver, conf.getDuplex()); #endif } else if (type == "CAST") { display = new CCASTInfo(modem); diff --git a/OLED.cpp b/OLED.cpp index 34365aa..fddbe4d 100644 --- a/OLED.cpp +++ b/OLED.cpp @@ -169,15 +169,15 @@ const unsigned char logo_POCSAG_bmp [] = 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -COLED::COLED(unsigned char displayType, unsigned char displayBrightness, bool displayInvert, bool displayScroll, bool displayRotate, bool displayLogoScreensaver, bool slot1Enabled, bool slot2Enabled) : +COLED::COLED(unsigned char displayType, unsigned char displayBrightness, bool displayInvert, bool displayScroll, bool displayRotate, bool displayLogoScreensaver, bool duplex) : m_displayType(displayType), m_displayBrightness(displayBrightness), m_displayInvert(displayInvert), m_displayScroll(displayScroll), m_displayRotate(displayRotate), m_displayLogoScreensaver(displayLogoScreensaver), -m_slot1Enabled(slot1Enabled), -m_slot2Enabled(slot2Enabled), +m_duplex(duplex), +//m_duplex(true), // uncomment to force duplex display for testing! m_ipaddress(), m_display() { @@ -382,7 +382,7 @@ int COLED::writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, boo } // if both slots, use lines 2-3 for slot 1, lines 4-5 for slot 2 // if single slot, use lines 2-3 - if ( m_slot1Enabled && m_slot2Enabled ) { + if ( m_duplex ) { if (slotNo == 1U) { m_display.fillRect(0,OLED_LINE2,m_display.width(),40,BLACK); @@ -430,7 +430,7 @@ void COLED::clearDMRInt(unsigned int slotNo) { // if both slots, use lines 2-3 for slot 1, lines 4-5 for slot 2 // if single slot, use lines 2-3 - if ( m_slot1Enabled && m_slot2Enabled ){ + if ( m_duplex ){ if (slotNo == 1U) { m_display.fillRect(0, OLED_LINE3, m_display.width(), 40, BLACK); m_display.setCursor(0,OLED_LINE3); diff --git a/OLED.h b/OLED.h index 5f3ead0..a703ba5 100644 --- a/OLED.h +++ b/OLED.h @@ -41,7 +41,7 @@ class COLED : public CDisplay { public: - COLED(unsigned char displayType, unsigned char displayBrighness, bool displayInvert, bool displayScroll, bool displayRotate, bool displayLogoScreensaver, bool slot1Enabled, bool slot2Enabled); + COLED(unsigned char displayType, unsigned char displayBrighness, bool displayInvert, bool displayScroll, bool displayRotate, bool displayLogoScreensaver, bool duplex); virtual ~COLED(); virtual bool open(); @@ -88,7 +88,7 @@ private: bool m_displayScroll; bool m_displayRotate; bool m_displayLogoScreensaver; - bool m_slot1Enabled; + bool m_duplex; bool m_slot2Enabled; std::string m_ipaddress; ArduiPi_OLED m_display; From 125f21735bedb1c56ee7fc732847f74884067737 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 12 Mar 2021 19:56:05 +0000 Subject: [PATCH 02/23] Move the host lookup for the DMR Direct Network. --- DMRDirectNetwork.cpp | 7 +++---- DMRDirectNetwork.h | 4 +++- Version.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/DMRDirectNetwork.cpp b/DMRDirectNetwork.cpp index 8bb397f..4ed871c 100644 --- a/DMRDirectNetwork.cpp +++ b/DMRDirectNetwork.cpp @@ -31,6 +31,8 @@ const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; CDMRDirectNetwork::CDMRDirectNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug) : +m_address(address), +m_port(port), m_addr(), m_addrLen(0U), m_id(NULL), @@ -70,9 +72,6 @@ m_beacon(false) assert(id > 1000U); assert(!password.empty()); - if (CUDPSocket::lookup(address, port, m_addr, m_addrLen) != 0) - m_addrLen = 0U; - m_buffer = new unsigned char[BUFFER_LENGTH]; m_salt = new unsigned char[sizeof(uint32_t)]; m_id = new uint8_t[4U]; @@ -122,7 +121,7 @@ void CDMRDirectNetwork::setConfig(const std::string& callsign, unsigned int rxFr bool CDMRDirectNetwork::open() { - if (m_addrLen == 0U) { + if (CUDPSocket::lookup(m_address, m_port, m_addr, m_addrLen) != 0) { LogError("DMR, Could not lookup the address of the DMR Network"); return false; } diff --git a/DMRDirectNetwork.h b/DMRDirectNetwork.h index 896d5e4..30ba951 100644 --- a/DMRDirectNetwork.h +++ b/DMRDirectNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -58,6 +58,8 @@ public: virtual void close(); private: + std::string m_address; + unsigned int m_port; sockaddr_storage m_addr; unsigned int m_addrLen; uint8_t* m_id; diff --git a/Version.h b/Version.h index 8a94573..6e4502f 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210309"; +const char* VERSION = "20210312"; #endif From c2be5ab2f782b83f132019030eadc94d3f436689 Mon Sep 17 00:00:00 2001 From: SASANO Takayoshi Date: Sat, 13 Mar 2021 12:27:23 +0900 Subject: [PATCH 03/23] delete unused variable --- OLED.h | 1 - 1 file changed, 1 deletion(-) diff --git a/OLED.h b/OLED.h index a703ba5..3f63226 100644 --- a/OLED.h +++ b/OLED.h @@ -89,7 +89,6 @@ private: bool m_displayRotate; bool m_displayLogoScreensaver; bool m_duplex; - bool m_slot2Enabled; std::string m_ipaddress; ArduiPi_OLED m_display; From fb0d1ef5e21f110c735630bf3ec8972ba42e6180 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 14 Mar 2021 12:16:39 +0000 Subject: [PATCH 04/23] Allow the USRP audio format to be used natively by the FM networking. --- Conf.cpp | 10 +++- Conf.h | 2 + FMNetwork.cpp | 151 +++++++++++++++++++++++++++++++++++++------------- FMNetwork.h | 13 ++++- MMDVM.ini | 2 + MMDVMHost.cpp | 4 +- Version.h | 2 +- 7 files changed, 139 insertions(+), 45 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 7c9f478..d69d297 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -283,6 +283,7 @@ m_pocsagLocalPort(0U), m_pocsagNetworkModeHang(3U), m_pocsagNetworkDebug(false), m_fmNetworkEnabled(false), +m_fmNetworkFormat("MMDVM"), m_fmGatewayAddress(), m_fmGatewayPort(0U), m_fmLocalAddress(), @@ -440,7 +441,7 @@ bool CConf::read() value++; } else { // if value is not quoted, remove after # (to make comment) - ::strtok(value, "#"); + (void)::strtok(value, "#"); } if (section == SECTION_GENERAL) { @@ -998,6 +999,8 @@ bool CConf::read() } else if (section == SECTION_FM_NETWORK) { if (::strcmp(key, "Enable") == 0) m_fmNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Format") == 0) + m_fmNetworkFormat = value; else if (::strcmp(key, "LocalAddress") == 0) m_fmLocalAddress = value; else if (::strcmp(key, "LocalPort") == 0) @@ -2197,6 +2200,11 @@ bool CConf::getFMNetworkEnabled() const return m_fmNetworkEnabled; } +std::string CConf::getFMNetworkFormat() const +{ + return m_fmNetworkFormat; +} + std::string CConf::getFMGatewayAddress() const { return m_fmGatewayAddress; diff --git a/Conf.h b/Conf.h index 430bbeb..7a5c56a 100644 --- a/Conf.h +++ b/Conf.h @@ -296,6 +296,7 @@ public: // The FM Network section bool getFMNetworkEnabled() const; + std::string getFMNetworkFormat() const; std::string getFMGatewayAddress() const; unsigned int getFMGatewayPort() const; std::string getFMLocalAddress() const; @@ -603,6 +604,7 @@ private: bool m_pocsagNetworkDebug; bool m_fmNetworkEnabled; + std::string m_fmNetworkFormat; std::string m_fmGatewayAddress; unsigned int m_fmGatewayPort; std::string m_fmLocalAddress; diff --git a/FMNetwork.cpp b/FMNetwork.cpp index c10e3d8..d9aa0e5 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -27,7 +27,8 @@ const unsigned int BUFFER_LENGTH = 500U; -CFMNetwork::CFMNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug) : +CFMNetwork::CFMNetwork(const std::string& format, const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug) : +m_format(FMF_MMDVM), m_socket(localAddress, localPort), m_addr(), m_addrLen(0U), @@ -35,7 +36,8 @@ m_sampleRate(sampleRate), m_debug(debug), m_enabled(false), m_buffer(2000U, "FM Network"), -m_pollTimer(1000U, 5U) +m_pollTimer(1000U, 5U), +m_seqNo(0U) { assert(gatewayPort > 0U); assert(!gatewayAddress.empty()); @@ -44,6 +46,9 @@ m_pollTimer(1000U, 5U) if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) m_addrLen = 0U; + if (format == "USRP") + m_format = FMF_USRP; + #if !defined(_WIN32) && !defined(_WIN64) int error; m_incoming = ::src_new(SRC_SINC_FASTEST, 1, &error); @@ -106,46 +111,97 @@ bool CFMNetwork::writeData(float* data, unsigned int nSamples) } #endif - unsigned int length = 3U; + unsigned char buffer[2000U]; + ::memset(buffer, 0x00U, 2000U); - unsigned char buffer[1500U]; - ::memset(buffer, 0x00U, 1500U); + unsigned int length = 0U; - buffer[0U] = 'F'; - buffer[1U] = 'M'; - buffer[2U] = 'D'; + if (m_format == FMF_USRP) { + buffer[length++] = 'U'; + buffer[length++] = 'S'; + buffer[length++] = 'R'; + buffer[length++] = 'P'; + + // Sequence number + buffer[length++] = (m_seqNo >> 24) & 0xFFU; + buffer[length++] = (m_seqNo >> 16) & 0xFFU; + buffer[length++] = (m_seqNo >> 8) & 0xFFU; + buffer[length++] = (m_seqNo >> 0) & 0xFFU; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // PTT, this may be wrong + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x01U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Type, 0 for audio + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + } else { + buffer[length++] = 'F'; + buffer[length++] = 'M'; + buffer[length++] = 'D'; + } #if defined(_WIN32) || defined(_WIN64) - for (long i = 0L; i < nSamples; i++) { - short val = ( short)((data[i] ) * 32767.0F); // Changing audio format from U16BE to S16LE + for (unsigned int i = 0U; i < nSamples; i++) { + short val = short(data[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE #else for (long i = 0L; i < src.output_frames_gen; i++) { - short val = ( short)((src.data_out[i] ) * 32767.0F ); // Changing audio format from U16BE to S16LE + short val = short(src.data_out[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE #endif - buffer[length++] = (val >> 0) & 0xFFU; // changing from BE to LE - buffer[length++] = (val >> 8) & 0xFFU; // changing from BE to LE + buffer[length++] = (val >> 0) & 0xFFU; + buffer[length++] = (val >> 8) & 0xFFU; } if (m_debug) CUtils::dump(1U, "FM Network Data Sent", buffer, length); + m_seqNo++; + return m_socket.write(buffer, length, m_addr, m_addrLen); } bool CFMNetwork::writeEOT() { - unsigned char buffer[10U]; - ::memset(buffer, 0x00U, 10U); + if (m_format == FMF_MMDVM) { + unsigned char buffer[10U]; + ::memset(buffer, 0x00U, 10U); - buffer[0U] = 'F'; - buffer[1U] = 'M'; - buffer[2U] = 'E'; + buffer[0U] = 'F'; + buffer[1U] = 'M'; + buffer[2U] = 'E'; - if (m_debug) - CUtils::dump(1U, "FM Network End of Transmission Sent", buffer, 3U); + if (m_debug) + CUtils::dump(1U, "FM Network End of Transmission Sent", buffer, 3U); - return m_socket.write(buffer, 3U, m_addr, m_addrLen); + return m_socket.write(buffer, 3U, m_addr, m_addrLen); + } + + return true; } void CFMNetwork::clock(unsigned int ms) @@ -170,21 +226,36 @@ void CFMNetwork::clock(unsigned int ms) // return; //} - // Ignore incoming polls - if (::memcmp(buffer, "FMP", 3U) == 0) - return; - - // Invalid packet type? - if (::memcmp(buffer, "FMD", 3U) != 0) - return; - if (!m_enabled) return; if (m_debug) CUtils::dump(1U, "FM Network Data Received", buffer, length); - m_buffer.addData(buffer + 3U, length - 3U); + if (m_format == FMF_USRP) { + // Invalid packet type? + if (::memcmp(buffer, "USRP", 4U) != 0) + return; + + // The type is a big-endian 4-byte integer + unsigned int type = (buffer[20U] << 24) + + (buffer[21U] << 16) + + (buffer[22U] << 8) + + (buffer[23U] << 0); + + if (type == 0U) + m_buffer.addData(buffer + 32U, length - 32U); + } else { + // Ignore incoming polls + if (::memcmp(buffer, "FMP", 3U) == 0) + return; + + // Invalid packet type? + if (::memcmp(buffer, "FMD", 3U) != 0) + return; + + m_buffer.addData(buffer + 3U, length - 3U); + } } unsigned int CFMNetwork::read(float* data, unsigned int nSamples) @@ -274,16 +345,18 @@ void CFMNetwork::enable(bool enabled) m_enabled = enabled; } -bool CFMNetwork::writePoll() +void CFMNetwork::writePoll() { - unsigned char buffer[3U]; + if (m_format == FMF_MMDVM) { + unsigned char buffer[3U]; - buffer[0U] = 'F'; - buffer[1U] = 'M'; - buffer[2U] = 'P'; + buffer[0U] = 'F'; + buffer[1U] = 'M'; + buffer[2U] = 'P'; - if (m_debug) - CUtils::dump(1U, "FM Network Poll Sent", buffer, 3U); + if (m_debug) + CUtils::dump(1U, "FM Network Poll Sent", buffer, 3U); - return m_socket.write(buffer, 3U, m_addr, m_addrLen); + m_socket.write(buffer, 3U, m_addr, m_addrLen); + } } diff --git a/FMNetwork.h b/FMNetwork.h index aa99751..d7b1ff7 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -30,9 +30,14 @@ #include #include +enum FM_FORMAT { + FMF_MMDVM, + FMF_USRP +}; + class CFMNetwork { public: - CFMNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug); + CFMNetwork(const std::string& format, const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug); ~CFMNetwork(); bool open(); @@ -52,6 +57,7 @@ public: void clock(unsigned int ms); private: + FM_FORMAT m_format; CUDPSocket m_socket; sockaddr_storage m_addr; unsigned int m_addrLen; @@ -60,12 +66,13 @@ private: bool m_enabled; CRingBuffer m_buffer; CTimer m_pollTimer; + unsigned int m_seqNo; #if !defined(_WIN32) && !defined(_WIN64) SRC_STATE* m_incoming; SRC_STATE* m_outgoing; #endif - bool writePoll(); + void writePoll(); }; #endif diff --git a/MMDVM.ini b/MMDVM.ini index 8c89a56..255c12d 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -275,6 +275,8 @@ Debug=0 [FM Network] Enable=1 +# Values are MMDVM and USRP +Format=USRP LocalAddress=127.0.0.1 LocalPort=3810 GatewayAddress=127.0.0.1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 428aa1c..b78d7e9 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1796,6 +1796,7 @@ bool CMMDVMHost::createPOCSAGNetwork() bool CMMDVMHost::createFMNetwork() { + std::string format = m_conf.getFMNetworkFormat(); std::string gatewayAddress = m_conf.getFMGatewayAddress(); unsigned int gatewayPort = m_conf.getFMGatewayPort(); std::string localAddress = m_conf.getFMLocalAddress(); @@ -1805,6 +1806,7 @@ bool CMMDVMHost::createFMNetwork() bool debug = m_conf.getFMNetworkDebug(); LogInfo("FM Network Parameters"); + LogInfo(" Format: %s", format.c_str()); LogInfo(" Gateway Address: %s", gatewayAddress.c_str()); LogInfo(" Gateway Port: %u", gatewayPort); LogInfo(" Local Address: %s", localAddress.c_str()); @@ -1812,7 +1814,7 @@ bool CMMDVMHost::createFMNetwork() LogInfo(" Sample Rate: %u", sampleRate); LogInfo(" Mode Hang: %us", m_fmNetModeHang); - m_fmNetwork = new CFMNetwork(localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, debug); + m_fmNetwork = new CFMNetwork(format, localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, debug); bool ret = m_fmNetwork->open(); if (!ret) { diff --git a/Version.h b/Version.h index 7365a93..028594f 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210312"; +const char* VERSION = "20210314"; #endif From 75e8e95aad0945572d7995e8e51eb80b394f71a0 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 14 Mar 2021 14:59:34 +0000 Subject: [PATCH 05/23] Add FM network audio gain and optional pre- and de-emphasis. --- Conf.cpp | 42 ++++++++++++++++++++++++++++++---- Conf.h | 12 ++++++++-- FMControl.cpp | 63 +++++++++++++++++++++++++++++++-------------------- FMControl.h | 12 ++++++---- FMNetwork.cpp | 32 +++++++++++++------------- FMNetwork.h | 30 ++++++++++++------------ MMDVM.ini | 6 ++++- MMDVMHost.cpp | 24 +++++++++++++++----- 8 files changed, 147 insertions(+), 74 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index d69d297..83d22f4 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -283,12 +283,16 @@ m_pocsagLocalPort(0U), m_pocsagNetworkModeHang(3U), m_pocsagNetworkDebug(false), m_fmNetworkEnabled(false), -m_fmNetworkFormat("MMDVM"), +m_fmNetworkProtocol("MMDVM"), m_fmGatewayAddress(), m_fmGatewayPort(0U), m_fmLocalAddress(), m_fmLocalPort(0U), m_fmSampleRate(8000U), +m_fmPreEmphasis(true), +m_fmDeEmphasis(true), +m_fmTXAudioGain(1.0F), +m_fmRXAudioGain(1.0F), m_fmNetworkModeHang(3U), m_fmNetworkDebug(false), m_ax25NetworkEnabled(false), @@ -999,8 +1003,8 @@ bool CConf::read() } else if (section == SECTION_FM_NETWORK) { if (::strcmp(key, "Enable") == 0) m_fmNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Format") == 0) - m_fmNetworkFormat = value; + else if (::strcmp(key, "Protocol") == 0) + m_fmNetworkProtocol = value; else if (::strcmp(key, "LocalAddress") == 0) m_fmLocalAddress = value; else if (::strcmp(key, "LocalPort") == 0) @@ -1011,6 +1015,14 @@ bool CConf::read() m_fmGatewayPort = (unsigned int)::atoi(value); else if (::strcmp(key, "SampleRate") == 0) m_fmSampleRate = (unsigned int)::atoi(value); + else if (::strcmp(key, "PreEmphasis") == 0) + m_fmPreEmphasis = ::atoi(value) == 1; + else if (::strcmp(key, "DeEmphasis") == 0) + m_fmDeEmphasis = ::atoi(value) == 1; + else if (::strcmp(key, "TXAudioGain") == 0) + m_fmTXAudioGain = float(::atof(value)); + else if (::strcmp(key, "RXAudioGain") == 0) + m_fmRXAudioGain = float(::atof(value)); else if (::strcmp(key, "ModeHang") == 0) m_fmNetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) @@ -2200,9 +2212,9 @@ bool CConf::getFMNetworkEnabled() const return m_fmNetworkEnabled; } -std::string CConf::getFMNetworkFormat() const +std::string CConf::getFMNetworkProtocol() const { - return m_fmNetworkFormat; + return m_fmNetworkProtocol; } std::string CConf::getFMGatewayAddress() const @@ -2230,6 +2242,26 @@ unsigned int CConf::getFMSampleRate() const return m_fmSampleRate; } +bool CConf::getFMPreEmphasis() const +{ + return m_fmPreEmphasis; +} + +bool CConf::getFMDeEmphasis() const +{ + return m_fmDeEmphasis; +} + +float CConf::getFMTXAudioGain() const +{ + return m_fmTXAudioGain; +} + +float CConf::getFMRXAudioGain() const +{ + return m_fmRXAudioGain; +} + unsigned int CConf::getFMNetworkModeHang() const { return m_fmNetworkModeHang; diff --git a/Conf.h b/Conf.h index 7a5c56a..aad1155 100644 --- a/Conf.h +++ b/Conf.h @@ -296,12 +296,16 @@ public: // The FM Network section bool getFMNetworkEnabled() const; - std::string getFMNetworkFormat() const; + std::string getFMNetworkProtocol() const; std::string getFMGatewayAddress() const; unsigned int getFMGatewayPort() const; std::string getFMLocalAddress() const; unsigned int getFMLocalPort() const; unsigned int getFMSampleRate() const; + bool getFMPreEmphasis() const; + bool getFMDeEmphasis() const; + float getFMTXAudioGain() const; + float getFMRXAudioGain() const; unsigned int getFMNetworkModeHang() const; bool getFMNetworkDebug() const; @@ -604,12 +608,16 @@ private: bool m_pocsagNetworkDebug; bool m_fmNetworkEnabled; - std::string m_fmNetworkFormat; + std::string m_fmNetworkProtocol; std::string m_fmGatewayAddress; unsigned int m_fmGatewayPort; std::string m_fmLocalAddress; unsigned int m_fmLocalPort; unsigned int m_fmSampleRate; + bool m_fmPreEmphasis; + bool m_fmDeEmphasis; + float m_fmTXAudioGain; + float m_fmRXAudioGain; unsigned int m_fmNetworkModeHang; bool m_fmNetworkDebug; diff --git a/FMControl.cpp b/FMControl.cpp index 076cbc9..c44c324 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -31,20 +31,27 @@ const float PREEMPHASIS_GAIN_DB = 0.0F; // Audio gain adjustment const float FILTER_GAIN_DB = 2.0F; // Audio gain adjustment const unsigned int FM_MASK = 0x00000FFFU; -CFMControl::CFMControl(CFMNetwork* network) : +CFMControl::CFMControl(CFMNetwork* network, float txAudioGain, float rxAudioGain, bool preEmphasisOn, bool deEmphasisOn) : m_network(network), +m_txAudioGain(txAudioGain), +m_rxAudioGain(rxAudioGain), +m_preEmphasisOn(preEmphasisOn), +m_deEmphasisOn(deEmphasisOn), m_enabled(false), m_incomingRFAudio(1600U, "Incoming RF FM Audio"), -m_preemphasis (NULL), -m_deemphasis (NULL), +m_preEmphasis(NULL), +m_deEmphasis(NULL), m_filterStage1(NULL), m_filterStage2(NULL), m_filterStage3(NULL) { - m_preemphasis = new CIIRDirectForm1Filter(8.315375384336983F,-7.03334621603483F,0.0F,1.0F,0.282029168302153F,0.0F, PREEMPHASIS_GAIN_DB); - m_deemphasis = new CIIRDirectForm1Filter(0.07708787090460224F,0.07708787090460224F,0.0F,1.0F,-0.8458242581907955F,0.0F, DEEMPHASIS_GAIN_DB); + assert(txAudioGain > 0.0F); + assert(rxAudioGain > 0.0F); - //cheby type 1 0.2dB cheby type 1 3rd order 300-2700Hz fs=8000 + m_preEmphasis = new CIIRDirectForm1Filter(8.315375384336983F, -7.03334621603483F,0.0F,1.0F, 0.282029168302153F,0.0F, PREEMPHASIS_GAIN_DB); + m_deEmphasis = new CIIRDirectForm1Filter(0.07708787090460224F, 0.07708787090460224F,0.0F, 1.0F, -0.8458242581907955F,0.0F, DEEMPHASIS_GAIN_DB); + + // Chebyshev type 1 0.2dB cheby type 1 3rd order 300-2700Hz fs=8000 m_filterStage1 = new CIIRDirectForm1Filter(0.29495028f, 0.0f, -0.29495028f, 1.0f, -0.61384624f, -0.057158668f, FILTER_GAIN_DB); m_filterStage2 = new CIIRDirectForm1Filter(1.0f, 2.0f, 1.0f, 1.0f, 0.9946123f, 0.6050482f, FILTER_GAIN_DB); m_filterStage3 = new CIIRDirectForm1Filter(1.0f, -2.0f, 1.0f, 1.0f, -1.8414584f, 0.8804949f, FILTER_GAIN_DB); @@ -52,8 +59,8 @@ m_filterStage3(NULL) CFMControl::~CFMControl() { - delete m_preemphasis ; - delete m_deemphasis ; + delete m_preEmphasis; + delete m_deEmphasis; delete m_filterStage1; delete m_filterStage2; @@ -79,42 +86,45 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) m_incomingRFAudio.addData(data + 1U, length - 1U); unsigned int bufferLength = m_incomingRFAudio.dataSize(); - if (bufferLength > 240U) //160 samples 12-bit - bufferLength = 240U; //160 samples 12-bit + if (bufferLength > 240U) // 160 samples 12-bit + bufferLength = 240U; // 160 samples 12-bit if (bufferLength >= 3U) { - bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 - unsigned char bufferData[240U]; //160 samples 12-bit + bufferLength = bufferLength - bufferLength % 3U; // Round down to nearest multiple of 3 + unsigned char bufferData[240U]; // 160 samples 12-bit m_incomingRFAudio.getData(bufferData, bufferLength); unsigned int pack = 0U; unsigned char* packPointer = (unsigned char*)&pack; - float out[160U]; //160 samples 12-bit + float out[160U]; // 160 samples 12-bit unsigned int nOut = 0U; short unpackedSamples[2U]; for (unsigned int i = 0U; i < bufferLength; i += 3U) { - //extract unsigned 12 bit unsigned sample pairs packed into 3 bytes to 16 bit signed - packPointer[0U] = bufferData[i]; + // Extract unsigned 12 bit unsigned sample pairs packed into 3 bytes to 16 bit signed + packPointer[0U] = bufferData[i + 0U]; packPointer[1U] = bufferData[i + 1U]; packPointer[2U] = bufferData[i + 2U]; + unpackedSamples[1U] = short(int(pack & FM_MASK) - 2048); unpackedSamples[0U] = short(int(pack >> 12 & FM_MASK) - 2048); // - //process unpacked sample pair + // Process unpacked sample pair for (unsigned char j = 0U; j < 2U; j++) { // Convert to float (-1.0 to +1.0) - float sampleFloat = float(unpackedSamples[j]) / 2048.0F; + float sampleFloat = (float(unpackedSamples[j]) * m_rxAudioGain) / 2048.0F; // De-emphasise and remove CTCSS - sampleFloat = m_deemphasis->filter(sampleFloat); + if (m_deEmphasisOn) + sampleFloat = m_deEmphasis->filter(sampleFloat); + out[nOut++] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(sampleFloat))); } } #if defined(DUMP_RF_AUDIO) FILE * audiofile = fopen("./audiodump.bin", "ab"); - if(audiofile != NULL) { + if (audiofile != NULL) { fwrite(out, sizeof(float), nOut, audiofile); fclose(audiofile); } @@ -133,8 +143,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) if (m_network == NULL) return 0U; - if (space > 240U) //160 samples 12-bit - space = 240U; //160 samples 12-bit + if (space > 240U) // 160 samples 12-bit + space = 240U; // 160 samples 12-bit float netData[160U]; // Modem can handle up to 160 samples at a time unsigned int length = m_network->read(netData, 160U); //160 samples 12-bit @@ -146,14 +156,17 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) unsigned int nData = 0U; for (unsigned int i = 0; i < length; i++) { + float sampleFloat = netData[i] * m_txAudioGain; + // Pre-emphasis - float sampleFloat = m_preemphasis->filter(netData[i]); + if (m_preEmphasisOn) + sampleFloat = m_preEmphasis->filter(sampleFloat); // Convert float to 12-bit samples (0 to 4095) unsigned int sample12bit = (unsigned int)((sampleFloat + 1.0F) * 2048.0F + 0.5F); - // pack 2 samples onto 3 bytes - if((i & 1U) == 0) { + // Pack 2 samples into 3 bytes + if ((i & 1U) == 0) { pack = 0U; pack = sample12bit << 12; } else { diff --git a/FMControl.h b/FMControl.h index ac2142e..9344f77 100644 --- a/FMControl.h +++ b/FMControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -30,7 +30,7 @@ class CFMControl { public: - CFMControl(CFMNetwork* network); + CFMControl(CFMNetwork* network, float txAudioGain, float rxAudioGain, bool preEmphasisOn, bool deEmphasisOn); ~CFMControl(); bool writeModem(const unsigned char* data, unsigned int length); @@ -43,10 +43,14 @@ public: private: CFMNetwork* m_network; + float m_txAudioGain; + float m_rxAudioGain; + bool m_preEmphasisOn; + bool m_deEmphasisOn; bool m_enabled; CRingBuffer m_incomingRFAudio; - CIIRDirectForm1Filter* m_preemphasis; - CIIRDirectForm1Filter* m_deemphasis; + CIIRDirectForm1Filter* m_preEmphasis; + CIIRDirectForm1Filter* m_deEmphasis; CIIRDirectForm1Filter* m_filterStage1; CIIRDirectForm1Filter* m_filterStage2; CIIRDirectForm1Filter* m_filterStage3; diff --git a/FMNetwork.cpp b/FMNetwork.cpp index d9aa0e5..85947c9 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -27,8 +27,8 @@ const unsigned int BUFFER_LENGTH = 500U; -CFMNetwork::CFMNetwork(const std::string& format, const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug) : -m_format(FMF_MMDVM), +CFMNetwork::CFMNetwork(const std::string& protocol, const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug) : +m_protocol(FMNP_MMDVM), m_socket(localAddress, localPort), m_addr(), m_addrLen(0U), @@ -46,8 +46,8 @@ m_seqNo(0U) if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) m_addrLen = 0U; - if (format == "USRP") - m_format = FMF_USRP; + if (protocol == "USRP") + m_protocol = FMNP_USRP; #if !defined(_WIN32) && !defined(_WIN64) int error; @@ -116,7 +116,7 @@ bool CFMNetwork::writeData(float* data, unsigned int nSamples) unsigned int length = 0U; - if (m_format == FMF_USRP) { + if (m_protocol == FMNP_USRP) { buffer[length++] = 'U'; buffer[length++] = 'S'; buffer[length++] = 'R'; @@ -187,7 +187,7 @@ bool CFMNetwork::writeData(float* data, unsigned int nSamples) bool CFMNetwork::writeEOT() { - if (m_format == FMF_MMDVM) { + if (m_protocol == FMNP_MMDVM) { unsigned char buffer[10U]; ::memset(buffer, 0x00U, 10U); @@ -220,11 +220,11 @@ void CFMNetwork::clock(unsigned int ms) if (length <= 0) return; - // Check if the data is for us // does not accept data from USRP - //if (!CUDPSocket::match(addr, m_addr)) { - // LogMessage("FM packet received from an invalid source"); - // return; - //} + // Check if the data is for us + if (!CUDPSocket::match(addr, m_addr)) { + LogMessage("FM packet received from an invalid source"); + return; + } if (!m_enabled) return; @@ -232,7 +232,7 @@ void CFMNetwork::clock(unsigned int ms) if (m_debug) CUtils::dump(1U, "FM Network Data Received", buffer, length); - if (m_format == FMF_USRP) { + if (m_protocol == FMNP_USRP) { // Invalid packet type? if (::memcmp(buffer, "USRP", 4U) != 0) return; @@ -304,9 +304,9 @@ unsigned int CFMNetwork::read(float* data, unsigned int nSamples) } else { #endif for (unsigned int i = 0U; i < nSamples; i++) { - short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + // Changing audio format from U16BE to S16LE - ((buffer[i * 2U + 1U] & 0xFFU) << 8); // Changing audio format from U16BE to S16LE - data[i] = (float(val) / 65536.0F); // Changing audio format from U16BE to S16LE + short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + + ((buffer[i * 2U + 1U] & 0xFFU) << 8); + data[i] = float(val) / 65536.0F; } return nSamples; @@ -347,7 +347,7 @@ void CFMNetwork::enable(bool enabled) void CFMNetwork::writePoll() { - if (m_format == FMF_MMDVM) { + if (m_protocol == FMNP_MMDVM) { unsigned char buffer[3U]; buffer[0U] = 'F'; diff --git a/FMNetwork.h b/FMNetwork.h index d7b1ff7..90f4225 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -30,14 +30,14 @@ #include #include -enum FM_FORMAT { - FMF_MMDVM, - FMF_USRP +enum FM_NETWORK_PROTOCOL { + FMNP_MMDVM, + FMNP_USRP }; class CFMNetwork { public: - CFMNetwork(const std::string& format, const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug); + CFMNetwork(const std::string& protocol, const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug); ~CFMNetwork(); bool open(); @@ -57,19 +57,19 @@ public: void clock(unsigned int ms); private: - FM_FORMAT m_format; - CUDPSocket m_socket; - sockaddr_storage m_addr; - unsigned int m_addrLen; - unsigned int m_sampleRate; - bool m_debug; - bool m_enabled; + FM_NETWORK_PROTOCOL m_protocol; + CUDPSocket m_socket; + sockaddr_storage m_addr; + unsigned int m_addrLen; + unsigned int m_sampleRate; + bool m_debug; + bool m_enabled; CRingBuffer m_buffer; - CTimer m_pollTimer; - unsigned int m_seqNo; + CTimer m_pollTimer; + unsigned int m_seqNo; #if !defined(_WIN32) && !defined(_WIN64) - SRC_STATE* m_incoming; - SRC_STATE* m_outgoing; + SRC_STATE* m_incoming; + SRC_STATE* m_outgoing; #endif void writePoll(); diff --git a/MMDVM.ini b/MMDVM.ini index 255c12d..be1dbcf 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -276,12 +276,16 @@ Debug=0 [FM Network] Enable=1 # Values are MMDVM and USRP -Format=USRP +Protocol=USRP LocalAddress=127.0.0.1 LocalPort=3810 GatewayAddress=127.0.0.1 GatewayPort=4810 SampleRate=8000 +PreEmphasis=1 +DeEmphasis=1 +TXAudioGain=1.0 +RXAudioGain=1.0 # ModeHang=3 Debug=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index b78d7e9..2f51e69 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -681,15 +681,19 @@ int CMMDVMHost::run() } if (m_fmEnabled) { - m_fmRFModeHang = m_conf.getFMModeHang(); + bool preEmphasis = m_conf.getFMPreEmphasis(); + bool deEmphasis = m_conf.getFMDeEmphasis(); + float txAudioGain = m_conf.getFMTXAudioGain(); + float rxAudioGain = m_conf.getFMRXAudioGain(); + m_fmRFModeHang = m_conf.getFMModeHang(); - m_fm = new CFMControl(m_fmNetwork); + m_fm = new CFMControl(m_fmNetwork, txAudioGain, rxAudioGain, preEmphasis, deEmphasis); } bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); if (remoteControlEnabled) { std::string address = m_conf.getRemoteControlAddress(); - unsigned int port = m_conf.getRemoteControlPort(); + unsigned int port = m_conf.getRemoteControlPort(); LogInfo("Remote Control Parameters"); LogInfo(" Address: %s", address.c_str()); @@ -1796,25 +1800,33 @@ bool CMMDVMHost::createPOCSAGNetwork() bool CMMDVMHost::createFMNetwork() { - std::string format = m_conf.getFMNetworkFormat(); + std::string protocol = m_conf.getFMNetworkProtocol(); std::string gatewayAddress = m_conf.getFMGatewayAddress(); unsigned int gatewayPort = m_conf.getFMGatewayPort(); std::string localAddress = m_conf.getFMLocalAddress(); unsigned int localPort = m_conf.getFMLocalPort(); unsigned int sampleRate = m_conf.getFMSampleRate(); + bool preEmphasis = m_conf.getFMPreEmphasis(); + bool deEmphasis = m_conf.getFMDeEmphasis(); + float txAudioGain = m_conf.getFMTXAudioGain(); + float rxAudioGain = m_conf.getFMRXAudioGain(); m_fmNetModeHang = m_conf.getFMNetworkModeHang(); bool debug = m_conf.getFMNetworkDebug(); LogInfo("FM Network Parameters"); - LogInfo(" Format: %s", format.c_str()); + LogInfo(" Protocol: %s", protocol.c_str()); LogInfo(" Gateway Address: %s", gatewayAddress.c_str()); LogInfo(" Gateway Port: %u", gatewayPort); LogInfo(" Local Address: %s", localAddress.c_str()); LogInfo(" Local Port: %u", localPort); LogInfo(" Sample Rate: %u", sampleRate); + LogInfo(" Pre-Emphasis: %s", preEmphasis ? "yes" : "no"); + LogInfo(" De-Emphasis: %s", deEmphasis ? "yes" : "no"); + LogInfo(" TX Audio Gain: %.2f", txAudioGain); + LogInfo(" RX Audio Gain: %.2f", rxAudioGain); LogInfo(" Mode Hang: %us", m_fmNetModeHang); - m_fmNetwork = new CFMNetwork(format, localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, debug); + m_fmNetwork = new CFMNetwork(protocol, localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, debug); bool ret = m_fmNetwork->open(); if (!ret) { From d0ccc0ee6105a3956cf04004e31389953488961b Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 14 Mar 2021 16:24:48 +0000 Subject: [PATCH 06/23] Try and fix a crash. --- FMControl.cpp | 2 +- FMNetwork.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index c44c324..7f1ff07 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -147,7 +147,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) space = 240U; // 160 samples 12-bit float netData[160U]; // Modem can handle up to 160 samples at a time - unsigned int length = m_network->read(netData, 160U); //160 samples 12-bit + unsigned int length = m_network->read(netData, 160U); // 160 samples 12-bit if (length == 0U) return 0U; diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 85947c9..947ceb8 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -25,7 +25,7 @@ #include #include -const unsigned int BUFFER_LENGTH = 500U; +const unsigned int BUFFER_LENGTH = 1500U; CFMNetwork::CFMNetwork(const std::string& protocol, const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug) : m_protocol(FMNP_MMDVM), @@ -111,8 +111,8 @@ bool CFMNetwork::writeData(float* data, unsigned int nSamples) } #endif - unsigned char buffer[2000U]; - ::memset(buffer, 0x00U, 2000U); + unsigned char buffer[1500U]; + ::memset(buffer, 0x00U, 1500U); unsigned int length = 0U; @@ -237,6 +237,9 @@ void CFMNetwork::clock(unsigned int ms) if (::memcmp(buffer, "USRP", 4U) != 0) return; + if (length < 32) + return; + // The type is a big-endian 4-byte integer unsigned int type = (buffer[20U] << 24) + (buffer[21U] << 16) + @@ -254,6 +257,9 @@ void CFMNetwork::clock(unsigned int ms) if (::memcmp(buffer, "FMD", 3U) != 0) return; + if (length < 3) + return; + m_buffer.addData(buffer + 3U, length - 3U); } } From 42570c905d9017f8aa876d07a909fbea60c338ef Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 14 Mar 2021 19:04:54 +0000 Subject: [PATCH 07/23] Handle updated M17 modem serial data. --- Modem.cpp | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/Modem.cpp b/Modem.cpp index d6ed93f..6af10d2 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -74,9 +74,10 @@ const unsigned char MMDVM_P25_LOST = 0x32U; const unsigned char MMDVM_NXDN_DATA = 0x40U; const unsigned char MMDVM_NXDN_LOST = 0x41U; -const unsigned char MMDVM_M17_HEADER = 0x45U; -const unsigned char MMDVM_M17_DATA = 0x46U; -const unsigned char MMDVM_M17_LOST = 0x47U; +const unsigned char MMDVM_M17_LINK_SETUP = 0x45U; +const unsigned char MMDVM_M17_STREAM = 0x46U; +const unsigned char MMDVM_M17_PACKET = 0x47U; +const unsigned char MMDVM_M17_LOST = 0x48U; const unsigned char MMDVM_POCSAG_DATA = 0x50U; @@ -648,9 +649,9 @@ void CModem::clock(unsigned int ms) } break; - case MMDVM_M17_HEADER: { + case MMDVM_M17_LINK_SETUP: { if (m_trace) - CUtils::dump(1U, "RX M17 Header", m_buffer, m_length); + CUtils::dump(1U, "RX M17 Link Setup", m_buffer, m_length); unsigned char data = m_length - 2U; m_rxM17Data.addData(&data, 1U); @@ -662,9 +663,23 @@ void CModem::clock(unsigned int ms) } break; - case MMDVM_M17_DATA: { + case MMDVM_M17_STREAM: { if (m_trace) - CUtils::dump(1U, "RX M17 Data", m_buffer, m_length); + CUtils::dump(1U, "RX M17 Stream Data", m_buffer, m_length); + + unsigned char data = m_length - 2U; + m_rxM17Data.addData(&data, 1U); + + data = TAG_DATA; + m_rxM17Data.addData(&data, 1U); + + m_rxM17Data.addData(m_buffer + 3U, m_length - 3U); + } + break; + + case MMDVM_M17_PACKET: { + if (m_trace) + CUtils::dump(1U, "RX M17 Packet Data", m_buffer, m_length); unsigned char data = m_length - 2U; m_rxM17Data.addData(&data, 1U); @@ -1019,10 +1034,17 @@ void CModem::clock(unsigned int ms) m_txM17Data.getData(m_buffer, len); if (m_trace) { - if (m_buffer[2U] == MMDVM_M17_HEADER) - CUtils::dump(1U, "TX M17 Header", m_buffer, len); - else - CUtils::dump(1U, "TX M17 Data", m_buffer, len); + switch (m_buffer[2U]) { + case MMDVM_M17_LINK_SETUP: + CUtils::dump(1U, "TX M17 Link Setup", m_buffer, len); + break; + case MMDVM_M17_STREAM: + CUtils::dump(1U, "TX M17 Stream Data", m_buffer, len); + break; + case MMDVM_M17_PACKET: + CUtils::dump(1U, "TX M17 Packet Data", m_buffer, len); + break; + } } int ret = m_port->write(m_buffer, len); @@ -1487,9 +1509,9 @@ bool CModem::writeM17Data(const unsigned char* data, unsigned int length) buffer[1U] = length + 2U; if (data[0U] == TAG_HEADER) - buffer[2U] = MMDVM_M17_HEADER; + buffer[2U] = MMDVM_M17_LINK_SETUP; else - buffer[2U] = MMDVM_M17_DATA; + buffer[2U] = MMDVM_M17_STREAM; ::memcpy(buffer + 3U, data + 1U, length - 1U); From a3e4a250bd51d36a479c735e87e009a47a2f9fb5 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 14 Mar 2021 21:00:47 +0000 Subject: [PATCH 08/23] Make the Null Controller respond properly. --- NullController.cpp | 143 ++++++++++++++++++++++++++++++++++++++++++++- NullController.h | 7 +++ 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/NullController.cpp b/NullController.cpp index fb48a04..edfeffe 100644 --- a/NullController.cpp +++ b/NullController.cpp @@ -18,7 +18,31 @@ #include "NullController.h" -CNullController::CNullController() +#include +#include + +const unsigned char MMDVM_FRAME_START = 0xE0U; + +const unsigned char MMDVM_GET_VERSION = 0x00U; +const unsigned char MMDVM_GET_STATUS = 0x01U; +const unsigned char MMDVM_SET_CONFIG = 0x02U; +const unsigned char MMDVM_SET_MODE = 0x03U; +const unsigned char MMDVM_SET_FREQ = 0x04U; + +const unsigned char MMDVM_FM_PARAMS1 = 0x60U; +const unsigned char MMDVM_FM_PARAMS2 = 0x61U; +const unsigned char MMDVM_FM_PARAMS3 = 0x62U; +const unsigned char MMDVM_FM_PARAMS4 = 0x63U; + +const unsigned char MMDVM_ACK = 0x70U; +const unsigned char MMDVM_NAK = 0x7FU; + +const unsigned char PROTOCOL_VERSION = 2U; + +const char* HARDWARE = "Null Modem Controller"; + +CNullController::CNullController() : +m_buffer(200U, "Null Controller Buffer") { } @@ -33,15 +57,128 @@ bool CNullController::open() int CNullController::read(unsigned char* buffer, unsigned int length) { - return 0; + unsigned int dataSize = m_buffer.dataSize(); + if (dataSize == 0U) + return 0; + + if (length > dataSize) + length = dataSize; + + m_buffer.getData(buffer, length); + + return int(length); } int CNullController::write(const unsigned char* buffer, unsigned int length) { - return length; + switch (buffer[2U]) { + case MMDVM_GET_VERSION: + writeVersion(); + break; + case MMDVM_GET_STATUS: + writeStatus(); + break; + case MMDVM_SET_CONFIG: + case MMDVM_SET_FREQ: + case MMDVM_SET_MODE: + case MMDVM_FM_PARAMS1: + case MMDVM_FM_PARAMS2: + case MMDVM_FM_PARAMS3: + case MMDVM_FM_PARAMS4: + writeAck(buffer[2U]); + break; + default: + break; + } + + return int(length); } void CNullController::close() { } + +void CNullController::writeVersion() +{ + unsigned char reply[200U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_GET_VERSION; + + reply[3U] = PROTOCOL_VERSION; + + // Return two bytes of mode capabilities + reply[4U] = 0xFFU; + reply[5U] = 0xFFU; + + // CPU type/manufacturer. 0=Atmel ARM, 1=NXP ARM, 2=St-Micro ARM + reply[6U] = 2U; + + // Reserve 16 bytes for the UDID + ::memset(reply + 7U, 0x00U, 16U); + + uint8_t count = 23U; + for (uint8_t i = 0U; HARDWARE[i] != 0x00U; i++, count++) + reply[count] = HARDWARE[i]; + + reply[1U] = count; + + m_buffer.addData(reply, count); +} + +void CNullController::writeStatus() +{ + unsigned char reply[30U]; + + // Send all sorts of interesting internal values + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 20U; + reply[2U] = MMDVM_GET_STATUS; + + reply[3U] = 0U; + + reply[4U] = 0x00U; + + reply[5U] = 0x00U; + + reply[6U] = 20U; + + reply[7U] = 20U; + reply[8U] = 20U; + + reply[9U] = 20U; + + reply[10U] = 20U; + + reply[11U] = 20U; + + reply[12U] = 20U; + + reply[13U] = 20U; + + reply[14U] = 0x00U; + reply[15U] = 0x00U; + + reply[16U] = 20U; + + reply[17U] = 20U; + + reply[18U] = 0x00U; + reply[19U] = 0x00U; + + m_buffer.addData(reply, 20U); +} + +void CNullController::writeAck(unsigned char type) +{ + unsigned char reply[4U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 4U; + reply[2U] = MMDVM_ACK; + reply[3U] = type; + + m_buffer.addData(reply, 4U); +} diff --git a/NullController.h b/NullController.h index bbf0681..2dad99b 100644 --- a/NullController.h +++ b/NullController.h @@ -21,6 +21,8 @@ #include "ModemPort.h" +#include "RingBuffer.h" + class CNullController : public IModemPort { public: CNullController(); @@ -35,6 +37,11 @@ public: virtual void close(); private: + CRingBuffer m_buffer; + + void writeVersion(); + void writeStatus(); + void writeAck(unsigned char type); }; #endif From 95cb575a2e7a535ae3aeeb8b416e167e13655242 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 14 Mar 2021 22:54:33 +0000 Subject: [PATCH 09/23] Improve FM data tracing. --- Modem.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Modem.cpp b/Modem.cpp index 6af10d2..795302b 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -1078,8 +1078,12 @@ void CModem::clock(unsigned int ms) m_txFMData.getData((unsigned char*)&len, sizeof(unsigned int)); m_txFMData.getData(m_buffer, len); - if (m_trace) - CUtils::dump(1U, "TX FM Data", m_buffer, len); + if (m_trace) { + if (m_buffer[2U] == MMDVM_FM_CONTROL) + CUtils::dump(1U, "TX FM Control", m_buffer, len); + else + CUtils::dump(1U, "TX FM Data", m_buffer, len); + } int ret = m_port->write(m_buffer, len); if (ret != int(len)) From 629cdcfb2ac7e3168dce987d88cca75dc7d1e443 Mon Sep 17 00:00:00 2001 From: Daniel Caujolle-Bert Date: Sat, 20 Mar 2021 18:08:02 +0100 Subject: [PATCH 10/23] Unitying RemoteCommand with latest DMRGateway's RemoteControl PR. --- RemoteCommand.cpp | 21 ++++++++++++++++++++- RemoteControl.cpp | 18 +++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/RemoteCommand.cpp b/RemoteCommand.cpp index 143895c..20db947 100644 --- a/RemoteCommand.cpp +++ b/RemoteCommand.cpp @@ -22,6 +22,10 @@ #include "Log.h" #include +#include +#include + +const unsigned int BUFFER_LENGTH = 100U; int main(int argc, char** argv) { @@ -67,6 +71,9 @@ int CRemoteCommand::send(const std::string& command) { sockaddr_storage addr; unsigned int addrLen; + char buffer[BUFFER_LENGTH]; + int retStatus = 0; + if (CUDPSocket::lookup("127.0.0.1", m_port, addr, addrLen) != 0) { LogError("Unable to resolve the address of the host"); return 1; @@ -86,7 +93,19 @@ int CRemoteCommand::send(const std::string& command) LogMessage("Command sent: \"%s\" to port: %u", command.c_str(), m_port); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + int len = socket.read((unsigned char*)&buffer[0], BUFFER_LENGTH, addr, addrLen); + if (len > 0) { + buffer[len] = '\0'; + LogMessage("%s", buffer); + } + else + { + retStatus = 1; + } + socket.close(); - return 0; + return retStatus; } diff --git a/RemoteControl.cpp b/RemoteControl.cpp index b42718f..5274829 100644 --- a/RemoteControl.cpp +++ b/RemoteControl.cpp @@ -55,7 +55,8 @@ REMOTE_COMMAND CRemoteControl::getCommand() m_args.clear(); char command[BUFFER_LENGTH]; - char buffer[BUFFER_LENGTH]; + char buffer[BUFFER_LENGTH * 2]; + std::string replyStr = "OK"; sockaddr_storage address; unsigned int addrlen; int ret = m_socket.read((unsigned char*)buffer, BUFFER_LENGTH, address, addrlen); @@ -89,6 +90,8 @@ REMOTE_COMMAND CRemoteControl::getCommand() m_command = RCD_MODE_P25; else if (m_args.at(1U) == "nxdn") m_command = RCD_MODE_NXDN; + else + replyStr = "KO"; } else if (m_args.at(0U) == "enable" && m_args.size() >= ENABLE_ARGS) { if (m_args.at(1U) == "dstar") m_command = RCD_ENABLE_DSTAR; @@ -102,6 +105,8 @@ REMOTE_COMMAND CRemoteControl::getCommand() m_command = RCD_ENABLE_NXDN; else if (m_args.at(1U) == "fm") m_command = RCD_ENABLE_FM; + else + replyStr = "KO"; } else if (m_args.at(0U) == "disable" && m_args.size() >= DISABLE_ARGS) { if (m_args.at(1U) == "dstar") m_command = RCD_DISABLE_DSTAR; @@ -115,6 +120,8 @@ REMOTE_COMMAND CRemoteControl::getCommand() m_command = RCD_DISABLE_NXDN; else if (m_args.at(1U) == "fm") m_command = RCD_DISABLE_FM; + else + replyStr = "KO"; } else if (m_args.at(0U) == "page" && m_args.size() >= PAGE_ARGS) { // Page command is in the form of "page " m_command = RCD_PAGE; @@ -125,13 +132,18 @@ REMOTE_COMMAND CRemoteControl::getCommand() // Reload command is in the form of "reload" m_command = RCD_RELOAD; } + else + replyStr = "KO"; + ::snprintf(buffer, BUFFER_LENGTH * 2, "%s remote command of \"%s\" received", ((m_command == RCD_NONE) ? "Invalid" : "Valid"), command); if (m_command == RCD_NONE) { m_args.clear(); - LogWarning("Invalid remote command of \"%s\" received", command); + LogWarning(buffer); } else { - LogMessage("Valid remote command of \"%s\" received", command); + LogMessage(buffer); } + + m_socket.write((unsigned char*)replyStr.c_str(), replyStr.length(), address, addrlen); } return m_command; From 27b7d3fc4147af66bc007b8d87c2a122cf31fda5 Mon Sep 17 00:00:00 2001 From: Daniel Caujolle-Bert Date: Mon, 22 Mar 2021 20:27:08 +0100 Subject: [PATCH 11/23] Add RemoteCommand 'status' command. As DMRGateway, it reports connection status. Command sent: "status" to port: 7642 dstar:n/a dmr:conn ysf:n/a p25:n/a nxdn:n/a fm:n/a RemoveCommand has been slighlty modified, as using Log on a read-only filesystem simply forbids the strings to be displayed. Another solution would be to set LogInitialisse's filePath to "/tmp/" for *nix systems. --- DMRDirectNetwork.cpp | 5 +++++ DMRDirectNetwork.h | 2 ++ DMRGatewayNetwork.cpp | 5 +++++ DMRGatewayNetwork.h | 2 ++ DMRNetwork.h | 2 ++ DStarNetwork.cpp | 5 +++++ DStarNetwork.h | 2 ++ MMDVMHost.cpp | 13 ++++++++++++- MMDVMHost.h | 2 ++ NXDNIcomNetwork.cpp | 5 +++++ NXDNIcomNetwork.h | 2 ++ NXDNKenwoodNetwork.cpp | 5 +++++ NXDNKenwoodNetwork.h | 2 ++ NXDNNetwork.h | 2 ++ P25Network.cpp | 5 +++++ P25Network.h | 2 ++ RemoteCommand.cpp | 8 ++++---- RemoteControl.cpp | 15 +++++++++++++-- RemoteControl.h | 8 ++++++-- YSFNetwork.cpp | 5 +++++ YSFNetwork.h | 2 ++ 21 files changed, 90 insertions(+), 9 deletions(-) diff --git a/DMRDirectNetwork.cpp b/DMRDirectNetwork.cpp index 4ed871c..a378f7a 100644 --- a/DMRDirectNetwork.cpp +++ b/DMRDirectNetwork.cpp @@ -316,6 +316,11 @@ bool CDMRDirectNetwork::writeTalkerAlias(unsigned int id, unsigned char type, co return write(buffer, 15U); } +bool CDMRDirectNetwork::isConnected() const +{ + return (m_status == RUNNING); +} + void CDMRDirectNetwork::close() { LogMessage("Closing DMR Network"); diff --git a/DMRDirectNetwork.h b/DMRDirectNetwork.h index 30ba951..f6e0834 100644 --- a/DMRDirectNetwork.h +++ b/DMRDirectNetwork.h @@ -55,6 +55,8 @@ public: virtual void clock(unsigned int ms); + virtual bool isConnected() const; + virtual void close(); private: diff --git a/DMRGatewayNetwork.cpp b/DMRGatewayNetwork.cpp index 5150d77..dd86e76 100644 --- a/DMRGatewayNetwork.cpp +++ b/DMRGatewayNetwork.cpp @@ -287,6 +287,11 @@ bool CDMRGatewayNetwork::writeTalkerAlias(unsigned int id, unsigned char type, c return write(buffer, 15U); } +bool CDMRGatewayNetwork::isConnected() const +{ + return (m_enabled && (m_addrLen != 0)); +} + void CDMRGatewayNetwork::close() { LogMessage("DMR, Closing DMR Network"); diff --git a/DMRGatewayNetwork.h b/DMRGatewayNetwork.h index 55afc72..bc00385 100644 --- a/DMRGatewayNetwork.h +++ b/DMRGatewayNetwork.h @@ -56,6 +56,8 @@ public: virtual void clock(unsigned int ms); + virtual bool isConnected() const; + virtual void close(); private: diff --git a/DMRNetwork.h b/DMRNetwork.h index 69d3926..4a3c4d7 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -48,6 +48,8 @@ public: virtual void clock(unsigned int ms) = 0; + virtual bool isConnected() const = 0; + virtual void close() = 0; private: diff --git a/DStarNetwork.cpp b/DStarNetwork.cpp index 21bbc9d..4a978e2 100644 --- a/DStarNetwork.cpp +++ b/DStarNetwork.cpp @@ -314,6 +314,11 @@ void CDStarNetwork::reset() m_inId = 0U; } +bool CDStarNetwork::isConnected() const +{ + return (m_enabled && (m_addrLen != 0)); +} + void CDStarNetwork::close() { m_socket.close(); diff --git a/DStarNetwork.h b/DStarNetwork.h index 1e0d5f0..cb41b78 100644 --- a/DStarNetwork.h +++ b/DStarNetwork.h @@ -46,6 +46,8 @@ public: void reset(); + bool isConnected() const; + void close(); void clock(unsigned int ms); diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 2d76284..8409aac 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -635,7 +635,7 @@ int CMMDVMHost::run() LogInfo(" Address: %s", address.c_str()); LogInfo(" Port: %u", port); - m_remoteControl = new CRemoteControl(address, port); + m_remoteControl = new CRemoteControl(this, address, port); ret = m_remoteControl->open(); if (!ret) { @@ -2140,3 +2140,14 @@ void CMMDVMHost::processEnableCommand(bool& mode, bool enabled) if (!m_modem->writeConfig()) LogError("Cannot write Config to MMDVM"); } + +void CMMDVMHost::buildNetworkStatusString(std::string &str) +{ + str = ""; + str += std::string("dstar:") + (((m_dstarNetwork == NULL) || (m_dstarEnabled == false)) ? "n/a" : (m_dstarNetwork->isConnected() ? "conn" : "disc")); + str += std::string(" dmr:") + (((m_dmrNetwork == NULL) || (m_dmrEnabled == false)) ? "n/a" : (m_dmrNetwork->isConnected() ? "conn" : "disc")); + str += std::string(" ysf:") + (((m_ysfNetwork == NULL) || (m_ysfEnabled == false)) ? "n/a" : (m_ysfNetwork->isConnected() ? "conn" : "disc")); + str += std::string(" p25:") + (((m_p25Network == NULL) || (m_p25Enabled == false)) ? "n/a" : (m_p25Network->isConnected() ? "conn" : "disc")); + str += std::string(" nxdn:") + (((m_nxdnNetwork == NULL) || (m_nxdnEnabled == false)) ? "n/a" : (m_nxdnNetwork->isConnected() ? "conn" : "disc")); + str += std::string(" fm:") + (m_fmEnabled ? "conn" : "n/a"); +} diff --git a/MMDVMHost.h b/MMDVMHost.h index 735952a..dd8ccf4 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -51,6 +51,8 @@ public: int run(); + void buildNetworkStatusString(std::string &str); + private: CConf m_conf; CModem* m_modem; diff --git a/NXDNIcomNetwork.cpp b/NXDNIcomNetwork.cpp index b13ca2a..5f20b37 100644 --- a/NXDNIcomNetwork.cpp +++ b/NXDNIcomNetwork.cpp @@ -153,6 +153,11 @@ void CNXDNIcomNetwork::reset() { } +bool CNXDNIcomNetwork::isConnected() const +{ + return (m_enabled && (m_addrLen != 0)); +} + void CNXDNIcomNetwork::close() { m_socket.close(); diff --git a/NXDNIcomNetwork.h b/NXDNIcomNetwork.h index 3113a9f..9f74710 100644 --- a/NXDNIcomNetwork.h +++ b/NXDNIcomNetwork.h @@ -43,6 +43,8 @@ public: virtual void reset(); + virtual bool isConnected() const; + virtual void close(); virtual void clock(unsigned int ms); diff --git a/NXDNKenwoodNetwork.cpp b/NXDNKenwoodNetwork.cpp index 67de39b..3866133 100644 --- a/NXDNKenwoodNetwork.cpp +++ b/NXDNKenwoodNetwork.cpp @@ -835,6 +835,11 @@ void CNXDNKenwoodNetwork::reset() m_seen4 = false; } +bool CNXDNKenwoodNetwork::isConnected() const +{ + return (m_enabled && (m_rtcpAddrLen != 0U) && (m_rtpAddrLen != 0U)); +} + void CNXDNKenwoodNetwork::close() { m_rtcpSocket.close(); diff --git a/NXDNKenwoodNetwork.h b/NXDNKenwoodNetwork.h index af28618..dc7bf1d 100644 --- a/NXDNKenwoodNetwork.h +++ b/NXDNKenwoodNetwork.h @@ -42,6 +42,8 @@ public: virtual void reset(); + virtual bool isConnected() const; + virtual void close(); virtual void clock(unsigned int ms); diff --git a/NXDNNetwork.h b/NXDNNetwork.h index 564196b..107e02f 100644 --- a/NXDNNetwork.h +++ b/NXDNNetwork.h @@ -46,6 +46,8 @@ public: virtual void reset() = 0; + virtual bool isConnected() const = 0; + virtual void close() = 0; virtual void clock(unsigned int ms) = 0; diff --git a/P25Network.cpp b/P25Network.cpp index 3bb39b9..2734373 100644 --- a/P25Network.cpp +++ b/P25Network.cpp @@ -424,6 +424,11 @@ unsigned int CP25Network::read(unsigned char* data, unsigned int length) return c; } +bool CP25Network::isConnected() const +{ + return (m_enabled && (m_addrLen != 0)); +} + void CP25Network::close() { m_socket.close(); diff --git a/P25Network.h b/P25Network.h index 4c52761..6b8407c 100644 --- a/P25Network.h +++ b/P25Network.h @@ -43,6 +43,8 @@ public: unsigned int read(unsigned char* data, unsigned int length); + bool isConnected() const; + void close(); void clock(unsigned int ms); diff --git a/RemoteCommand.cpp b/RemoteCommand.cpp index 20db947..c893d79 100644 --- a/RemoteCommand.cpp +++ b/RemoteCommand.cpp @@ -75,7 +75,7 @@ int CRemoteCommand::send(const std::string& command) int retStatus = 0; if (CUDPSocket::lookup("127.0.0.1", m_port, addr, addrLen) != 0) { - LogError("Unable to resolve the address of the host"); + ::fprintf(stderr, "Unable to resolve the address of the host\n"); return 1; } @@ -91,14 +91,14 @@ int CRemoteCommand::send(const std::string& command) return 1; } - LogMessage("Command sent: \"%s\" to port: %u", command.c_str(), m_port); + ::fprintf(stdout, "Command sent: \"%s\" to port: %u\n", command.c_str(), m_port); std::this_thread::sleep_for(std::chrono::milliseconds(50)); - int len = socket.read((unsigned char*)&buffer[0], BUFFER_LENGTH, addr, addrLen); + int len = socket.read((unsigned char*)buffer, BUFFER_LENGTH, addr, addrLen); if (len > 0) { buffer[len] = '\0'; - LogMessage("%s", buffer); + ::fprintf(stdout, "%s\n", buffer); } else { diff --git a/RemoteControl.cpp b/RemoteControl.cpp index 5274829..a195d35 100644 --- a/RemoteControl.cpp +++ b/RemoteControl.cpp @@ -17,6 +17,7 @@ */ #include "RemoteControl.h" +#include "MMDVMHost.h" #include "Log.h" #include @@ -32,7 +33,8 @@ const unsigned int CW_ARGS = 2U; const unsigned int BUFFER_LENGTH = 100U; -CRemoteControl::CRemoteControl(const std::string address, unsigned int port) : +CRemoteControl::CRemoteControl(CMMDVMHost *host, const std::string address, unsigned int port) : +m_host(host), m_socket(address, port), m_command(RCD_NONE), m_args() @@ -131,7 +133,16 @@ REMOTE_COMMAND CRemoteControl::getCommand() } else if (m_args.at(0U) == "reload") { // Reload command is in the form of "reload" m_command = RCD_RELOAD; - } + } else if (m_args.at(0U) == "status") { + if (m_host != NULL) { + m_host->buildNetworkStatusString(replyStr); + } + else { + replyStr = "KO"; + } + + m_command = RCD_CONNECTION_STATUS; + } else replyStr = "KO"; diff --git a/RemoteControl.h b/RemoteControl.h index 3f07f03..addbb3e 100644 --- a/RemoteControl.h +++ b/RemoteControl.h @@ -24,6 +24,8 @@ #include #include +class CMMDVMHost; + enum REMOTE_COMMAND { RCD_NONE, RCD_MODE_IDLE, @@ -48,12 +50,13 @@ enum REMOTE_COMMAND { RCD_DISABLE_FM, RCD_PAGE, RCD_CW, - RCD_RELOAD + RCD_RELOAD, + RCD_CONNECTION_STATUS }; class CRemoteControl { public: - CRemoteControl(const std::string address, unsigned int port); + CRemoteControl(class CMMDVMHost *host, const std::string address, unsigned int port); ~CRemoteControl(); bool open(); @@ -69,6 +72,7 @@ public: void close(); private: + CMMDVMHost* m_host; CUDPSocket m_socket; REMOTE_COMMAND m_command; std::vector m_args; diff --git a/YSFNetwork.cpp b/YSFNetwork.cpp index 089a932..451d3af 100644 --- a/YSFNetwork.cpp +++ b/YSFNetwork.cpp @@ -183,6 +183,11 @@ void CYSFNetwork::reset() ::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH); } +bool CYSFNetwork::isConnected() const +{ + return (m_enabled && (m_addrLen != 0)); +} + void CYSFNetwork::close() { m_socket.close(); diff --git a/YSFNetwork.h b/YSFNetwork.h index aef43d3..3fd7c56 100644 --- a/YSFNetwork.h +++ b/YSFNetwork.h @@ -42,6 +42,8 @@ public: void reset(); + bool isConnected() const; + void close(); void clock(unsigned int ms); From b5420fef155c35bca1987ddb7175d55604b25671 Mon Sep 17 00:00:00 2001 From: Daniel Caujolle-Bert Date: Tue, 23 Mar 2021 22:32:36 +0100 Subject: [PATCH 12/23] Fix *Network::isConnected(). As m_enabled is changed accordingly to the modem current mode, it's not valid to use it for network connexion status. --- DMRGatewayNetwork.cpp | 2 +- DStarNetwork.cpp | 2 +- NXDNIcomNetwork.cpp | 2 +- NXDNKenwoodNetwork.cpp | 2 +- P25Network.cpp | 2 +- YSFNetwork.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DMRGatewayNetwork.cpp b/DMRGatewayNetwork.cpp index dd86e76..775a79d 100644 --- a/DMRGatewayNetwork.cpp +++ b/DMRGatewayNetwork.cpp @@ -289,7 +289,7 @@ bool CDMRGatewayNetwork::writeTalkerAlias(unsigned int id, unsigned char type, c bool CDMRGatewayNetwork::isConnected() const { - return (m_enabled && (m_addrLen != 0)); + return (m_addrLen != 0); } void CDMRGatewayNetwork::close() diff --git a/DStarNetwork.cpp b/DStarNetwork.cpp index 4a978e2..c702cfa 100644 --- a/DStarNetwork.cpp +++ b/DStarNetwork.cpp @@ -316,7 +316,7 @@ void CDStarNetwork::reset() bool CDStarNetwork::isConnected() const { - return (m_enabled && (m_addrLen != 0)); + return (m_addrLen != 0); } void CDStarNetwork::close() diff --git a/NXDNIcomNetwork.cpp b/NXDNIcomNetwork.cpp index 5f20b37..730f445 100644 --- a/NXDNIcomNetwork.cpp +++ b/NXDNIcomNetwork.cpp @@ -155,7 +155,7 @@ void CNXDNIcomNetwork::reset() bool CNXDNIcomNetwork::isConnected() const { - return (m_enabled && (m_addrLen != 0)); + return (m_addrLen != 0); } void CNXDNIcomNetwork::close() diff --git a/NXDNKenwoodNetwork.cpp b/NXDNKenwoodNetwork.cpp index 3866133..bed3316 100644 --- a/NXDNKenwoodNetwork.cpp +++ b/NXDNKenwoodNetwork.cpp @@ -837,7 +837,7 @@ void CNXDNKenwoodNetwork::reset() bool CNXDNKenwoodNetwork::isConnected() const { - return (m_enabled && (m_rtcpAddrLen != 0U) && (m_rtpAddrLen != 0U)); + return ((m_rtcpAddrLen != 0U) && (m_rtpAddrLen != 0U)); } void CNXDNKenwoodNetwork::close() diff --git a/P25Network.cpp b/P25Network.cpp index 2734373..77a9a7d 100644 --- a/P25Network.cpp +++ b/P25Network.cpp @@ -426,7 +426,7 @@ unsigned int CP25Network::read(unsigned char* data, unsigned int length) bool CP25Network::isConnected() const { - return (m_enabled && (m_addrLen != 0)); + return (m_addrLen != 0); } void CP25Network::close() diff --git a/YSFNetwork.cpp b/YSFNetwork.cpp index 451d3af..3fc5eb6 100644 --- a/YSFNetwork.cpp +++ b/YSFNetwork.cpp @@ -185,7 +185,7 @@ void CYSFNetwork::reset() bool CYSFNetwork::isConnected() const { - return (m_enabled && (m_addrLen != 0)); + return (m_addrLen != 0); } void CYSFNetwork::close() From dbf771d80c51c3469a9275de9afbc3346d119ebf Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 25 Mar 2021 21:07:44 +0000 Subject: [PATCH 13/23] Fixed M17 to be compatible with the latest protocol speciication. --- Conf.cpp | 10 +- Conf.h | 4 +- M17CRC.cpp | 2 +- M17Control.cpp | 396 ++++++++++++++++++++------------------ M17Control.h | 19 +- M17Convolution.cpp | 2 +- M17Convolution.h | 2 +- M17Defines.h | 25 ++- M17LICH.cpp | 143 -------------- M17LSF.cpp | 193 +++++++++++++++++++ M17LICH.h => M17LSF.h | 26 ++- M17Network.cpp | 2 +- M17Network.h | 2 +- M17Utils.cpp | 15 +- MMDVM.ini | 2 +- MMDVMHost.cpp | 6 +- MMDVMHost.vcxproj | 4 +- MMDVMHost.vcxproj.filters | 4 +- Makefile | 2 +- Makefile.Pi | 2 +- Makefile.Pi.Adafruit | 2 +- Makefile.Pi.HD44780 | 2 +- Makefile.Pi.OLED | 2 +- Makefile.Pi.PCF8574 | 2 +- Version.h | 2 +- 25 files changed, 481 insertions(+), 390 deletions(-) delete mode 100644 M17LICH.cpp create mode 100644 M17LSF.cpp rename M17LICH.h => M17LSF.h (73%) diff --git a/Conf.cpp b/Conf.cpp index 83d22f4..dcc9bc4 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -182,7 +182,7 @@ m_nxdnRemoteGateway(false), m_nxdnTXHang(5U), m_nxdnModeHang(10U), m_m17Enabled(false), -m_m17ColorCode(1U), +m_m17CAN(0U), m_m17SelfOnly(false), m_m17AllowEncryption(false), m_m17TXHang(5U), @@ -779,8 +779,8 @@ bool CConf::read() } else if (section == SECTION_M17) { if (::strcmp(key, "Enable") == 0) m_m17Enabled = ::atoi(value) == 1; - else if (::strcmp(key, "ColorCode") == 0) - m_m17ColorCode = (unsigned int)::atoi(value); + else if (::strcmp(key, "CAN") == 0) + m_m17CAN = (unsigned int)::atoi(value); else if (::strcmp(key, "SelfOnly") == 0) m_m17SelfOnly = ::atoi(value) == 1; else if (::strcmp(key, "AllowEncryption") == 0) @@ -1707,9 +1707,9 @@ bool CConf::getM17Enabled() const return m_m17Enabled; } -unsigned int CConf::getM17ColorCode() const +unsigned int CConf::getM17CAN() const { - return m_m17ColorCode; + return m_m17CAN; } bool CConf::getM17SelfOnly() const diff --git a/Conf.h b/Conf.h index aad1155..dc31ef5 100644 --- a/Conf.h +++ b/Conf.h @@ -173,7 +173,7 @@ public: // The M17 section bool getM17Enabled() const; - unsigned int getM17ColorCode() const; + unsigned int getM17CAN() const; bool getM17SelfOnly() const; bool getM17AllowEncryption() const; unsigned int getM17TXHang() const; @@ -496,7 +496,7 @@ private: unsigned int m_nxdnModeHang; bool m_m17Enabled; - unsigned int m_m17ColorCode; + unsigned int m_m17CAN; bool m_m17SelfOnly; bool m_m17AllowEncryption; unsigned int m_m17TXHang; diff --git a/M17CRC.cpp b/M17CRC.cpp index 7ba4da6..cd41697 100644 --- a/M17CRC.cpp +++ b/M17CRC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Jonathan Naylor G4KLX * * 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 diff --git a/M17Control.cpp b/M17Control.cpp index a36d0eb..5ab306e 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 Jonathan Naylor, G4KLX + * Copyright (C) 2020,2021 Jonathan Naylor, G4KLX * * 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 @@ -57,9 +57,9 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04 #define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) #define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) -CM17Control::CM17Control(const std::string& callsign, unsigned int colorCode, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) : +CM17Control::CM17Control(const std::string& callsign, unsigned int can, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) : m_callsign(callsign), -m_colorCode(colorCode), +m_can(can), m_selfOnly(selfOnly), m_allowEncryption(allowEncryption), m_network(network), @@ -78,10 +78,10 @@ m_netFrames(0U), m_rfFN(0U), m_rfErrs(0U), m_rfBits(1U), -m_rfLICH(), -m_rfLICHn(0U), -m_netLICH(), -m_netLICHn(0U), +m_rfLSF(), +m_rfLSFn(0U), +m_netLSF(), +m_netLSFn(0U), m_rssiMapper(rssiMapper), m_rssi(0U), m_maxRSSI(0U), @@ -109,8 +109,8 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char type = data[0U]; if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) { - std::string source = m_rfLICH.getSource(); - std::string dest = m_rfLICH.getDest(); + std::string source = m_rfLSF.getSource(); + std::string dest = m_rfLSF.getDest(); if (m_rssi != 0U) LogMessage("M17, transmission lost from %s to %s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", source.c_str(), dest.c_str(), float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); @@ -125,6 +125,11 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) return false; } + if (type == TAG_LOST && m_rfState == RS_RF_REJECTED) { + writeEndRF(); + return false; + } + if (type == TAG_LOST) { m_rfState = RS_RF_LISTENING; return false; @@ -158,14 +163,22 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) interleaver(temp, data + 2U); if (m_rfState == RS_RF_LISTENING && data[0U] == TAG_HEADER) { - m_rfLICH.reset(); + m_rfLSF.reset(); CM17Convolution conv; - unsigned char frame[M17_LICH_LENGTH_BYTES]; + unsigned char frame[M17_LSF_LENGTH_BYTES]; conv.decodeLinkSetup(data + 2U + M17_SYNC_LENGTH_BYTES, frame); - bool valid = CM17CRC::checkCRC(frame, M17_LICH_LENGTH_BYTES); + bool valid = CM17CRC::checkCRC(frame, M17_LSF_LENGTH_BYTES); if (valid) { + m_rfLSF.setLinkSetup(frame); + + bool ret = processRFHeader(false); + if (!ret) { + m_rfLSF.reset(); + return false; + } + m_rfFrames = 0U; m_rfErrs = 0U; m_rfBits = 1U; @@ -174,22 +187,23 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) m_maxRSSI = m_rssi; m_aveRSSI = m_rssi; m_rssiCount = 1U; - m_rfLICHn = 0U; + m_rfLSFn = 0U; m_rfFN = 0U; #if defined(DUMP_M17) openFile(); #endif - m_rfLICH.setLinkSetup(frame); - - m_rfState = RS_RF_LATE_ENTRY; - return true; } else { m_rfState = RS_RF_LATE_ENTRY; } } + if (m_rfState == RS_RF_LISTENING && data[0U] == TAG_DATA) { + m_rfState = RS_RF_LATE_ENTRY; + m_rfLSF.reset(); + } + if (m_rfState == RS_RF_LATE_ENTRY && data[0U] == TAG_DATA) { unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICHFEC(data + 2U + M17_SYNC_LENGTH_BYTES, frag1, frag2, frag3, frag4); @@ -199,23 +213,24 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned int lich3 = CGolay24128::decode24128(frag3); unsigned int lich4 = CGolay24128::decode24128(frag4); - unsigned int colorCode = (lich4 >> 7) & 0x1FU; - if (colorCode != m_colorCode) + unsigned int can = lich4 & 0x1FU; + if (can != m_can) return false; - bool lateEntry = false; - if (!m_rfLICH.isValid()) { - unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; - CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); + unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; + CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); - unsigned int n = (lich4 >> 4) & 0x07U; - m_rfLICH.setFragment(lich, n); + m_rfLSFn = (lich4 >> 5) & 0x07U; + m_rfLSF.setFragment(lich, m_rfLSFn); - lateEntry = true; - } - - bool valid = m_rfLICH.isValid(); + bool valid = m_rfLSF.isValid(); if (valid) { + bool ret = processRFHeader(true); + if (!ret) { + m_rfLSF.reset(); + return false; + } + m_rfFrames = 0U; m_rfErrs = 0U; m_rfBits = 1U; @@ -224,68 +239,13 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) m_maxRSSI = m_rssi; m_aveRSSI = m_rssi; m_rssiCount = 1U; - m_rfLICHn = 0U; #if defined(DUMP_M17) openFile(); #endif - std::string source = m_rfLICH.getSource(); - std::string dest = m_rfLICH.getDest(); - - if (m_selfOnly) { - bool ret = checkCallsign(source); - if (!ret) { - LogMessage("M17, invalid access attempt from %s to %s", source.c_str(), dest.c_str()); - m_rfState = RS_RF_REJECTED; - return false; - } - } - - unsigned char dataType = m_rfLICH.getDataType(); - switch (dataType) { - case 1U: - LogMessage("M17, received RF %s data transmission from %s to %s", lateEntry ? "late entry" : "", source.c_str(), dest.c_str()); - m_rfState = RS_RF_DATA; - break; - case 2U: - LogMessage("M17, received RF %s voice transmission from %s to %s", lateEntry ? "late entry" : "", source.c_str(), dest.c_str()); - m_rfState = RS_RF_AUDIO; - break; - case 3U: - LogMessage("M17, received RF %s voice + data transmission from %s to %s", lateEntry ? "late entry" : "", source.c_str(), dest.c_str()); - m_rfState = RS_RF_AUDIO; - break; - default: - LogMessage("M17, received RF %s unknown transmission from %s to %s", lateEntry ? "late entry" : "", source.c_str(), dest.c_str()); - m_rfState = RS_RF_DATA; - break; - } - - m_display->writeM17(source.c_str(), dest.c_str(), "R"); - - if (m_duplex) { - // Create a Link Setup frame - data[0U] = TAG_HEADER; - data[1U] = 0x00U; - - // Generate the sync - CSync::addM17LinkSetupSync(data + 2U); - - unsigned char setup[M17_LICH_LENGTH_BYTES]; - m_rfLICH.getLinkSetup(setup); - - // Add the convolution FEC - CM17Convolution conv; - conv.encodeLinkSetup(setup, data + 2U + M17_SYNC_LENGTH_BYTES); - - unsigned char temp[M17_FRAME_LENGTH_BYTES]; - interleaver(data + 2U, temp); - decorrelator(temp, data + 2U); - - writeQueueRF(data); - } - - // Fall through to the next section + // Fall through + } else { + return false; } } @@ -309,13 +269,13 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) frame[1U] = m_rfFN >> 0; // Add silent audio - unsigned char dataType = m_rfLICH.getDataType(); + unsigned char dataType = m_rfLSF.getDataType(); switch (dataType) { - case 2U: + case M17_DATA_TYPE_VOICE: ::memcpy(frame + M17_FN_LENGTH_BYTES + 0U, M17_3200_SILENCE, 8U); ::memcpy(frame + M17_FN_LENGTH_BYTES + 8U, M17_3200_SILENCE, 8U); break; - case 3U: + case M17_DATA_TYPE_VOICE_DATA: ::memcpy(frame + M17_FN_LENGTH_BYTES + 0U, M17_1600_SILENCE, 8U); break; default: @@ -335,14 +295,14 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) CSync::addM17StreamSync(rfData + 2U); unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; - m_netLICH.getFragment(lich, m_rfLICHn); + m_rfLSF.getFragment(lich, m_rfLSFn); unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); - // Add the Color Code and fragment number - frag4 |= (m_rfLICHn & 0x07U) << 4; - frag4 |= (m_colorCode & 0x1FU) << 7; + // Add the CAN and fragment number + frag4 |= (m_rfLSFn & 0x07U) << 5; + frag4 |= m_can & 0x1FU; // Add Golay to the LICH fragment here unsigned int lich1 = CGolay24128::encode24128(frag1); @@ -361,7 +321,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) for (unsigned int i = 2U; i < (M17_FRAME_LENGTH_BYTES + 2U); i++) errors += countBits(rfData[i] ^ data[i]); - LogDebug("M17, FN: %u, errs: %u/384 (%.1f%%)", m_rfFN, errors, float(errors) / 3.84F); + LogDebug("M17, FN: %u, errs: %u/384 (%.1f%%)", m_rfFN & 0x7FU, errors, float(errors) / 3.84F); m_rfBits += M17_FRAME_LENGTH_BITS; m_rfErrs += errors; @@ -372,32 +332,34 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char temp[M17_FRAME_LENGTH_BYTES]; interleaver(rfData + 2U, temp); - decorrelator(rfData, data + 2U); + decorrelator(temp, rfData + 2U); if (m_duplex) writeQueueRF(rfData); - unsigned char netData[M17_LICH_LENGTH_BYTES + M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES]; + if (m_network != NULL && m_rfTimeoutTimer.isRunning() && !m_rfTimeoutTimer.hasExpired()) { + unsigned char netData[M17_LSF_LENGTH_BYTES + M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES]; - m_rfLICH.getNetwork(netData + 0U); + m_rfLSF.getNetwork(netData + 0U); - // Copy the FN and payload from the frame - ::memcpy(netData + M17_LICH_LENGTH_BYTES - M17_CRC_LENGTH_BYTES, frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES); + // Copy the FN and payload from the frame + ::memcpy(netData + M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES, frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES); - // The CRC is added in the networking code + // The CRC is added in the networking code - writeNetwork(netData); + m_network->write(netData); + } m_rfFrames++; - m_rfLICHn++; - if (m_rfLICHn >= 6U) - m_rfLICHn = 0U; + m_rfLSFn++; + if (m_rfLSFn >= 6U) + m_rfLSFn = 0U; // EOT? if ((m_rfFN & 0x8000U) == 0x8000U) { - std::string source = m_rfLICH.getSource(); - std::string dest = m_rfLICH.getDest(); + std::string source = m_rfLSF.getSource(); + std::string dest = m_rfLSF.getDest(); if (m_rssi != 0U) LogMessage("M17, received RF end of transmission from %s to %s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", source.c_str(), dest.c_str(), float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); @@ -409,22 +371,6 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) return true; } - if (m_rfState == RS_RF_REJECTED && data[0U] == TAG_DATA) { - CM17Convolution conv; - unsigned char frame[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES]; - conv.decodeData(data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES, frame); - - bool valid = CM17CRC::checkCRC(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); - if (valid) { - // Handle the EOT for rejected frames - unsigned int fn = (frame[0U] << 8) + (frame[1U] << 0); - if ((fn & 0x8000U) == 0x8000U) - writeEndRF(); - } - - return false; - } - return false; } @@ -449,7 +395,7 @@ void CM17Control::writeEndRF() m_rfTimeoutTimer.stop(); - m_rfLICH.reset(); + m_rfLSF.reset(); if (m_netState == RS_NET_IDLE) { m_display->clearM17(); @@ -471,7 +417,7 @@ void CM17Control::writeEndNet() m_networkWatchdog.stop(); m_packetTimer.stop(); - m_netLICH.reset(); + m_netLSF.reset(); m_display->clearM17(); @@ -494,29 +440,30 @@ void CM17Control::writeNetwork() m_networkWatchdog.start(); - m_netLICH.setNetwork(netData); + m_netLSF.setNetwork(netData); + m_netLSF.setCAN(m_can); if (!m_allowEncryption) { - bool ret = m_rfLICH.isNONCENull(); - if (!ret) + unsigned char type = m_netLSF.getEncryptionType(); + if (type != M17_ENCRYPTION_TYPE_NONE) return; } if (m_netState == RS_NET_IDLE) { - std::string source = m_netLICH.getSource(); - std::string dest = m_netLICH.getDest(); + std::string source = m_netLSF.getSource(); + std::string dest = m_netLSF.getDest(); - unsigned char dataType = m_netLICH.getDataType(); + unsigned char dataType = m_netLSF.getDataType(); switch (dataType) { - case 1U: + case M17_DATA_TYPE_DATA: LogMessage("M17, received network data transmission from %s to %s", source.c_str(), dest.c_str()); m_netState = RS_NET_DATA; break; - case 2U: + case M17_DATA_TYPE_VOICE: LogMessage("M17, received network voice transmission from %s to %s", source.c_str(), dest.c_str()); m_netState = RS_NET_AUDIO; break; - case 3U: + case M17_DATA_TYPE_VOICE_DATA: LogMessage("M17, received network voice + data transmission from %s to %s", source.c_str(), dest.c_str()); m_netState = RS_NET_AUDIO; break; @@ -532,7 +479,7 @@ void CM17Control::writeNetwork() m_packetTimer.start(); m_elapsed.start(); m_netFrames = 0U; - m_netLICHn = 0U; + m_netLSFn = 0U; // Create a dummy start message unsigned char start[M17_FRAME_LENGTH_BYTES + 2U]; @@ -543,8 +490,8 @@ void CM17Control::writeNetwork() // Generate the sync CSync::addM17LinkSetupSync(start + 2U); - unsigned char setup[M17_LICH_LENGTH_BYTES]; - m_netLICH.getLinkSetup(setup); + unsigned char setup[M17_LSF_LENGTH_BYTES]; + m_netLSF.getLinkSetup(setup); // Add the convolution FEC CM17Convolution conv; @@ -557,66 +504,144 @@ void CM17Control::writeNetwork() writeQueueNet(start); } - unsigned char data[M17_FRAME_LENGTH_BYTES + 2U]; + if (m_netState == RS_NET_AUDIO) { + unsigned char data[M17_FRAME_LENGTH_BYTES + 2U]; - data[0U] = TAG_DATA; - data[1U] = 0x00U; + data[0U] = TAG_DATA; + data[1U] = 0x00U; - // Generate the sync - CSync::addM17StreamSync(data + 2U); + // Generate the sync + CSync::addM17StreamSync(data + 2U); - m_netFrames++; + m_netFrames++; - // Add the fragment LICH - unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; - m_netLICH.getFragment(lich, m_netLICHn); + // Add the fragment LICH + unsigned char lich[M17_LSF_FRAGMENT_LENGTH_BYTES]; + m_netLSF.getFragment(lich, m_netLSFn); - unsigned int frag1, frag2, frag3, frag4; - CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); + unsigned int frag1, frag2, frag3, frag4; + CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); - // Add the Color Code and fragment number - frag4 |= (m_netLICHn & 0x07U) << 4; - frag4 |= (m_colorCode & 0x1FU) << 7; + // Add the Color Code and fragment number + frag4 |= (m_netLSFn & 0x07U) << 4; + frag4 |= (m_can & 0x1FU) << 7; - // Add Golay to the LICH fragment here - unsigned int lich1 = CGolay24128::encode24128(frag1); - unsigned int lich2 = CGolay24128::encode24128(frag2); - unsigned int lich3 = CGolay24128::encode24128(frag3); - unsigned int lich4 = CGolay24128::encode24128(frag4); + // Add Golay to the LICH fragment here + unsigned int lich1 = CGolay24128::encode24128(frag1); + unsigned int lich2 = CGolay24128::encode24128(frag2); + unsigned int lich3 = CGolay24128::encode24128(frag3); + unsigned int lich4 = CGolay24128::encode24128(frag4); - CM17Utils::combineFragmentLICHFEC(lich1, lich2, lich3, lich4, data + 2U + M17_SYNC_LENGTH_BYTES); + CM17Utils::combineFragmentLICHFEC(lich1, lich2, lich3, lich4, data + 2U + M17_SYNC_LENGTH_BYTES); - // Add the FN and the data/audio - unsigned char payload[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES]; - ::memcpy(payload, netData + 28U, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES); + // Add the FN and the data/audio + unsigned char payload[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES]; + ::memcpy(payload, netData + 28U, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES); - // Add the CRC - CM17CRC::encodeCRC(payload, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); + // Add the CRC + CM17CRC::encodeCRC(payload, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); - // Add the Convolution FEC - CM17Convolution conv; - conv.encodeData(payload, data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES); + // Add the Convolution FEC + CM17Convolution conv; + conv.encodeData(payload, data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES); - unsigned char temp[M17_FRAME_LENGTH_BYTES]; - interleaver(data + 2U, temp); - decorrelator(temp, data + 2U); + unsigned char temp[M17_FRAME_LENGTH_BYTES]; + interleaver(data + 2U, temp); + decorrelator(temp, data + 2U); - writeQueueNet(data); + writeQueueNet(data); - m_netLICHn++; - if (m_netLICHn >= 6U) - m_netLICHn = 0U; + m_netLSFn++; + if (m_netLSFn >= 6U) + m_netLSFn = 0U; - // EOT handling - uint16_t fn = (netData[28U] << 8) + (netData[29U] << 0); - if ((fn & 0x8000U) == 0x8000U) { - std::string source = m_netLICH.getSource(); - std::string dest = m_netLICH.getDest(); - LogMessage("M17, received network end of transmission from %s to %s, %.1f seconds", source.c_str(), dest.c_str(), float(m_netFrames) / 25.0F); - writeEndNet(); + // EOT handling + uint16_t fn = (netData[28U] << 8) + (netData[29U] << 0); + if ((fn & 0x8000U) == 0x8000U) { + std::string source = m_netLSF.getSource(); + std::string dest = m_netLSF.getDest(); + LogMessage("M17, received network end of transmission from %s to %s, %.1f seconds", source.c_str(), dest.c_str(), float(m_netFrames) / 25.0F); + writeEndNet(); + } } } +bool CM17Control::processRFHeader(bool lateEntry) +{ + unsigned char can = m_rfLSF.getCAN(); + if (can != m_can) + return false; + + std::string source = m_rfLSF.getSource(); + std::string dest = m_rfLSF.getDest(); + + if (!m_allowEncryption) { + unsigned char type = m_rfLSF.getEncryptionType(); + if (type != M17_ENCRYPTION_TYPE_NONE) { + LogMessage("M17, access attempt with encryption from %s to %s", source.c_str(), dest.c_str()); + m_rfState = RS_RF_REJECTED; + return false; + } + } + + if (m_selfOnly) { + bool ret = checkCallsign(source); + if (!ret) { + LogMessage("M17, invalid access attempt from %s to %s", source.c_str(), dest.c_str()); + m_rfState = RS_RF_REJECTED; + return false; + } + } + + unsigned char dataType = m_rfLSF.getDataType(); + switch (dataType) { + case M17_DATA_TYPE_DATA: + LogMessage("M17, received RF%sdata transmission from %s to %s", lateEntry ? " late entry " : " ", source.c_str(), dest.c_str()); + m_rfState = RS_RF_DATA; + break; + case M17_DATA_TYPE_VOICE: + LogMessage("M17, received RF%svoice transmission from %s to %s", lateEntry ? " late entry " : " ", source.c_str(), dest.c_str()); + m_rfState = RS_RF_AUDIO; + break; + case M17_DATA_TYPE_VOICE_DATA: + LogMessage("M17, received RF%svoice + data transmission from %s to %s", lateEntry ? " late entry " : " ", source.c_str(), dest.c_str()); + m_rfState = RS_RF_AUDIO; + break; + default: + LogMessage("M17, received RF%sunknown transmission from %s to %s", lateEntry ? " late entry " : " ", source.c_str(), dest.c_str()); + m_rfState = RS_RF_DATA; + break; + } + + m_display->writeM17(source.c_str(), dest.c_str(), "R"); + + if (m_duplex) { + unsigned char data[M17_FRAME_LENGTH_BYTES + 2U]; + + // Create a Link Setup frame + data[0U] = TAG_HEADER; + data[1U] = 0x00U; + + // Generate the sync + CSync::addM17LinkSetupSync(data + 2U); + + unsigned char setup[M17_LSF_LENGTH_BYTES]; + m_rfLSF.getLinkSetup(setup); + + // Add the convolution FEC + CM17Convolution conv; + conv.encodeLinkSetup(setup, data + 2U + M17_SYNC_LENGTH_BYTES); + + unsigned char temp[M17_FRAME_LENGTH_BYTES]; + interleaver(data + 2U, temp); + decorrelator(temp, data + 2U); + + writeQueueRF(data); + } + + return true; +} + void CM17Control::clock(unsigned int ms) { if (m_network != NULL) @@ -678,19 +703,6 @@ void CM17Control::writeQueueNet(const unsigned char *data) m_queue.addData(data, len); } -void CM17Control::writeNetwork(const unsigned char *data) -{ - assert(data != NULL); - - if (m_network == NULL) - return; - - if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) - return; - - m_network->write(data); -} - void CM17Control::interleaver(const unsigned char* in, unsigned char* out) const { assert(in != NULL); diff --git a/M17Control.h b/M17Control.h index 276478c..9ed515c 100644 --- a/M17Control.h +++ b/M17Control.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -24,9 +24,9 @@ #include "M17Defines.h" #include "RingBuffer.h" #include "StopWatch.h" -#include "M17LICH.h" #include "Display.h" #include "Defines.h" +#include "M17LSF.h" #include "Timer.h" #include "Modem.h" @@ -34,7 +34,7 @@ class CM17Control { public: - CM17Control(const std::string& callsign, unsigned int colorCode, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper); + CM17Control(const std::string& callsign, unsigned int can, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper); ~CM17Control(); bool writeModem(unsigned char* data, unsigned int len); @@ -49,7 +49,7 @@ public: private: std::string m_callsign; - unsigned int m_colorCode; + unsigned int m_can; bool m_selfOnly; bool m_allowEncryption; CM17Network* m_network; @@ -68,10 +68,10 @@ private: unsigned int m_rfFN; unsigned int m_rfErrs; unsigned int m_rfBits; - CM17LICH m_rfLICH; - unsigned int m_rfLICHn; - CM17LICH m_netLICH; - unsigned int m_netLICHn; + CM17LSF m_rfLSF; + unsigned int m_rfLSFn; + CM17LSF m_netLSF; + unsigned int m_netLSFn; CRSSIInterpolator* m_rssiMapper; unsigned char m_rssi; unsigned char m_maxRSSI; @@ -81,9 +81,10 @@ private: bool m_enabled; FILE* m_fp; + bool processRFHeader(bool lateEntry); + void writeQueueRF(const unsigned char* data); void writeQueueNet(const unsigned char* data); - void writeNetwork(const unsigned char* data); void writeNetwork(); void interleaver(const unsigned char* in, unsigned char* out) const; diff --git a/M17Convolution.cpp b/M17Convolution.cpp index 1f64a76..5a83ab0 100644 --- a/M17Convolution.cpp +++ b/M17Convolution.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Jonathan Naylor G4KLX * * 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 diff --git a/M17Convolution.h b/M17Convolution.h index e3f5d82..91843ba 100644 --- a/M17Convolution.h +++ b/M17Convolution.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Jonathan Naylor G4KLX * * 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 diff --git a/M17Defines.h b/M17Defines.h index 2eae167..5dc07f7 100644 --- a/M17Defines.h +++ b/M17Defines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -31,12 +31,18 @@ const unsigned char M17_PACKET_SYNC_BYTES[] = {0x75U, 0xFFU}; const unsigned int M17_SYNC_LENGTH_BITS = 16U; const unsigned int M17_SYNC_LENGTH_BYTES = M17_SYNC_LENGTH_BITS / 8U; -const unsigned int M17_LICH_LENGTH_BITS = 240U; -const unsigned int M17_LICH_LENGTH_BYTES = M17_LICH_LENGTH_BITS / 8U; +const unsigned int M17_LSF_LENGTH_BITS = 240U; +const unsigned int M17_LSF_LENGTH_BYTES = M17_LSF_LENGTH_BITS / 8U; -const unsigned int M17_LICH_FRAGMENT_LENGTH_BITS = M17_LICH_LENGTH_BITS / 6U; +const unsigned int M17_LSF_FRAGMENT_LENGTH_BITS = M17_LSF_LENGTH_BITS / 6U; +const unsigned int M17_LSF_FRAGMENT_LENGTH_BYTES = M17_LSF_FRAGMENT_LENGTH_BITS / 8U; + +const unsigned int M17_LICH_FRAGMENT_LENGTH_BITS = M17_LSF_FRAGMENT_LENGTH_BITS + 8U; const unsigned int M17_LICH_FRAGMENT_LENGTH_BYTES = M17_LICH_FRAGMENT_LENGTH_BITS / 8U; +const unsigned int M17_LSF_FRAGMENT_FEC_LENGTH_BITS = M17_LSF_FRAGMENT_LENGTH_BITS * 2U; +const unsigned int M17_LSF_FRAGMENT_FEC_LENGTH_BYTES = M17_LSF_FRAGMENT_FEC_LENGTH_BITS / 8U; + const unsigned int M17_LICH_FRAGMENT_FEC_LENGTH_BITS = M17_LICH_FRAGMENT_LENGTH_BITS * 2U; const unsigned int M17_LICH_FRAGMENT_FEC_LENGTH_BYTES = M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 8U; @@ -56,4 +62,15 @@ const unsigned int M17_CRC_LENGTH_BYTES = M17_CRC_LENGTH_BITS / 8U; const unsigned char M17_3200_SILENCE[] = {0x01U, 0x00U, 0x09U, 0x43U, 0x9CU, 0xE4U, 0x21U, 0x08U}; const unsigned char M17_1600_SILENCE[] = {0x01U, 0x00U, 0x04U, 0x00U, 0x25U, 0x75U, 0xDDU, 0xF2U}; +const unsigned char M17_PACKET_TYPE = 0U; +const unsigned char M17_STREAM_TYPE = 1U; + +const unsigned char M17_DATA_TYPE_DATA = 0x01U; +const unsigned char M17_DATA_TYPE_VOICE = 0x02U; +const unsigned char M17_DATA_TYPE_VOICE_DATA = 0x03U; + +const unsigned char M17_ENCRYPTION_TYPE_NONE = 0x00U; +const unsigned char M17_ENCRYPTION_TYPE_AES = 0x01U; +const unsigned char M17_ENCRYPTION_TYPE_SCRAMBLE = 0x02U; + #endif diff --git a/M17LICH.cpp b/M17LICH.cpp deleted file mode 100644 index e99fd8d..0000000 --- a/M17LICH.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2020 by Jonathan Naylor G4KLX - * - * 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; either version 2 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 for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "M17LICH.h" -#include "M17Utils.h" -#include "M17Defines.h" -#include "M17CRC.h" - -#include -#include - -CM17LICH::CM17LICH() : -m_lich(NULL), -m_valid(false) -{ - m_lich = new unsigned char[M17_LICH_LENGTH_BYTES]; -} - -CM17LICH::~CM17LICH() -{ - delete[] m_lich; -} - -void CM17LICH::getNetwork(unsigned char* data) const -{ - assert(data != NULL); - - ::memcpy(data, m_lich, M17_LICH_LENGTH_BYTES); -} - -void CM17LICH::setNetwork(const unsigned char* data) -{ - assert(data != NULL); - - ::memcpy(m_lich, data, M17_LICH_LENGTH_BYTES); - - m_valid = true; -} - -std::string CM17LICH::getSource() const -{ - std::string callsign; - CM17Utils::decodeCallsign(m_lich + 6U, callsign); - - return callsign; -} - -void CM17LICH::setSource(const std::string& callsign) -{ - CM17Utils::encodeCallsign(callsign, m_lich + 6U); -} - -std::string CM17LICH::getDest() const -{ - std::string callsign; - CM17Utils::decodeCallsign(m_lich + 0U, callsign); - - return callsign; -} - -void CM17LICH::setDest(const std::string& callsign) -{ - CM17Utils::encodeCallsign(callsign, m_lich + 0U); -} - -unsigned char CM17LICH::getDataType() const -{ - return (m_lich[13U] >> 1) & 0x03U; -} - -void CM17LICH::setDataType(unsigned char type) -{ - m_lich[13U] &= 0xF9U; - m_lich[13U] |= (type << 1) & 0x06U; -} - -bool CM17LICH::isNONCENull() const -{ - return ::memcmp(m_lich + 14U, M17_NULL_NONCE, M17_NONCE_LENGTH_BYTES) == 0; -} - -void CM17LICH::reset() -{ - ::memset(m_lich, 0x00U, 30U); - - m_valid = false; -} - -bool CM17LICH::isValid() const -{ - return m_valid; -} - -void CM17LICH::getLinkSetup(unsigned char* data) const -{ - assert(data != NULL); - - ::memcpy(data, m_lich, M17_LICH_LENGTH_BYTES); - - CM17CRC::encodeCRC(data, M17_LICH_LENGTH_BYTES); -} - -void CM17LICH::setLinkSetup(const unsigned char* data) -{ - assert(data != NULL); - - ::memcpy(m_lich, data, M17_LICH_LENGTH_BYTES); - - m_valid = CM17CRC::checkCRC(m_lich, M17_LICH_LENGTH_BYTES); -} - -void CM17LICH::getFragment(unsigned char* data, unsigned int n) const -{ - assert(data != NULL); - - CM17CRC::encodeCRC(m_lich, M17_LICH_LENGTH_BYTES); - - ::memcpy(data, m_lich + (n * M17_LICH_FRAGMENT_LENGTH_BYTES), M17_LICH_FRAGMENT_LENGTH_BYTES); -} - -void CM17LICH::setFragment(const unsigned char* data, unsigned int n) -{ - assert(data != NULL); - - ::memcpy(m_lich + (n * M17_LICH_FRAGMENT_LENGTH_BYTES), data, M17_LICH_FRAGMENT_LENGTH_BYTES); - - m_valid = CM17CRC::checkCRC(m_lich, M17_LICH_LENGTH_BYTES); -} diff --git a/M17LSF.cpp b/M17LSF.cpp new file mode 100644 index 0000000..4d48f40 --- /dev/null +++ b/M17LSF.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX + * + * 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; either version 2 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "M17LSF.h" +#include "M17Utils.h" +#include "M17Defines.h" +#include "M17CRC.h" + +#include +#include + +CM17LSF::CM17LSF() : +m_lsf(NULL), +m_valid(false) +{ + m_lsf = new unsigned char[M17_LSF_LENGTH_BYTES]; +} + +CM17LSF::~CM17LSF() +{ + delete[] m_lsf; +} + +void CM17LSF::getNetwork(unsigned char* data) const +{ + assert(data != NULL); + + ::memcpy(data, m_lsf, M17_LSF_LENGTH_BYTES); +} + +void CM17LSF::setNetwork(const unsigned char* data) +{ + assert(data != NULL); + + ::memcpy(m_lsf, data, M17_LSF_LENGTH_BYTES); + + m_valid = true; +} + +std::string CM17LSF::getSource() const +{ + if (m_lsf[6U] == 0xFFU && m_lsf[7U] == 0xFFU && m_lsf[8U] == 0xFFU && + m_lsf[9U] == 0xFFU && m_lsf[10U] == 0xFFU && m_lsf[11U] == 0xFFU) + return "******"; + + std::string callsign; + CM17Utils::decodeCallsign(m_lsf + 6U, callsign); + + return callsign; +} + +void CM17LSF::setSource(const std::string& callsign) +{ + CM17Utils::encodeCallsign(callsign, m_lsf + 6U); +} + +std::string CM17LSF::getDest() const +{ + if (m_lsf[0U] == 0xFFU && m_lsf[1U] == 0xFFU && m_lsf[2U] == 0xFFU && + m_lsf[3U] == 0xFFU && m_lsf[4U] == 0xFFU && m_lsf[5U] == 0xFFU) + return "******"; + + std::string callsign; + CM17Utils::decodeCallsign(m_lsf + 0U, callsign); + + return callsign; +} + +void CM17LSF::setDest(const std::string& callsign) +{ + CM17Utils::encodeCallsign(callsign, m_lsf + 0U); +} + +unsigned char CM17LSF::getPacketStream() const +{ + return m_lsf[13U] & 0x01U; +} + +void CM17LSF::setPacketStream(unsigned char ps) +{ + m_lsf[13U] &= 0xF7U; + m_lsf[13U] |= ps & 0x01U; +} + +unsigned char CM17LSF::getDataType() const +{ + return (m_lsf[13U] >> 1) & 0x03U; +} + +void CM17LSF::setDataType(unsigned char type) +{ + m_lsf[13U] &= 0xF9U; + m_lsf[13U] |= (type << 1) & 0x06U; +} + +unsigned char CM17LSF::getEncryptionType() const +{ + return (m_lsf[13U] >> 3) & 0x03U; +} + +void CM17LSF::setEncryptionType(unsigned char type) +{ + m_lsf[13U] &= 0xE7U; + m_lsf[13U] |= (type << 3) & 0x18U; +} + +unsigned char CM17LSF::getEncryptionSubType() const +{ + return (m_lsf[13U] >> 5) & 0x03U; +} + +void CM17LSF::setEncryptionSubType(unsigned char type) +{ + m_lsf[13U] &= 0x9FU; + m_lsf[13U] |= (type << 5) & 0x60U; +} + +unsigned char CM17LSF::getCAN() const +{ + return ((m_lsf[12U] << 1) & 0x0EU) | ((m_lsf[13U] >> 7) & 0x01U); +} + +void CM17LSF::setCAN(unsigned char can) +{ + m_lsf[13U] &= 0x7FU; + m_lsf[13U] |= (can << 7) & 0x80U; + + m_lsf[12U] &= 0xF8U; + m_lsf[12U] |= (can >> 1) & 0x07U; +} + +void CM17LSF::reset() +{ + ::memset(m_lsf, 0x00U, 30U); + + m_valid = false; +} + +bool CM17LSF::isValid() const +{ + return m_valid; +} + +void CM17LSF::getLinkSetup(unsigned char* data) const +{ + assert(data != NULL); + + ::memcpy(data, m_lsf, M17_LSF_LENGTH_BYTES); + + CM17CRC::encodeCRC(data, M17_LSF_LENGTH_BYTES); +} + +void CM17LSF::setLinkSetup(const unsigned char* data) +{ + assert(data != NULL); + + ::memcpy(m_lsf, data, M17_LSF_LENGTH_BYTES); + + m_valid = CM17CRC::checkCRC(m_lsf, M17_LSF_LENGTH_BYTES); +} + +void CM17LSF::getFragment(unsigned char* data, unsigned int n) const +{ + assert(data != NULL); + + CM17CRC::encodeCRC(m_lsf, M17_LSF_LENGTH_BYTES); + + ::memcpy(data, m_lsf + (n * M17_LSF_FRAGMENT_LENGTH_BYTES), M17_LSF_FRAGMENT_LENGTH_BYTES); +} + +void CM17LSF::setFragment(const unsigned char* data, unsigned int n) +{ + assert(data != NULL); + + ::memcpy(m_lsf + (n * M17_LSF_FRAGMENT_LENGTH_BYTES), data, M17_LSF_FRAGMENT_LENGTH_BYTES); + + m_valid = CM17CRC::checkCRC(m_lsf, M17_LSF_LENGTH_BYTES); +} diff --git a/M17LICH.h b/M17LSF.h similarity index 73% rename from M17LICH.h rename to M17LSF.h index 804de3e..a12c1fe 100644 --- a/M17LICH.h +++ b/M17LSF.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -16,15 +16,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined(M17LICH_H) -#define M17LICH_H +#if !defined(M17LSF_H) +#define M17LSF_H #include -class CM17LICH { +class CM17LSF { public: - CM17LICH(); - ~CM17LICH(); + CM17LSF(); + ~CM17LSF(); void getNetwork(unsigned char* data) const; void setNetwork(const unsigned char* data); @@ -35,10 +35,20 @@ public: std::string getDest() const; void setDest(const std::string& callsign); + unsigned char getPacketStream() const; + void setPacketStream(unsigned char ps); + unsigned char getDataType() const; void setDataType(unsigned char type); - bool isNONCENull() const; + unsigned char getEncryptionType() const; + void setEncryptionType(unsigned char type); + + unsigned char getEncryptionSubType() const; + void setEncryptionSubType(unsigned char type); + + unsigned char getCAN() const; + void setCAN(unsigned char can); void reset(); bool isValid() const; @@ -50,7 +60,7 @@ public: void setFragment(const unsigned char* data, unsigned int n); private: - unsigned char* m_lich; + unsigned char* m_lsf; bool m_valid; }; diff --git a/M17Network.cpp b/M17Network.cpp index 56a2135..2fd213d 100644 --- a/M17Network.cpp +++ b/M17Network.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2019,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Jonathan Naylor G4KLX * * 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 diff --git a/M17Network.h b/M17Network.h index e65e1f3..9fc555a 100644 --- a/M17Network.h +++ b/M17Network.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Jonathan Naylor G4KLX * * 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 diff --git a/M17Utils.cpp b/M17Utils.cpp index 1ba33b1..5a22adf 100644 --- a/M17Utils.cpp +++ b/M17Utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -60,12 +60,13 @@ void CM17Utils::decodeCallsign(const unsigned char* encoded, std::string& callsi callsign.clear(); - uint64_t enc = (uint64_t(encoded[0U]) << 40) + - (uint64_t(encoded[1U]) << 32) + - (uint64_t(encoded[2U]) << 24) + - (uint64_t(encoded[3U]) << 16) + - (uint64_t(encoded[4U]) << 8) + - (uint64_t(encoded[5U]) << 0); + uint64_t enc = + (uint64_t(encoded[0U]) << 40) + + (uint64_t(encoded[1U]) << 32) + + (uint64_t(encoded[2U]) << 24) + + (uint64_t(encoded[3U]) << 16) + + (uint64_t(encoded[4U]) << 8) + + (uint64_t(encoded[5U]) << 0); if (enc >= 262144000000000ULL) // 40^9 return; diff --git a/MMDVM.ini b/MMDVM.ini index be1dbcf..b4fe1e1 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -149,7 +149,7 @@ TXHang=5 [M17] Enable=1 -ColorCode=3 +CAN=0 SelfOnly=0 TXHang=5 # ModeHang=10 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 592531a..b21870a 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -634,19 +634,19 @@ int CMMDVMHost::run() if (m_m17Enabled) { bool selfOnly = m_conf.getM17SelfOnly(); - unsigned int colorCode = m_conf.getM17ColorCode(); + unsigned int can = m_conf.getM17CAN(); bool allowEncryption = m_conf.getM17AllowEncryption(); unsigned int txHang = m_conf.getM17TXHang(); m_m17RFModeHang = m_conf.getM17ModeHang(); LogInfo("M17 RF Parameters"); LogInfo(" Self Only: %s", selfOnly ? "yes" : "no"); - LogInfo(" Color Code: %u", colorCode); + LogInfo(" CAN: %u", can); LogInfo(" Allow Encryption: %s", allowEncryption ? "yes" : "no"); LogInfo(" TX Hang: %us", txHang); LogInfo(" Mode Hang: %us", m_m17RFModeHang); - m_m17 = new CM17Control(m_callsign, colorCode, selfOnly, allowEncryption, m_m17Network, m_display, m_timeout, m_duplex, rssi); + m_m17 = new CM17Control(m_callsign, can, selfOnly, allowEncryption, m_m17Network, m_display, m_timeout, m_duplex, rssi); } CTimer pocsagTimer(1000U, 30U); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 182f62a..bebf213 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -199,7 +199,7 @@ - + @@ -308,7 +308,7 @@ - + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 36320cd..77f0c68 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -296,7 +296,7 @@ Header Files - + Header Files @@ -610,7 +610,7 @@ Source Files - + Source Files diff --git a/Makefile b/Makefile index 901697a..fa6b777 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o AX25Control.o AX25Network.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LICH.o M17Network.o M17Utils.o MMDVMHost.o \ + Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \ Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \ NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o \ diff --git a/Makefile.Pi b/Makefile.Pi index 528c972..c0ab7f6 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LICH.o M17Network.o M17Utils.o MMDVMHost.o \ + Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \ Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \ NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o \ diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index d4e75dd..a0538a1 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -11,7 +11,7 @@ OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LICH.o M17Network.o M17Utils.o \ + Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \ MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \ NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \ NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 215d9f1..3885dc3 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LICH.o M17Network.o M17Utils.o \ + Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \ MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \ NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \ NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 889c72d..ab99eb2 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -14,7 +14,7 @@ OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LICH.o M17Network.o M17Utils.o MMDVMHost.o \ + Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \ Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \ NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ NXDNUDCH.o OLED.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index ce09839..2fff7d9 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -11,7 +11,7 @@ OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LICH.o M17Network.o M17Utils.o \ + Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \ MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \ NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \ NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ diff --git a/Version.h b/Version.h index 028594f..31bfcac 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210314"; +const char* VERSION = "20210325"; #endif From 242cf502403b6647d6a8af81cd96aaf490b5dd32 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 26 Mar 2021 20:34:08 +0000 Subject: [PATCH 14/23] Remove the CAN processing from the LICH. --- M17Control.cpp | 10 ++-------- Version.h | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/M17Control.cpp b/M17Control.cpp index 5ab306e..37e2c2e 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -213,10 +213,6 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned int lich3 = CGolay24128::decode24128(frag3); unsigned int lich4 = CGolay24128::decode24128(frag4); - unsigned int can = lich4 & 0x1FU; - if (can != m_can) - return false; - unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); @@ -300,9 +296,8 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); - // Add the CAN and fragment number + // Add the fragment number frag4 |= (m_rfLSFn & 0x07U) << 5; - frag4 |= m_can & 0x1FU; // Add Golay to the LICH fragment here unsigned int lich1 = CGolay24128::encode24128(frag1); @@ -522,9 +517,8 @@ void CM17Control::writeNetwork() unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); - // Add the Color Code and fragment number + // Add the fragment number frag4 |= (m_netLSFn & 0x07U) << 4; - frag4 |= (m_can & 0x1FU) << 7; // Add Golay to the LICH fragment here unsigned int lich1 = CGolay24128::encode24128(frag1); diff --git a/Version.h b/Version.h index 31bfcac..564260a 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210325"; +const char* VERSION = "20210326"; #endif From 0a94b0deb66ce838a78bc43c5775d5f9be7bfbb4 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 26 Mar 2021 22:21:20 +0000 Subject: [PATCH 15/23] Add the LICH CRC. --- M17CRC.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++------ M17CRC.h | 12 +++++--- M17Control.cpp | 36 ++++++++++++++---------- M17LSF.cpp | 8 +++--- 4 files changed, 101 insertions(+), 30 deletions(-) diff --git a/M17CRC.cpp b/M17CRC.cpp index cd41697..695511e 100644 --- a/M17CRC.cpp +++ b/M17CRC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -21,7 +21,7 @@ #include #include -const uint16_t CRC_TABLE[] = {0x0000U, 0x5935U, 0xB26AU, 0xEB5FU, 0x3DE1U, 0x64D4U, 0x8F8BU, 0xD6BEU, 0x7BC2U, 0x22F7U, 0xC9A8U, +const uint16_t CRC16_TABLE[] = {0x0000U, 0x5935U, 0xB26AU, 0xEB5FU, 0x3DE1U, 0x64D4U, 0x8F8BU, 0xD6BEU, 0x7BC2U, 0x22F7U, 0xC9A8U, 0x909DU, 0x4623U, 0x1F16U, 0xF449U, 0xAD7CU, 0xF784U, 0xAEB1U, 0x45EEU, 0x1CDBU, 0xCA65U, 0x9350U, 0x780FU, 0x213AU, 0x8C46U, 0xD573U, 0x3E2CU, 0x6719U, 0xB1A7U, 0xE892U, 0x03CDU, 0x5AF8U, 0xB63DU, 0xEF08U, 0x0457U, 0x5D62U, 0x8BDCU, 0xD2E9U, 0x39B6U, 0x6083U, 0xCDFFU, 0x94CAU, 0x7F95U, 0x26A0U, @@ -46,12 +46,30 @@ const uint16_t CRC_TABLE[] = {0x0000U, 0x5935U, 0xB26AU, 0xEB5FU, 0x3DE1U, 0x64D 0xAC02U, 0xF537U, 0x2389U, 0x7ABCU, 0x91E3U, 0xC8D6U, 0x65AAU, 0x3C9FU, 0xD7C0U, 0x8EF5U, 0x584BU, 0x017EU, 0xEA21U, 0xB314U}; -bool CM17CRC::checkCRC(const unsigned char* in, unsigned int nBytes) +const uint8_t CRC4_TABLE[] = { + 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc, 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6, + 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1, 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb, + 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf, 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5, + 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2, 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8, + 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa, 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0, + 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7, 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd, + 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9, 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3, + 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4, 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe, + 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0, 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa, + 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd, 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7, + 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3, 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9, + 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe, 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4, + 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6, 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc, + 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb, 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1, + 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5, 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf, + 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8, 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2}; + +bool CM17CRC::checkCRC16(const unsigned char* in, unsigned int nBytes) { assert(in != NULL); assert(nBytes > 2U); - uint16_t crc = createCRC(in, nBytes - 2U); + uint16_t crc = createCRC16(in, nBytes - 2U); uint8_t temp[2U]; temp[0U] = (crc >> 8) & 0xFFU; @@ -60,26 +78,67 @@ bool CM17CRC::checkCRC(const unsigned char* in, unsigned int nBytes) return temp[0U] == in[nBytes - 2U] && temp[1U] == in[nBytes - 1U]; } -void CM17CRC::encodeCRC(unsigned char* in, unsigned int nBytes) +void CM17CRC::encodeCRC16(unsigned char* in, unsigned int nBytes) { assert(in != NULL); assert(nBytes > 2U); - uint16_t crc = createCRC(in, nBytes - 2U); + uint16_t crc = createCRC16(in, nBytes - 2U); in[nBytes - 2U] = (crc >> 8) & 0xFFU; in[nBytes - 1U] = (crc >> 0) & 0xFFU; } -uint16_t CM17CRC::createCRC(const unsigned char* in, unsigned int nBytes) +uint16_t CM17CRC::createCRC16(const unsigned char* in, unsigned int nBytes) { assert(in != NULL); uint16_t crc = 0xFFFFU; for (unsigned int i = 0U; i < nBytes; i++) - crc = (crc << 8) ^ CRC_TABLE[((crc >> 8) ^ uint16_t(in[i])) & 0x00FFU]; + crc = (crc << 8) ^ CRC16_TABLE[((crc >> 8) ^ uint16_t(in[i])) & 0x00FFU]; return crc; } +bool CM17CRC::checkCRC8(unsigned char* in, unsigned int nBytes) +{ + assert(in != NULL); + assert(nBytes > 1U); + + uint8_t save = in[nBytes - 1U] & 0x0FU; + + // Mask out the 4-bit CRC location + in[nBytes - 1U] &= 0xF0U; + + uint8_t crc = createCRC8(in, nBytes); + + // Restore the original CRC + in[nBytes - 1U] |= save; + + return save == crc; +} + +void CM17CRC::encodeCRC8(unsigned char* in, unsigned int nBytes) +{ + assert(in != NULL); + assert(nBytes > 1U); + + in[nBytes - 1U] &= 0xF0U; + + uint8_t crc = createCRC8(in, nBytes); + + in[nBytes - 1U] |= crc & 0x0FU; +} + +uint8_t CM17CRC::createCRC8(const unsigned char* in, unsigned int nBytes) +{ + assert(in != NULL); + + uint8_t crc = 0x0FU; + + for (unsigned int i = 0U; i < nBytes; i++) + crc = CRC4_TABLE[crc ^ in[i]]; + + return crc; +} diff --git a/M17CRC.h b/M17CRC.h index 22c8f31..5bc33bb 100644 --- a/M17CRC.h +++ b/M17CRC.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -24,11 +24,15 @@ class CM17CRC { public: - static bool checkCRC(const unsigned char* in, unsigned int nBytes); - static void encodeCRC(unsigned char* in, unsigned int nBytes); + static bool checkCRC16(const unsigned char* in, unsigned int nBytes); + static void encodeCRC16(unsigned char* in, unsigned int nBytes); + + static bool checkCRC8(unsigned char* in, unsigned int nBytes); + static void encodeCRC8(unsigned char* in, unsigned int nBytes); private: - static uint16_t createCRC(const unsigned char* in, unsigned int nBytes); + static uint16_t createCRC16(const unsigned char* in, unsigned int nBytes); + static uint8_t createCRC8(const unsigned char* in, unsigned int nBytes); }; #endif diff --git a/M17Control.cpp b/M17Control.cpp index 37e2c2e..10238ce 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -169,7 +169,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char frame[M17_LSF_LENGTH_BYTES]; conv.decodeLinkSetup(data + 2U + M17_SYNC_LENGTH_BYTES, frame); - bool valid = CM17CRC::checkCRC(frame, M17_LSF_LENGTH_BYTES); + bool valid = CM17CRC::checkCRC16(frame, M17_LSF_LENGTH_BYTES); if (valid) { m_rfLSF.setLinkSetup(frame); @@ -196,6 +196,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) return true; } else { m_rfState = RS_RF_LATE_ENTRY; + return false; } } @@ -216,6 +217,9 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); + if (!CM17CRC::checkCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES)) + return false; + m_rfLSFn = (lich4 >> 5) & 0x07U; m_rfLSF.setFragment(lich, m_rfLSFn); @@ -253,7 +257,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char frame[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES]; conv.decodeData(data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES, frame); - bool valid = CM17CRC::checkCRC(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); + bool valid = CM17CRC::checkCRC16(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); if (valid) { m_rfFN = (frame[0U] << 8) + (frame[1U] << 0); } else { @@ -279,7 +283,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) } // Add the CRC - CM17CRC::encodeCRC(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); + CM17CRC::encodeCRC16(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); } unsigned char rfData[2U + M17_FRAME_LENGTH_BYTES]; @@ -293,12 +297,15 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; m_rfLSF.getFragment(lich, m_rfLSFn); + // Add the fragment number + lich[5U] = (m_rfLSFn & 0x07U) << 5; + + // Add the CRC + CM17CRC::encodeCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); + unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); - // Add the fragment number - frag4 |= (m_rfLSFn & 0x07U) << 5; - // Add Golay to the LICH fragment here unsigned int lich1 = CGolay24128::encode24128(frag1); unsigned int lich2 = CGolay24128::encode24128(frag2); @@ -362,11 +369,9 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) LogMessage("M17, received RF end of transmission from %s to %s, %.1f seconds, BER: %.1f%%", source.c_str(), dest.c_str(), float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits)); writeEndRF(); } - - return true; } - return false; + return true; } unsigned int CM17Control::readModem(unsigned char* data) @@ -511,15 +516,18 @@ void CM17Control::writeNetwork() m_netFrames++; // Add the fragment LICH - unsigned char lich[M17_LSF_FRAGMENT_LENGTH_BYTES]; + unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; m_netLSF.getFragment(lich, m_netLSFn); + // Add the fragment number + lich[5U] = (m_netLSFn & 0x07U) << 5; + + // Add the CRC + CM17CRC::encodeCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); + unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); - // Add the fragment number - frag4 |= (m_netLSFn & 0x07U) << 4; - // Add Golay to the LICH fragment here unsigned int lich1 = CGolay24128::encode24128(frag1); unsigned int lich2 = CGolay24128::encode24128(frag2); @@ -533,7 +541,7 @@ void CM17Control::writeNetwork() ::memcpy(payload, netData + 28U, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES); // Add the CRC - CM17CRC::encodeCRC(payload, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); + CM17CRC::encodeCRC16(payload, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); // Add the Convolution FEC CM17Convolution conv; diff --git a/M17LSF.cpp b/M17LSF.cpp index 4d48f40..6caa1c4 100644 --- a/M17LSF.cpp +++ b/M17LSF.cpp @@ -162,7 +162,7 @@ void CM17LSF::getLinkSetup(unsigned char* data) const ::memcpy(data, m_lsf, M17_LSF_LENGTH_BYTES); - CM17CRC::encodeCRC(data, M17_LSF_LENGTH_BYTES); + CM17CRC::encodeCRC16(data, M17_LSF_LENGTH_BYTES); } void CM17LSF::setLinkSetup(const unsigned char* data) @@ -171,14 +171,14 @@ void CM17LSF::setLinkSetup(const unsigned char* data) ::memcpy(m_lsf, data, M17_LSF_LENGTH_BYTES); - m_valid = CM17CRC::checkCRC(m_lsf, M17_LSF_LENGTH_BYTES); + m_valid = CM17CRC::checkCRC16(m_lsf, M17_LSF_LENGTH_BYTES); } void CM17LSF::getFragment(unsigned char* data, unsigned int n) const { assert(data != NULL); - CM17CRC::encodeCRC(m_lsf, M17_LSF_LENGTH_BYTES); + CM17CRC::encodeCRC16(m_lsf, M17_LSF_LENGTH_BYTES); ::memcpy(data, m_lsf + (n * M17_LSF_FRAGMENT_LENGTH_BYTES), M17_LSF_FRAGMENT_LENGTH_BYTES); } @@ -189,5 +189,5 @@ void CM17LSF::setFragment(const unsigned char* data, unsigned int n) ::memcpy(m_lsf + (n * M17_LSF_FRAGMENT_LENGTH_BYTES), data, M17_LSF_FRAGMENT_LENGTH_BYTES); - m_valid = CM17CRC::checkCRC(m_lsf, M17_LSF_LENGTH_BYTES); + m_valid = CM17CRC::checkCRC16(m_lsf, M17_LSF_LENGTH_BYTES); } From 8efd77132f6c77f5484ee70e4f63f5bde3fea716 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 26 Mar 2021 22:45:33 +0000 Subject: [PATCH 16/23] Rename the CRC4 functions correctly. --- M17CRC.cpp | 10 +++++----- M17CRC.h | 6 +++--- M17Control.cpp | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/M17CRC.cpp b/M17CRC.cpp index 695511e..1fd42f0 100644 --- a/M17CRC.cpp +++ b/M17CRC.cpp @@ -101,7 +101,7 @@ uint16_t CM17CRC::createCRC16(const unsigned char* in, unsigned int nBytes) return crc; } -bool CM17CRC::checkCRC8(unsigned char* in, unsigned int nBytes) +bool CM17CRC::checkCRC4(unsigned char* in, unsigned int nBytes) { assert(in != NULL); assert(nBytes > 1U); @@ -111,7 +111,7 @@ bool CM17CRC::checkCRC8(unsigned char* in, unsigned int nBytes) // Mask out the 4-bit CRC location in[nBytes - 1U] &= 0xF0U; - uint8_t crc = createCRC8(in, nBytes); + uint8_t crc = createCRC4(in, nBytes); // Restore the original CRC in[nBytes - 1U] |= save; @@ -119,19 +119,19 @@ bool CM17CRC::checkCRC8(unsigned char* in, unsigned int nBytes) return save == crc; } -void CM17CRC::encodeCRC8(unsigned char* in, unsigned int nBytes) +void CM17CRC::encodeCRC4(unsigned char* in, unsigned int nBytes) { assert(in != NULL); assert(nBytes > 1U); in[nBytes - 1U] &= 0xF0U; - uint8_t crc = createCRC8(in, nBytes); + uint8_t crc = createCRC4(in, nBytes); in[nBytes - 1U] |= crc & 0x0FU; } -uint8_t CM17CRC::createCRC8(const unsigned char* in, unsigned int nBytes) +uint8_t CM17CRC::createCRC4(const unsigned char* in, unsigned int nBytes) { assert(in != NULL); diff --git a/M17CRC.h b/M17CRC.h index 5bc33bb..a1cfa53 100644 --- a/M17CRC.h +++ b/M17CRC.h @@ -27,12 +27,12 @@ public: static bool checkCRC16(const unsigned char* in, unsigned int nBytes); static void encodeCRC16(unsigned char* in, unsigned int nBytes); - static bool checkCRC8(unsigned char* in, unsigned int nBytes); - static void encodeCRC8(unsigned char* in, unsigned int nBytes); + static bool checkCRC4(unsigned char* in, unsigned int nBytes); + static void encodeCRC4(unsigned char* in, unsigned int nBytes); private: static uint16_t createCRC16(const unsigned char* in, unsigned int nBytes); - static uint8_t createCRC8(const unsigned char* in, unsigned int nBytes); + static uint8_t createCRC4(const unsigned char* in, unsigned int nBytes); }; #endif diff --git a/M17Control.cpp b/M17Control.cpp index 10238ce..070ccfd 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -217,7 +217,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); - if (!CM17CRC::checkCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES)) + if (!CM17CRC::checkCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES)) return false; m_rfLSFn = (lich4 >> 5) & 0x07U; @@ -301,7 +301,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) lich[5U] = (m_rfLSFn & 0x07U) << 5; // Add the CRC - CM17CRC::encodeCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); + CM17CRC::encodeCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); @@ -523,7 +523,7 @@ void CM17Control::writeNetwork() lich[5U] = (m_netLSFn & 0x07U) << 5; // Add the CRC - CM17CRC::encodeCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); + CM17CRC::encodeCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); From 4422444179ec9ccb64e040263361114eafc27a67 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 27 Mar 2021 14:51:53 +0000 Subject: [PATCH 17/23] Disable the LICH CRC and clean up the payload checksum handling. --- M17Control.cpp | 55 ++++++++++++++++++-------------------------------- Version.h | 2 +- 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/M17Control.cpp b/M17Control.cpp index 070ccfd..14d1c83 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -217,8 +217,8 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); - if (!CM17CRC::checkCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES)) - return false; + // if (!CM17CRC::checkCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES)) + // return false; m_rfLSFn = (lich4 >> 5) & 0x07U; m_rfLSF.setFragment(lich, m_rfLSFn); @@ -249,7 +249,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) } } - if ((m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA) && data[0U] == TAG_DATA) { + if (m_rfState == RS_RF_AUDIO && data[0U] == TAG_DATA) { #if defined(DUMP_M17) writeFile(data + 2U); #endif @@ -261,28 +261,13 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) if (valid) { m_rfFN = (frame[0U] << 8) + (frame[1U] << 0); } else { - // Create a silence frame m_rfFN++; // The new FN frame[0U] = m_rfFN >> 8; frame[1U] = m_rfFN >> 0; - // Add silent audio - unsigned char dataType = m_rfLSF.getDataType(); - switch (dataType) { - case M17_DATA_TYPE_VOICE: - ::memcpy(frame + M17_FN_LENGTH_BYTES + 0U, M17_3200_SILENCE, 8U); - ::memcpy(frame + M17_FN_LENGTH_BYTES + 8U, M17_3200_SILENCE, 8U); - break; - case M17_DATA_TYPE_VOICE_DATA: - ::memcpy(frame + M17_FN_LENGTH_BYTES + 0U, M17_1600_SILENCE, 8U); - break; - default: - break; - } - - // Add the CRC + // Recalculate the CRC CM17CRC::encodeCRC16(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); } @@ -301,7 +286,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) lich[5U] = (m_rfLSFn & 0x07U) << 5; // Add the CRC - CM17CRC::encodeCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); + // CM17CRC::encodeCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); @@ -318,20 +303,20 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) conv.encodeData(frame, rfData + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES); // Calculate the BER - if (valid) { - unsigned int errors = 0U; - for (unsigned int i = 2U; i < (M17_FRAME_LENGTH_BYTES + 2U); i++) - errors += countBits(rfData[i] ^ data[i]); - - LogDebug("M17, FN: %u, errs: %u/384 (%.1f%%)", m_rfFN & 0x7FU, errors, float(errors) / 3.84F); - - m_rfBits += M17_FRAME_LENGTH_BITS; - m_rfErrs += errors; - - float ber = float(m_rfErrs) / float(m_rfBits); - m_display->writeM17BER(ber); + unsigned int errors = 0U; + for (unsigned int i = 0U; i < (M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES); i++) { + unsigned int offset = i + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES; + errors += countBits(rfData[offset] ^ data[offset]); } + LogDebug("M17, FN: %u, errs: %u/144 (%.1f%%)", m_rfFN & 0x7FU, errors, float(errors) / 1.44F); + + m_rfBits += M17_FN_LENGTH_BITS + M17_PAYLOAD_LENGTH_BITS; + m_rfErrs += errors; + + float ber = float(m_rfErrs) / float(m_rfBits); + m_display->writeM17BER(ber); + unsigned char temp[M17_FRAME_LENGTH_BYTES]; interleaver(rfData + 2U, temp); decorrelator(temp, rfData + 2U); @@ -358,8 +343,8 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) if (m_rfLSFn >= 6U) m_rfLSFn = 0U; - // EOT? - if ((m_rfFN & 0x8000U) == 0x8000U) { + // Only check for the EOT marker if the frame has a valid CRC + if (valid && (m_rfFN & 0x8000U) == 0x8000U) { std::string source = m_rfLSF.getSource(); std::string dest = m_rfLSF.getDest(); @@ -523,7 +508,7 @@ void CM17Control::writeNetwork() lich[5U] = (m_netLSFn & 0x07U) << 5; // Add the CRC - CM17CRC::encodeCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); + // CM17CRC::encodeCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); diff --git a/Version.h b/Version.h index 564260a..19fef83 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210326"; +const char* VERSION = "20210327"; #endif From 6ac672e10619f4abe0e113ceaebcea00cbb62f11 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 27 Mar 2021 20:00:53 +0000 Subject: [PATCH 18/23] Finally process the Golay(24,12,8) parity bit. --- AMBEFEC.cpp | 37 +++++++++++++------------------------ Golay24128.cpp | 24 ++++++++++++++---------- Golay24128.h | 6 +++--- M17Control.cpp | 29 ++++++++--------------------- M17Control.h | 2 -- Utils.cpp | 14 +++++++++++++- Utils.h | 4 +++- YSFFICH.cpp | 14 +++++++++----- 8 files changed, 63 insertions(+), 67 deletions(-) diff --git a/AMBEFEC.cpp b/AMBEFEC.cpp index 864c35d..4b28046 100644 --- a/AMBEFEC.cpp +++ b/AMBEFEC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010,2014,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2010,2014,2016,2018,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016 Mathias Weyland, HB9FRV * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "Golay24128.h" #include "Hamming.h" #include "AMBEFEC.h" +#include "Utils.h" #include #include @@ -792,10 +793,12 @@ unsigned int CAMBEFEC::regenerateIMBE(unsigned char* bytes) const unsigned int CAMBEFEC::regenerateDStar(unsigned int& a, unsigned int& b) const { + bool valid; + unsigned int orig_a = a; unsigned int orig_b = b; - unsigned int data = CGolay24128::decode24128(a); + unsigned int data = CGolay24128::decode24128(a, valid); a = CGolay24128::encode24128(data); @@ -804,35 +807,29 @@ unsigned int CAMBEFEC::regenerateDStar(unsigned int& a, unsigned int& b) const b ^= p; - unsigned int datb = CGolay24128::decode24128(b); + unsigned int datb = CGolay24128::decode24128(b, valid); b = CGolay24128::encode24128(datb); b ^= p; - unsigned int errsA = 0U, errsB = 0U; - unsigned int v = a ^ orig_a; - while (v != 0U) { - v &= v - 1U; - errsA++; - } + unsigned int errsA = CUtils::countBits(v); v = b ^ orig_b; - while (v != 0U) { - v &= v - 1U; - errsB++; - } + unsigned int errsB = CUtils::countBits(v); return errsA + errsB; } unsigned int CAMBEFEC::regenerateDMR(unsigned int& a, unsigned int& b, unsigned int& c) const { + bool valid; + unsigned int orig_a = a; unsigned int orig_b = b; - unsigned int data = CGolay24128::decode24128(a); + unsigned int data = CGolay24128::decode24128(a, valid); a = CGolay24128::encode24128(data); @@ -847,19 +844,11 @@ unsigned int CAMBEFEC::regenerateDMR(unsigned int& a, unsigned int& b, unsigned b ^= p; - unsigned int errsA = 0U, errsB = 0U; - unsigned int v = a ^ orig_a; - while (v != 0U) { - v &= v - 1U; - errsA++; - } + unsigned int errsA = CUtils::countBits(v); v = b ^ orig_b; - while (v != 0U) { - v &= v - 1U; - errsB++; - } + unsigned int errsB = CUtils::countBits(v); if (errsA >= 4U || ((errsA + errsB) >= 6U && errsA >= 2U)) { a = 0xF00292U; diff --git a/Golay24128.cpp b/Golay24128.cpp index 417da00..715c8dc 100644 --- a/Golay24128.cpp +++ b/Golay24128.cpp @@ -1,9 +1,10 @@ /* - * Copyright (C) 2010,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2010,2016,2021 by Jonathan Naylor G4KLX * Copyright (C) 2002 by Robert H. Morelos-Zaragoza. All rights reserved. */ #include "Golay24128.h" +#include "Utils.h" #include #include @@ -1089,20 +1090,23 @@ unsigned int CGolay24128::decode23127(unsigned int code) return code >> 11; } -unsigned int CGolay24128::decode24128(unsigned int code) +unsigned int CGolay24128::decode24128(unsigned int input, bool& valid) { - return decode23127(code >> 1); + unsigned int syndrome = ::get_syndrome_23127(input >> 1); + unsigned int error_pattern = DECODING_TABLE_23127[syndrome] << 1; + + unsigned int output = input ^ error_pattern; + + valid = (CUtils::countBits(syndrome) < 3U) || !(CUtils::countBits(output) & 1); + + return output >> 12; } -unsigned int CGolay24128::decode24128(unsigned char* bytes) +unsigned int CGolay24128::decode24128(unsigned char* bytes, bool& valid) { assert(bytes != NULL); - unsigned int code = bytes[0U]; - code <<= 8; - code |= bytes[1U]; - code <<= 8; - code |= bytes[2U]; + unsigned int code = (bytes[0U] << 16) | (bytes[1U] << 8) | (bytes[2U] << 0); - return decode23127(code >> 1); + return decode24128(code, valid); } diff --git a/Golay24128.h b/Golay24128.h index 1ac7852..721dcbc 100644 --- a/Golay24128.h +++ b/Golay24128.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2010,2016,2021 by Jonathan Naylor G4KLX * * 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 @@ -25,8 +25,8 @@ public: static unsigned int encode24128(unsigned int data); static unsigned int decode23127(unsigned int code); - static unsigned int decode24128(unsigned int code); - static unsigned int decode24128(unsigned char* bytes); + static unsigned int decode24128(unsigned int code, bool& valid); + static unsigned int decode24128(unsigned char* bytes, bool& valid); }; #endif diff --git a/M17Control.cpp b/M17Control.cpp index 14d1c83..4defcd7 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -206,13 +206,14 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) } if (m_rfState == RS_RF_LATE_ENTRY && data[0U] == TAG_DATA) { - unsigned int frag1, frag2, frag3, frag4; - CM17Utils::splitFragmentLICHFEC(data + 2U + M17_SYNC_LENGTH_BYTES, frag1, frag2, frag3, frag4); + bool valid1, valid2, valid3, valid4; + unsigned int lich1 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 0U, valid1); + unsigned int lich2 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 3U, valid2); + unsigned int lich3 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 6U, valid3); + unsigned int lich4 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 9U, valid4); - unsigned int lich1 = CGolay24128::decode24128(frag1); - unsigned int lich2 = CGolay24128::decode24128(frag2); - unsigned int lich3 = CGolay24128::decode24128(frag3); - unsigned int lich4 = CGolay24128::decode24128(frag4); + if (!valid1 || !valid2 || !valid3 || !valid4) + return false; unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); @@ -306,7 +307,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned int errors = 0U; for (unsigned int i = 0U; i < (M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES); i++) { unsigned int offset = i + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES; - errors += countBits(rfData[offset] ^ data[offset]); + errors += CUtils::countBits(rfData[offset] ^ data[offset]); } LogDebug("M17, FN: %u, errs: %u/144 (%.1f%%)", m_rfFN & 0x7FU, errors, float(errors) / 1.44F); @@ -785,17 +786,3 @@ void CM17Control::enable(bool enabled) m_enabled = enabled; } - -unsigned int CM17Control::countBits(unsigned char byte) -{ - unsigned int count = 0U; - - const unsigned char* p = &byte; - - for (unsigned int i = 0U; i < 8U; i++) { - if (READ_BIT(p, i) != 0U) - count++; - } - - return count; -} diff --git a/M17Control.h b/M17Control.h index 9ed515c..d351099 100644 --- a/M17Control.h +++ b/M17Control.h @@ -92,8 +92,6 @@ private: bool checkCallsign(const std::string& source) const; - unsigned int countBits(unsigned char byte); - void writeEndRF(); void writeEndNet(); diff --git a/Utils.cpp b/Utils.cpp index 49ded13..3ecdf60 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX + * Copyright (C) 2009,2014,2015,2016,2021 Jonathan Naylor, G4KLX * * 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 @@ -144,3 +144,15 @@ void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte) byte |= bits[6U] ? 0x40U : 0x00U; byte |= bits[7U] ? 0x80U : 0x00U; } + +unsigned int CUtils::countBits(unsigned int v) +{ + unsigned int count = 0U; + + while (v != 0U) { + v &= v - 1U; + count++; + } + + return count; +} diff --git a/Utils.h b/Utils.h index ade28c0..1929aa0 100644 --- a/Utils.h +++ b/Utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009,2014,2015 by Jonathan Naylor, G4KLX + * Copyright (C) 2009,2014,2015,2021 by Jonathan Naylor, G4KLX * * 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 @@ -30,6 +30,8 @@ public: static void bitsToByteBE(const bool* bits, unsigned char& byte); static void bitsToByteLE(const bool* bits, unsigned char& byte); + static unsigned int countBits(unsigned int v); + private: }; diff --git a/YSFFICH.cpp b/YSFFICH.cpp index 7227014..ce37a7f 100644 --- a/YSFFICH.cpp +++ b/YSFFICH.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2019,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,2019,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -99,10 +99,14 @@ bool CYSFFICH::decode(const unsigned char* bytes) unsigned char output[13U]; viterbi.chainback(output, 96U); - unsigned int b0 = CGolay24128::decode24128(output + 0U); - unsigned int b1 = CGolay24128::decode24128(output + 3U); - unsigned int b2 = CGolay24128::decode24128(output + 6U); - unsigned int b3 = CGolay24128::decode24128(output + 9U); + bool valid1, valid2, valid3, valid4; + unsigned int b0 = CGolay24128::decode24128(output + 0U, valid1); + unsigned int b1 = CGolay24128::decode24128(output + 3U, valid2); + unsigned int b2 = CGolay24128::decode24128(output + 6U, valid3); + unsigned int b3 = CGolay24128::decode24128(output + 9U, valid4); + + if (!valid1 || !valid2 || !valid3 || !valid4) + return false; m_fich[0U] = (b0 >> 4) & 0xFFU; m_fich[1U] = ((b0 << 4) & 0xF0U) | ((b1 >> 8) & 0x0FU); From 389bd3b928d63516120034ab98a4796869644c60 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 28 Mar 2021 15:29:26 +0100 Subject: [PATCH 19/23] Remove the CRC4 processing. --- M17CRC.cpp | 60 -------------------------------------------------- M17CRC.h | 4 ---- M17Control.cpp | 9 -------- Version.h | 2 +- 4 files changed, 1 insertion(+), 74 deletions(-) diff --git a/M17CRC.cpp b/M17CRC.cpp index 1fd42f0..e65b10c 100644 --- a/M17CRC.cpp +++ b/M17CRC.cpp @@ -46,24 +46,6 @@ const uint16_t CRC16_TABLE[] = {0x0000U, 0x5935U, 0xB26AU, 0xEB5FU, 0x3DE1U, 0x6 0xAC02U, 0xF537U, 0x2389U, 0x7ABCU, 0x91E3U, 0xC8D6U, 0x65AAU, 0x3C9FU, 0xD7C0U, 0x8EF5U, 0x584BU, 0x017EU, 0xEA21U, 0xB314U}; -const uint8_t CRC4_TABLE[] = { - 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc, 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6, - 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1, 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb, - 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf, 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5, - 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2, 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8, - 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa, 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0, - 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7, 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd, - 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9, 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3, - 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4, 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe, - 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0, 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa, - 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd, 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7, - 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3, 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9, - 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe, 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4, - 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6, 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc, - 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb, 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1, - 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5, 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf, - 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8, 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2}; - bool CM17CRC::checkCRC16(const unsigned char* in, unsigned int nBytes) { assert(in != NULL); @@ -100,45 +82,3 @@ uint16_t CM17CRC::createCRC16(const unsigned char* in, unsigned int nBytes) return crc; } - -bool CM17CRC::checkCRC4(unsigned char* in, unsigned int nBytes) -{ - assert(in != NULL); - assert(nBytes > 1U); - - uint8_t save = in[nBytes - 1U] & 0x0FU; - - // Mask out the 4-bit CRC location - in[nBytes - 1U] &= 0xF0U; - - uint8_t crc = createCRC4(in, nBytes); - - // Restore the original CRC - in[nBytes - 1U] |= save; - - return save == crc; -} - -void CM17CRC::encodeCRC4(unsigned char* in, unsigned int nBytes) -{ - assert(in != NULL); - assert(nBytes > 1U); - - in[nBytes - 1U] &= 0xF0U; - - uint8_t crc = createCRC4(in, nBytes); - - in[nBytes - 1U] |= crc & 0x0FU; -} - -uint8_t CM17CRC::createCRC4(const unsigned char* in, unsigned int nBytes) -{ - assert(in != NULL); - - uint8_t crc = 0x0FU; - - for (unsigned int i = 0U; i < nBytes; i++) - crc = CRC4_TABLE[crc ^ in[i]]; - - return crc; -} diff --git a/M17CRC.h b/M17CRC.h index a1cfa53..d06a9de 100644 --- a/M17CRC.h +++ b/M17CRC.h @@ -27,12 +27,8 @@ public: static bool checkCRC16(const unsigned char* in, unsigned int nBytes); static void encodeCRC16(unsigned char* in, unsigned int nBytes); - static bool checkCRC4(unsigned char* in, unsigned int nBytes); - static void encodeCRC4(unsigned char* in, unsigned int nBytes); - private: static uint16_t createCRC16(const unsigned char* in, unsigned int nBytes); - static uint8_t createCRC4(const unsigned char* in, unsigned int nBytes); }; #endif diff --git a/M17Control.cpp b/M17Control.cpp index 4defcd7..aaf2342 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -218,9 +218,6 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); - // if (!CM17CRC::checkCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES)) - // return false; - m_rfLSFn = (lich4 >> 5) & 0x07U; m_rfLSF.setFragment(lich, m_rfLSFn); @@ -286,9 +283,6 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) // Add the fragment number lich[5U] = (m_rfLSFn & 0x07U) << 5; - // Add the CRC - // CM17CRC::encodeCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); - unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); @@ -508,9 +502,6 @@ void CM17Control::writeNetwork() // Add the fragment number lich[5U] = (m_netLSFn & 0x07U) << 5; - // Add the CRC - // CM17CRC::encodeCRC4(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); - unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); diff --git a/Version.h b/Version.h index 19fef83..36c3a74 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210327"; +const char* VERSION = "20210328"; #endif From 8dc54ed21f8ee4677acec9ce701f451af22dc58d Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Mar 2021 19:36:55 +0100 Subject: [PATCH 20/23] Ignore M17 packet data, for now. --- DMRControl.cpp | 2 +- DMRDefines.h | 8 ++++---- DMRSlot.cpp | 36 ++++++++++++++++++------------------ DStarControl.cpp | 8 ++++---- DStarDefines.h | 6 +++--- DStarNetwork.cpp | 6 +++--- Defines.h | 7 ++++--- FMControl.cpp | 2 +- M17Control.cpp | 20 +++++++++++++++----- Modem.cpp | 48 ++++++++++++++++++++++++------------------------ NXDNControl.cpp | 20 ++++++++++---------- P25Control.cpp | 16 ++++++++-------- Version.h | 2 +- YSFControl.cpp | 20 ++++++++++---------- 14 files changed, 106 insertions(+), 95 deletions(-) diff --git a/DMRControl.cpp b/DMRControl.cpp index 5761080..40178ba 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -50,7 +50,7 @@ bool CDMRControl::processWakeup(const unsigned char* data) assert(data != NULL); // Wakeups always come in on slot 1 - if (data[0U] != TAG_DATA || data[1U] != (DMR_IDLE_RX | DMR_SYNC_DATA | DT_CSBK)) + if (data[0U] != TAG_DATA1 || data[1U] != (DMR_IDLE_RX | DMR_SYNC_DATA | DT_CSBK)) return false; CDMRCSBK csbk; diff --git a/DMRDefines.h b/DMRDefines.h index 5b53c33..ca08c19 100644 --- a/DMRDefines.h +++ b/DMRDefines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2021 by Jonathan Naylor G4KLX * * 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 @@ -19,7 +19,7 @@ #if !defined(DMRDefines_H) #define DMRDefines_H -#include "Defines.h" // For TAG_DATA +#include "Defines.h" // For TAG_DATA1 const unsigned int DMR_FRAME_LENGTH_BITS = 264U; const unsigned int DMR_FRAME_LENGTH_BYTES = 33U; @@ -54,13 +54,13 @@ const unsigned char DIRECT_SLOT2_DATA_SYNC[] = {0x0DU, 0x75U, 0x57U, 0xF5U, 0xF const unsigned char SYNC_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U}; // The PR FILL and Data Sync pattern. -const unsigned char DMR_IDLE_DATA[] = {TAG_DATA, 0x00U, +const unsigned char DMR_IDLE_DATA[] = {TAG_DATA1, 0x00U, 0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U, 0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U, 0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U}; // A silence frame only -const unsigned char DMR_SILENCE_DATA[] = {TAG_DATA, 0x00U, +const unsigned char DMR_SILENCE_DATA[] = {TAG_DATA1, 0x00U, 0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU, 0xB9U, 0xE8U, 0x81U, 0x52U, 0x60U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x73U, 0x00U, 0x2AU, 0x6BU, 0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU}; diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 1f405ca..374dc40 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -255,7 +255,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) // Convert the Data Sync to be from the BS or MS as needed CSync::addDMRDataSync(data + 2U, m_duplex); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; m_rfTimeoutTimer.start(); @@ -315,7 +315,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) bptc.decode(data + 2U, payload); bptc.encode(payload, data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; if (m_duplex) @@ -404,7 +404,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) // Convert the Data Sync to be from the BS or MS as needed CSync::addDMRDataSync(data + 2U, m_duplex); - data[0U] = m_rfFrames == 0U ? TAG_EOT : TAG_DATA; + data[0U] = m_rfFrames == 0U ? TAG_EOT : TAG_DATA1; data[1U] = 0x00U; if (m_duplex) @@ -472,7 +472,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) // Convert the Data Sync to be from the BS or MS as needed CSync::addDMRDataSync(data + 2U, m_duplex); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; if (m_duplex) @@ -545,7 +545,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) m_rfFrames--; - data[0U] = m_rfFrames == 0U ? TAG_EOT : TAG_DATA; + data[0U] = m_rfFrames == 0U ? TAG_EOT : TAG_DATA1; data[1U] = 0x00U; if (m_duplex) @@ -586,7 +586,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) m_display->writeDMRRSSI(m_slotNo, m_rssi); if (!m_rfTimeout) { - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; if (m_duplex) @@ -752,7 +752,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) emb.getData(data + 2U); if (!m_rfTimeout) { - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeNetworkRF(data, DT_VOICE, errors); @@ -828,7 +828,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) slotType.setDataType(DT_VOICE_LC_HEADER); slotType.getData(start + 2U); - start[0U] = TAG_DATA; + start[0U] = TAG_DATA1; start[1U] = 0x00U; m_rfTimeoutTimer.start(); @@ -880,7 +880,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) m_rfBits += 141U; m_rfFrames++; - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; if (m_duplex) @@ -1088,7 +1088,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // Convert the Data Sync to be from the BS or MS as needed CSync::addDMRDataSync(data + 2U, m_duplex); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; m_lastFrameValid = false; @@ -1177,7 +1177,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) slotType.setDataType(DT_VOICE_LC_HEADER); slotType.getData(start + 2U); - start[0U] = TAG_DATA; + start[0U] = TAG_DATA1; start[1U] = 0x00U; if (m_duplex) { @@ -1224,7 +1224,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) bptc.decode(data + 2U, payload); bptc.encode(payload, data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeQueueNet(data); @@ -1304,7 +1304,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // Convert the Data Sync to be from the BS or MS as needed CSync::addDMRDataSync(data + 2U, m_duplex); - data[0U] = m_netFrames == 0U ? TAG_EOT : TAG_DATA; + data[0U] = m_netFrames == 0U ? TAG_EOT : TAG_DATA1; data[1U] = 0x00U; // Put a small delay into starting transmission @@ -1374,7 +1374,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) slotType.setDataType(DT_VOICE_LC_HEADER); slotType.getData(start + 2U); - start[0U] = TAG_DATA; + start[0U] = TAG_DATA1; start[1U] = 0x00U; if (m_duplex) { @@ -1417,7 +1417,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netErrs += m_fec.regenerateDMR(data + 2U); m_netBits += 141U; - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; // Convert the Audio Sync to be from the BS or MS as needed @@ -1572,7 +1572,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) emb.setLCSS(lcss); emb.getData(data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; // Initialise the lost packet data @@ -1633,7 +1633,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // Convert the Data Sync to be from the BS or MS as needed CSync::addDMRDataSync(data + 2U, m_duplex); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; if (csbko == CSBKO_PRECCSBK && csbk.getDataContent()) { @@ -1732,7 +1732,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netFrames--; - data[0U] = m_netFrames == 0U ? TAG_EOT : TAG_DATA; + data[0U] = m_netFrames == 0U ? TAG_EOT : TAG_DATA1; data[1U] = 0x00U; #if defined(DUMP_DMR) diff --git a/DStarControl.cpp b/DStarControl.cpp index 786702a..61837db 100644 --- a/DStarControl.cpp +++ b/DStarControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 Jonathan Naylor, G4KLX + * Copyright (C) 2015-2019,2021 Jonathan Naylor, G4KLX * * 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 @@ -429,7 +429,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) } return false; - } else if (type == TAG_DATA) { + } else if (type == TAG_DATA1) { if (m_rfState == RS_RF_REJECTED) { return false; } else if (m_rfState == RS_RF_INVALID) { @@ -779,13 +779,13 @@ void CDStarControl::writeNetwork() LogMessage("D-Star, received network end of transmission from %8.8s/%4.4s to %8.8s, %.1f seconds, %u%% packet loss, BER: %.1f%%", my1, my2, your, float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames, float(m_netErrs * 100U) / float(m_netBits)); writeEndNet(); - } else if (type == TAG_DATA) { + } else if (type == TAG_DATA1) { if (m_netState != RS_NET_AUDIO) return; unsigned char n = data[1U]; - data[1U] = TAG_DATA; + data[1U] = TAG_DATA1; unsigned int errors = 0U; if (!m_netHeader.isDataPacket()) diff --git a/DStarDefines.h b/DStarDefines.h index 2a3e90c..f6ad749 100644 --- a/DStarDefines.h +++ b/DStarDefines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2018,2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2018,2019,2021 by Jonathan Naylor G4KLX * * 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 @@ -35,8 +35,8 @@ const unsigned char DSTAR_NULL_SLOW_SYNC_BYTES[] = { 0x55, 0x2D, 0x16 }; // Note that these are already scrambled, 0x66 0x66 0x66 otherwise const unsigned char DSTAR_NULL_SLOW_DATA_BYTES[] = { 0x16, 0x29, 0xF5 }; -const unsigned char DSTAR_NULL_FRAME_SYNC_BYTES[] = { TAG_DATA, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16 }; -const unsigned char DSTAR_NULL_FRAME_DATA_BYTES[] = { TAG_DATA, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x16, 0x29, 0xF5 }; +const unsigned char DSTAR_NULL_FRAME_SYNC_BYTES[] = { TAG_DATA1, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16 }; +const unsigned char DSTAR_NULL_FRAME_DATA_BYTES[] = { TAG_DATA1, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x16, 0x29, 0xF5 }; const unsigned int DSTAR_VOICE_FRAME_LENGTH_BYTES = 9U; const unsigned int DSTAR_DATA_FRAME_LENGTH_BYTES = 3U; diff --git a/DStarNetwork.cpp b/DStarNetwork.cpp index 4a978e2..2de9051 100644 --- a/DStarNetwork.cpp +++ b/DStarNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2019,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2014,2016,2019,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -263,7 +263,7 @@ void CDStarNetwork::clock(unsigned int ms) m_inId = 0U; ctrl[1U] = TAG_EOT; } else { - ctrl[1U] = TAG_DATA; + ctrl[1U] = TAG_DATA1; } ctrl[2U] = buffer[7] & 0x3FU; @@ -299,7 +299,7 @@ unsigned int CDStarNetwork::read(unsigned char* data, unsigned int length) switch (buffer[0U]) { case TAG_HEADER: - case TAG_DATA: + case TAG_DATA1: case TAG_EOT: ::memcpy(data, buffer, c); return c; diff --git a/Defines.h b/Defines.h index 0381a43..58f4348 100644 --- a/Defines.h +++ b/Defines.h @@ -36,9 +36,10 @@ const unsigned char MODE_ERROR = 100U; const unsigned char MODE_QUIT = 110U; const unsigned char TAG_HEADER = 0x00U; -const unsigned char TAG_DATA = 0x01U; -const unsigned char TAG_LOST = 0x02U; -const unsigned char TAG_EOT = 0x03U; +const unsigned char TAG_DATA1 = 0x01U; +const unsigned char TAG_DATA2 = 0x02U; +const unsigned char TAG_LOST = 0x03U; +const unsigned char TAG_EOT = 0x04U; const unsigned int DSTAR_MODEM_DATA_LEN = 220U; diff --git a/FMControl.cpp b/FMControl.cpp index 7f1ff07..1708c61 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -81,7 +81,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (data[0U] == TAG_EOT) return m_network->writeEOT(); - if (data[0U] != TAG_DATA) + if (data[0U] != TAG_DATA1) return false; m_incomingRFAudio.addData(data + 1U, length - 1U); diff --git a/M17Control.cpp b/M17Control.cpp index aaf2342..653413d 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -135,6 +135,12 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) return false; } + // Ignore packet data + if (type == TAG_DATA2) { + m_rfState = RS_RF_LISTENING; + return false; + } + // Have we got RSSI bytes on the end? if (len == (M17_FRAME_LENGTH_BYTES + 4U)) { uint16_t raw = 0U; @@ -200,12 +206,12 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) } } - if (m_rfState == RS_RF_LISTENING && data[0U] == TAG_DATA) { + if (m_rfState == RS_RF_LISTENING && data[0U] == TAG_DATA1) { m_rfState = RS_RF_LATE_ENTRY; m_rfLSF.reset(); } - if (m_rfState == RS_RF_LATE_ENTRY && data[0U] == TAG_DATA) { + if (m_rfState == RS_RF_LATE_ENTRY && data[0U] == TAG_DATA1) { bool valid1, valid2, valid3, valid4; unsigned int lich1 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 0U, valid1); unsigned int lich2 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 3U, valid2); @@ -247,7 +253,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) } } - if (m_rfState == RS_RF_AUDIO && data[0U] == TAG_DATA) { + if (m_rfState == RS_RF_AUDIO && data[0U] == TAG_DATA1) { #if defined(DUMP_M17) writeFile(data + 2U); #endif @@ -271,7 +277,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char rfData[2U + M17_FRAME_LENGTH_BYTES]; - rfData[0U] = TAG_DATA; + rfData[0U] = TAG_DATA1; rfData[1U] = 0x00U; // Generate the sync @@ -487,7 +493,7 @@ void CM17Control::writeNetwork() if (m_netState == RS_NET_AUDIO) { unsigned char data[M17_FRAME_LENGTH_BYTES + 2U]; - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; // Generate the sync @@ -547,6 +553,10 @@ void CM17Control::writeNetwork() bool CM17Control::processRFHeader(bool lateEntry) { + unsigned char packetStream = m_rfLSF.getPacketStream(); + if (packetStream == M17_PACKET_TYPE) + return false; + unsigned char can = m_rfLSF.getCAN(); if (can != m_can) return false; diff --git a/Modem.cpp b/Modem.cpp index 795302b..1a33935 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -468,7 +468,7 @@ void CModem::clock(unsigned int ms) unsigned char data = m_length - m_offset + 1U; m_rxDStarData.addData(&data, 1U); - data = TAG_DATA; + data = TAG_DATA1; m_rxDStarData.addData(&data, 1U); m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); @@ -509,7 +509,7 @@ void CModem::clock(unsigned int ms) if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) data = TAG_EOT; else - data = TAG_DATA; + data = TAG_DATA1; m_rxDMRData1.addData(&data, 1U); m_rxDMRData1.addData(m_buffer + m_offset, m_length - m_offset); @@ -526,7 +526,7 @@ void CModem::clock(unsigned int ms) if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) data = TAG_EOT; else - data = TAG_DATA; + data = TAG_DATA1; m_rxDMRData2.addData(&data, 1U); m_rxDMRData2.addData(m_buffer + m_offset, m_length - m_offset); @@ -564,7 +564,7 @@ void CModem::clock(unsigned int ms) unsigned char data = m_length - m_offset + 1U; m_rxYSFData.addData(&data, 1U); - data = TAG_DATA; + data = TAG_DATA1; m_rxYSFData.addData(&data, 1U); m_rxYSFData.addData(m_buffer + m_offset, m_length - m_offset); @@ -604,7 +604,7 @@ void CModem::clock(unsigned int ms) unsigned char data = m_length - m_offset + 1U; m_rxP25Data.addData(&data, 1U); - data = TAG_DATA; + data = TAG_DATA1; m_rxP25Data.addData(&data, 1U); m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); @@ -630,7 +630,7 @@ void CModem::clock(unsigned int ms) unsigned char data = m_length - m_offset + 1U; m_rxNXDNData.addData(&data, 1U); - data = TAG_DATA; + data = TAG_DATA1; m_rxNXDNData.addData(&data, 1U); m_rxNXDNData.addData(m_buffer + m_offset, m_length - m_offset); @@ -670,7 +670,7 @@ void CModem::clock(unsigned int ms) unsigned char data = m_length - 2U; m_rxM17Data.addData(&data, 1U); - data = TAG_DATA; + data = TAG_DATA1; m_rxM17Data.addData(&data, 1U); m_rxM17Data.addData(m_buffer + 3U, m_length - 3U); @@ -684,7 +684,7 @@ void CModem::clock(unsigned int ms) unsigned char data = m_length - 2U; m_rxM17Data.addData(&data, 1U); - data = TAG_DATA; + data = TAG_DATA2; m_rxM17Data.addData(&data, 1U); m_rxM17Data.addData(m_buffer + 3U, m_length - 3U); @@ -710,7 +710,7 @@ void CModem::clock(unsigned int ms) unsigned int data1 = m_length - m_offset + 1U; m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); - unsigned char data2 = TAG_DATA; + unsigned char data2 = TAG_DATA1; m_rxFMData.addData(&data2, 1U); m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); @@ -1322,7 +1322,7 @@ bool CModem::writeDStarData(const unsigned char* data, unsigned int length) case TAG_HEADER: buffer[2U] = MMDVM_DSTAR_HEADER; break; - case TAG_DATA: + case TAG_DATA1: buffer[2U] = MMDVM_DSTAR_DATA; break; case TAG_EOT: @@ -1361,7 +1361,7 @@ bool CModem::writeDMRData1(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); - if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + if (data[0U] != TAG_DATA1 && data[0U] != TAG_EOT) return false; unsigned char buffer[40U]; @@ -1384,7 +1384,7 @@ bool CModem::writeDMRData2(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); - if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + if (data[0U] != TAG_DATA1 && data[0U] != TAG_EOT) return false; unsigned char buffer[40U]; @@ -1414,7 +1414,7 @@ bool CModem::writeYSFData(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); - if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + if (data[0U] != TAG_DATA1 && data[0U] != TAG_EOT) return false; unsigned char buffer[130U]; @@ -1444,7 +1444,7 @@ bool CModem::writeP25Data(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); - if (data[0U] != TAG_HEADER && data[0U] != TAG_DATA && data[0U] != TAG_EOT) + if (data[0U] != TAG_HEADER && data[0U] != TAG_DATA1 && data[0U] != TAG_EOT) return false; unsigned char buffer[250U]; @@ -1474,7 +1474,7 @@ bool CModem::writeNXDNData(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); - if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + if (data[0U] != TAG_DATA1 && data[0U] != TAG_EOT) return false; unsigned char buffer[130U]; @@ -1504,7 +1504,7 @@ bool CModem::writeM17Data(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); - if (data[0U] != TAG_HEADER && data[0U] != TAG_DATA && data[0U] != TAG_EOT) + if (data[0U] != TAG_HEADER && data[0U] != TAG_DATA1 && data[0U] != TAG_EOT) return false; unsigned char buffer[130U]; @@ -1823,7 +1823,7 @@ bool CModem::writePOCSAGInfo(unsigned int ric, const std::string& message) unsigned char buffer[250U]; buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 11U; + buffer[1U] = (unsigned char)length + 11U; buffer[2U] = MMDVM_QSO_INFO; buffer[3U] = MODE_POCSAG; @@ -1832,7 +1832,7 @@ bool CModem::writePOCSAGInfo(unsigned int ric, const std::string& message) ::memcpy(buffer + 11U, message.c_str(), length); - int ret = m_port->write(buffer, length + 11U); + int ret = m_port->write(buffer, (unsigned int)length + 11U); return ret != int(length + 11U); } @@ -1846,14 +1846,14 @@ bool CModem::writeIPInfo(const std::string& address) unsigned char buffer[25U]; buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 4U; + buffer[1U] = (unsigned char)length + 4U; buffer[2U] = MMDVM_QSO_INFO; buffer[3U] = 250U; ::memcpy(buffer + 4U, address.c_str(), length); - int ret = m_port->write(buffer, length + 4U); + int ret = m_port->write(buffer, (unsigned int)length + 4U); return ret != int(length + 4U); } @@ -2485,7 +2485,7 @@ bool CModem::sendCWId(const std::string& callsign) { assert(m_port != NULL); - unsigned int length = callsign.length(); + unsigned int length = (unsigned int)callsign.length(); if (length > 200U) length = 200U; @@ -2631,7 +2631,7 @@ bool CModem::setFMCallsignParams() assert(m_port != NULL); unsigned char buffer[80U]; - unsigned char len = 10U + m_fmCallsign.size(); + unsigned char len = 10U + (unsigned char)m_fmCallsign.size(); buffer[0U] = MMDVM_FRAME_START; buffer[1U] = len; @@ -2692,7 +2692,7 @@ bool CModem::setFMAckParams() assert(m_port != NULL); unsigned char buffer[80U]; - unsigned char len = 8U + m_fmRfAck.size(); + unsigned char len = 8U + (unsigned char)m_fmRfAck.size(); buffer[0U] = MMDVM_FRAME_START; buffer[1U] = len; @@ -2811,7 +2811,7 @@ bool CModem::setFMExtParams() assert(m_port != NULL); unsigned char buffer[80U]; - unsigned char len = 7U + m_fmExtAck.size(); + unsigned char len = 7U + (unsigned char)m_fmExtAck.size(); buffer[0U] = MMDVM_FRAME_START; buffer[1U] = len; diff --git a/NXDNControl.cpp b/NXDNControl.cpp index 119fad6..d040ca7 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 Jonathan Naylor, G4KLX + * Copyright (C) 2015-2021 Jonathan Naylor, G4KLX * * 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 @@ -223,7 +223,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne m_rfLayer3 = layer3; - data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA; + data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA1; data[1U] = 0x00U; CSync::addNXDNSync(data + 2U); @@ -401,7 +401,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne // Create a dummy start message unsigned char start[NXDN_FRAME_LENGTH_BYTES + 2U]; - start[0U] = TAG_DATA; + start[0U] = TAG_DATA1; start[1U] = 0x00U; // Generate the sync @@ -539,7 +539,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne facch12.getRaw(netData + 5U + 14U); } - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; scrambler(data + 2U); @@ -638,12 +638,12 @@ bool CNXDNControl::processData(unsigned char option, unsigned char *data) if (validUDCH) { type = layer3.getMessageType(); - data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA; + data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA1; udch.setRAN(m_ran); udch.encode(data + 2U); } else { - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; } @@ -785,7 +785,7 @@ void CNXDNControl::writeNetwork() } if (m_netState == RS_NET_DATA) { - data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA; + data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA1; data[1U] = 0x00U; CNXDNUDCH udch; @@ -826,7 +826,7 @@ void CNXDNControl::writeNetwork() facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); - data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA; + data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA1; data[1U] = 0x00U; scrambler(data + 2U); @@ -907,7 +907,7 @@ void CNXDNControl::writeNetwork() // Create a dummy start message unsigned char start[NXDN_FRAME_LENGTH_BYTES + 2U]; - start[0U] = TAG_DATA; + start[0U] = TAG_DATA1; start[1U] = 0x00U; // Generate the sync @@ -942,7 +942,7 @@ void CNXDNControl::writeNetwork() m_netFrames++; - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; CNXDNSACCH sacch; diff --git a/P25Control.cpp b/P25Control.cpp index b9825f0..3e382ea 100644 --- a/P25Control.cpp +++ b/P25Control.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016-2019 by Jonathan Naylor G4KLX +* Copyright (C) 2016-2019,2021 by Jonathan Naylor G4KLX * Copyright (C) 2018 by Bryan Biedenkapp * * This program is free software; you can redistribute it and/or modify @@ -303,7 +303,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) ::memcpy(m_rfLDU, data + 2U, P25_LDU_FRAME_LENGTH_BYTES); if (m_duplex) { - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U); } @@ -349,7 +349,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) ::memcpy(m_rfLDU, data + 2U, P25_LDU_FRAME_LENGTH_BYTES); if (m_duplex) { - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U); } @@ -399,7 +399,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) setBusyBits(data + 2U, P25_SS0_START, true, true); if (m_duplex) { - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeQueueRF(data, P25_TSDU_FRAME_LENGTH_BYTES + 2U); @@ -425,7 +425,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) setBusyBits(data + 2U, P25_SS0_START, true, true); if (m_duplex) { - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeQueueRF(data, P25_TSDU_FRAME_LENGTH_BYTES + 2U); @@ -569,7 +569,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) addBusyBits(pdu + 2U, newBitLength, false, true); if (m_duplex) { - pdu[0U] = TAG_DATA; + pdu[0U] = TAG_DATA1; pdu[1U] = 0x00U; writeQueueRF(pdu, newByteLength + 2U); } @@ -1010,7 +1010,7 @@ void CP25Control::createNetLDU1() unsigned char buffer[P25_LDU_FRAME_LENGTH_BYTES + 2U]; ::memset(buffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 2U); - buffer[0U] = TAG_DATA; + buffer[0U] = TAG_DATA1; buffer[1U] = 0x00U; // Add the sync @@ -1058,7 +1058,7 @@ void CP25Control::createNetLDU2() unsigned char buffer[P25_LDU_FRAME_LENGTH_BYTES + 2U]; ::memset(buffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 2U); - buffer[0U] = TAG_DATA; + buffer[0U] = TAG_DATA1; buffer[1U] = 0x00U; // Add the sync diff --git a/Version.h b/Version.h index 36c3a74..7dbf25d 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210328"; +const char* VERSION = "20210329"; #endif diff --git a/YSFControl.cpp b/YSFControl.cpp index 8855160..efb2213 100644 --- a/YSFControl.cpp +++ b/YSFControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 Jonathan Naylor, G4KLX + * Copyright (C) 2015-2021 Jonathan Naylor, G4KLX * * 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 @@ -265,7 +265,7 @@ bool CYSFControl::processVWData(bool valid, unsigned char *data) fich.encode(data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeNetwork(data, m_rfFrames % 128U); @@ -358,7 +358,7 @@ bool CYSFControl::processVWData(bool valid, unsigned char *data) fich.encode(data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeNetwork(data, m_rfFrames % 128U); @@ -434,7 +434,7 @@ bool CYSFControl::processDNData(bool valid, unsigned char *data) fich.encode(data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeNetwork(data, m_rfFrames % 128U); @@ -540,7 +540,7 @@ bool CYSFControl::processDNData(bool valid, unsigned char *data) fich.encode(data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeNetwork(data, m_rfFrames % 128U); @@ -636,7 +636,7 @@ bool CYSFControl::processDNData(bool valid, unsigned char *data) CYSFPayload payload; payload.writeHeader(buffer + 2U, csd1, csd2); - buffer[0U] = TAG_DATA; + buffer[0U] = TAG_DATA1; buffer[1U] = 0x00U; writeNetwork(buffer, m_rfFrames % 128U); @@ -660,7 +660,7 @@ bool CYSFControl::processDNData(bool valid, unsigned char *data) fich.encode(data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeNetwork(data, m_rfFrames % 128U); @@ -733,7 +733,7 @@ bool CYSFControl::processFRData(bool valid, unsigned char *data) fich.encode(data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeNetwork(data, m_rfFrames % 128U); @@ -814,7 +814,7 @@ bool CYSFControl::processFRData(bool valid, unsigned char *data) fich.encode(data + 2U); - data[0U] = TAG_DATA; + data[0U] = TAG_DATA1; data[1U] = 0x00U; writeNetwork(data, m_rfFrames % 128U); @@ -949,7 +949,7 @@ void CYSFControl::writeNetwork() return; } - data[33U] = end ? TAG_EOT : TAG_DATA; + data[33U] = end ? TAG_EOT : TAG_DATA1; data[34U] = 0x00U; if (valid) { From c08b41a17a641e9fc6e7e71642c3580a1ed37341 Mon Sep 17 00:00:00 2001 From: Daniel Caujolle-Bert Date: Wed, 31 Mar 2021 13:34:31 +0200 Subject: [PATCH 21/23] Fix nasty bug in UDPSocket::close(). --- UDPSocket.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/UDPSocket.cpp b/UDPSocket.cpp index ad8a0eb..7b819fe 100644 --- a/UDPSocket.cpp +++ b/UDPSocket.cpp @@ -188,6 +188,8 @@ bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std return false; } + close(index); + int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); if (fd < 0) { #if defined(_WIN32) || defined(_WIN64) @@ -344,13 +346,13 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s void CUDPSocket::close() { - for (int i = 0; i < UDP_SOCKET_MAX; i++) - close(m_fd[i]); + for (unsigned int i = 0; i < UDP_SOCKET_MAX; i++) + close(i); } void CUDPSocket::close(const unsigned int index) { - if (m_fd[index] >= 0) { + if ((index < UDP_SOCKET_MAX) && (m_fd[index] >= 0)) { #if defined(_WIN32) || defined(_WIN64) ::closesocket(m_fd[index]); #else From ffb4bdb0423ba23c88464f2ccd5742260a96ba70 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 7 Apr 2021 19:56:28 +0100 Subject: [PATCH 22/23] Refactor the Golay 24,12,8 code and its uses. --- AMBEFEC.cpp | 26 +++++++++++++++++--------- Golay24128.cpp | 20 +++++++++++--------- Golay24128.h | 5 +++-- M17Control.cpp | 10 +++++----- Version.h | 2 +- YSFFICH.cpp | 12 ++++++------ 6 files changed, 43 insertions(+), 32 deletions(-) diff --git a/AMBEFEC.cpp b/AMBEFEC.cpp index 4b28046..03f8ac2 100644 --- a/AMBEFEC.cpp +++ b/AMBEFEC.cpp @@ -793,22 +793,25 @@ unsigned int CAMBEFEC::regenerateIMBE(unsigned char* bytes) const unsigned int CAMBEFEC::regenerateDStar(unsigned int& a, unsigned int& b) const { - bool valid; - unsigned int orig_a = a; unsigned int orig_b = b; - unsigned int data = CGolay24128::decode24128(a, valid); - - a = CGolay24128::encode24128(data); + unsigned int data; + bool valid1 = CGolay24128::decode24128(a, data); + if (!valid1) + return 10U; // The PRNG unsigned int p = PRNG_TABLE[data]; b ^= p; - unsigned int datb = CGolay24128::decode24128(b, valid); + unsigned int datb; + bool valid2 = CGolay24128::decode24128(b, datb); + if (!valid2) + return 10U; + a = CGolay24128::encode24128(data); b = CGolay24128::encode24128(datb); b ^= p; @@ -824,12 +827,17 @@ unsigned int CAMBEFEC::regenerateDStar(unsigned int& a, unsigned int& b) const unsigned int CAMBEFEC::regenerateDMR(unsigned int& a, unsigned int& b, unsigned int& c) const { - bool valid; - unsigned int orig_a = a; unsigned int orig_b = b; - unsigned int data = CGolay24128::decode24128(a, valid); + unsigned int data; + bool valid = CGolay24128::decode24128(a, data); + if (!valid) { + a = 0xF00292U; + b = 0x0E0B20U; + c = 0x000000U; + return 10U; // An invalid A block gives an error count of 10 + } a = CGolay24128::encode24128(data); diff --git a/Golay24128.cpp b/Golay24128.cpp index 715c8dc..22cef65 100644 --- a/Golay24128.cpp +++ b/Golay24128.cpp @@ -1090,23 +1090,25 @@ unsigned int CGolay24128::decode23127(unsigned int code) return code >> 11; } -unsigned int CGolay24128::decode24128(unsigned int input, bool& valid) +bool CGolay24128::decode24128(unsigned int in, unsigned int& out) { - unsigned int syndrome = ::get_syndrome_23127(input >> 1); + unsigned int syndrome = ::get_syndrome_23127(in >> 1); unsigned int error_pattern = DECODING_TABLE_23127[syndrome] << 1; - unsigned int output = input ^ error_pattern; + out = in ^ error_pattern; - valid = (CUtils::countBits(syndrome) < 3U) || !(CUtils::countBits(output) & 1); + bool valid = (CUtils::countBits(syndrome) < 3U) || !(CUtils::countBits(out) & 1); - return output >> 12; + out >>= 12; + + return valid; } -unsigned int CGolay24128::decode24128(unsigned char* bytes, bool& valid) +bool CGolay24128::decode24128(unsigned char* in, unsigned int& out) { - assert(bytes != NULL); + assert(in != NULL); - unsigned int code = (bytes[0U] << 16) | (bytes[1U] << 8) | (bytes[2U] << 0); + unsigned int code = (in[0U] << 16) | (in[1U] << 8) | (in[2U] << 0); - return decode24128(code, valid); + return decode24128(code, out); } diff --git a/Golay24128.h b/Golay24128.h index 721dcbc..169b31a 100644 --- a/Golay24128.h +++ b/Golay24128.h @@ -25,8 +25,9 @@ public: static unsigned int encode24128(unsigned int data); static unsigned int decode23127(unsigned int code); - static unsigned int decode24128(unsigned int code, bool& valid); - static unsigned int decode24128(unsigned char* bytes, bool& valid); + + static bool decode24128(unsigned int in, unsigned int& out); + static bool decode24128(unsigned char* in, unsigned int& out); }; #endif diff --git a/M17Control.cpp b/M17Control.cpp index 653413d..f518037 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -212,11 +212,11 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) } if (m_rfState == RS_RF_LATE_ENTRY && data[0U] == TAG_DATA1) { - bool valid1, valid2, valid3, valid4; - unsigned int lich1 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 0U, valid1); - unsigned int lich2 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 3U, valid2); - unsigned int lich3 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 6U, valid3); - unsigned int lich4 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 9U, valid4); + unsigned int lich1, lich2, lich3, lich4; + bool valid1 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 0U, lich1); + bool valid2 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 3U, lich2); + bool valid3 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 6U, lich3); + bool valid4 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 9U, lich4); if (!valid1 || !valid2 || !valid3 || !valid4) return false; diff --git a/Version.h b/Version.h index 7dbf25d..9aea486 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210329"; +const char* VERSION = "20210407"; #endif diff --git a/YSFFICH.cpp b/YSFFICH.cpp index ce37a7f..cbe3175 100644 --- a/YSFFICH.cpp +++ b/YSFFICH.cpp @@ -99,13 +99,13 @@ bool CYSFFICH::decode(const unsigned char* bytes) unsigned char output[13U]; viterbi.chainback(output, 96U); - bool valid1, valid2, valid3, valid4; - unsigned int b0 = CGolay24128::decode24128(output + 0U, valid1); - unsigned int b1 = CGolay24128::decode24128(output + 3U, valid2); - unsigned int b2 = CGolay24128::decode24128(output + 6U, valid3); - unsigned int b3 = CGolay24128::decode24128(output + 9U, valid4); + unsigned int b0, b1, b2, b3; + bool valid0 = CGolay24128::decode24128(output + 0U, b0); + bool valid1 = CGolay24128::decode24128(output + 3U, b1); + bool valid2 = CGolay24128::decode24128(output + 6U, b2); + bool valid3 = CGolay24128::decode24128(output + 9U, b3); - if (!valid1 || !valid2 || !valid3 || !valid4) + if (!valid0 || !valid1 || !valid2 || !valid3) return false; m_fich[0U] = (b0 >> 4) & 0xFFU; From dad34bea987a539adced43bde14b726fba2b0ae3 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 8 Apr 2021 18:36:27 +0100 Subject: [PATCH 23/23] Don't send RPTCL on DMR under error conditions. --- DMRDirectNetwork.cpp | 14 +++++++------- DMRDirectNetwork.h | 2 +- DMRGatewayNetwork.cpp | 2 +- DMRGatewayNetwork.h | 4 ++-- DMRNetwork.h | 4 ++-- MMDVMHost.cpp | 2 +- Version.h | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/DMRDirectNetwork.cpp b/DMRDirectNetwork.cpp index a378f7a..a27a646 100644 --- a/DMRDirectNetwork.cpp +++ b/DMRDirectNetwork.cpp @@ -321,11 +321,11 @@ bool CDMRDirectNetwork::isConnected() const return (m_status == RUNNING); } -void CDMRDirectNetwork::close() +void CDMRDirectNetwork::close(bool sayGoodbye) { LogMessage("Closing DMR Network"); - if (m_status == RUNNING) { + if (sayGoodbye && (m_status == RUNNING)) { unsigned char buffer[9U]; ::memcpy(buffer + 0U, "RPTCL", 5U); ::memcpy(buffer + 5U, m_id, 4U); @@ -377,7 +377,7 @@ void CDMRDirectNetwork::clock(unsigned int ms) int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen); if (length < 0) { LogError("DMR, Socket has failed, retrying connection to the master"); - close(); + close(false); open(); return; } @@ -408,7 +408,7 @@ void CDMRDirectNetwork::clock(unsigned int ms) the Network sometimes times out and reaches here. We want it to reconnect so... */ LogError("DMR, Login to the master has failed, retrying network ..."); - close(); + close(false); open(); return; } @@ -452,7 +452,7 @@ void CDMRDirectNetwork::clock(unsigned int ms) } } else if (::memcmp(m_buffer, "MSTCL", 5U) == 0) { LogError("DMR, Master is closing down"); - close(); + close(false); open(); } else if (::memcmp(m_buffer, "MSTPONG", 7U) == 0) { m_timeoutTimer.start(); @@ -466,7 +466,7 @@ void CDMRDirectNetwork::clock(unsigned int ms) m_timeoutTimer.clock(ms); if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { LogError("DMR, Connection to the master has timed out, retrying connection"); - close(); + close(false); open(); } } @@ -635,7 +635,7 @@ bool CDMRDirectNetwork::write(const unsigned char* data, unsigned int length) bool ret = m_socket.write(data, length, m_addr, m_addrLen); if (!ret) { LogError("DMR, Socket has failed when writing data to the master, retrying connection"); - m_socket.close(); + close(false); open(); return false; } diff --git a/DMRDirectNetwork.h b/DMRDirectNetwork.h index f6e0834..6df82cc 100644 --- a/DMRDirectNetwork.h +++ b/DMRDirectNetwork.h @@ -57,7 +57,7 @@ public: virtual bool isConnected() const; - virtual void close(); + virtual void close(bool sayGoodbye); private: std::string m_address; diff --git a/DMRGatewayNetwork.cpp b/DMRGatewayNetwork.cpp index 775a79d..f6dfe47 100644 --- a/DMRGatewayNetwork.cpp +++ b/DMRGatewayNetwork.cpp @@ -292,7 +292,7 @@ bool CDMRGatewayNetwork::isConnected() const return (m_addrLen != 0); } -void CDMRGatewayNetwork::close() +void CDMRGatewayNetwork::close(bool sayGoodbye) { LogMessage("DMR, Closing DMR Network"); diff --git a/DMRGatewayNetwork.h b/DMRGatewayNetwork.h index bc00385..7bca94f 100644 --- a/DMRGatewayNetwork.h +++ b/DMRGatewayNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -58,7 +58,7 @@ public: virtual bool isConnected() const; - virtual void close(); + virtual void close(bool sayGoodbye); private: std::string m_addressStr; diff --git a/DMRNetwork.h b/DMRNetwork.h index 4a3c4d7..006e097 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -50,7 +50,7 @@ public: virtual bool isConnected() const = 0; - virtual void close() = 0; + virtual void close(bool sayGoodbye) = 0; private: }; diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 8409aac..ab8b5b1 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1118,7 +1118,7 @@ int CMMDVMHost::run() } if (m_dmrNetwork != NULL) { - m_dmrNetwork->close(); + m_dmrNetwork->close(true); delete m_dmrNetwork; } diff --git a/Version.h b/Version.h index 6e4502f..486d545 100644 --- a/Version.h +++ b/Version.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015-2021 by Jonathan Naylor G4KLX * * 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 @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210312"; +const char* VERSION = "20210408"; #endif