From bc791577e79b27ea57ff775133233b4d7e3ebf5e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 16:08:58 +0100 Subject: [PATCH 001/115] Beginnings of FM networking. --- Conf.cpp | 60 +++++++++++++++++ Conf.h | 17 +++++ FMControl.h | 55 ++++++++++++++++ FMNetwork.h | 55 ++++++++++++++++ MMDVM.ini | 9 +++ MMDVMHost.cpp | 131 ++++++++++++++++++++++++++++++++++---- MMDVMHost.h | 6 ++ MMDVMHost.vcxproj | 2 + MMDVMHost.vcxproj.filters | 6 ++ Modem.cpp | 83 +++++++++++++++++++++++- Modem.h | 6 ++ 11 files changed, 416 insertions(+), 14 deletions(-) create mode 100644 FMControl.h create mode 100644 FMNetwork.h diff --git a/Conf.cpp b/Conf.cpp index 8c07bc6..071c717 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -51,6 +51,7 @@ enum SECTION { SECTION_P25_NETWORK, SECTION_NXDN_NETWORK, SECTION_POCSAG_NETWORK, + SECTION_FM_NETWORK, SECTION_TFTSERIAL, SECTION_HD44780, SECTION_NEXTION, @@ -246,6 +247,13 @@ m_pocsagLocalAddress(), m_pocsagLocalPort(0U), m_pocsagNetworkModeHang(3U), m_pocsagNetworkDebug(false), +m_fmNetworkEnabled(false), +m_fmGatewayAddress(), +m_fmGatewayPort(0U), +m_fmLocalAddress(), +m_fmLocalPort(0U), +m_fmNetworkModeHang(3U), +m_fmNetworkDebug(false), m_tftSerialPort("/dev/ttyAMA0"), m_tftSerialBrightness(50U), m_hd44780Rows(2U), @@ -351,6 +359,8 @@ bool CConf::read() section = SECTION_NXDN_NETWORK; else if (::strncmp(buffer, "[POCSAG Network]", 16U) == 0) section = SECTION_POCSAG_NETWORK; + else if (::strncmp(buffer, "[FM Network]", 12U) == 0) + section = SECTION_FM_NETWORK; else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0) section = SECTION_TFTSERIAL; else if (::strncmp(buffer, "[HD44780]", 9U) == 0) @@ -858,6 +868,21 @@ bool CConf::read() m_pocsagNetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) m_pocsagNetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_POCSAG_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_fmNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "LocalAddress") == 0) + m_fmLocalAddress = value; + else if (::strcmp(key, "LocalPort") == 0) + m_fmLocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "GatewayAddress") == 0) + m_fmGatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_fmGatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_fmNetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_fmNetworkDebug = ::atoi(value) == 1; } else if (section == SECTION_TFTSERIAL) { if (::strcmp(key, "Port") == 0) m_tftSerialPort = value; @@ -1871,6 +1896,41 @@ bool CConf::getPOCSAGNetworkDebug() const return m_pocsagNetworkDebug; } +bool CConf::getFMNetworkEnabled() const +{ + return m_fmNetworkEnabled; +} + +std::string CConf::getFMGatewayAddress() const +{ + return m_fmGatewayAddress; +} + +unsigned int CConf::getFMGatewayPort() const +{ + return m_fmGatewayPort; +} + +std::string CConf::getFMLocalAddress() const +{ + return m_fmLocalAddress; +} + +unsigned int CConf::getFMLocalPort() const +{ + return m_fmLocalPort; +} + +unsigned int CConf::getFMNetworkModeHang() const +{ + return m_fmNetworkModeHang; +} + +bool CConf::getFMNetworkDebug() const +{ + return m_fmNetworkDebug; +} + std::string CConf::getTFTSerialPort() const { return m_tftSerialPort; diff --git a/Conf.h b/Conf.h index f5a40bd..915a21c 100644 --- a/Conf.h +++ b/Conf.h @@ -257,6 +257,15 @@ public: unsigned int getPOCSAGNetworkModeHang() const; bool getPOCSAGNetworkDebug() const; + // The FM Network section + bool getFMNetworkEnabled() const; + std::string getFMGatewayAddress() const; + unsigned int getFMGatewayPort() const; + std::string getFMLocalAddress() const; + unsigned int getFMLocalPort() const; + unsigned int getFMNetworkModeHang() const; + bool getFMNetworkDebug() const; + // The TFTSERIAL section std::string getTFTSerialPort() const; unsigned int getTFTSerialBrightness() const; @@ -518,6 +527,14 @@ private: unsigned int m_pocsagNetworkModeHang; bool m_pocsagNetworkDebug; + bool m_fmNetworkEnabled; + std::string m_fmGatewayAddress; + unsigned int m_fmGatewayPort; + std::string m_fmLocalAddress; + unsigned int m_fmLocalPort; + unsigned int m_fmNetworkModeHang; + bool m_fmNetworkDebug; + std::string m_tftSerialPort; unsigned int m_tftSerialBrightness; diff --git a/FMControl.h b/FMControl.h new file mode 100644 index 0000000..57dfd0b --- /dev/null +++ b/FMControl.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015-2019 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. + */ + +#if !defined(FMControl_H) +#define FMControl_H + +#include "FMNetwork.h" +#include "RingBuffer.h" +#include "StopWatch.h" +#include "Defines.h" +#include "Timer.h" +#include "Modem.h" + +#include + +class CFMControl { +public: + CFMControl(CFMNetwork* network); + ~CFMControl(); + + bool writeModem(unsigned char* data, unsigned int len); + + unsigned int readModem(unsigned char* data, unsigned int space); + + void clock(unsigned int ms); + + void enable(bool enabled); + +private: + CFMNetwork* m_network; + CRingBuffer m_queue; + bool m_enabled; + FILE* m_fp; + + bool openFile(); + bool writeFile(const unsigned char* data); + void closeFile(); +}; + +#endif diff --git a/FMNetwork.h b/FMNetwork.h new file mode 100644 index 0000000..5229098 --- /dev/null +++ b/FMNetwork.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef FMNetwork_H +#define FMNetwork_H + +#include "RingBuffer.h" +#include "UDPSocket.h" +#include "Timer.h" + +#include +#include + +class CFMNetwork { +public: + CFMNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug); + ~CFMNetwork(); + + bool open(); + + void enable(bool enabled); + + unsigned int read(unsigned char* data); + + void reset(); + + void close(); + + void clock(unsigned int ms); + +private: + CUDPSocket m_socket; + in_addr m_address; + unsigned int m_port; + bool m_debug; + bool m_enabled; + CRingBuffer m_buffer; +}; + +#endif diff --git a/MMDVM.ini b/MMDVM.ini index 5e71a84..a86bdd3 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -227,6 +227,15 @@ GatewayPort=4800 # ModeHang=3 Debug=0 +[FM Network] +Enable=1 +LocalAddress=127.0.0.1 +LocalPort=3810 +GatewayAddress=127.0.0.1 +GatewayPort=4810 +# ModeHang=3 +Debug=0 + [TFT Serial] # Port=modem Port=/dev/ttyAMA0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index e2a7766..b9f866e 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -119,12 +119,14 @@ m_ysf(NULL), m_p25(NULL), m_nxdn(NULL), m_pocsag(NULL), +m_fm(NULL), m_dstarNetwork(NULL), m_dmrNetwork(NULL), m_ysfNetwork(NULL), m_p25Network(NULL), m_nxdnNetwork(NULL), m_pocsagNetwork(NULL), +m_fmNetwork(NULL), m_display(NULL), m_ump(NULL), m_mode(MODE_IDLE), @@ -139,6 +141,7 @@ m_ysfNetModeHang(3U), m_p25NetModeHang(3U), m_nxdnNetModeHang(3U), m_pocsagNetModeHang(3U), +m_fmNetModeHang(3U), m_modeTimer(1000U), m_dmrTXTimer(1000U), m_cwIdTimer(1000U), @@ -317,6 +320,12 @@ int CMMDVMHost::run() return 1; } + if (m_fmEnabled && m_conf.getFMNetworkEnabled()) { + ret = createFMNetwork(); + if (!ret) + return 1; + } + in_addr transparentAddress; unsigned int transparentPort = 0U; CUDPSocket* transparentSocket = NULL; @@ -606,6 +615,9 @@ int CMMDVMHost::run() pocsagTimer.start(); } + if (m_fmEnabled) + m_fm = new CFMControl(m_fmNetwork); + bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); if (remoteControlEnabled) { unsigned int port = m_conf.getRemoteControlPort(); @@ -798,6 +810,22 @@ int CMMDVMHost::run() } } + len = m_modem->readFMData(data); + if (m_nxdn != NULL && len > 0U) { + if (m_mode == MODE_IDLE) { + bool ret = m_fm->writeModem(data, len); + if (ret) { + m_modeTimer.setTimeout(m_nxdnRFModeHang); + setMode(MODE_FM); + } + } else if (m_mode == MODE_FM) { + m_fm->writeModem(data, len); + m_modeTimer.start(); + } else if (m_mode != MODE_LOCKOUT) { + LogWarning("FM modem data received when in mode %u", m_mode); + } + } + len = m_modem->readTransparentData(data); if (transparentSocket != NULL && len > 0U) transparentSocket->write(data, len, transparentAddress, transparentPort); @@ -948,6 +976,25 @@ int CMMDVMHost::run() } } + if (m_fm != NULL) { + unsigned int space = m_modem->getFMSpace(); + if (space > 0U) { + len = m_fm->readModem(data, space); + if (len > 0U) { + if (m_mode == MODE_IDLE) { + m_modeTimer.setTimeout(m_fmNetModeHang); + setMode(MODE_FM); + } + if (m_mode == MODE_FM) { + m_modem->writeFMData(data, len); + m_modeTimer.start(); + } else if (m_mode != MODE_LOCKOUT) { + LogWarning("FM data received when in mode %u", m_mode); + } + } + } + } + if (transparentSocket != NULL) { in_addr address; unsigned int port = 0U; @@ -980,6 +1027,8 @@ int CMMDVMHost::run() m_nxdn->clock(ms); if (m_pocsag != NULL) m_pocsag->clock(ms); + if (m_fm != NULL) + m_fm->clock(ms); if (m_dstarNetwork != NULL) m_dstarNetwork->clock(ms); @@ -993,6 +1042,8 @@ int CMMDVMHost::run() m_nxdnNetwork->clock(ms); if (m_pocsagNetwork != NULL) m_pocsagNetwork->clock(ms); + if (m_fmNetwork != NULL) + m_fmNetwork->clock(ms); if (m_mobileGPS != NULL) m_mobileGPS->clock(ms); @@ -1118,6 +1169,11 @@ int CMMDVMHost::run() delete m_pocsagNetwork; } + if (m_fmNetwork != NULL) { + m_fmNetwork->close(); + delete m_fmNetwork; + } + if (transparentSocket != NULL) { transparentSocket->close(); delete transparentSocket; @@ -1134,6 +1190,7 @@ int CMMDVMHost::run() delete m_p25; delete m_nxdn; delete m_pocsag; + delete m_fm; return 0; } @@ -1517,6 +1574,36 @@ bool CMMDVMHost::createPOCSAGNetwork() return true; } +bool CMMDVMHost::createFMNetwork() +{ + std::string gatewayAddress = m_conf.getFMGatewayAddress(); + unsigned int gatewayPort = m_conf.getFMGatewayPort(); + std::string localAddress = m_conf.getFMLocalAddress(); + unsigned int localPort = m_conf.getFMLocalPort(); + m_fmNetModeHang = m_conf.getFMNetworkModeHang(); + bool debug = m_conf.getFMNetworkDebug(); + + LogInfo("FM Network Parameters"); + 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(" Mode Hang: %us", m_fmNetModeHang); + + m_fmNetwork = new CFMNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug); + + bool ret = m_fmNetwork->open(); + if (!ret) { + delete m_fmNetwork; + m_fmNetwork = NULL; + return false; + } + + m_fmNetwork->enable(true); + + return true; +} + void CMMDVMHost::readParams() { m_dstarEnabled = m_conf.getDStarEnabled(); @@ -1564,6 +1651,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(true); if (m_dmr != NULL) @@ -1598,6 +1687,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1636,6 +1727,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1670,6 +1763,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1704,6 +1799,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(true); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1738,6 +1835,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(true); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1812,6 +1911,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1852,6 +1953,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1890,6 +1993,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(true); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(true); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(true); if (m_dstar != NULL) m_dstar->enable(true); if (m_dmr != NULL) @@ -1980,55 +2085,55 @@ void CMMDVMHost::remoteControl() processModeCommand(MODE_NXDN, m_nxdnRFModeHang); break; case RCD_MODE_FM: - if (m_fmEnabled != false) + if (m_fmEnabled) processModeCommand(MODE_FM, 0); break; case RCD_ENABLE_DSTAR: - if (m_dstar != NULL && m_dstarEnabled==false) + if (m_dstar != NULL && !m_dstarEnabled) processEnableCommand(m_dstarEnabled, true); break; case RCD_ENABLE_DMR: - if (m_dmr != NULL && m_dmrEnabled==false) + if (m_dmr != NULL && !m_dmrEnabled) processEnableCommand(m_dmrEnabled, true); break; case RCD_ENABLE_YSF: - if (m_ysf != NULL && m_ysfEnabled==false) + if (m_ysf != NULL && !m_ysfEnabled) processEnableCommand(m_ysfEnabled, true); break; case RCD_ENABLE_P25: - if (m_p25 != NULL && m_p25Enabled==false) + if (m_p25 != NULL && !m_p25Enabled) processEnableCommand(m_p25Enabled, true); break; case RCD_ENABLE_NXDN: - if (m_nxdn != NULL && m_nxdnEnabled==false) + if (m_nxdn != NULL && !m_nxdnEnabled) processEnableCommand(m_nxdnEnabled, true); break; case RCD_ENABLE_FM: - if (m_fmEnabled==false) + if (!m_fmEnabled) processEnableCommand(m_fmEnabled, true); break; case RCD_DISABLE_DSTAR: - if (m_dstar != NULL && m_dstarEnabled==true) + if (m_dstar != NULL && m_dstarEnabled) processEnableCommand(m_dstarEnabled, false); break; case RCD_DISABLE_DMR: - if (m_dmr != NULL && m_dmrEnabled==true) + if (m_dmr != NULL && m_dmrEnabled) processEnableCommand(m_dmrEnabled, false); break; case RCD_DISABLE_YSF: - if (m_ysf != NULL && m_ysfEnabled==true) + if (m_ysf != NULL && m_ysfEnabled) processEnableCommand(m_ysfEnabled, false); break; case RCD_DISABLE_P25: - if (m_p25 != NULL && m_p25Enabled==true) + if (m_p25 != NULL && m_p25Enabled) processEnableCommand(m_p25Enabled, false); break; case RCD_DISABLE_NXDN: - if (m_nxdn != NULL && m_nxdnEnabled==true) + if (m_nxdn != NULL && m_nxdnEnabled) processEnableCommand(m_nxdnEnabled, false); break; case RCD_DISABLE_FM: - if (m_fmEnabled == true) + if (m_fmEnabled) processEnableCommand(m_fmEnabled, false); break; case RCD_PAGE: diff --git a/MMDVMHost.h b/MMDVMHost.h index 17d6786..ea268c6 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -33,8 +33,10 @@ #include "YSFNetwork.h" #include "P25Network.h" #include "DMRNetwork.h" +#include "FMNetwork.h" #include "DMRLookup.h" #include "MobileGPS.h" +#include "FMControl.h" #include "Display.h" #include "Timer.h" #include "Modem.h" @@ -62,12 +64,14 @@ private: CP25Control* m_p25; CNXDNControl* m_nxdn; CPOCSAGControl* m_pocsag; + CFMControl* m_fm; CDStarNetwork* m_dstarNetwork; CDMRNetwork* m_dmrNetwork; CYSFNetwork* m_ysfNetwork; CP25Network* m_p25Network; CNXDNNetwork* m_nxdnNetwork; CPOCSAGNetwork* m_pocsagNetwork; + CFMNetwork* m_fmNetwork; CDisplay* m_display; CUMP* m_ump; unsigned char m_mode; @@ -82,6 +86,7 @@ private: unsigned int m_p25NetModeHang; unsigned int m_nxdnNetModeHang; unsigned int m_pocsagNetModeHang; + unsigned int m_fmNetModeHang; CTimer m_modeTimer; CTimer m_dmrTXTimer; CTimer m_cwIdTimer; @@ -114,6 +119,7 @@ private: bool createP25Network(); bool createNXDNNetwork(); bool createPOCSAGNetwork(); + bool createFMNetwork(); void remoteControl(); void processModeCommand(unsigned char mode, unsigned int timeout); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 812c7a4..6aee2cb 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -181,6 +181,8 @@ + + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index fb8a362..55fda11 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -299,6 +299,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/Modem.cpp b/Modem.cpp index edbebec..02276f2 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -79,6 +79,7 @@ const unsigned char MMDVM_POCSAG_DATA = 0x50U; 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_DATA = 0x65U; const unsigned char MMDVM_ACK = 0x70U; const unsigned char MMDVM_NAK = 0x7FU; @@ -150,6 +151,8 @@ m_txP25Data(1000U, "Modem TX P25"), m_rxNXDNData(1000U, "Modem RX NXDN"), m_txNXDNData(1000U, "Modem TX NXDN"), m_txPOCSAGData(1000U, "Modem TX POCSAG"), +m_rxFMData(1000U, "Modem RX FM"), +m_txFMData(1000U, "Modem TX FM"), m_rxTransparentData(1000U, "Modem RX Transparent"), m_txTransparentData(1000U, "Modem TX Transparent"), m_sendTransparentDataFrameType(0U), @@ -163,6 +166,7 @@ m_ysfSpace(0U), m_p25Space(0U), m_nxdnSpace(0U), m_pocsagSpace(0U), +m_fmSpace(0U), m_tx(false), m_cd(false), m_lockout(false), @@ -572,6 +576,20 @@ void CModem::clock(unsigned int ms) } break; + case MMDVM_FM_DATA: { + if (m_trace) + CUtils::dump(1U, "RX FM Data", m_buffer, m_length); + + unsigned char data = m_length - 2U; + m_rxFMData.addData(&data, 1U); + + data = TAG_DATA; + m_rxFMData.addData(&data, 1U); + + m_rxFMData.addData(m_buffer + 3U, m_length - 3U); + } + break; + case MMDVM_GET_STATUS: { // if (m_trace) // CUtils::dump(1U, "GET_STATUS", m_buffer, m_length); @@ -615,9 +633,11 @@ void CModem::clock(unsigned int ms) m_nxdnSpace = m_buffer[11U]; if (m_length > 12U) m_pocsagSpace = m_buffer[12U]; + if (m_length > 13U) + m_fmSpace = m_buffer[13U]; m_inactivityTimer.start(); - // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, int(m_lockout), int(m_cd)); + // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, m_fmSpace, int(m_lockout), int(m_cd)); } break; @@ -821,6 +841,23 @@ void CModem::clock(unsigned int ms) m_pocsagSpace--; } + if (m_fmSpace > 1U && !m_txFMData.isEmpty()) { + unsigned char len = 0U; + m_txFMData.getData(&len, 1U); + m_txFMData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX FM Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing FM data to the MMDVM"); + + m_playoutTimer.start(); + + m_fmSpace--; + } + if (!m_txTransparentData.isEmpty()) { unsigned char len = 0U; m_txTransparentData.getData(&len, 1U); @@ -928,6 +965,20 @@ unsigned int CModem::readNXDNData(unsigned char* data) return len; } +unsigned int CModem::readFMData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxFMData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxFMData.getData(&len, 1U); + m_rxFMData.getData(data, len); + + return len; +} + unsigned int CModem::readTransparentData(unsigned char* data) { assert(data != NULL); @@ -1169,6 +1220,36 @@ bool CModem::writePOCSAGData(const unsigned char* data, unsigned int length) return true; } +unsigned int CModem::getFMSpace() const +{ + return (m_txFMData.freeSpace() * 2U) / 3U; +} + +bool CModem::writeFMData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + length = (length * 2U) / 3U; + + if (length > 252U) + return false; + + unsigned char buffer[255U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_FM_DATA; + + ::memcpy(buffer + 3U, data, length); + + unsigned char len = length + 3U; + m_txFMData.addData(&len, 1U); + m_txFMData.addData(buffer, len); + + return true; +} + bool CModem::writeTransparentData(const unsigned char* data, unsigned int length) { assert(data != NULL); diff --git a/Modem.h b/Modem.h index 6404d89..7605225 100644 --- a/Modem.h +++ b/Modem.h @@ -57,6 +57,7 @@ public: virtual unsigned int readYSFData(unsigned char* data); virtual unsigned int readP25Data(unsigned char* data); virtual unsigned int readNXDNData(unsigned char* data); + virtual unsigned int readFMData(unsigned char* data); virtual unsigned int readTransparentData(unsigned char* data); virtual unsigned int readSerial(unsigned char* data, unsigned int length); @@ -68,6 +69,7 @@ public: virtual bool hasP25Space() const; virtual bool hasNXDNSpace() const; virtual bool hasPOCSAGSpace() const; + virtual unsigned int getFMSpace() const; virtual bool hasTX() const; virtual bool hasCD() const; @@ -83,6 +85,7 @@ public: virtual bool writeP25Data(const unsigned char* data, unsigned int length); virtual bool writeNXDNData(const unsigned char* data, unsigned int length); virtual bool writePOCSAGData(const unsigned char* data, unsigned int length); + virtual bool writeFMData(const unsigned char* data, unsigned int length); virtual bool writeTransparentData(const unsigned char* data, unsigned int length); @@ -165,6 +168,8 @@ private: CRingBuffer m_rxNXDNData; CRingBuffer m_txNXDNData; CRingBuffer m_txPOCSAGData; + CRingBuffer m_rxFMData; + CRingBuffer m_txFMData; CRingBuffer m_rxTransparentData; CRingBuffer m_txTransparentData; unsigned int m_sendTransparentDataFrameType; @@ -178,6 +183,7 @@ private: unsigned int m_p25Space; unsigned int m_nxdnSpace; unsigned int m_pocsagSpace; + unsigned int m_fmSpace; bool m_tx; bool m_cd; bool m_lockout; From b3d287965f65a5710bf7084991fd911aa3878f18 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 21:49:18 +0100 Subject: [PATCH 002/115] Create a dummy FM Control class. --- FMControl.cpp | 113 ++++++++++++++++++++++++++++++ FMControl.h | 14 ++-- FMNetwork.cpp | 141 ++++++++++++++++++++++++++++++++++++++ FMNetwork.h | 4 +- MMDVMHost.cpp | 36 ++++++++-- MMDVMHost.vcxproj | 2 + MMDVMHost.vcxproj.filters | 6 ++ Makefile | 11 +-- Makefile.Pi | 11 +-- Makefile.Pi.Adafruit | 11 +-- Makefile.Pi.HD44780 | 11 +-- Makefile.Pi.OLED | 11 +-- Makefile.Pi.PCF8574 | 11 +-- Makefile.Solaris | 10 +-- Modem.cpp | 70 ++++++++++++++++++- Modem.h | 5 ++ 16 files changed, 419 insertions(+), 48 deletions(-) create mode 100644 FMControl.cpp create mode 100644 FMNetwork.cpp diff --git a/FMControl.cpp b/FMControl.cpp new file mode 100644 index 0000000..f6d0df4 --- /dev/null +++ b/FMControl.cpp @@ -0,0 +1,113 @@ +/* + * 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 "FMControl.h" + +#include +#include + +CFMControl::CFMControl(CFMNetwork* network) : +m_network(network), +m_queue(3000U, "FM Control"), +m_enabled(false), +m_fp(NULL) +{ + assert(network != NULL); +} + +CFMControl::~CFMControl() +{ +} + +bool CFMControl::writeModem(unsigned char* data, unsigned int len) +{ + assert(data != NULL); + assert(len > 0U); + + // Unpack serial data (12-bit unsigned values) + + // De-emphasise the data + + // Repack the data (16-bit unsigned values) + + return true; +} + +unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) +{ + assert(data != NULL); + assert(space > 0U); + + // Unpack serial data (16-bit unsigned values) + + // Pre-emphasise the data + + // Repack the data (12-bit unsigned values) + + return 0U; +} + +void CFMControl::clock(unsigned int ms) +{ + // May not be needed +} + +void CFMControl::enable(bool enabled) +{ + // May not be needed +} + +bool CFMControl::openFile() +{ + if (m_fp != NULL) + return true; + + time_t t; + ::time(&t); + + struct tm* tm = ::localtime(&t); + + char name[100U]; + ::sprintf(name, "FM_%04d%02d%02d_%02d%02d%02d.ambe", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + + m_fp = ::fopen(name, "wb"); + if (m_fp == NULL) + return false; + + ::fwrite("FM", 1U, 2U, m_fp); + + return true; +} + +bool CFMControl::writeFile(const unsigned char* data, unsigned int length) +{ + if (m_fp == NULL) + return false; + + ::fwrite(data, 1U, length, m_fp); + + return true; +} + +void CFMControl::closeFile() +{ + if (m_fp != NULL) { + ::fclose(m_fp); + m_fp = NULL; + } +} diff --git a/FMControl.h b/FMControl.h index 57dfd0b..177638e 100644 --- a/FMControl.h +++ b/FMControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 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 @@ -33,7 +33,7 @@ public: CFMControl(CFMNetwork* network); ~CFMControl(); - bool writeModem(unsigned char* data, unsigned int len); + bool writeModem(unsigned char* data, unsigned int length); unsigned int readModem(unsigned char* data, unsigned int space); @@ -42,13 +42,13 @@ public: void enable(bool enabled); private: - CFMNetwork* m_network; - CRingBuffer m_queue; - bool m_enabled; - FILE* m_fp; + CFMNetwork* m_network; + CRingBuffer m_queue; + bool m_enabled; + FILE* m_fp; bool openFile(); - bool writeFile(const unsigned char* data); + bool writeFile(const unsigned char* data, unsigned int length); void closeFile(); }; diff --git a/FMNetwork.cpp b/FMNetwork.cpp new file mode 100644 index 0000000..91cd1c9 --- /dev/null +++ b/FMNetwork.cpp @@ -0,0 +1,141 @@ +/* + * 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 "FMNetwork.h" +#include "Defines.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +const unsigned int BUFFER_LENGTH = 500U; + +CFMNetwork::CFMNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : +m_socket(localAddress, localPort), +m_address(), +m_port(gatewayPort), +m_debug(debug), +m_enabled(false), +m_buffer(2000U, "FM Network") +{ + assert(gatewayPort > 0U); + assert(!gatewayAddress.empty()); + + m_address = CUDPSocket::lookup(gatewayAddress); +} + +CFMNetwork::~CFMNetwork() +{ +} + +bool CFMNetwork::open() +{ + LogMessage("Opening FM network connection"); + + if (m_address.s_addr == INADDR_NONE) + return false; + + return m_socket.open(); +} + +bool CFMNetwork::write(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + + unsigned char buffer[500U]; + ::memset(buffer, 0x00U, 500U); + + buffer[0U] = 'F'; + buffer[1U] = 'M'; + buffer[2U] = 'D'; + + ::memcpy(buffer + 3U, data, length); + + if (m_debug) + CUtils::dump(1U, "FM Network Data Sent", buffer, length + 3U); + + return m_socket.write(buffer, length + 3U, m_address, m_port); +} + +void CFMNetwork::clock(unsigned int ms) +{ + unsigned char buffer[BUFFER_LENGTH]; + + in_addr address; + unsigned int port; + int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return; + + // Check if the data is for us + if (m_address.s_addr != address.s_addr || port != m_port) { + LogMessage("FM packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); + 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); +} + +unsigned int CFMNetwork::read(unsigned char* data, unsigned int space) +{ + assert(data != NULL); + + unsigned int bytes = m_buffer.dataSize(); + if (bytes == 0U) + return 0U; + + if (bytes < space) + space = bytes; + + m_buffer.getData(data, space); + + return space; +} + +void CFMNetwork::reset() +{ +} + +void CFMNetwork::close() +{ + m_socket.close(); + + LogMessage("Closing FM network connection"); +} + +void CFMNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + else if (!enabled && m_enabled) + m_buffer.clear(); + + m_enabled = enabled; +} diff --git a/FMNetwork.h b/FMNetwork.h index 5229098..e4c01ae 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -35,7 +35,9 @@ public: void enable(bool enabled); - unsigned int read(unsigned char* data); + bool write(const unsigned char* data, unsigned int length); + + unsigned int read(unsigned char* data, unsigned int space); void reset(); diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index b9f866e..bac53e0 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1274,7 +1274,6 @@ bool CMMDVMHost::createModem() bool callsignAtEnd = m_conf.getFMCallsignAtEnd(); bool callsignAtLatch = m_conf.getFMCallsignAtLatch(); std::string rfAck = m_conf.getFMRFAck(); - std::string extAck = m_conf.getFMExtAck(); unsigned int ackSpeed = m_conf.getFMAckSpeed(); unsigned int ackFrequency = m_conf.getFMAckFrequency(); unsigned int ackMinTime = m_conf.getFMAckMinTime(); @@ -1291,7 +1290,6 @@ bool CMMDVMHost::createModem() bool cosInvert = m_conf.getFMCOSInvert(); unsigned int rfAudioBoost = m_conf.getFMRFAudioBoost(); float maxDevLevel = m_conf.getFMMaxDevLevel(); - unsigned int extAudioBoost = m_conf.getFMExtAudioBoost(); LogInfo("FM Parameters"); LogInfo(" Callsign: %s", callsign.c_str()); @@ -1305,7 +1303,6 @@ bool CMMDVMHost::createModem() LogInfo(" Callsign At End: %s", callsignAtEnd ? "yes" : "no"); LogInfo(" Callsign At Latch: %s", callsignAtLatch ? "yes" : "no"); LogInfo(" RF Ack: %s", rfAck.c_str()); - // LogInfo(" Ext. Ack: %s", extAck.c_str()); LogInfo(" Ack Speed: %uWPM", ackSpeed); LogInfo(" Ack Frequency: %uHz", ackFrequency); LogInfo(" Ack Min Time: %us", ackMinTime); @@ -1322,11 +1319,20 @@ bool CMMDVMHost::createModem() LogInfo(" COS Invert: %s", cosInvert ? "yes" : "no"); LogInfo(" RF Audio Boost: x%u", rfAudioBoost); LogInfo(" Max. Deviation Level: %.1f%%", maxDevLevel); - // LogInfo(" Ext. Audio Boost: x%u", extAudioBoost); m_modem->setFMCallsignParams(callsign, callsignSpeed, callsignFrequency, callsignTime, callsignHoldoff, callsignHighLevel, callsignLowLevel, callsignAtStart, callsignAtEnd, callsignAtLatch); m_modem->setFMAckParams(rfAck, ackSpeed, ackFrequency, ackMinTime, ackDelay, ackLevel); m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel); + + if (m_conf.getFMNetworkEnabled()) { + std::string extAck = m_conf.getFMExtAck(); + unsigned int extAudioBoost = m_conf.getFMExtAudioBoost(); + + LogInfo(" Ext. Ack: %s", extAck.c_str()); + LogInfo(" Ext. Audio Boost: x%u", extAudioBoost); + + m_modem->setFMExtParams(extAck, extAudioBoost); + } } bool ret = m_modem->open(); @@ -1665,6 +1671,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_fm != NULL) + m_fm->enable(false); m_modem->setMode(MODE_DSTAR); if (m_ump != NULL) m_ump->setMode(MODE_DSTAR); @@ -1701,6 +1709,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_fm != NULL) + m_fm->enable(false); m_modem->setMode(MODE_DMR); if (m_ump != NULL) m_ump->setMode(MODE_DMR); @@ -1741,6 +1751,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_fm != NULL) + m_fm->enable(false); m_modem->setMode(MODE_YSF); if (m_ump != NULL) m_ump->setMode(MODE_YSF); @@ -1777,6 +1789,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_fm != NULL) + m_fm->enable(false); m_modem->setMode(MODE_P25); if (m_ump != NULL) m_ump->setMode(MODE_P25); @@ -1813,6 +1827,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(true); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_fm != NULL) + m_fm->enable(false); m_modem->setMode(MODE_NXDN); if (m_ump != NULL) m_ump->setMode(MODE_NXDN); @@ -1849,6 +1865,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(true); + if (m_fm != NULL) + m_fm->enable(false); m_modem->setMode(MODE_POCSAG); if (m_ump != NULL) m_ump->setMode(MODE_POCSAG); @@ -1872,6 +1890,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_fmNetwork != NULL) + m_fmNetwork->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1884,6 +1904,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_fm != NULL) + m_fm->enable(true); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -1925,6 +1947,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_fm != NULL) + m_fm->enable(false); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -1967,6 +1991,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_fm != NULL) + m_fm->enable(false); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -2007,6 +2033,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(true); if (m_pocsag != NULL) m_pocsag->enable(true); + if (m_fm != NULL) + m_fm->enable(true); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 6aee2cb..cb65730 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -279,6 +279,8 @@ + + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 55fda11..4c0b48f 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -568,5 +568,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index efdaba6..716a8f6 100644 --- a/Makefile +++ b/Makefile @@ -9,11 +9,12 @@ LDFLAGS = -g OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 \ - POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ - TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi b/Makefile.Pi index 640c07f..7d7e1f1 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -9,11 +9,12 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o \ - UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 24c2907..5009315 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -10,11 +10,12 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index c2faad2..5c875f6 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -9,11 +9,12 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index d2db40c..d4288cc 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -9,11 +9,12 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 4c5d3a3..53ecc80 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -10,11 +10,12 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Solaris b/Makefile.Solaris index c50d41e..8c6ac68 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -9,11 +9,11 @@ LDFLAGS = -g OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ - NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o \ - QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ - UMP.o UserDB.o UserDBebtry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \ + POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ + TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBebtry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Modem.cpp b/Modem.cpp index 02276f2..7c8ec97 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -79,6 +79,7 @@ const unsigned char MMDVM_POCSAG_DATA = 0x50U; 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_FM_DATA = 0x65U; const unsigned char MMDVM_ACK = 0x70U; @@ -184,6 +185,7 @@ m_fmCallsignAtStart(true), m_fmCallsignAtEnd(true), m_fmCallsignAtLatch(true), m_fmRfAck("K"), +m_fmExtAck("N"), m_fmAckSpeed(20U), m_fmAckFrequency(1750U), m_fmAckMinTime(4U), @@ -199,7 +201,9 @@ m_fmHangTime(5U), m_fmUseCOS(true), m_fmCOSInvert(false), m_fmRFAudioBoost(1U), -m_fmMaxDevLevel(90.0F) +m_fmExtAudioBoost(1U), +m_fmMaxDevLevel(90.0F), +m_fmExtEnable(false) { m_buffer = new unsigned char[BUFFER_LENGTH]; @@ -333,6 +337,16 @@ bool CModem::open() m_serial = NULL; return false; } + + if (m_fmExtEnable) { + ret = setFMExtParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + } } m_statusTimer.start(); @@ -2013,6 +2027,13 @@ void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctc m_fmMaxDevLevel = maxDevLevel; } +void CModem::setFMExtParams(const std::string& ack, unsigned int audioBoost) +{ + m_fmExtAck = ack; + m_fmExtAudioBoost = audioBoost; + m_fmExtEnable = true; +} + bool CModem::setFMCallsignParams() { assert(m_serial != NULL); @@ -2189,6 +2210,53 @@ bool CModem::setFMMiscParams() return true; } +bool CModem::setFMExtParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 4U + m_fmExtAck.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS4; + + buffer[3U] = m_fmExtAudioBoost; + + for (unsigned int i = 0U; i < m_fmExtAck.size(); i++) + buffer[4U + i] = m_fmExtAck.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS4 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS4 command from the modem"); + return false; + } + + return true; +} + void CModem::printDebug() { if (m_buffer[2U] == MMDVM_DEBUG1) { diff --git a/Modem.h b/Modem.h index 7605225..81b4a21 100644 --- a/Modem.h +++ b/Modem.h @@ -48,6 +48,7 @@ public: virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); + virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost); virtual bool open(); @@ -202,6 +203,7 @@ private: bool m_fmCallsignAtEnd; bool m_fmCallsignAtLatch; std::string m_fmRfAck; + std::string m_fmExtAck; unsigned int m_fmAckSpeed; unsigned int m_fmAckFrequency; unsigned int m_fmAckMinTime; @@ -217,7 +219,9 @@ private: bool m_fmUseCOS; bool m_fmCOSInvert; unsigned int m_fmRFAudioBoost; + unsigned int m_fmExtAudioBoost; float m_fmMaxDevLevel; + bool m_fmExtEnable; bool readVersion(); bool readStatus(); @@ -226,6 +230,7 @@ private: bool setFMCallsignParams(); bool setFMAckParams(); bool setFMMiscParams(); + bool setFMExtParams(); void printDebug(); From c2ca65f8893df02e73bb831236d201694dcf0430 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 22:03:57 +0100 Subject: [PATCH 003/115] Add more parameters to the external ack data. --- Modem.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Modem.cpp b/Modem.cpp index 7c8ec97..ec6bbd3 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -2215,16 +2215,20 @@ bool CModem::setFMExtParams() assert(m_serial != NULL); unsigned char buffer[80U]; - unsigned char len = 4U + m_fmExtAck.size(); + unsigned char len = 7U + m_fmExtAck.size(); buffer[0U] = MMDVM_FRAME_START; buffer[1U] = len; buffer[2U] = MMDVM_FM_PARAMS4; buffer[3U] = m_fmExtAudioBoost; + buffer[4U] = m_fmAckSpeed; + buffer[5U] = m_fmAckFrequency / 10U; + + buffer[6U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); for (unsigned int i = 0U; i < m_fmExtAck.size(); i++) - buffer[4U + i] = m_fmExtAck.at(i); + buffer[7U + i] = m_fmExtAck.at(i); // CUtils::dump(1U, "Written", buffer, len); From 51a1e2bb9cca182a115038576d34f469961d4597 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 8 May 2020 13:17:29 +0200 Subject: [PATCH 004/115] Fix FM network section detection in Conf.cpp --- Conf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Conf.cpp b/Conf.cpp index 071c717..ae77dd2 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -868,7 +868,7 @@ bool CConf::read() m_pocsagNetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) m_pocsagNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_POCSAG_NETWORK) { + } else if (section == SECTION_FM_NETWORK) { if (::strcmp(key, "Enable") == 0) m_fmNetworkEnabled = ::atoi(value) == 1; else if (::strcmp(key, "LocalAddress") == 0) From 7ae77a01a944a64aa35bc0e842d5c7c07f29b368 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 8 May 2020 13:12:37 +0100 Subject: [PATCH 005/115] Add the data packing and unpacking code. --- Conf.cpp | 2 +- FMControl.cpp | 128 +++++++++++++++++++++++++++++--------------------- FMControl.h | 18 ++----- MMDVMHost.cpp | 4 +- Version.h | 2 +- 5 files changed, 81 insertions(+), 73 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 071c717..ae77dd2 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -868,7 +868,7 @@ bool CConf::read() m_pocsagNetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) m_pocsagNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_POCSAG_NETWORK) { + } else if (section == SECTION_FM_NETWORK) { if (::strcmp(key, "Enable") == 0) m_fmNetworkEnabled = ::atoi(value) == 1; else if (::strcmp(key, "LocalAddress") == 0) diff --git a/FMControl.cpp b/FMControl.cpp index f6d0df4..8e1a10c 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -19,13 +19,15 @@ #include "FMControl.h" #include -#include + +const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#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]) CFMControl::CFMControl(CFMNetwork* network) : m_network(network), -m_queue(3000U, "FM Control"), -m_enabled(false), -m_fp(NULL) +m_enabled(false) { assert(network != NULL); } @@ -34,32 +36,90 @@ CFMControl::~CFMControl() { } -bool CFMControl::writeModem(unsigned char* data, unsigned int len) +bool CFMControl::writeModem(const unsigned char* data, unsigned int length) { assert(data != NULL); - assert(len > 0U); + assert(length > 0U); + assert(m_network != NULL); - // Unpack serial data (12-bit unsigned values) + float samples[170U]; + unsigned int nSamples = 0U; - // De-emphasise the data + // Unpack the serial data into float values. + for (unsigned int i = 0U; i < length; i += 3U) { + unsigned short sample1 = 0U; + unsigned short sample2 = 0U; + unsigned short MASK = 0x0001U; - // Repack the data (16-bit unsigned values) + const unsigned char* base = data + i; + for (unsigned int j = 0U; j < 12U; j++, MASK <<= 1) { + unsigned int pos1 = j; + unsigned int pos2 = j + 12U; - return true; + bool b1 = READ_BIT(base, pos1) != 0U; + bool b2 = READ_BIT(base, pos2) != 0U; + + if (b1) + sample1 |= MASK; + if (b2) + sample2 |= MASK; + } + + // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) + samples[nSamples++] = (float(sample1) - 2048.0F) / 2048.0F; + samples[nSamples++] = (float(sample2) - 2048.0F) / 2048.0F; + } + + // De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) + + unsigned char out[350U]; + unsigned int nOut = 0U; + + // Repack the data (8-bit unsigned values containing unsigned 16-bit data) + for (unsigned int i = 0U; i < nSamples; i++) { + unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); + out[nOut++] = (sample >> 8) & 0xFFU; + out[nOut++] = (sample >> 0) & 0xFFU; + } + + return m_network->write(out, nOut); } unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) { assert(data != NULL); assert(space > 0U); + assert(m_network != NULL); - // Unpack serial data (16-bit unsigned values) + unsigned char netData[300U]; + unsigned int length = m_network->read(netData, 270U); + if (length == 0U) + return 0U; - // Pre-emphasise the data + float samples[170U]; + unsigned int nSamples = 0U; - // Repack the data (12-bit unsigned values) + // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) + for (unsigned int i = 0U; i < length; i += 2U) { + unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; + samples[nSamples++] = (float(sample) / 32767.0F) - 1.0F; + } - return 0U; + // Pre-emphasise the data and other stuff. + + // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) + unsigned int offset = 0U; + for (unsigned int i = 0U; i < nSamples; i++) { + unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); + unsigned short MASK = 0x0001U; + for (unsigned int j = 0U; j < 12U; j++, MASK <<= 1) { + bool b = (sample & MASK) != 0U; + WRITE_BIT(data, offset, b); + offset++; + } + } + + return nSamples; } void CFMControl::clock(unsigned int ms) @@ -71,43 +131,3 @@ void CFMControl::enable(bool enabled) { // May not be needed } - -bool CFMControl::openFile() -{ - if (m_fp != NULL) - return true; - - time_t t; - ::time(&t); - - struct tm* tm = ::localtime(&t); - - char name[100U]; - ::sprintf(name, "FM_%04d%02d%02d_%02d%02d%02d.ambe", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - - m_fp = ::fopen(name, "wb"); - if (m_fp == NULL) - return false; - - ::fwrite("FM", 1U, 2U, m_fp); - - return true; -} - -bool CFMControl::writeFile(const unsigned char* data, unsigned int length) -{ - if (m_fp == NULL) - return false; - - ::fwrite(data, 1U, length, m_fp); - - return true; -} - -void CFMControl::closeFile() -{ - if (m_fp != NULL) { - ::fclose(m_fp); - m_fp = NULL; - } -} diff --git a/FMControl.h b/FMControl.h index 177638e..bcae8a3 100644 --- a/FMControl.h +++ b/FMControl.h @@ -20,20 +20,14 @@ #define FMControl_H #include "FMNetwork.h" -#include "RingBuffer.h" -#include "StopWatch.h" #include "Defines.h" -#include "Timer.h" -#include "Modem.h" - -#include class CFMControl { public: CFMControl(CFMNetwork* network); ~CFMControl(); - bool writeModem(unsigned char* data, unsigned int length); + bool writeModem(const unsigned char* data, unsigned int length); unsigned int readModem(unsigned char* data, unsigned int space); @@ -42,14 +36,8 @@ public: void enable(bool enabled); private: - CFMNetwork* m_network; - CRingBuffer m_queue; - bool m_enabled; - FILE* m_fp; - - bool openFile(); - bool writeFile(const unsigned char* data, unsigned int length); - void closeFile(); + CFMNetwork* m_network; + bool m_enabled; }; #endif diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index bac53e0..c6f5137 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -811,11 +811,11 @@ int CMMDVMHost::run() } len = m_modem->readFMData(data); - if (m_nxdn != NULL && len > 0U) { + if (m_fm != NULL && len > 0U) { if (m_mode == MODE_IDLE) { bool ret = m_fm->writeModem(data, len); if (ret) { - m_modeTimer.setTimeout(m_nxdnRFModeHang); + m_modeTimer.setTimeout(m_nxdnRFModeHang); // XXX setMode(MODE_FM); } } else if (m_mode == MODE_FM) { diff --git a/Version.h b/Version.h index 7bf2d5a..b663e2a 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200506"; +const char* VERSION = "20200507"; #endif From 8cdc1ffe7f9a935efbfbe647f1c8f6c8e1b7a98a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 16:41:06 +0200 Subject: [PATCH 006/115] Pack and unpack using shifting and masking --- FMControl.cpp | 46 ++++++++++++++++++++++++---------------------- FMControl.h | 11 +++++++++++ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 8e1a10c..d5e7a14 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -49,21 +49,17 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) for (unsigned int i = 0U; i < length; i += 3U) { unsigned short sample1 = 0U; unsigned short sample2 = 0U; - unsigned short MASK = 0x0001U; + unsigned short MASK = ~(0xFFFFF000); - const unsigned char* base = data + i; - for (unsigned int j = 0U; j < 12U; j++, MASK <<= 1) { - unsigned int pos1 = j; - unsigned int pos2 = j + 12U; + int pack = 0; + char* packPointer = (char*)&pack; - bool b1 = READ_BIT(base, pos1) != 0U; - bool b2 = READ_BIT(base, pos2) != 0U; + packPointer[1] = data[i]; + packPointer[2] = data[i + 1]; + packPointer[3] = data[i + 2]; - if (b1) - sample1 |= MASK; - if (b2) - sample2 |= MASK; - } + sample2 = (short)(pack & MASK); + sample1 = (short)(pack >> 12); // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) samples[nSamples++] = (float(sample1) - 2048.0F) / 2048.0F; @@ -108,18 +104,24 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) // Pre-emphasise the data and other stuff. // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) - unsigned int offset = 0U; - for (unsigned int i = 0U; i < nSamples; i++) { - unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); - unsigned short MASK = 0x0001U; - for (unsigned int j = 0U; j < 12U; j++, MASK <<= 1) { - bool b = (sample & MASK) != 0U; - WRITE_BIT(data, offset, b); - offset++; - } + int pack = 0; + char* packPointer = (char*)&pack; + unsigned int j = 0U; + unsigned int i = 0U; + for (; i < nSamples && j < space; i += 2, j += 3) { + unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); + unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); + + pack = 0; + pack = ((int)sample1) << 12; + pack |= sample2; + + data[j] = packPointer[1]; + data[j + 1] = packPointer[2]; + data[j + 2] = packPointer[3]; } - return nSamples; + return j;//return the number of bytes written } void CFMControl::clock(unsigned int ms) diff --git a/FMControl.h b/FMControl.h index bcae8a3..2d184e2 100644 --- a/FMControl.h +++ b/FMControl.h @@ -22,6 +22,17 @@ #include "FMNetwork.h" #include "Defines.h" +typedef struct +{ + union + { + int pack; + char packBytes[4]; + }; + +} SamplePack; + + class CFMControl { public: CFMControl(CFMNetwork* network); From 93652c764e928afd09cb6a7262dffd65ea0bc935 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 17:05:04 +0200 Subject: [PATCH 007/115] Using correct types --- FMControl.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index d5e7a14..b2e6652 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -49,14 +49,14 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) for (unsigned int i = 0U; i < length; i += 3U) { unsigned short sample1 = 0U; unsigned short sample2 = 0U; - unsigned short MASK = ~(0xFFFFF000); + unsigned int MASK = 0x00000FFFU; - int pack = 0; - char* packPointer = (char*)&pack; + unsigned int pack = 0U; + unsigned char* packPointer = (unsigned char*)&pack; - packPointer[1] = data[i]; - packPointer[2] = data[i + 1]; - packPointer[3] = data[i + 2]; + packPointer[1U] = data[i]; + packPointer[2U] = data[i + 1U]; + packPointer[3U] = data[i + 2U]; sample2 = (short)(pack & MASK); sample1 = (short)(pack >> 12); @@ -104,21 +104,21 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) // Pre-emphasise the data and other stuff. // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) - int pack = 0; - char* packPointer = (char*)&pack; + unsigned int pack = 0U; + unsigned char* packPointer = (unsigned char*)&pack; unsigned int j = 0U; unsigned int i = 0U; - for (; i < nSamples && j < space; i += 2, j += 3) { + for (; i < nSamples && j < space; i += 2U, j += 3U) { unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); pack = 0; - pack = ((int)sample1) << 12; + pack = ((unsigned int)sample1) << 12; pack |= sample2; - data[j] = packPointer[1]; - data[j + 1] = packPointer[2]; - data[j + 2] = packPointer[3]; + data[j] = packPointer[1U]; + data[j + 1U] = packPointer[2U]; + data[j + 2U] = packPointer[3U]; } return j;//return the number of bytes written From c48f45d2da712d7742e14096daeec7ca206d9b5a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 17:30:22 +0200 Subject: [PATCH 008/115] remove union --- FMControl.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/FMControl.h b/FMControl.h index 2d184e2..bcae8a3 100644 --- a/FMControl.h +++ b/FMControl.h @@ -22,17 +22,6 @@ #include "FMNetwork.h" #include "Defines.h" -typedef struct -{ - union - { - int pack; - char packBytes[4]; - }; - -} SamplePack; - - class CFMControl { public: CFMControl(CFMNetwork* network); From dc9e6ade235a32f665ffc455e7c80fcaca5c84c6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 20:41:57 +0200 Subject: [PATCH 009/115] Add filter --- IIDirectForm1Filter.cpp | 56 +++++++++++++++++++++++++++++++++++++++++ IIRDirectForm1Filter.h | 50 ++++++++++++++++++++++++++++++++++++ Makefile.Pi | 2 +- Makefile.Pi.HD44780 | 2 +- Makefile.Pi.OLED | 2 +- Makefile.Pi.PCF8574 | 2 +- Makefile.Solaris | 2 +- 7 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 IIDirectForm1Filter.cpp create mode 100644 IIRDirectForm1Filter.h diff --git a/IIDirectForm1Filter.cpp b/IIDirectForm1Filter.cpp new file mode 100644 index 0000000..51e4e13 --- /dev/null +++ b/IIDirectForm1Filter.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Geoffrey Merck - F4FXL KC3FRA + * + * 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 "IIRDirectForm1Filter.h" +#include "math.h" + +CIIRDirectForm1Filter::CIIRDirectForm1Filter(float b0, float b1, float b2, float , float a1, float a2, float addtionalGaindB) : +m_b0(b0), +m_b1(b1), +m_b2(b2), +m_a1(a1), +m_a2(a2), +m_additionalGainLin(::powf(10.0F, addtionalGaindB / 20.0F)) +{ + +} + +float CIIRDirectForm1Filter::filter(float sample) +{ + float output = m_b0 * sample + + m_b1 * m_x1 + + m_b2 * m_x2 + - m_a1 * m_y1 + - m_a2 * m_y2; + + m_x2 = m_x1; + m_y2 = m_y1; + m_x1 = sample; + m_y1 = output; + + return output * m_additionalGainLin; +} + +void CIIRDirectForm1Filter::reset() +{ + m_x1 = 0.0f; + m_x2 = 0.0f; + m_y1 = 0.0f; + m_y2 = 0.0f; +} diff --git a/IIRDirectForm1Filter.h b/IIRDirectForm1Filter.h new file mode 100644 index 0000000..f575f7f --- /dev/null +++ b/IIRDirectForm1Filter.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Geoffrey Merck - F4FXL KC3FRA + * + * 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. + */ + +#if !defined(IIRDIRECTFORM1FILTER_H) +#define IIRDIRECTFORM1FILTER_H + +class CIIRDirectForm1Filter +{ +public: + CIIRDirectForm1Filter(float b0, float b1, float b2, float, float a1, float a2, float additionalGaindB); + float filter(float sample); + void reset(); + +private: +// delay line + float m_x2; // x[n-2] + float m_y2; // y[n-2] + float m_x1; // x[n-1] + float m_y1; // y[n-1] + + // coefficients + // FIR + float m_b0; + float m_b1; + float m_b2; + // IIR + float m_a1; + float m_a2; + + float m_additionalGainLin; +}; + + +#endif \ No newline at end of file diff --git a/Makefile.Pi b/Makefile.Pi index 7d7e1f1..06ef859 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -9,7 +9,7 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 5c875f6..9c42ca8 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -9,7 +9,7 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index d4288cc..63be413 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -9,7 +9,7 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 53ecc80..4c89696 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -10,7 +10,7 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Solaris b/Makefile.Solaris index 8c6ac68..ffe9564 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -9,7 +9,7 @@ LDFLAGS = -g OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \ POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ From bc22709abb3b3131a7484a9d4afd4765105a537c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 21:16:02 +0200 Subject: [PATCH 010/115] Add preemphasis and deemphasis --- FMControl.cpp | 15 ++++++++++----- FMControl.h | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index b2e6652..e3836d7 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -20,14 +20,13 @@ #include -const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; - -#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]) +#define EMPHASIS_GAIN_DB 0 //Gain needs to be the same for pre an deeemphasis CFMControl::CFMControl(CFMNetwork* network) : m_network(network), -m_enabled(false) +m_enabled(false), +m_preemphasis(0.3889703087993727F, -0.3290005228984741F, 0.0F, 1.0F, 0.282029168302153F, 0.0F, EMPHASIS_GAIN_DB), +m_deemphasis(1.0F, 0.282029168302153F, 0.0F, 0.3889703087993727F, -0.3290005228984741F, 0.0F, EMPHASIS_GAIN_DB) { assert(network != NULL); } @@ -67,6 +66,9 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) } // De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) + for(unsigned int i = 0U; i < nSamples; i++) { + samples[i] = m_deemphasis.filter(samples[i]); + } unsigned char out[350U]; unsigned int nOut = 0U; @@ -102,6 +104,9 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) } // Pre-emphasise the data and other stuff. + for(unsigned int i = 0U; i < nSamples; i++) { + samples[i] = m_preemphasis.filter(samples[i]); + } // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; diff --git a/FMControl.h b/FMControl.h index bcae8a3..941b347 100644 --- a/FMControl.h +++ b/FMControl.h @@ -21,6 +21,7 @@ #include "FMNetwork.h" #include "Defines.h" +#include "IIRDirectForm1Filter.h" class CFMControl { public: @@ -38,6 +39,8 @@ public: private: CFMNetwork* m_network; bool m_enabled; + CIIRDirectForm1Filter m_preemphasis; + CIIRDirectForm1Filter m_deemphasis; }; #endif From e28dfe79dd27f672e3d1d82adb673e95846a06ff Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 21:23:32 +0200 Subject: [PATCH 011/115] Fix typo in file name --- IIDirectForm1Filter.cpp => IIRDirectForm1Filter.cpp | 0 Makefile | 2 +- Makefile.Pi | 2 +- Makefile.Pi.Adafruit | 2 +- Makefile.Pi.OLED | 2 +- Makefile.Pi.PCF8574 | 2 +- Makefile.Solaris | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename IIDirectForm1Filter.cpp => IIRDirectForm1Filter.cpp (100%) diff --git a/IIDirectForm1Filter.cpp b/IIRDirectForm1Filter.cpp similarity index 100% rename from IIDirectForm1Filter.cpp rename to IIRDirectForm1Filter.cpp diff --git a/Makefile b/Makefile index 716a8f6..2091355 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ LDFLAGS = -g OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Pi b/Makefile.Pi index 06ef859..a7d416c 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -9,7 +9,7 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 5009315..09125e3 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -10,7 +10,7 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 63be413..2ea260c 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -9,7 +9,7 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 IIDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 4c89696..1513f45 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -10,7 +10,7 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ diff --git a/Makefile.Solaris b/Makefile.Solaris index ffe9564..ec34917 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -9,7 +9,7 @@ LDFLAGS = -g OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ + DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \ POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ From 467140dbf863fc37fa1779705206cfc11c1c49f8 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 9 May 2020 12:41:37 +0100 Subject: [PATCH 012/115] VS2019 fixes. --- FMControl.cpp | 6 ++---- MMDVMHost.vcxproj | 2 ++ MMDVMHost.vcxproj.filters | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index e3836d7..68aeab8 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -66,9 +66,8 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) } // De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) - for(unsigned int i = 0U; i < nSamples; i++) { + for (unsigned int i = 0U; i < nSamples; i++) samples[i] = m_deemphasis.filter(samples[i]); - } unsigned char out[350U]; unsigned int nOut = 0U; @@ -104,9 +103,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) } // Pre-emphasise the data and other stuff. - for(unsigned int i = 0U; i < nSamples; i++) { + for (unsigned int i = 0U; i < nSamples; i++) samples[i] = m_preemphasis.filter(samples[i]); - } // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index cb65730..63ba164 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -188,6 +188,7 @@ + @@ -285,6 +286,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 4c0b48f..8dc6f12 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -305,6 +305,9 @@ Header Files + + Header Files + @@ -574,5 +577,8 @@ Source Files + + Source Files + \ No newline at end of file From 33fedb781d909efa581fed6b96f84dcf3e34d9af Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 10:31:53 +0200 Subject: [PATCH 013/115] Handle no network --- FMControl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 68aeab8..fa81728 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -28,7 +28,6 @@ m_enabled(false), m_preemphasis(0.3889703087993727F, -0.3290005228984741F, 0.0F, 1.0F, 0.282029168302153F, 0.0F, EMPHASIS_GAIN_DB), m_deemphasis(1.0F, 0.282029168302153F, 0.0F, 0.3889703087993727F, -0.3290005228984741F, 0.0F, EMPHASIS_GAIN_DB) { - assert(network != NULL); } CFMControl::~CFMControl() @@ -39,7 +38,9 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) { assert(data != NULL); assert(length > 0U); - assert(m_network != NULL); + + if(m_network == NULL) + return false; float samples[170U]; unsigned int nSamples = 0U; @@ -86,7 +87,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) { assert(data != NULL); assert(space > 0U); - assert(m_network != NULL); + if(m_network == NULL) + return 0; unsigned char netData[300U]; unsigned int length = m_network->read(netData, 270U); From 0178ba0aba9cfe72138a0fd8de2a046ddf86db93 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 21:49:11 +0200 Subject: [PATCH 014/115] Buffer incoming modem audio --- FMControl.cpp | 82 ++++++++++++++++++++++++++++++--------------------- FMControl.h | 5 ++-- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index fa81728..45310ce 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -21,12 +21,14 @@ #include #define EMPHASIS_GAIN_DB 0 //Gain needs to be the same for pre an deeemphasis +#define RF_AUDIO_SAMP_RATE 8000 CFMControl::CFMControl(CFMNetwork* network) : m_network(network), m_enabled(false), -m_preemphasis(0.3889703087993727F, -0.3290005228984741F, 0.0F, 1.0F, 0.282029168302153F, 0.0F, EMPHASIS_GAIN_DB), -m_deemphasis(1.0F, 0.282029168302153F, 0.0F, 0.3889703087993727F, -0.3290005228984741F, 0.0F, EMPHASIS_GAIN_DB) +// m_preemphasis(0.3889703087993727F, -0.3290005228984741F, 0.0F, 1.0F, 0.282029168302153F, 0.0F, EMPHASIS_GAIN_DB), +// m_deemphasis(1.0F, 0.282029168302153F, 0.0F, 0.3889703087993727F, -0.3290005228984741F, 0.0F, EMPHASIS_GAIN_DB), +m_incomingRFAudio(1000U, "Incoming RF FM Audio") { } @@ -45,42 +47,54 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) float samples[170U]; unsigned int nSamples = 0U; - // Unpack the serial data into float values. - for (unsigned int i = 0U; i < length; i += 3U) { - unsigned short sample1 = 0U; - unsigned short sample2 = 0U; - unsigned int MASK = 0x00000FFFU; + + m_incomingRFAudio.addData(data, length); + unsigned int bufferLength = m_incomingRFAudio.dataSize(); - unsigned int pack = 0U; - unsigned char* packPointer = (unsigned char*)&pack; + if(bufferLength >= 3) { + bufferLength = bufferLength - bufferLength % 3; //round down to nearest multiple of 3 + unsigned char bufferData[bufferLength]; + m_incomingRFAudio.getData(bufferData, bufferLength); - packPointer[1U] = data[i]; - packPointer[2U] = data[i + 1U]; - packPointer[3U] = data[i + 2U]; + // Unpack the serial data into float values. + for (unsigned int i = 0U; i < length; i += 3U) { + unsigned short sample1 = 0U; + unsigned short sample2 = 0U; + unsigned int MASK = 0x00000FFFU; - sample2 = (short)(pack & MASK); - sample1 = (short)(pack >> 12); + unsigned int pack = 0U; + unsigned char* packPointer = (unsigned char*)&pack; - // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) - samples[nSamples++] = (float(sample1) - 2048.0F) / 2048.0F; - samples[nSamples++] = (float(sample2) - 2048.0F) / 2048.0F; + packPointer[1U] = bufferData[i]; + packPointer[2U] = bufferData[i + 1U]; + packPointer[3U] = bufferData[i + 2U]; + + sample2 = (short)(pack & MASK); + sample1 = (short)(pack >> 12); + + // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) + samples[nSamples++] = (float(sample1) - 2048.0F) / 2048.0F; + samples[nSamples++] = (float(sample2) - 2048.0F) / 2048.0F; + } + + // De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) + // for (unsigned int i = 0U; i < nSamples; i++) + // samples[i] = m_deemphasis.filter(samples[i]); + + unsigned char out[350U]; + unsigned int nOut = 0U; + + // Repack the data (8-bit unsigned values containing unsigned 16-bit data) + for (unsigned int i = 0U; i < nSamples; i++) { + unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); + out[nOut++] = (sample >> 8) & 0xFFU; + out[nOut++] = (sample >> 0) & 0xFFU; + } + + return m_network->write(out, nOut); } - // De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) - for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_deemphasis.filter(samples[i]); - - unsigned char out[350U]; - unsigned int nOut = 0U; - - // Repack the data (8-bit unsigned values containing unsigned 16-bit data) - for (unsigned int i = 0U; i < nSamples; i++) { - unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); - out[nOut++] = (sample >> 8) & 0xFFU; - out[nOut++] = (sample >> 0) & 0xFFU; - } - - return m_network->write(out, nOut); + return 0U; } unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) @@ -105,8 +119,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) } // Pre-emphasise the data and other stuff. - for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_preemphasis.filter(samples[i]); + // for (unsigned int i = 0U; i < nSamples; i++) + // samples[i] = m_preemphasis.filter(samples[i]); // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; diff --git a/FMControl.h b/FMControl.h index 941b347..3a95cc4 100644 --- a/FMControl.h +++ b/FMControl.h @@ -39,8 +39,9 @@ public: private: CFMNetwork* m_network; bool m_enabled; - CIIRDirectForm1Filter m_preemphasis; - CIIRDirectForm1Filter m_deemphasis; + // CIIRDirectForm1Filter m_preemphasis; + // CIIRDirectForm1Filter m_deemphasis; + CRingBuffer m_incomingRFAudio; }; #endif From 6b4fe7dd3350d3ba9857372a469d20bc029ba07a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 22:08:36 +0200 Subject: [PATCH 015/115] Loop using correct length --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index 45310ce..4a04e72 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -57,7 +57,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) m_incomingRFAudio.getData(bufferData, bufferLength); // Unpack the serial data into float values. - for (unsigned int i = 0U; i < length; i += 3U) { + for (unsigned int i = 0U; i < bufferLength; i += 3U) { unsigned short sample1 = 0U; unsigned short sample2 = 0U; unsigned int MASK = 0x00000FFFU; From 29b36a66f869d11bd2eea5ef4ba39cd8fb2e06ec Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 11 May 2020 12:59:28 +0100 Subject: [PATCH 016/115] Use more conventional handling of FM mode timing. --- Conf.cpp | 16 ++++++++++++---- Conf.h | 2 ++ FMControl.cpp | 26 ++++++++++++++++---------- MMDVM.ini | 1 + MMDVMHost.cpp | 16 ++++++++-------- MMDVMHost.h | 1 + Modem.cpp | 19 ++++++++++++++++--- 7 files changed, 56 insertions(+), 25 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index ae77dd2..fd0f12d 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -203,6 +203,7 @@ m_fmCOSInvert(false), m_fmRFAudioBoost(1U), m_fmMaxDevLevel(90.0F), m_fmExtAudioBoost(1U), +m_fmModeHang(10U), m_dstarNetworkEnabled(false), m_dstarGatewayAddress(), m_dstarGatewayPort(0U), @@ -411,12 +412,12 @@ bool CConf::read() else if (::strcmp(key, "Duplex") == 0) m_duplex = ::atoi(value) == 1; else if (::strcmp(key, "ModeHang") == 0) - m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = - m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = (unsigned int)::atoi(value); + m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = m_nxdnNetworkModeHang = m_pocsagNetworkModeHang = m_fmNetworkModeHang = + m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_fmModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "RFModeHang") == 0) - m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = (unsigned int)::atoi(value); + m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_fmModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "NetModeHang") == 0) - m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = (unsigned int)::atoi(value); + m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = m_nxdnNetworkModeHang = m_pocsagNetworkModeHang = m_fmNetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Display") == 0) m_display = value; else if (::strcmp(key, "Daemon") == 0) @@ -774,6 +775,8 @@ bool CConf::read() m_fmMaxDevLevel = float(::atof(value)); else if (::strcmp(key, "ExtAudioBoost") == 0) m_fmExtAudioBoost = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_fmModeHang = (unsigned int)::atoi(value); } else if (section == SECTION_DSTAR_NETWORK) { if (::strcmp(key, "Enable") == 0) m_dstarNetworkEnabled = ::atoi(value) == 1; @@ -1676,6 +1679,11 @@ unsigned int CConf::getFMExtAudioBoost() const return m_fmExtAudioBoost; } +unsigned int CConf::getFMModeHang() const +{ + return m_fmModeHang; +} + bool CConf::getDStarNetworkEnabled() const { return m_dstarNetworkEnabled; diff --git a/Conf.h b/Conf.h index 915a21c..5c03afd 100644 --- a/Conf.h +++ b/Conf.h @@ -200,6 +200,7 @@ public: unsigned int getFMRFAudioBoost() const; float getFMMaxDevLevel() const; unsigned int getFMExtAudioBoost() const; + unsigned int getFMModeHang() const; // The D-Star Network section bool getDStarNetworkEnabled() const; @@ -476,6 +477,7 @@ private: unsigned int m_fmRFAudioBoost; float m_fmMaxDevLevel; unsigned int m_fmExtAudioBoost; + unsigned int m_fmModeHang; bool m_dstarNetworkEnabled; std::string m_dstarGatewayAddress; diff --git a/FMControl.cpp b/FMControl.cpp index 45310ce..c1d3fd0 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -41,18 +41,23 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); - if(m_network == NULL) + if (data[0U] == TAG_HEADER) + return true; + + if (data[0U] != TAG_DATA) return false; + if (m_network == NULL) + return true; + float samples[170U]; unsigned int nSamples = 0U; - - m_incomingRFAudio.addData(data, length); + m_incomingRFAudio.addData(data + 1U, length - 1U); unsigned int bufferLength = m_incomingRFAudio.dataSize(); - if(bufferLength >= 3) { - bufferLength = bufferLength - bufferLength % 3; //round down to nearest multiple of 3 + if (bufferLength >= 3U) { + bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 unsigned char bufferData[bufferLength]; m_incomingRFAudio.getData(bufferData, bufferLength); @@ -69,8 +74,8 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) packPointer[2U] = bufferData[i + 1U]; packPointer[3U] = bufferData[i + 2U]; - sample2 = (short)(pack & MASK); - sample1 = (short)(pack >> 12); + sample2 = short(pack & MASK); + sample1 = short(pack >> 12); // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) samples[nSamples++] = (float(sample1) - 2048.0F) / 2048.0F; @@ -94,15 +99,16 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) return m_network->write(out, nOut); } - return 0U; + return true; } unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) { assert(data != NULL); assert(space > 0U); - if(m_network == NULL) - return 0; + + if (m_network == NULL) + return 0U; unsigned char netData[300U]; unsigned int length = m_network->read(netData, 270U); diff --git a/MMDVM.ini b/MMDVM.ini index a86bdd3..f55ad04 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -170,6 +170,7 @@ COSInvert=0 RFAudioBoost=1 MaxDevLevel=90 ExtAudioBoost=1 +# ModeHang=10 [D-Star Network] Enable=1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 7740d1b..c8914ba 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -135,6 +135,7 @@ m_dmrRFModeHang(10U), m_ysfRFModeHang(10U), m_p25RFModeHang(10U), m_nxdnRFModeHang(10U), +m_fmRFModeHang(10U), m_dstarNetModeHang(3U), m_dmrNetModeHang(3U), m_ysfNetModeHang(3U), @@ -618,8 +619,11 @@ int CMMDVMHost::run() pocsagTimer.start(); } - if (m_fmEnabled) + if (m_fmEnabled) { + m_fmRFModeHang = m_conf.getFMModeHang(); + m_fm = new CFMControl(m_fmNetwork); + } bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); if (remoteControlEnabled) { @@ -658,12 +662,6 @@ int CMMDVMHost::run() else if (!error && m_mode == MODE_ERROR) setMode(MODE_IDLE); - unsigned char mode = m_modem->getMode(); - if (mode == MODE_FM && m_mode != MODE_FM) - setMode(mode); - else if (mode != MODE_FM && m_mode == MODE_FM) - setMode(mode); - if (m_ump != NULL) { bool tx = m_modem->hasTX(); m_ump->setTX(tx); @@ -818,7 +816,7 @@ int CMMDVMHost::run() if (m_mode == MODE_IDLE) { bool ret = m_fm->writeModem(data, len); if (ret) { - m_modeTimer.setTimeout(m_nxdnRFModeHang); // XXX + m_modeTimer.setTimeout(m_fmRFModeHang); setMode(MODE_FM); } } else if (m_mode == MODE_FM) { @@ -1293,6 +1291,7 @@ bool CMMDVMHost::createModem() bool cosInvert = m_conf.getFMCOSInvert(); unsigned int rfAudioBoost = m_conf.getFMRFAudioBoost(); float maxDevLevel = m_conf.getFMMaxDevLevel(); + unsigned int modeHangTime = m_conf.getFMModeHang(); LogInfo("FM Parameters"); LogInfo(" Callsign: %s", callsign.c_str()); @@ -1322,6 +1321,7 @@ bool CMMDVMHost::createModem() LogInfo(" COS Invert: %s", cosInvert ? "yes" : "no"); LogInfo(" RF Audio Boost: x%u", rfAudioBoost); LogInfo(" Max. Deviation Level: %.1f%%", maxDevLevel); + LogInfo(" Mode Hang: %us", modeHangTime); m_modem->setFMCallsignParams(callsign, callsignSpeed, callsignFrequency, callsignTime, callsignHoldoff, callsignHighLevel, callsignLowLevel, callsignAtStart, callsignAtEnd, callsignAtLatch); m_modem->setFMAckParams(rfAck, ackSpeed, ackFrequency, ackMinTime, ackDelay, ackLevel); diff --git a/MMDVMHost.h b/MMDVMHost.h index ea268c6..110f268 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -80,6 +80,7 @@ private: unsigned int m_ysfRFModeHang; unsigned int m_p25RFModeHang; unsigned int m_nxdnRFModeHang; + unsigned int m_fmRFModeHang; unsigned int m_dstarNetModeHang; unsigned int m_dmrNetModeHang; unsigned int m_ysfNetModeHang; diff --git a/Modem.cpp b/Modem.cpp index ec6bbd3..a65c4fa 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -81,6 +81,7 @@ 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_FM_DATA = 0x65U; +const unsigned char MMDVM_FM_CONTROL = 0x66U; const unsigned char MMDVM_ACK = 0x70U; const unsigned char MMDVM_NAK = 0x7FU; @@ -604,6 +605,20 @@ void CModem::clock(unsigned int ms) } break; + case MMDVM_FM_CONTROL: { + if (m_trace) + CUtils::dump(1U, "RX FM Control", m_buffer, m_length); + + unsigned char data = m_length - 2U; + m_rxFMData.addData(&data, 1U); + + data = TAG_HEADER; + m_rxFMData.addData(&data, 1U); + + m_rxFMData.addData(m_buffer + 3U, m_length - 3U); + } + break; + case MMDVM_GET_STATUS: { // if (m_trace) // CUtils::dump(1U, "GET_STATUS", m_buffer, m_length); @@ -1236,7 +1251,7 @@ bool CModem::writePOCSAGData(const unsigned char* data, unsigned int length) unsigned int CModem::getFMSpace() const { - return (m_txFMData.freeSpace() * 2U) / 3U; + return m_txFMData.freeSpace(); } bool CModem::writeFMData(const unsigned char* data, unsigned int length) @@ -1244,8 +1259,6 @@ bool CModem::writeFMData(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); - length = (length * 2U) / 3U; - if (length > 252U) return false; From 7bca8578521db2aa39961e7240397b37d2f7d259 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 22:08:36 +0200 Subject: [PATCH 017/115] Loop using correct length --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index c1d3fd0..a3a7528 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -62,7 +62,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) m_incomingRFAudio.getData(bufferData, bufferLength); // Unpack the serial data into float values. - for (unsigned int i = 0U; i < length; i += 3U) { + for (unsigned int i = 0U; i < bufferLength; i += 3U) { unsigned short sample1 = 0U; unsigned short sample2 = 0U; unsigned int MASK = 0x00000FFFU; From 039ef44a635956865eac8166ae51633f3267a439 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 11 May 2020 15:32:39 +0100 Subject: [PATCH 018/115] Fix the setMode(MODE_FM) command. --- MMDVMHost.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index c8914ba..15e12f5 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1894,7 +1894,7 @@ void CMMDVMHost::setMode(unsigned char mode) if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); if (m_fmNetwork != NULL) - m_fmNetwork->enable(false); + m_fmNetwork->enable(true); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1909,15 +1909,12 @@ void CMMDVMHost::setMode(unsigned char mode) m_pocsag->enable(false); if (m_fm != NULL) m_fm->enable(true); - if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { - m_modem->writeDMRStart(false); - m_dmrTXTimer.stop(); - } + m_modem->setMode(MODE_FM); if (m_ump != NULL) m_ump->setMode(MODE_FM); m_display->setFM(); m_mode = MODE_FM; - m_modeTimer.stop(); + m_modeTimer.start(); m_cwIdTimer.stop(); createLockFile("FM"); break; From bc6f832b7d4fd5a4ac228f974ea7a02880301157 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 22:08:36 +0200 Subject: [PATCH 019/115] Loop using correct length --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index c1d3fd0..a3a7528 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -62,7 +62,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) m_incomingRFAudio.getData(bufferData, bufferLength); // Unpack the serial data into float values. - for (unsigned int i = 0U; i < length; i += 3U) { + for (unsigned int i = 0U; i < bufferLength; i += 3U) { unsigned short sample1 = 0U; unsigned short sample2 = 0U; unsigned int MASK = 0x00000FFFU; From cbcbe4c56a4579039fe705dd75d1c91e467f9771 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 18:38:07 +0200 Subject: [PATCH 020/115] Used fixed length array --- FMControl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index a3a7528..bc1e0b0 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -22,6 +22,7 @@ #define EMPHASIS_GAIN_DB 0 //Gain needs to be the same for pre an deeemphasis #define RF_AUDIO_SAMP_RATE 8000 +#define FM_AUDIO_BLOCK_SIZE 240 CFMControl::CFMControl(CFMNetwork* network) : m_network(network), @@ -55,10 +56,12 @@ 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 > 255U) + bufferLength = 255U; if (bufferLength >= 3U) { bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 - unsigned char bufferData[bufferLength]; + unsigned char bufferData[255]; m_incomingRFAudio.getData(bufferData, bufferLength); // Unpack the serial data into float values. From c413c3a855343112261494b60f35ef2a222907b1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 14 May 2020 22:01:10 +0200 Subject: [PATCH 021/115] Tighten code, reactivate emphasis --- FMControl.cpp | 48 ++++++++++++++++++++++++------------------------ FMControl.h | 4 ++-- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index bc1e0b0..0041797 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -20,16 +20,15 @@ #include -#define EMPHASIS_GAIN_DB 0 //Gain needs to be the same for pre an deeemphasis -#define RF_AUDIO_SAMP_RATE 8000 -#define FM_AUDIO_BLOCK_SIZE 240 +const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis +const unsigned int FM_MASK = 0x00000FFFU; CFMControl::CFMControl(CFMNetwork* network) : m_network(network), m_enabled(false), -// m_preemphasis(0.3889703087993727F, -0.3290005228984741F, 0.0F, 1.0F, 0.282029168302153F, 0.0F, EMPHASIS_GAIN_DB), -// m_deemphasis(1.0F, 0.282029168302153F, 0.0F, 0.3889703087993727F, -0.3290005228984741F, 0.0F, EMPHASIS_GAIN_DB), -m_incomingRFAudio(1000U, "Incoming RF FM Audio") +m_incomingRFAudio(1600U, "Incoming RF FM Audio"), +m_preemphasis(0.3889703155F, -0.32900055326F, 0.0F, 1.0F, 0.2820291817F, 0.0F, EMPHASIS_GAIN_DB), +m_deemphasis(1.0F, 0.2820291817F, 0.0F, 0.3889703155F, -0.32900055326F, 0.0F, EMPHASIS_GAIN_DB) { } @@ -50,9 +49,6 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (m_network == NULL) return true; - - float samples[170U]; - unsigned int nSamples = 0U; m_incomingRFAudio.addData(data + 1U, length - 1U); unsigned int bufferLength = m_incomingRFAudio.dataSize(); @@ -61,14 +57,16 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (bufferLength >= 3U) { bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 - unsigned char bufferData[255]; + unsigned char bufferData[255U]; m_incomingRFAudio.getData(bufferData, bufferLength); + + unsigned int nSamples = 0; + float samples[85U]; // 255 / 3; // Unpack the serial data into float values. for (unsigned int i = 0U; i < bufferLength; i += 3U) { unsigned short sample1 = 0U; unsigned short sample2 = 0U; - unsigned int MASK = 0x00000FFFU; unsigned int pack = 0U; unsigned char* packPointer = (unsigned char*)&pack; @@ -77,7 +75,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) packPointer[2U] = bufferData[i + 1U]; packPointer[3U] = bufferData[i + 2U]; - sample2 = short(pack & MASK); + sample2 = short(pack & FM_MASK); sample1 = short(pack >> 12); // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) @@ -85,11 +83,11 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) samples[nSamples++] = (float(sample2) - 2048.0F) / 2048.0F; } - // De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) - // for (unsigned int i = 0U; i < nSamples; i++) - // samples[i] = m_deemphasis.filter(samples[i]); + //De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) + for (unsigned int i = 0U; i < nSamples; i++) + samples[i] = m_deemphasis.filter(samples[i]); - unsigned char out[350U]; + unsigned short out[170U]; // 85 * 2 unsigned int nOut = 0U; // Repack the data (8-bit unsigned values containing unsigned 16-bit data) @@ -99,7 +97,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) out[nOut++] = (sample >> 0) & 0xFFU; } - return m_network->write(out, nOut); + return m_network->write((unsigned char*)out, nOut); } return true; @@ -113,23 +111,25 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) if (m_network == NULL) return 0U; - unsigned char netData[300U]; - unsigned int length = m_network->read(netData, 270U); + if(space > 252U) + space = 252U; + + unsigned char netData[168U];//84 * 2 modem can handle up to 84 samples (252 bytes) at a time + unsigned int length = m_network->read(netData, 168U); if (length == 0U) return 0U; - float samples[170U]; + float samples[84U]; unsigned int nSamples = 0U; - // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) for (unsigned int i = 0U; i < length; i += 2U) { unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; samples[nSamples++] = (float(sample) / 32767.0F) - 1.0F; } - // Pre-emphasise the data and other stuff. - // for (unsigned int i = 0U; i < nSamples; i++) - // samples[i] = m_preemphasis.filter(samples[i]); + //Pre-emphasise the data and other stuff. + for (unsigned int i = 0U; i < nSamples; i++) + samples[i] = m_preemphasis.filter(samples[i]); // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; diff --git a/FMControl.h b/FMControl.h index 3a95cc4..5a4a8cd 100644 --- a/FMControl.h +++ b/FMControl.h @@ -39,9 +39,9 @@ public: private: CFMNetwork* m_network; bool m_enabled; - // CIIRDirectForm1Filter m_preemphasis; - // CIIRDirectForm1Filter m_deemphasis; CRingBuffer m_incomingRFAudio; + CIIRDirectForm1Filter m_preemphasis; + CIIRDirectForm1Filter m_deemphasis; }; #endif From 2165b38379315b2ec55308d32a1e86352f814683 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 14 May 2020 22:01:38 +0200 Subject: [PATCH 022/115] Make sur we always return even length --- FMNetwork.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 91cd1c9..cfe6105 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -107,6 +107,7 @@ unsigned int CFMNetwork::read(unsigned char* data, unsigned int space) { assert(data != NULL); + unsigned int bytes = m_buffer.dataSize(); if (bytes == 0U) return 0U; @@ -114,6 +115,10 @@ unsigned int CFMNetwork::read(unsigned char* data, unsigned int space) if (bytes < space) space = bytes; + //we store usignedshorts, therefore ensure we always return and even number of data + if(space > 0 && space % 2 != 0) + space--;//round down to multiple of 2 + m_buffer.getData(data, space); return space; From d96e2204bf0571c6860a7fe01f5a4a115886cb8d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 14 May 2020 22:02:05 +0200 Subject: [PATCH 023/115] Initialize all members --- IIRDirectForm1Filter.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/IIRDirectForm1Filter.cpp b/IIRDirectForm1Filter.cpp index 51e4e13..946acdd 100644 --- a/IIRDirectForm1Filter.cpp +++ b/IIRDirectForm1Filter.cpp @@ -21,14 +21,18 @@ #include "math.h" CIIRDirectForm1Filter::CIIRDirectForm1Filter(float b0, float b1, float b2, float , float a1, float a2, float addtionalGaindB) : +m_x2(0.0F), +m_y2(0.0F), +m_x1(0.0F), +m_y1(0.0F), m_b0(b0), m_b1(b1), m_b2(b2), m_a1(a1), m_a2(a2), -m_additionalGainLin(::powf(10.0F, addtionalGaindB / 20.0F)) +m_additionalGainLin(0.0F) { - + m_additionalGainLin = ::powf(10.0F, addtionalGaindB / 20.0F); } float CIIRDirectForm1Filter::filter(float sample) From b5316907ad1f02947fd1d68c21eec6c2337b8be8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 15 May 2020 20:19:57 +0200 Subject: [PATCH 024/115] Handle FM EOT --- FMControl.cpp | 3 +++ Modem.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/FMControl.cpp b/FMControl.cpp index 0041797..f4a0f27 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -44,6 +44,9 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (data[0U] == TAG_HEADER) return true; + if (data[0U] == TAG_EOT) + return m_network->write(data, 1U); + if (data[0U] != TAG_DATA) return false; diff --git a/Modem.cpp b/Modem.cpp index b73f54c..4d5aaab 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -82,6 +82,7 @@ const unsigned char MMDVM_FM_PARAMS3 = 0x62U; const unsigned char MMDVM_FM_PARAMS4 = 0x63U; const unsigned char MMDVM_FM_DATA = 0x65U; const unsigned char MMDVM_FM_CONTROL = 0x66U; +const unsigned char MMDVM_FM_EOT = 0x67U; const unsigned char MMDVM_ACK = 0x70U; const unsigned char MMDVM_NAK = 0x7FU; @@ -632,6 +633,19 @@ void CModem::clock(unsigned int ms) } break; + case MMDVM_FM_EOT: { + if(m_trace) + CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); + + unsigned char data = m_length - 2U; + m_rxFMData.addData(&data, 1U); + + data = TAG_EOT; + m_rxFMData.addData(&data, 1U); + + m_rxFMData.addData(m_buffer + 3U, m_length - 3U); + } + case MMDVM_GET_STATUS: { // if (m_trace) // CUtils::dump(1U, "GET_STATUS", m_buffer, m_length); From a66f4c6188787ec6749c9374d7affb9a8ed89770 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 16 May 2020 13:09:28 +0100 Subject: [PATCH 025/115] Add an FM EOT network message. --- FMControl.cpp | 6 +++--- FMNetwork.cpp | 17 ++++++++++++++++- FMNetwork.h | 4 +++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index f4a0f27..18d90c5 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -45,7 +45,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) return true; if (data[0U] == TAG_EOT) - return m_network->write(data, 1U); + return m_network->writeEOT(); if (data[0U] != TAG_DATA) return false; @@ -55,7 +55,7 @@ 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 > 255U) + if (bufferLength > 255U) bufferLength = 255U; if (bufferLength >= 3U) { @@ -100,7 +100,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) out[nOut++] = (sample >> 0) & 0xFFU; } - return m_network->write((unsigned char*)out, nOut); + return m_network->writeData((unsigned char*)out, nOut); } return true; diff --git a/FMNetwork.cpp b/FMNetwork.cpp index cfe6105..4e3df87 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -55,7 +55,7 @@ bool CFMNetwork::open() return m_socket.open(); } -bool CFMNetwork::write(const unsigned char* data, unsigned int length) +bool CFMNetwork::writeData(const unsigned char* data, unsigned int length) { assert(data != NULL); @@ -74,6 +74,21 @@ bool CFMNetwork::write(const unsigned char* data, unsigned int length) return m_socket.write(buffer, length + 3U, m_address, m_port); } +bool CFMNetwork::writeEOT() +{ + unsigned char buffer[10U]; + ::memset(buffer, 0x00U, 10U); + + buffer[0U] = 'F'; + buffer[1U] = 'M'; + buffer[2U] = 'E'; + + if (m_debug) + CUtils::dump(1U, "FM Network Data Sent", buffer, 3U); + + return m_socket.write(buffer, 3U, m_address, m_port); +} + void CFMNetwork::clock(unsigned int ms) { unsigned char buffer[BUFFER_LENGTH]; diff --git a/FMNetwork.h b/FMNetwork.h index e4c01ae..fba36d2 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -35,7 +35,9 @@ public: void enable(bool enabled); - bool write(const unsigned char* data, unsigned int length); + bool writeData(const unsigned char* data, unsigned int length); + + bool writeEOT(); unsigned int read(unsigned char* data, unsigned int space); From 734af9453ca53aaf22565876003388357f4e3871 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 16 May 2020 17:16:05 +0200 Subject: [PATCH 026/115] Fix message for FM EOT --- FMNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 4e3df87..57095c5 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -84,7 +84,7 @@ bool CFMNetwork::writeEOT() buffer[2U] = 'E'; if (m_debug) - CUtils::dump(1U, "FM Network Data Sent", buffer, 3U); + CUtils::dump(1U, "FM Network End of Transmission Sent", buffer, 3U); return m_socket.write(buffer, 3U, m_address, m_port); } From 23e92af6faa7430dc8afe8e60153c9c9d26c5d00 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 16 May 2020 17:40:42 +0200 Subject: [PATCH 027/115] Add Poll message --- FMNetwork.cpp | 25 ++++++++++++++++++++++++- FMNetwork.h | 3 +++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 57095c5..10078b5 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -33,7 +33,8 @@ m_address(), m_port(gatewayPort), m_debug(debug), m_enabled(false), -m_buffer(2000U, "FM Network") +m_buffer(2000U, "FM Network"), +m_pollTimer(1000U, 5U) { assert(gatewayPort > 0U); assert(!gatewayAddress.empty()); @@ -52,6 +53,8 @@ bool CFMNetwork::open() if (m_address.s_addr == INADDR_NONE) return false; + m_pollTimer.start(); + return m_socket.open(); } @@ -91,6 +94,12 @@ bool CFMNetwork::writeEOT() void CFMNetwork::clock(unsigned int ms) { + m_pollTimer.clock(ms); + if (m_pollTimer.hasExpired()) { + writePoll(); + m_pollTimer.start(); + } + unsigned char buffer[BUFFER_LENGTH]; in_addr address; @@ -159,3 +168,17 @@ void CFMNetwork::enable(bool enabled) m_enabled = enabled; } + +bool CFMNetwork::writePoll() +{ + unsigned char buffer[3U]; + + buffer[0U] = 'F'; + buffer[1U] = 'M'; + buffer[2U] = 'P'; + + if (m_debug) + CUtils::dump(1U, "FM Network Poll Sent", buffer, 3U); + + return m_socket.write(buffer, 3U, m_address, m_port); +} diff --git a/FMNetwork.h b/FMNetwork.h index fba36d2..453e776 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -54,6 +54,9 @@ private: bool m_debug; bool m_enabled; CRingBuffer m_buffer; + CTimer m_pollTimer; + + bool writePoll(); }; #endif From 578ef5a3d41021cacf937c5366077a9cf15ee872 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 16 May 2020 17:45:24 +0200 Subject: [PATCH 028/115] Handle poll message --- FMNetwork.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 10078b5..67d0f2e 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -114,6 +114,10 @@ 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; From 1290f9c49eaea3a69b09408b1e09f5ccc536a548 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 20 May 2020 18:07:57 +0200 Subject: [PATCH 029/115] do not write EOT when network is not set --- FMControl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 18d90c5..0867914 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -41,6 +41,9 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); + if (m_network == NULL) + return true; + if (data[0U] == TAG_HEADER) return true; @@ -50,8 +53,6 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (data[0U] != TAG_DATA) return false; - if (m_network == NULL) - return true; m_incomingRFAudio.addData(data + 1U, length - 1U); unsigned int bufferLength = m_incomingRFAudio.dataSize(); From 303a0163d37d0fb3ae758e174354f012bc1995d2 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 23 May 2020 13:03:55 +0100 Subject: [PATCH 030/115] Make the modem speed dynamic with a default of 115200. --- Conf.cpp | 1400 +++++++++++++++++++++--------------------- Conf.h | 2 + Display.cpp | 10 +- I2CController.cpp | 10 +- I2CController.h | 4 +- MMDVM.ini | 1 + MMDVMHost.cpp | 6 +- Modem.cpp | 6 +- Modem.h | 2 +- SerialController.cpp | 27 +- SerialController.h | 18 +- UMP.cpp | 4 +- Version.h | 2 +- 13 files changed, 746 insertions(+), 746 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index ca2a347..eae0db6 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -28,38 +28,38 @@ const int BUFFER_SIZE = 500; enum SECTION { - SECTION_NONE, - SECTION_GENERAL, - SECTION_INFO, - SECTION_LOG, - SECTION_CWID, - SECTION_DMRID_LOOKUP, - SECTION_NXDNID_LOOKUP, - SECTION_MODEM, - SECTION_TRANSPARENT, - SECTION_UMP, - SECTION_DSTAR, - SECTION_DMR, - SECTION_FUSION, - SECTION_P25, - SECTION_NXDN, - SECTION_POCSAG, - SECTION_FM, - SECTION_DSTAR_NETWORK, - SECTION_DMR_NETWORK, - SECTION_FUSION_NETWORK, - SECTION_P25_NETWORK, - SECTION_NXDN_NETWORK, - SECTION_POCSAG_NETWORK, - SECTION_FM_NETWORK, - SECTION_TFTSERIAL, - SECTION_HD44780, - SECTION_NEXTION, - SECTION_OLED, - SECTION_LCDPROC, - SECTION_LOCK_FILE, - SECTION_MOBILE_GPS, - SECTION_REMOTE_CONTROL + SECTION_NONE, + SECTION_GENERAL, + SECTION_INFO, + SECTION_LOG, + SECTION_CWID, + SECTION_DMRID_LOOKUP, + SECTION_NXDNID_LOOKUP, + SECTION_MODEM, + SECTION_TRANSPARENT, + SECTION_UMP, + SECTION_DSTAR, + SECTION_DMR, + SECTION_FUSION, + SECTION_P25, + SECTION_NXDN, + SECTION_POCSAG, + SECTION_FM, + SECTION_DSTAR_NETWORK, + SECTION_DMR_NETWORK, + SECTION_FUSION_NETWORK, + SECTION_P25_NETWORK, + SECTION_NXDN_NETWORK, + SECTION_POCSAG_NETWORK, + SECTION_FM_NETWORK, + SECTION_TFTSERIAL, + SECTION_HD44780, + SECTION_NEXTION, + SECTION_OLED, + SECTION_LCDPROC, + SECTION_LOCK_FILE, + SECTION_MOBILE_GPS, + SECTION_REMOTE_CONTROL }; CConf::CConf(const std::string& file) : @@ -92,6 +92,7 @@ m_nxdnIdLookupFile(), m_nxdnIdLookupTime(0U), m_modemPort(), m_modemProtocol("uart"), +m_modemSpeed(115200U), m_modemAddress(0x22), m_modemRXInvert(false), m_modemTXInvert(false), @@ -305,346 +306,348 @@ CConf::~CConf() bool CConf::read() { - FILE* fp = ::fopen(m_file.c_str(), "rt"); - if (fp == NULL) { - ::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str()); - return false; - } + FILE* fp = ::fopen(m_file.c_str(), "rt"); + if (fp == NULL) { + ::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str()); + return false; + } - SECTION section = SECTION_NONE; + SECTION section = SECTION_NONE; - char buffer[BUFFER_SIZE]; - while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) { - if (buffer[0U] == '#') - continue; + char buffer[BUFFER_SIZE]; + while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) { + if (buffer[0U] == '#') + continue; - if (buffer[0U] == '[') { - if (::strncmp(buffer, "[General]", 9U) == 0) - section = SECTION_GENERAL; - else if (::strncmp(buffer, "[Info]", 6U) == 0) - section = SECTION_INFO; - else if (::strncmp(buffer, "[Log]", 5U) == 0) - section = SECTION_LOG; - else if (::strncmp(buffer, "[CW Id]", 7U) == 0) - section = SECTION_CWID; - else if (::strncmp(buffer, "[DMR Id Lookup]", 15U) == 0) - section = SECTION_DMRID_LOOKUP; - else if (::strncmp(buffer, "[NXDN Id Lookup]", 16U) == 0) - section = SECTION_NXDNID_LOOKUP; - else if (::strncmp(buffer, "[Modem]", 7U) == 0) - section = SECTION_MODEM; - else if (::strncmp(buffer, "[Transparent Data]", 18U) == 0) - section = SECTION_TRANSPARENT; - else if (::strncmp(buffer, "[UMP]", 5U) == 0) - section = SECTION_UMP; - else if (::strncmp(buffer, "[D-Star]", 8U) == 0) - section = SECTION_DSTAR; - else if (::strncmp(buffer, "[DMR]", 5U) == 0) - section = SECTION_DMR; - else if (::strncmp(buffer, "[System Fusion]", 15U) == 0) - section = SECTION_FUSION; - else if (::strncmp(buffer, "[P25]", 5U) == 0) - section = SECTION_P25; - else if (::strncmp(buffer, "[NXDN]", 6U) == 0) - section = SECTION_NXDN; - else if (::strncmp(buffer, "[POCSAG]", 8U) == 0) - section = SECTION_POCSAG; - else if (::strncmp(buffer, "[FM]", 4U) == 0) - section = SECTION_FM; - else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0) - section = SECTION_DSTAR_NETWORK; - else if (::strncmp(buffer, "[DMR Network]", 13U) == 0) - section = SECTION_DMR_NETWORK; - else if (::strncmp(buffer, "[System Fusion Network]", 23U) == 0) - section = SECTION_FUSION_NETWORK; - else if (::strncmp(buffer, "[P25 Network]", 13U) == 0) - section = SECTION_P25_NETWORK; - else if (::strncmp(buffer, "[NXDN Network]", 14U) == 0) - section = SECTION_NXDN_NETWORK; - else if (::strncmp(buffer, "[POCSAG Network]", 16U) == 0) - section = SECTION_POCSAG_NETWORK; - else if (::strncmp(buffer, "[FM Network]", 12U) == 0) - section = SECTION_FM_NETWORK; - else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0) - section = SECTION_TFTSERIAL; - else if (::strncmp(buffer, "[HD44780]", 9U) == 0) - section = SECTION_HD44780; - else if (::strncmp(buffer, "[Nextion]", 9U) == 0) - section = SECTION_NEXTION; - else if (::strncmp(buffer, "[OLED]", 6U) == 0) - section = SECTION_OLED; - else if (::strncmp(buffer, "[LCDproc]", 9U) == 0) - section = SECTION_LCDPROC; - else if (::strncmp(buffer, "[Lock File]", 11U) == 0) - section = SECTION_LOCK_FILE; - else if (::strncmp(buffer, "[Mobile GPS]", 12U) == 0) - section = SECTION_MOBILE_GPS; - else if (::strncmp(buffer, "[Remote Control]", 16U) == 0) - section = SECTION_REMOTE_CONTROL; - else - section = SECTION_NONE; + if (buffer[0U] == '[') { + if (::strncmp(buffer, "[General]", 9U) == 0) + section = SECTION_GENERAL; + else if (::strncmp(buffer, "[Info]", 6U) == 0) + section = SECTION_INFO; + else if (::strncmp(buffer, "[Log]", 5U) == 0) + section = SECTION_LOG; + else if (::strncmp(buffer, "[CW Id]", 7U) == 0) + section = SECTION_CWID; + else if (::strncmp(buffer, "[DMR Id Lookup]", 15U) == 0) + section = SECTION_DMRID_LOOKUP; + else if (::strncmp(buffer, "[NXDN Id Lookup]", 16U) == 0) + section = SECTION_NXDNID_LOOKUP; + else if (::strncmp(buffer, "[Modem]", 7U) == 0) + section = SECTION_MODEM; + else if (::strncmp(buffer, "[Transparent Data]", 18U) == 0) + section = SECTION_TRANSPARENT; + else if (::strncmp(buffer, "[UMP]", 5U) == 0) + section = SECTION_UMP; + else if (::strncmp(buffer, "[D-Star]", 8U) == 0) + section = SECTION_DSTAR; + else if (::strncmp(buffer, "[DMR]", 5U) == 0) + section = SECTION_DMR; + else if (::strncmp(buffer, "[System Fusion]", 15U) == 0) + section = SECTION_FUSION; + else if (::strncmp(buffer, "[P25]", 5U) == 0) + section = SECTION_P25; + else if (::strncmp(buffer, "[NXDN]", 6U) == 0) + section = SECTION_NXDN; + else if (::strncmp(buffer, "[POCSAG]", 8U) == 0) + section = SECTION_POCSAG; + else if (::strncmp(buffer, "[FM]", 4U) == 0) + section = SECTION_FM; + else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0) + section = SECTION_DSTAR_NETWORK; + else if (::strncmp(buffer, "[DMR Network]", 13U) == 0) + section = SECTION_DMR_NETWORK; + else if (::strncmp(buffer, "[System Fusion Network]", 23U) == 0) + section = SECTION_FUSION_NETWORK; + else if (::strncmp(buffer, "[P25 Network]", 13U) == 0) + section = SECTION_P25_NETWORK; + else if (::strncmp(buffer, "[NXDN Network]", 14U) == 0) + section = SECTION_NXDN_NETWORK; + else if (::strncmp(buffer, "[POCSAG Network]", 16U) == 0) + section = SECTION_POCSAG_NETWORK; + else if (::strncmp(buffer, "[FM Network]", 12U) == 0) + section = SECTION_FM_NETWORK; + else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0) + section = SECTION_TFTSERIAL; + else if (::strncmp(buffer, "[HD44780]", 9U) == 0) + section = SECTION_HD44780; + else if (::strncmp(buffer, "[Nextion]", 9U) == 0) + section = SECTION_NEXTION; + else if (::strncmp(buffer, "[OLED]", 6U) == 0) + section = SECTION_OLED; + else if (::strncmp(buffer, "[LCDproc]", 9U) == 0) + section = SECTION_LCDPROC; + else if (::strncmp(buffer, "[Lock File]", 11U) == 0) + section = SECTION_LOCK_FILE; + else if (::strncmp(buffer, "[Mobile GPS]", 12U) == 0) + section = SECTION_MOBILE_GPS; + else if (::strncmp(buffer, "[Remote Control]", 16U) == 0) + section = SECTION_REMOTE_CONTROL; + else + section = SECTION_NONE; - continue; - } - - char* key = ::strtok(buffer, " \t=\r\n"); - if (key == NULL) - continue; - - char* value = ::strtok(NULL, "\r\n"); - if (value == NULL) - continue; - - // Remove quotes from the value - size_t len = ::strlen(value); - if (len > 1U && *value == '"' && value[len - 1U] == '"') { - value[len - 1U] = '\0'; - value++; - } - - if (section == SECTION_GENERAL) { - if (::strcmp(key, "Callsign") == 0) { - // Convert the callsign to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_fmCallsign = m_cwIdCallsign = m_callsign = value; - } else if (::strcmp(key, "Id") == 0) - m_id = m_p25Id = m_dmrId = (unsigned int)::atoi(value); - else if (::strcmp(key, "Timeout") == 0) - m_fmTimeout = m_timeout = (unsigned int)::atoi(value); - else if (::strcmp(key, "Duplex") == 0) - m_duplex = ::atoi(value) == 1; - else if (::strcmp(key, "ModeHang") == 0) - m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = m_nxdnNetworkModeHang = m_pocsagNetworkModeHang = m_fmNetworkModeHang = - m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_fmModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "RFModeHang") == 0) - m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_fmModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "NetModeHang") == 0) - m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = m_nxdnNetworkModeHang = m_pocsagNetworkModeHang = m_fmNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Display") == 0) - m_display = value; - else if (::strcmp(key, "Daemon") == 0) - m_daemon = ::atoi(value) == 1; - } else if (section == SECTION_INFO) { - if (::strcmp(key, "TXFrequency") == 0) - m_pocsagFrequency = m_txFrequency = (unsigned int)::atoi(value); - else if (::strcmp(key, "RXFrequency") == 0) - m_rxFrequency = (unsigned int)::atoi(value); - else if (::strcmp(key, "Power") == 0) - m_power = (unsigned int)::atoi(value); - else if (::strcmp(key, "Latitude") == 0) - m_latitude = float(::atof(value)); - else if (::strcmp(key, "Longitude") == 0) - m_longitude = float(::atof(value)); - else if (::strcmp(key, "Height") == 0) - m_height = ::atoi(value); - else if (::strcmp(key, "Location") == 0) - m_location = value; - else if (::strcmp(key, "Description") == 0) - m_description = value; - else if (::strcmp(key, "URL") == 0) - m_url = value; - } else if (section == SECTION_LOG) { - if (::strcmp(key, "FilePath") == 0) - m_logFilePath = value; - else if (::strcmp(key, "FileRoot") == 0) - m_logFileRoot = value; - else if (::strcmp(key, "FileLevel") == 0) - m_logFileLevel = (unsigned int)::atoi(value); - else if (::strcmp(key, "DisplayLevel") == 0) - m_logDisplayLevel = (unsigned int)::atoi(value); - } else if (section == SECTION_CWID) { - if (::strcmp(key, "Enable") == 0) - m_cwIdEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Time") == 0) - m_cwIdTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "Callsign") == 0) { - // Convert the callsign to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_cwIdCallsign = value; + continue; } - } else if (section == SECTION_DMRID_LOOKUP) { - if (::strcmp(key, "File") == 0) - m_dmrIdLookupFile = value; - else if (::strcmp(key, "Time") == 0) - m_dmrIdLookupTime = (unsigned int)::atoi(value); - } else if (section == SECTION_NXDNID_LOOKUP) { - if (::strcmp(key, "File") == 0) - m_nxdnIdLookupFile = value; - else if (::strcmp(key, "Time") == 0) - m_nxdnIdLookupTime = (unsigned int)::atoi(value); - } else if (section == SECTION_MODEM) { - if (::strcmp(key, "Port") == 0) - m_modemPort = value; - else if (::strcmp(key, "Protocol") == 0) - m_modemProtocol = value; - else if (::strcmp(key, "Address") == 0) - m_modemAddress = (unsigned int)::strtoul(value, NULL, 16); - else if (::strcmp(key, "RXInvert") == 0) - m_modemRXInvert = ::atoi(value) == 1; - else if (::strcmp(key, "TXInvert") == 0) - m_modemTXInvert = ::atoi(value) == 1; - else if (::strcmp(key, "PTTInvert") == 0) - m_modemPTTInvert = ::atoi(value) == 1; - else if (::strcmp(key, "TXDelay") == 0) - m_modemTXDelay = (unsigned int)::atoi(value); - else if (::strcmp(key, "DMRDelay") == 0) - m_modemDMRDelay = (unsigned int)::atoi(value); - else if (::strcmp(key, "RXOffset") == 0) - m_modemRXOffset = ::atoi(value); - else if (::strcmp(key, "TXOffset") == 0) - m_modemTXOffset = ::atoi(value); - else if (::strcmp(key, "RXDCOffset") == 0) - m_modemRXDCOffset = ::atoi(value); - else if (::strcmp(key, "TXDCOffset") == 0) - m_modemTXDCOffset = ::atoi(value); - else if (::strcmp(key, "RFLevel") == 0) - m_modemRFLevel = float(::atof(value)); - else if (::strcmp(key, "RXLevel") == 0) - m_modemRXLevel = float(::atof(value)); - else if (::strcmp(key, "TXLevel") == 0) - m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value)); - else if (::strcmp(key, "CWIdTXLevel") == 0) - m_modemCWIdTXLevel = float(::atof(value)); - else if (::strcmp(key, "D-StarTXLevel") == 0) - m_modemDStarTXLevel = float(::atof(value)); - else if (::strcmp(key, "DMRTXLevel") == 0) - m_modemDMRTXLevel = float(::atof(value)); - else if (::strcmp(key, "YSFTXLevel") == 0) - m_modemYSFTXLevel = float(::atof(value)); - else if (::strcmp(key, "P25TXLevel") == 0) - m_modemP25TXLevel = float(::atof(value)); - else if (::strcmp(key, "NXDNTXLevel") == 0) - m_modemNXDNTXLevel = float(::atof(value)); - else if (::strcmp(key, "POCSAGTXLevel") == 0) - m_modemPOCSAGTXLevel = float(::atof(value)); - else if (::strcmp(key, "FMTXLevel") == 0) - m_modemFMTXLevel = float(::atof(value)); - else if (::strcmp(key, "RSSIMappingFile") == 0) - m_modemRSSIMappingFile = value; - else if (::strcmp(key, "Trace") == 0) - m_modemTrace = ::atoi(value) == 1; - else if (::strcmp(key, "Debug") == 0) - m_modemDebug = ::atoi(value) == 1; - } else if (section == SECTION_TRANSPARENT) { - if (::strcmp(key, "Enable") == 0) - m_transparentEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "RemoteAddress") == 0) - m_transparentRemoteAddress = value; - else if (::strcmp(key, "RemotePort") == 0) - m_transparentRemotePort = (unsigned int)::atoi(value); - else if (::strcmp(key, "LocalPort") == 0) - m_transparentLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "SendFrameType") == 0) - m_transparentSendFrameType = (unsigned int)::atoi(value); - } else if (section == SECTION_UMP) { - if (::strcmp(key, "Enable") == 0) - m_umpEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Port") == 0) - m_umpPort = value; - } else if (section == SECTION_DSTAR) { - if (::strcmp(key, "Enable") == 0) - m_dstarEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Module") == 0) { - // Convert the module to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_dstarModule = value; - } else if (::strcmp(key, "SelfOnly") == 0) - m_dstarSelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "BlackList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - if (::strlen(p) > 0U) { - for (unsigned int i = 0U; p[i] != 0; i++) - p[i] = ::toupper(p[i]); - std::string callsign = std::string(p); - callsign.resize(DSTAR_LONG_CALLSIGN_LENGTH, ' '); - m_dstarBlackList.push_back(callsign); + + char* key = ::strtok(buffer, " \t=\r\n"); + if (key == NULL) + continue; + + char* value = ::strtok(NULL, "\r\n"); + if (value == NULL) + continue; + + // Remove quotes from the value + size_t len = ::strlen(value); + if (len > 1U && *value == '"' && value[len - 1U] == '"') { + value[len - 1U] = '\0'; + value++; + } + + if (section == SECTION_GENERAL) { + if (::strcmp(key, "Callsign") == 0) { + // Convert the callsign to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_fmCallsign = m_cwIdCallsign = m_callsign = value; + } else if (::strcmp(key, "Id") == 0) + m_id = m_p25Id = m_dmrId = (unsigned int)::atoi(value); + else if (::strcmp(key, "Timeout") == 0) + m_fmTimeout = m_timeout = (unsigned int)::atoi(value); + else if (::strcmp(key, "Duplex") == 0) + m_duplex = ::atoi(value) == 1; + else if (::strcmp(key, "ModeHang") == 0) + m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = m_nxdnNetworkModeHang = m_pocsagNetworkModeHang = m_fmNetworkModeHang = + m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_fmModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "RFModeHang") == 0) + m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_fmModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "NetModeHang") == 0) + m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = m_nxdnNetworkModeHang = m_pocsagNetworkModeHang = m_fmNetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Display") == 0) + m_display = value; + else if (::strcmp(key, "Daemon") == 0) + m_daemon = ::atoi(value) == 1; + } else if (section == SECTION_INFO) { + if (::strcmp(key, "TXFrequency") == 0) + m_pocsagFrequency = m_txFrequency = (unsigned int)::atoi(value); + else if (::strcmp(key, "RXFrequency") == 0) + m_rxFrequency = (unsigned int)::atoi(value); + else if (::strcmp(key, "Power") == 0) + m_power = (unsigned int)::atoi(value); + else if (::strcmp(key, "Latitude") == 0) + m_latitude = float(::atof(value)); + else if (::strcmp(key, "Longitude") == 0) + m_longitude = float(::atof(value)); + else if (::strcmp(key, "Height") == 0) + m_height = ::atoi(value); + else if (::strcmp(key, "Location") == 0) + m_location = value; + else if (::strcmp(key, "Description") == 0) + m_description = value; + else if (::strcmp(key, "URL") == 0) + m_url = value; + } else if (section == SECTION_LOG) { + if (::strcmp(key, "FilePath") == 0) + m_logFilePath = value; + else if (::strcmp(key, "FileRoot") == 0) + m_logFileRoot = value; + else if (::strcmp(key, "FileLevel") == 0) + m_logFileLevel = (unsigned int)::atoi(value); + else if (::strcmp(key, "DisplayLevel") == 0) + m_logDisplayLevel = (unsigned int)::atoi(value); + } else if (section == SECTION_CWID) { + if (::strcmp(key, "Enable") == 0) + m_cwIdEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Time") == 0) + m_cwIdTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "Callsign") == 0) { + // Convert the callsign to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_cwIdCallsign = value; + } + } else if (section == SECTION_DMRID_LOOKUP) { + if (::strcmp(key, "File") == 0) + m_dmrIdLookupFile = value; + else if (::strcmp(key, "Time") == 0) + m_dmrIdLookupTime = (unsigned int)::atoi(value); + } else if (section == SECTION_NXDNID_LOOKUP) { + if (::strcmp(key, "File") == 0) + m_nxdnIdLookupFile = value; + else if (::strcmp(key, "Time") == 0) + m_nxdnIdLookupTime = (unsigned int)::atoi(value); + } else if (section == SECTION_MODEM) { + if (::strcmp(key, "Port") == 0) + m_modemPort = value; + else if (::strcmp(key, "Protocol") == 0) + m_modemProtocol = value; + else if (::strcmp(key, "Speed") == 0) + m_modemSpeed = (unsigned int)::atoi(value); + else if (::strcmp(key, "Address") == 0) + m_modemAddress = (unsigned int)::strtoul(value, NULL, 16); + else if (::strcmp(key, "RXInvert") == 0) + m_modemRXInvert = ::atoi(value) == 1; + else if (::strcmp(key, "TXInvert") == 0) + m_modemTXInvert = ::atoi(value) == 1; + else if (::strcmp(key, "PTTInvert") == 0) + m_modemPTTInvert = ::atoi(value) == 1; + else if (::strcmp(key, "TXDelay") == 0) + m_modemTXDelay = (unsigned int)::atoi(value); + else if (::strcmp(key, "DMRDelay") == 0) + m_modemDMRDelay = (unsigned int)::atoi(value); + else if (::strcmp(key, "RXOffset") == 0) + m_modemRXOffset = ::atoi(value); + else if (::strcmp(key, "TXOffset") == 0) + m_modemTXOffset = ::atoi(value); + else if (::strcmp(key, "RXDCOffset") == 0) + m_modemRXDCOffset = ::atoi(value); + else if (::strcmp(key, "TXDCOffset") == 0) + m_modemTXDCOffset = ::atoi(value); + else if (::strcmp(key, "RFLevel") == 0) + m_modemRFLevel = float(::atof(value)); + else if (::strcmp(key, "RXLevel") == 0) + m_modemRXLevel = float(::atof(value)); + else if (::strcmp(key, "TXLevel") == 0) + m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value)); + else if (::strcmp(key, "CWIdTXLevel") == 0) + m_modemCWIdTXLevel = float(::atof(value)); + else if (::strcmp(key, "D-StarTXLevel") == 0) + m_modemDStarTXLevel = float(::atof(value)); + else if (::strcmp(key, "DMRTXLevel") == 0) + m_modemDMRTXLevel = float(::atof(value)); + else if (::strcmp(key, "YSFTXLevel") == 0) + m_modemYSFTXLevel = float(::atof(value)); + else if (::strcmp(key, "P25TXLevel") == 0) + m_modemP25TXLevel = float(::atof(value)); + else if (::strcmp(key, "NXDNTXLevel") == 0) + m_modemNXDNTXLevel = float(::atof(value)); + else if (::strcmp(key, "POCSAGTXLevel") == 0) + m_modemPOCSAGTXLevel = float(::atof(value)); + else if (::strcmp(key, "FMTXLevel") == 0) + m_modemFMTXLevel = float(::atof(value)); + else if (::strcmp(key, "RSSIMappingFile") == 0) + m_modemRSSIMappingFile = value; + else if (::strcmp(key, "Trace") == 0) + m_modemTrace = ::atoi(value) == 1; + else if (::strcmp(key, "Debug") == 0) + m_modemDebug = ::atoi(value) == 1; + } else if (section == SECTION_TRANSPARENT) { + if (::strcmp(key, "Enable") == 0) + m_transparentEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "RemoteAddress") == 0) + m_transparentRemoteAddress = value; + else if (::strcmp(key, "RemotePort") == 0) + m_transparentRemotePort = (unsigned int)::atoi(value); + else if (::strcmp(key, "LocalPort") == 0) + m_transparentLocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "SendFrameType") == 0) + m_transparentSendFrameType = (unsigned int)::atoi(value); + } else if (section == SECTION_UMP) { + if (::strcmp(key, "Enable") == 0) + m_umpEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Port") == 0) + m_umpPort = value; + } else if (section == SECTION_DSTAR) { + if (::strcmp(key, "Enable") == 0) + m_dstarEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Module") == 0) { + // Convert the module to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_dstarModule = value; + } else if (::strcmp(key, "SelfOnly") == 0) + m_dstarSelfOnly = ::atoi(value) == 1; + else if (::strcmp(key, "BlackList") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + if (::strlen(p) > 0U) { + for (unsigned int i = 0U; p[i] != 0; i++) + p[i] = ::toupper(p[i]); + std::string callsign = std::string(p); + callsign.resize(DSTAR_LONG_CALLSIGN_LENGTH, ' '); + m_dstarBlackList.push_back(callsign); + } + p = ::strtok(NULL, ",\r\n"); } - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "AckReply") == 0) - m_dstarAckReply = ::atoi(value) == 1; - else if (::strcmp(key, "AckTime") == 0) - m_dstarAckTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckMessage") == 0) - m_dstarAckMessage = ::atoi(value) == 1; - else if (::strcmp(key, "ErrorReply") == 0) - m_dstarErrorReply = ::atoi(value) == 1; - else if (::strcmp(key, "RemoteGateway") == 0) - m_dstarRemoteGateway = ::atoi(value) == 1; - else if (::strcmp(key, "ModeHang") == 0) - m_dstarModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_DMR) { - if (::strcmp(key, "Enable") == 0) - m_dmrEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Beacons") == 0) - m_dmrBeacons = ::atoi(value) == 1 ? DMR_BEACONS_NETWORK : DMR_BEACONS_OFF; - else if (::strcmp(key, "BeaconInterval") == 0) { - m_dmrBeacons = m_dmrBeacons != DMR_BEACONS_OFF ? DMR_BEACONS_TIMED : DMR_BEACONS_OFF; - m_dmrBeaconInterval = (unsigned int)::atoi(value); - } else if (::strcmp(key, "BeaconDuration") == 0) - m_dmrBeaconDuration = (unsigned int)::atoi(value); - else if (::strcmp(key, "Id") == 0) - m_dmrId = (unsigned int)::atoi(value); - else if (::strcmp(key, "ColorCode") == 0) - m_dmrColorCode = (unsigned int)::atoi(value); - else if (::strcmp(key, "SelfOnly") == 0) - m_dmrSelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "EmbeddedLCOnly") == 0) - m_dmrEmbeddedLCOnly = ::atoi(value) == 1; - else if (::strcmp(key, "DumpTAData") == 0) - m_dmrDumpTAData = ::atoi(value) == 1; - else if (::strcmp(key, "Prefixes") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int prefix = (unsigned int)::atoi(p); - if (prefix > 0U && prefix <= 999U) - m_dmrPrefixes.push_back(prefix); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "BlackList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int id = (unsigned int)::atoi(p); - if (id > 0U) - m_dmrBlackList.push_back(id); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "WhiteList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int id = (unsigned int)::atoi(p); - if (id > 0U) - m_dmrWhiteList.push_back(id); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "Slot1TGWhiteList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int id = (unsigned int)::atoi(p); - if (id > 0U) - m_dmrSlot1TGWhiteList.push_back(id); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "Slot2TGWhiteList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int id = (unsigned int)::atoi(p); - if (id > 0U) - m_dmrSlot2TGWhiteList.push_back(id); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "TXHang") == 0) - m_dmrTXHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallHang") == 0) - m_dmrCallHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_dmrModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "OVCM") == 0) - switch(::atoi(value)) { + } else if (::strcmp(key, "AckReply") == 0) + m_dstarAckReply = ::atoi(value) == 1; + else if (::strcmp(key, "AckTime") == 0) + m_dstarAckTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckMessage") == 0) + m_dstarAckMessage = ::atoi(value) == 1; + else if (::strcmp(key, "ErrorReply") == 0) + m_dstarErrorReply = ::atoi(value) == 1; + else if (::strcmp(key, "RemoteGateway") == 0) + m_dstarRemoteGateway = ::atoi(value) == 1; + else if (::strcmp(key, "ModeHang") == 0) + m_dstarModeHang = (unsigned int)::atoi(value); + } else if (section == SECTION_DMR) { + if (::strcmp(key, "Enable") == 0) + m_dmrEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Beacons") == 0) + m_dmrBeacons = ::atoi(value) == 1 ? DMR_BEACONS_NETWORK : DMR_BEACONS_OFF; + else if (::strcmp(key, "BeaconInterval") == 0) { + m_dmrBeacons = m_dmrBeacons != DMR_BEACONS_OFF ? DMR_BEACONS_TIMED : DMR_BEACONS_OFF; + m_dmrBeaconInterval = (unsigned int)::atoi(value); + } else if (::strcmp(key, "BeaconDuration") == 0) + m_dmrBeaconDuration = (unsigned int)::atoi(value); + else if (::strcmp(key, "Id") == 0) + m_dmrId = (unsigned int)::atoi(value); + else if (::strcmp(key, "ColorCode") == 0) + m_dmrColorCode = (unsigned int)::atoi(value); + else if (::strcmp(key, "SelfOnly") == 0) + m_dmrSelfOnly = ::atoi(value) == 1; + else if (::strcmp(key, "EmbeddedLCOnly") == 0) + m_dmrEmbeddedLCOnly = ::atoi(value) == 1; + else if (::strcmp(key, "DumpTAData") == 0) + m_dmrDumpTAData = ::atoi(value) == 1; + else if (::strcmp(key, "Prefixes") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + unsigned int prefix = (unsigned int)::atoi(p); + if (prefix > 0U && prefix <= 999U) + m_dmrPrefixes.push_back(prefix); + p = ::strtok(NULL, ",\r\n"); + } + } else if (::strcmp(key, "BlackList") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + unsigned int id = (unsigned int)::atoi(p); + if (id > 0U) + m_dmrBlackList.push_back(id); + p = ::strtok(NULL, ",\r\n"); + } + } else if (::strcmp(key, "WhiteList") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + unsigned int id = (unsigned int)::atoi(p); + if (id > 0U) + m_dmrWhiteList.push_back(id); + p = ::strtok(NULL, ",\r\n"); + } + } else if (::strcmp(key, "Slot1TGWhiteList") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + unsigned int id = (unsigned int)::atoi(p); + if (id > 0U) + m_dmrSlot1TGWhiteList.push_back(id); + p = ::strtok(NULL, ",\r\n"); + } + } else if (::strcmp(key, "Slot2TGWhiteList") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + unsigned int id = (unsigned int)::atoi(p); + if (id > 0U) + m_dmrSlot2TGWhiteList.push_back(id); + p = ::strtok(NULL, ",\r\n"); + } + } else if (::strcmp(key, "TXHang") == 0) + m_dmrTXHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallHang") == 0) + m_dmrCallHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_dmrModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "OVCM") == 0) { + switch (::atoi(value)) { case 1: m_dmrOVCM = DMR_OVCM_RX_ON; break; @@ -657,342 +660,342 @@ bool CConf::read() default: m_dmrOVCM = DMR_OVCM_OFF; break; + } } - } else if (section == SECTION_FUSION) { - if (::strcmp(key, "Enable") == 0) - m_fusionEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LowDeviation") == 0) - m_fusionLowDeviation = ::atoi(value) == 1; - else if (::strcmp(key, "DGID") == 0) { - m_fusionDGIdEnabled = true; - m_fusionDGId = (unsigned int)::atoi(value); - } else if (::strcmp(key, "RemoteGateway") == 0) - m_fusionRemoteGateway = ::atoi(value) == 1; - else if (::strcmp(key, "SelfOnly") == 0) - m_fusionSelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "TXHang") == 0) - m_fusionTXHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_fusionModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_P25) { - if (::strcmp(key, "Enable") == 0) - m_p25Enabled = ::atoi(value) == 1; - else if (::strcmp(key, "Id") == 0) - m_p25Id = (unsigned int)::atoi(value); - else if (::strcmp(key, "NAC") == 0) - m_p25NAC = (unsigned int)::strtoul(value, NULL, 16); - else if (::strcmp(key, "OverrideUIDCheck") == 0) - m_p25OverrideUID = ::atoi(value) == 1; - else if (::strcmp(key, "SelfOnly") == 0) - m_p25SelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "RemoteGateway") == 0) - m_p25RemoteGateway = ::atoi(value) == 1; - else if (::strcmp(key, "TXHang") == 0) - m_p25TXHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_p25ModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_NXDN) { - if (::strcmp(key, "Enable") == 0) - m_nxdnEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Id") == 0) - m_nxdnId = (unsigned int)::atoi(value); - else if (::strcmp(key, "RAN") == 0) - m_nxdnRAN = (unsigned int)::atoi(value); - else if (::strcmp(key, "SelfOnly") == 0) - m_nxdnSelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "RemoteGateway") == 0) - m_nxdnRemoteGateway = ::atoi(value) == 1; - else if (::strcmp(key, "TXHang") == 0) - m_nxdnTXHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_nxdnModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_POCSAG) { - if (::strcmp(key, "Enable") == 0) - m_pocsagEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Frequency") == 0) - m_pocsagFrequency = (unsigned int)::atoi(value); - } - else if (section == SECTION_FM) { - if (::strcmp(key, "Enable") == 0) - m_fmEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Callsign") == 0) { - // Convert the callsign to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_fmCallsign = value; - } else if (::strcmp(key, "CallsignSpeed") == 0) - m_fmCallsignSpeed = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallsignFrequency") == 0) - m_fmCallsignFrequency = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallsignTime") == 0) - m_fmCallsignTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallsignHoldoff") == 0) - m_fmCallsignHoldoff = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallsignHighLevel") == 0) - m_fmCallsignHighLevel = float(::atof(value)); - else if (::strcmp(key, "CallsignLowLevel") == 0) - m_fmCallsignLowLevel = float(::atof(value)); - else if (::strcmp(key, "CallsignAtStart") == 0) - m_fmCallsignAtStart = ::atoi(value) == 1; - else if (::strcmp(key, "CallsignAtEnd") == 0) - m_fmCallsignAtEnd = ::atoi(value) == 1; - else if (::strcmp(key, "CallsignAtLatch") == 0) - m_fmCallsignAtLatch = ::atoi(value) == 1; - else if (::strcmp(key, "RFAck") == 0) { - // Convert the ack to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_fmRFAck = value; - } else if (::strcmp(key, "ExtAck") == 0) { - // Convert the ack to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_fmExtAck = value; - } else if (::strcmp(key, "AckSpeed") == 0) - m_fmAckSpeed = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckFrequency") == 0) - m_fmAckFrequency = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckMinTime") == 0) - m_fmAckMinTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckDelay") == 0) - m_fmAckDelay = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckLevel") == 0) - m_fmAckLevel = float(::atof(value)); - else if (::strcmp(key, "Timeout") == 0) - m_fmTimeout = (unsigned int)::atoi(value); - else if (::strcmp(key, "TimeoutLevel") == 0) - m_fmTimeoutLevel = float(::atof(value)); - else if (::strcmp(key, "CTCSSFrequency") == 0) - m_fmCTCSSFrequency = float(::atof(value)); - else if (::strcmp(key, "CTCSSThreshold") == 0) - m_fmCTCSSHighThreshold = m_fmCTCSSLowThreshold = (unsigned int)::atoi(value); - else if (::strcmp(key, "CTCSSHighThreshold") == 0) - m_fmCTCSSHighThreshold = (unsigned int)::atoi(value); - else if (::strcmp(key, "CTCSSLowThreshold") == 0) - m_fmCTCSSLowThreshold = (unsigned int)::atoi(value); - else if (::strcmp(key, "CTCSSLevel") == 0) - m_fmCTCSSLevel = float(::atof(value)); - else if (::strcmp(key, "KerchunkTime") == 0) - m_fmKerchunkTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "HangTime") == 0) - m_fmHangTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "UseCOS") == 0) - m_fmUseCOS = ::atoi(value) == 1; - else if (::strcmp(key, "COSInvert") == 0) - m_fmCOSInvert = ::atoi(value) == 1; - else if (::strcmp(key, "RFAudioBoost") == 0) - m_fmRFAudioBoost = (unsigned int)::atoi(value); - else if (::strcmp(key, "MaxDevLevel") == 0) - m_fmMaxDevLevel = float(::atof(value)); - else if (::strcmp(key, "ExtAudioBoost") == 0) - m_fmExtAudioBoost = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_fmModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_DSTAR_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_dstarNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "GatewayAddress") == 0) - m_dstarGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_dstarGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "LocalPort") == 0) - m_dstarLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_dstarNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_dstarNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_DMR_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_dmrNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Address") == 0) - m_dmrNetworkAddress = value; - else if (::strcmp(key, "Port") == 0) - m_dmrNetworkPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "Local") == 0) - m_dmrNetworkLocal = (unsigned int)::atoi(value); - else if (::strcmp(key, "Password") == 0) - m_dmrNetworkPassword = value; - else if (::strcmp(key, "Options") == 0) - m_dmrNetworkOptions = value; - else if (::strcmp(key, "Debug") == 0) - m_dmrNetworkDebug = ::atoi(value) == 1; - else if (::strcmp(key, "Jitter") == 0) - m_dmrNetworkJitter = (unsigned int)::atoi(value); - else if (::strcmp(key, "Slot1") == 0) - m_dmrNetworkSlot1 = ::atoi(value) == 1; - else if (::strcmp(key, "Slot2") == 0) - m_dmrNetworkSlot2 = ::atoi(value) == 1; - else if (::strcmp(key, "ModeHang") == 0) - m_dmrNetworkModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_FUSION_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_fusionNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LocalAddress") == 0) - m_fusionNetworkMyAddress = value; - else if (::strcmp(key, "LocalPort") == 0) - m_fusionNetworkMyPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "GatewayAddress") == 0) - m_fusionNetworkGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_fusionNetworkGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_fusionNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_fusionNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_P25_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_p25NetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "GatewayAddress") == 0) - m_p25GatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_p25GatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "LocalPort") == 0) - m_p25LocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_p25NetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_p25NetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_NXDN_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_nxdnNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LocalAddress") == 0) - m_nxdnLocalAddress = value; - else if (::strcmp(key, "LocalPort") == 0) - m_nxdnLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "GatewayAddress") == 0) - m_nxdnGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_nxdnGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_nxdnNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_nxdnNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_POCSAG_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_pocsagNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LocalAddress") == 0) - m_pocsagLocalAddress = value; - else if (::strcmp(key, "LocalPort") == 0) - m_pocsagLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "GatewayAddress") == 0) - m_pocsagGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_pocsagGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_pocsagNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_pocsagNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_FM_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_fmNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LocalAddress") == 0) - m_fmLocalAddress = value; - else if (::strcmp(key, "LocalPort") == 0) - m_fmLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "GatewayAddress") == 0) - m_fmGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_fmGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_fmNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_fmNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_TFTSERIAL) { - if (::strcmp(key, "Port") == 0) - m_tftSerialPort = value; - else if (::strcmp(key, "Brightness") == 0) - m_tftSerialBrightness = (unsigned int)::atoi(value); - } else if (section == SECTION_HD44780) { - if (::strcmp(key, "Rows") == 0) - m_hd44780Rows = (unsigned int)::atoi(value); - else if (::strcmp(key, "Columns") == 0) - m_hd44780Columns = (unsigned int)::atoi(value); - else if (::strcmp(key, "I2CAddress") == 0) - m_hd44780i2cAddress = (unsigned int)::strtoul(value, NULL, 16); - else if (::strcmp(key, "PWM") == 0) - m_hd44780PWM = ::atoi(value) == 1; - else if (::strcmp(key, "PWMPin") == 0) - m_hd44780PWMPin = (unsigned int)::atoi(value); - else if (::strcmp(key, "PWMBright") == 0) - m_hd44780PWMBright = (unsigned int)::atoi(value); - else if (::strcmp(key, "PWMDim") == 0) - m_hd44780PWMDim = (unsigned int)::atoi(value); - else if (::strcmp(key, "DisplayClock") == 0) - m_hd44780DisplayClock = ::atoi(value) == 1; - else if (::strcmp(key, "UTC") == 0) - m_hd44780UTC = ::atoi(value) == 1; - else if (::strcmp(key, "Pins") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int pin = (unsigned int)::atoi(p); - m_hd44780Pins.push_back(pin); - p = ::strtok(NULL, ",\r\n"); + } else if (section == SECTION_FUSION) { + if (::strcmp(key, "Enable") == 0) + m_fusionEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "LowDeviation") == 0) + m_fusionLowDeviation = ::atoi(value) == 1; + else if (::strcmp(key, "DGID") == 0) { + m_fusionDGIdEnabled = true; + m_fusionDGId = (unsigned int)::atoi(value); + } else if (::strcmp(key, "RemoteGateway") == 0) + m_fusionRemoteGateway = ::atoi(value) == 1; + else if (::strcmp(key, "SelfOnly") == 0) + m_fusionSelfOnly = ::atoi(value) == 1; + else if (::strcmp(key, "TXHang") == 0) + m_fusionTXHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_fusionModeHang = (unsigned int)::atoi(value); + } else if (section == SECTION_P25) { + if (::strcmp(key, "Enable") == 0) + m_p25Enabled = ::atoi(value) == 1; + else if (::strcmp(key, "Id") == 0) + m_p25Id = (unsigned int)::atoi(value); + else if (::strcmp(key, "NAC") == 0) + m_p25NAC = (unsigned int)::strtoul(value, NULL, 16); + else if (::strcmp(key, "OverrideUIDCheck") == 0) + m_p25OverrideUID = ::atoi(value) == 1; + else if (::strcmp(key, "SelfOnly") == 0) + m_p25SelfOnly = ::atoi(value) == 1; + else if (::strcmp(key, "RemoteGateway") == 0) + m_p25RemoteGateway = ::atoi(value) == 1; + else if (::strcmp(key, "TXHang") == 0) + m_p25TXHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_p25ModeHang = (unsigned int)::atoi(value); + } else if (section == SECTION_NXDN) { + if (::strcmp(key, "Enable") == 0) + m_nxdnEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Id") == 0) + m_nxdnId = (unsigned int)::atoi(value); + else if (::strcmp(key, "RAN") == 0) + m_nxdnRAN = (unsigned int)::atoi(value); + else if (::strcmp(key, "SelfOnly") == 0) + m_nxdnSelfOnly = ::atoi(value) == 1; + else if (::strcmp(key, "RemoteGateway") == 0) + m_nxdnRemoteGateway = ::atoi(value) == 1; + else if (::strcmp(key, "TXHang") == 0) + m_nxdnTXHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_nxdnModeHang = (unsigned int)::atoi(value); + } else if (section == SECTION_POCSAG) { + if (::strcmp(key, "Enable") == 0) + m_pocsagEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Frequency") == 0) + m_pocsagFrequency = (unsigned int)::atoi(value); + } else if (section == SECTION_FM) { + if (::strcmp(key, "Enable") == 0) + m_fmEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Callsign") == 0) { + // Convert the callsign to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_fmCallsign = value; + } else if (::strcmp(key, "CallsignSpeed") == 0) + m_fmCallsignSpeed = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallsignFrequency") == 0) + m_fmCallsignFrequency = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallsignTime") == 0) + m_fmCallsignTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallsignHoldoff") == 0) + m_fmCallsignHoldoff = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallsignHighLevel") == 0) + m_fmCallsignHighLevel = float(::atof(value)); + else if (::strcmp(key, "CallsignLowLevel") == 0) + m_fmCallsignLowLevel = float(::atof(value)); + else if (::strcmp(key, "CallsignAtStart") == 0) + m_fmCallsignAtStart = ::atoi(value) == 1; + else if (::strcmp(key, "CallsignAtEnd") == 0) + m_fmCallsignAtEnd = ::atoi(value) == 1; + else if (::strcmp(key, "CallsignAtLatch") == 0) + m_fmCallsignAtLatch = ::atoi(value) == 1; + else if (::strcmp(key, "RFAck") == 0) { + // Convert the ack to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_fmRFAck = value; + } else if (::strcmp(key, "ExtAck") == 0) { + // Convert the ack to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_fmExtAck = value; + } else if (::strcmp(key, "AckSpeed") == 0) + m_fmAckSpeed = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckFrequency") == 0) + m_fmAckFrequency = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckMinTime") == 0) + m_fmAckMinTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckDelay") == 0) + m_fmAckDelay = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckLevel") == 0) + m_fmAckLevel = float(::atof(value)); + else if (::strcmp(key, "Timeout") == 0) + m_fmTimeout = (unsigned int)::atoi(value); + else if (::strcmp(key, "TimeoutLevel") == 0) + m_fmTimeoutLevel = float(::atof(value)); + else if (::strcmp(key, "CTCSSFrequency") == 0) + m_fmCTCSSFrequency = float(::atof(value)); + else if (::strcmp(key, "CTCSSThreshold") == 0) + m_fmCTCSSHighThreshold = m_fmCTCSSLowThreshold = (unsigned int)::atoi(value); + else if (::strcmp(key, "CTCSSHighThreshold") == 0) + m_fmCTCSSHighThreshold = (unsigned int)::atoi(value); + else if (::strcmp(key, "CTCSSLowThreshold") == 0) + m_fmCTCSSLowThreshold = (unsigned int)::atoi(value); + else if (::strcmp(key, "CTCSSLevel") == 0) + m_fmCTCSSLevel = float(::atof(value)); + else if (::strcmp(key, "KerchunkTime") == 0) + m_fmKerchunkTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "HangTime") == 0) + m_fmHangTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "UseCOS") == 0) + m_fmUseCOS = ::atoi(value) == 1; + else if (::strcmp(key, "COSInvert") == 0) + m_fmCOSInvert = ::atoi(value) == 1; + else if (::strcmp(key, "RFAudioBoost") == 0) + m_fmRFAudioBoost = (unsigned int)::atoi(value); + else if (::strcmp(key, "MaxDevLevel") == 0) + m_fmMaxDevLevel = float(::atof(value)); + else if (::strcmp(key, "ExtAudioBoost") == 0) + m_fmExtAudioBoost = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_fmModeHang = (unsigned int)::atoi(value); + } else if (section == SECTION_DSTAR_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_dstarNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "GatewayAddress") == 0) + m_dstarGatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_dstarGatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "LocalPort") == 0) + m_dstarLocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_dstarNetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_dstarNetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_DMR_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_dmrNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Address") == 0) + m_dmrNetworkAddress = value; + else if (::strcmp(key, "Port") == 0) + m_dmrNetworkPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "Local") == 0) + m_dmrNetworkLocal = (unsigned int)::atoi(value); + else if (::strcmp(key, "Password") == 0) + m_dmrNetworkPassword = value; + else if (::strcmp(key, "Options") == 0) + m_dmrNetworkOptions = value; + else if (::strcmp(key, "Debug") == 0) + m_dmrNetworkDebug = ::atoi(value) == 1; + else if (::strcmp(key, "Jitter") == 0) + m_dmrNetworkJitter = (unsigned int)::atoi(value); + else if (::strcmp(key, "Slot1") == 0) + m_dmrNetworkSlot1 = ::atoi(value) == 1; + else if (::strcmp(key, "Slot2") == 0) + m_dmrNetworkSlot2 = ::atoi(value) == 1; + else if (::strcmp(key, "ModeHang") == 0) + m_dmrNetworkModeHang = (unsigned int)::atoi(value); + } else if (section == SECTION_FUSION_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_fusionNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "LocalAddress") == 0) + m_fusionNetworkMyAddress = value; + else if (::strcmp(key, "LocalPort") == 0) + m_fusionNetworkMyPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "GatewayAddress") == 0) + m_fusionNetworkGatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_fusionNetworkGatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_fusionNetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_fusionNetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_P25_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_p25NetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "GatewayAddress") == 0) + m_p25GatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_p25GatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "LocalPort") == 0) + m_p25LocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_p25NetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_p25NetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_NXDN_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_nxdnNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "LocalAddress") == 0) + m_nxdnLocalAddress = value; + else if (::strcmp(key, "LocalPort") == 0) + m_nxdnLocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "GatewayAddress") == 0) + m_nxdnGatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_nxdnGatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_nxdnNetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_nxdnNetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_POCSAG_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_pocsagNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "LocalAddress") == 0) + m_pocsagLocalAddress = value; + else if (::strcmp(key, "LocalPort") == 0) + m_pocsagLocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "GatewayAddress") == 0) + m_pocsagGatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_pocsagGatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_pocsagNetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_pocsagNetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_FM_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_fmNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "LocalAddress") == 0) + m_fmLocalAddress = value; + else if (::strcmp(key, "LocalPort") == 0) + m_fmLocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "GatewayAddress") == 0) + m_fmGatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_fmGatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_fmNetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_fmNetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_TFTSERIAL) { + if (::strcmp(key, "Port") == 0) + m_tftSerialPort = value; + else if (::strcmp(key, "Brightness") == 0) + m_tftSerialBrightness = (unsigned int)::atoi(value); + } else if (section == SECTION_HD44780) { + if (::strcmp(key, "Rows") == 0) + m_hd44780Rows = (unsigned int)::atoi(value); + else if (::strcmp(key, "Columns") == 0) + m_hd44780Columns = (unsigned int)::atoi(value); + else if (::strcmp(key, "I2CAddress") == 0) + m_hd44780i2cAddress = (unsigned int)::strtoul(value, NULL, 16); + else if (::strcmp(key, "PWM") == 0) + m_hd44780PWM = ::atoi(value) == 1; + else if (::strcmp(key, "PWMPin") == 0) + m_hd44780PWMPin = (unsigned int)::atoi(value); + else if (::strcmp(key, "PWMBright") == 0) + m_hd44780PWMBright = (unsigned int)::atoi(value); + else if (::strcmp(key, "PWMDim") == 0) + m_hd44780PWMDim = (unsigned int)::atoi(value); + else if (::strcmp(key, "DisplayClock") == 0) + m_hd44780DisplayClock = ::atoi(value) == 1; + else if (::strcmp(key, "UTC") == 0) + m_hd44780UTC = ::atoi(value) == 1; + else if (::strcmp(key, "Pins") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + unsigned int pin = (unsigned int)::atoi(p); + m_hd44780Pins.push_back(pin); + p = ::strtok(NULL, ",\r\n"); + } } + } else if (section == SECTION_NEXTION) { + if (::strcmp(key, "Port") == 0) + m_nextionPort = value; + else if (::strcmp(key, "Brightness") == 0) + m_nextionIdleBrightness = m_nextionBrightness = (unsigned int)::atoi(value); + else if (::strcmp(key, "DisplayClock") == 0) + m_nextionDisplayClock = ::atoi(value) == 1; + else if (::strcmp(key, "UTC") == 0) + m_nextionUTC = ::atoi(value) == 1; + else if (::strcmp(key, "IdleBrightness") == 0) + m_nextionIdleBrightness = (unsigned int)::atoi(value); + else if (::strcmp(key, "ScreenLayout") == 0) + m_nextionScreenLayout = (unsigned int)::atoi(value); + else if (::strcmp(key, "DisplayTempInFahrenheit") == 0) + m_nextionTempInFahrenheit = ::atoi(value) == 1; + } else if (section == SECTION_OLED) { + if (::strcmp(key, "Type") == 0) + m_oledType = (unsigned char)::atoi(value); + else if (::strcmp(key, "Brightness") == 0) + m_oledBrightness = (unsigned char)::atoi(value); + else if (::strcmp(key, "Invert") == 0) + m_oledInvert = ::atoi(value) == 1; + else if (::strcmp(key, "Scroll") == 0) + m_oledScroll = ::atoi(value) == 1; + else if (::strcmp(key, "Rotate") == 0) + m_oledRotate = ::atoi(value) == 1; + else if (::strcmp(key, "LogoScreensaver") == 0) + m_oledLogoScreensaver = ::atoi(value) == 1; + } else if (section == SECTION_LCDPROC) { + if (::strcmp(key, "Address") == 0) + m_lcdprocAddress = value; + else if (::strcmp(key, "Port") == 0) + m_lcdprocPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "LocalPort") == 0) + m_lcdprocLocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "DisplayClock") == 0) + m_lcdprocDisplayClock = ::atoi(value) == 1; + else if (::strcmp(key, "UTC") == 0) + m_lcdprocUTC = ::atoi(value) == 1; + else if (::strcmp(key, "DimOnIdle") == 0) + m_lcdprocDimOnIdle = ::atoi(value) == 1; + } else if (section == SECTION_LOCK_FILE) { + if (::strcmp(key, "Enable") == 0) + m_lockFileEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "File") == 0) + m_lockFileName = value; + } else if (section == SECTION_MOBILE_GPS) { + if (::strcmp(key, "Enable") == 0) + m_mobileGPSEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Address") == 0) + m_mobileGPSAddress = value; + else if (::strcmp(key, "Port") == 0) + m_mobileGPSPort = (unsigned int)::atoi(value); + } else if (section == SECTION_REMOTE_CONTROL) { + if (::strcmp(key, "Enable") == 0) + m_remoteControlEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Port") == 0) + m_remoteControlPort = (unsigned int)::atoi(value); } - } else if (section == SECTION_NEXTION) { - if (::strcmp(key, "Port") == 0) - m_nextionPort = value; - else if (::strcmp(key, "Brightness") == 0) - m_nextionIdleBrightness = m_nextionBrightness = (unsigned int)::atoi(value); - else if (::strcmp(key, "DisplayClock") == 0) - m_nextionDisplayClock = ::atoi(value) == 1; - else if (::strcmp(key, "UTC") == 0) - m_nextionUTC = ::atoi(value) == 1; - else if (::strcmp(key, "IdleBrightness") == 0) - m_nextionIdleBrightness = (unsigned int)::atoi(value); - else if (::strcmp(key, "ScreenLayout") == 0) - m_nextionScreenLayout = (unsigned int)::atoi(value); - else if (::strcmp(key, "DisplayTempInFahrenheit") == 0) - m_nextionTempInFahrenheit = ::atoi(value) == 1; - } else if (section == SECTION_OLED) { - if (::strcmp(key, "Type") == 0) - m_oledType = (unsigned char)::atoi(value); - else if (::strcmp(key, "Brightness") == 0) - m_oledBrightness = (unsigned char)::atoi(value); - else if (::strcmp(key, "Invert") == 0) - m_oledInvert = ::atoi(value) == 1; - else if (::strcmp(key, "Scroll") == 0) - m_oledScroll = ::atoi(value) == 1; - else if (::strcmp(key, "Rotate") == 0) - m_oledRotate = ::atoi(value) == 1; - else if (::strcmp(key, "LogoScreensaver") == 0) - m_oledLogoScreensaver = ::atoi(value) == 1; - } else if (section == SECTION_LCDPROC) { - if (::strcmp(key, "Address") == 0) - m_lcdprocAddress = value; - else if (::strcmp(key, "Port") == 0) - m_lcdprocPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "LocalPort") == 0) - m_lcdprocLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "DisplayClock") == 0) - m_lcdprocDisplayClock = ::atoi(value) == 1; - else if (::strcmp(key, "UTC") == 0) - m_lcdprocUTC = ::atoi(value) == 1; - else if (::strcmp(key, "DimOnIdle") == 0) - m_lcdprocDimOnIdle = ::atoi(value) == 1; - } else if (section == SECTION_LOCK_FILE) { - if (::strcmp(key, "Enable") == 0) - m_lockFileEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "File") == 0) - m_lockFileName = value; - } else if (section == SECTION_MOBILE_GPS) { - if (::strcmp(key, "Enable") == 0) - m_mobileGPSEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Address") == 0) - m_mobileGPSAddress = value; - else if (::strcmp(key, "Port") == 0) - m_mobileGPSPort = (unsigned int)::atoi(value); - } else if (section == SECTION_REMOTE_CONTROL) { - if (::strcmp(key, "Enable") == 0) - m_remoteControlEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Port") == 0) - m_remoteControlPort = (unsigned int)::atoi(value); } - } - ::fclose(fp); + ::fclose(fp); - return true; + return true; } std::string CConf::getCallsign() const @@ -1135,6 +1138,11 @@ std::string CConf::getModemProtocol() const return m_modemProtocol; } +unsigned int CConf::getModemSpeed() const +{ + return m_modemSpeed; +} + unsigned int CConf::getModemAddress() const { return m_modemAddress; diff --git a/Conf.h b/Conf.h index da8cdfc..b455a55 100644 --- a/Conf.h +++ b/Conf.h @@ -71,6 +71,7 @@ public: // The Modem section std::string getModemPort() const; std::string getModemProtocol() const; + unsigned int getModemSpeed() const; unsigned int getModemAddress() const; bool getModemRXInvert() const; bool getModemTXInvert() const; @@ -360,6 +361,7 @@ private: std::string m_modemPort; std::string m_modemProtocol; + unsigned int m_modemSpeed; unsigned int m_modemAddress; bool m_modemRXInvert; bool m_modemTXInvert; diff --git a/Display.cpp b/Display.cpp index 0b47b64..22bc953 100644 --- a/Display.cpp +++ b/Display.cpp @@ -511,7 +511,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) if (port == "modem") serial = new CModemSerialPort(modem); else - serial = new CSerialController(port, (type == "TFT Serial") ? SERIAL_9600 : SERIAL_115200); + serial = new CSerialController(port, (type == "TFT Serial") ? 9600U : 115200U); if (type == "TFT Surenoo") display = new CTFTSurenoo(conf.getCallsign(), dmrid, serial, brightness, conf.getDuplex()); @@ -565,11 +565,11 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) display = new CNullDisplay; } } else { - SERIAL_SPEED baudrate = SERIAL_9600; - if (screenLayout==4U) - baudrate = SERIAL_115200; + unsigned int baudrate = 9600U; + if (screenLayout == 4U) + baudrate = 115200U; - LogInfo(" Display baudrate: %u ",baudrate); + LogInfo(" Display baudrate: %u ", baudrate); ISerialPort* serial = new CSerialController(port, baudrate); display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation()); } diff --git a/I2CController.cpp b/I2CController.cpp index 247129c..c6b7c77 100644 --- a/I2CController.cpp +++ b/I2CController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004,2007-2011,2013,2014-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2002-2004,2007-2011,2013,2014-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX * * This program is free software; you can redistribute it and/or modify @@ -30,7 +30,7 @@ #include #include -CI2CController::CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address, bool assertRTS) : +CI2CController::CI2CController(const std::string& device, unsigned int speed, unsigned int address, bool assertRTS) : CSerialController(device, speed, assertRTS), m_address(address) { @@ -67,7 +67,7 @@ int CI2CController::write(const unsigned char* buffer, unsigned int length) #include #endif -CI2CController::CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address, bool assertRTS) : +CI2CController::CI2CController(const std::string& device, unsigned int speed, unsigned int address, bool assertRTS) : CSerialController(device, speed, assertRTS), m_address(address) { @@ -89,13 +89,13 @@ bool CI2CController::open() } if (::ioctl(m_fd, I2C_TENBIT, 0) < 0) { - LogError("CI2C: failed to set 7bitaddress"); + LogError("I2C: failed to set 7bitaddress"); ::close(m_fd); return false; } if (::ioctl(m_fd, I2C_SLAVE, m_address) < 0) { - LogError("CI2C: Failed to acquire bus access/talk to slave 0x%02X", m_address); + LogError("I2C: Failed to acquire bus access/talk to slave 0x%02X", m_address); ::close(m_fd); return false; } diff --git a/I2CController.h b/I2CController.h index 6e59672..a67db85 100644 --- a/I2CController.h +++ b/I2CController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX * * This program is free software; you can redistribute it and/or modify @@ -24,7 +24,7 @@ class CI2CController : public CSerialController { public: - CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address = 0x22U, bool assertRTS = false); + CI2CController(const std::string& device, unsigned int speed, unsigned int address = 0x22U, bool assertRTS = false); virtual ~CI2CController(); virtual bool open(); diff --git a/MMDVM.ini b/MMDVM.ini index 60bdff4..c031c49 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -45,6 +45,7 @@ Time=24 # Port=/dev/ttyAMA0 Port=\\.\COM4 Protocol=uart +Speed=115200 # Address=0x22 TXInvert=1 RXInvert=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 8957c29..9d9a01e 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1204,6 +1204,7 @@ bool CMMDVMHost::createModem() { std::string port = m_conf.getModemPort(); std::string protocol = m_conf.getModemProtocol(); + unsigned int speed = m_conf.getModemSpeed(); unsigned int address = m_conf.getModemAddress(); bool rxInvert = m_conf.getModemRXInvert(); bool txInvert = m_conf.getModemTXInvert(); @@ -1239,7 +1240,8 @@ bool CMMDVMHost::createModem() LogInfo(" Port: %s", port.c_str()); LogInfo(" Protocol: %s", protocol.c_str()); if (protocol == "i2c") - LogInfo(" i2c Address: %02X", address); + LogInfo(" I2C Address: %02X", address); + LogInfo(" Speed: %u", speed); LogInfo(" RX Invert: %s", rxInvert ? "yes" : "no"); LogInfo(" TX Invert: %s", txInvert ? "yes" : "no"); LogInfo(" PTT Invert: %s", pttInvert ? "yes" : "no"); @@ -1262,7 +1264,7 @@ bool CMMDVMHost::createModem() LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset); m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); - m_modem->setSerialParams(protocol,address); + m_modem->setSerialParams(protocol, address, speed); m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled); m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel); m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency); diff --git a/Modem.cpp b/Modem.cpp index 4d5aaab..f648d22 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -221,13 +221,13 @@ CModem::~CModem() delete[] m_buffer; } -void CModem::setSerialParams(const std::string& protocol, unsigned int address) +void CModem::setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) { // Create the serial controller instance according the protocol specified in conf. if (protocol == "i2c") - m_serial = new CI2CController(m_port, SERIAL_115200, address, true); + m_serial = new CI2CController(m_port, speed, address, true); else - m_serial = new CSerialController(m_port, SERIAL_115200, true); + m_serial = new CSerialController(m_port, speed, true); } void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) diff --git a/Modem.h b/Modem.h index c6bd0c6..48d59b4 100644 --- a/Modem.h +++ b/Modem.h @@ -37,7 +37,7 @@ public: CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); virtual ~CModem(); - virtual void setSerialParams(const std::string& protocol, unsigned int address); + virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed); virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled); virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel); diff --git a/SerialController.cpp b/SerialController.cpp index cfb448d..aacc6c6 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004,2007-2011,2013,2014-2017,2019 by Jonathan Naylor G4KLX + * Copyright (C) 2002-2004,2007-2011,2013,2014-2017,2019,2020 by Jonathan Naylor G4KLX * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX * * This program is free software; you can redistribute it and/or modify @@ -23,12 +23,11 @@ #include #include -#include - #if defined(_WIN32) || defined(_WIN64) #include #include #else +#include #include #include #include @@ -40,7 +39,7 @@ #if defined(_WIN32) || defined(_WIN64) -CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) : +CSerialController::CSerialController(const std::string& device, unsigned int speed, bool assertRTS) : m_device(device), m_speed(speed), m_assertRTS(assertRTS), @@ -221,7 +220,7 @@ void CSerialController::close() #else -CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) : +CSerialController::CSerialController(const std::string& device, unsigned int speed, bool assertRTS) : m_device(device), m_speed(speed), m_assertRTS(assertRTS), @@ -273,40 +272,40 @@ bool CSerialController::open() #endif switch (m_speed) { - case SERIAL_1200: + case 1200U: ::cfsetospeed(&termios, B1200); ::cfsetispeed(&termios, B1200); break; - case SERIAL_2400: + case 2400U: ::cfsetospeed(&termios, B2400); ::cfsetispeed(&termios, B2400); break; - case SERIAL_4800: + case 4800U: ::cfsetospeed(&termios, B4800); ::cfsetispeed(&termios, B4800); break; - case SERIAL_9600: + case 9600U: ::cfsetospeed(&termios, B9600); ::cfsetispeed(&termios, B9600); break; - case SERIAL_19200: + case 19200U: ::cfsetospeed(&termios, B19200); ::cfsetispeed(&termios, B19200); break; - case SERIAL_38400: + case 38400U: ::cfsetospeed(&termios, B38400); ::cfsetispeed(&termios, B38400); break; - case SERIAL_115200: + case 115200U: ::cfsetospeed(&termios, B115200); ::cfsetispeed(&termios, B115200); break; - case SERIAL_230400: + case 230400U: ::cfsetospeed(&termios, B230400); ::cfsetispeed(&termios, B230400); break; default: - LogError("Unsupported serial port speed - %d", int(m_speed)); + LogError("Unsupported serial port speed - %u", m_speed); ::close(m_fd); return false; } diff --git a/SerialController.h b/SerialController.h index 6dfc461..c7f97eb 100644 --- a/SerialController.h +++ b/SerialController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX * * This program is free software; you can redistribute it and/or modify @@ -28,21 +28,9 @@ #include #endif -enum SERIAL_SPEED { - SERIAL_1200 = 1200, - SERIAL_2400 = 2400, - SERIAL_4800 = 4800, - SERIAL_9600 = 9600, - SERIAL_19200 = 19200, - SERIAL_38400 = 38400, - SERIAL_76800 = 76800, - SERIAL_115200 = 115200, - SERIAL_230400 = 230400 -}; - class CSerialController : public ISerialPort { public: - CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS = false); + CSerialController(const std::string& device, unsigned int speed, bool assertRTS = false); virtual ~CSerialController(); virtual bool open(); @@ -59,7 +47,7 @@ public: protected: std::string m_device; - SERIAL_SPEED m_speed; + unsigned int m_speed; bool m_assertRTS; #if defined(_WIN32) || defined(_WIN64) HANDLE m_handle; diff --git a/UMP.cpp b/UMP.cpp index f843322..4aca606 100644 --- a/UMP.cpp +++ b/UMP.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2016,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 @@ -41,7 +41,7 @@ const unsigned char UMP_STATUS = 0x50U; const unsigned int BUFFER_LENGTH = 255U; CUMP::CUMP(const std::string& port) : -m_serial(port, SERIAL_115200), +m_serial(port, 115200U), m_open(false), m_buffer(NULL), m_length(0U), diff --git a/Version.h b/Version.h index c48a90e..46f5c4f 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200512"; +const char* VERSION = "20200523"; #endif From 0b185a0900e40b1ac8686551bb1667cc1c63815d Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 23 May 2020 16:49:21 +0100 Subject: [PATCH 031/115] Clean up the I2C controller code. --- I2CController.cpp | 63 ++++++++++----------------------------- I2CController.h | 14 +++++++-- MMDVMHost.cpp | 5 +++- MMDVMHost.vcxproj | 2 -- MMDVMHost.vcxproj.filters | 6 ---- Modem.cpp | 7 ++++- Modem.h | 4 +-- 7 files changed, 38 insertions(+), 63 deletions(-) diff --git a/I2CController.cpp b/I2CController.cpp index c6b7c77..9886443 100644 --- a/I2CController.cpp +++ b/I2CController.cpp @@ -17,6 +17,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#if defined(__linux__) + #include "I2CController.h" #include "Log.h" @@ -24,52 +26,18 @@ #include #include - -#if defined(_WIN32) || defined(_WIN64) - -#include -#include - -CI2CController::CI2CController(const std::string& device, unsigned int speed, unsigned int address, bool assertRTS) : -CSerialController(device, speed, assertRTS), -m_address(address) -{ -} - -CI2CController::~CI2CController() -{ -} - -bool CI2CController::open() -{ - return CSerialController::open(); -} - -int CI2CController::read(unsigned char* buffer, unsigned int length) -{ - return CSerialController::read(buffer, length); -} - -int CI2CController::write(const unsigned char* buffer, unsigned int length) -{ - return CSerialController::write(buffer, length); -} - -#else - #include #include #include #include #include #include -#if defined(__linux__) #include -#endif -CI2CController::CI2CController(const std::string& device, unsigned int speed, unsigned int address, bool assertRTS) : -CSerialController(device, speed, assertRTS), -m_address(address) +CI2CController::CI2CController(const std::string& device, unsigned int address) : +m_device(device), +m_address(address), +m_fd(-1) { } @@ -81,7 +49,6 @@ bool CI2CController::open() { assert(m_fd == -1); -#if defined(__linux__) m_fd = ::open(m_device.c_str(), O_RDWR); if (m_fd < 0) { LogError("Cannot open device - %s", m_device.c_str()); @@ -99,9 +66,6 @@ bool CI2CController::open() ::close(m_fd); return false; } -#else - #warning "I2C controller supports Linux only" -#endif return true; } @@ -117,7 +81,6 @@ int CI2CController::read(unsigned char* buffer, unsigned int length) unsigned int offset = 0U; while (offset < length) { -#if defined(__linux__) ssize_t n = ::read(m_fd, buffer + offset, 1U); if (n < 0) { if (errno != EAGAIN) { @@ -128,7 +91,6 @@ int CI2CController::read(unsigned char* buffer, unsigned int length) if (n > 0) offset += n; -#endif } return length; @@ -144,10 +106,7 @@ int CI2CController::write(const unsigned char* buffer, unsigned int length) unsigned int ptr = 0U; while (ptr < length) { - ssize_t n = 0U; -#if defined(__linux__) - n = ::write(m_fd, buffer + ptr, 1U); -#endif + ssize_t n = ::write(m_fd, buffer + ptr, 1U); if (n < 0) { if (errno != EAGAIN) { LogError("Error returned from write(), errno=%d", errno); @@ -162,4 +121,12 @@ int CI2CController::write(const unsigned char* buffer, unsigned int length) return length; } +void CI2CController::close() +{ + assert(m_fd != -1); + + ::close(m_fd); + m_fd = -1; +} + #endif diff --git a/I2CController.h b/I2CController.h index a67db85..14bc81e 100644 --- a/I2CController.h +++ b/I2CController.h @@ -20,11 +20,13 @@ #ifndef I2CController_H #define I2CController_H -#include "SerialController.h" +#if defined(__linux__) -class CI2CController : public CSerialController { +#include "SerialPort.h" + +class CI2CController : public ISerialPort { public: - CI2CController(const std::string& device, unsigned int speed, unsigned int address = 0x22U, bool assertRTS = false); + CI2CController(const std::string& device, unsigned int address = 0x22U); virtual ~CI2CController(); virtual bool open(); @@ -33,8 +35,14 @@ public: virtual int write(const unsigned char* buffer, unsigned int length); + virtual void close(); + private: + std::string m_device; unsigned int m_address; + int m_fd; }; #endif + +#endif diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 9d9a01e..c28f17e 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1238,10 +1238,13 @@ bool CMMDVMHost::createModem() LogInfo("Modem Parameters"); LogInfo(" Port: %s", port.c_str()); +#if defined(__linux__) LogInfo(" Protocol: %s", protocol.c_str()); if (protocol == "i2c") LogInfo(" I2C Address: %02X", address); - LogInfo(" Speed: %u", speed); + else +#endif + LogInfo(" Speed: %u", speed); LogInfo(" RX Invert: %s", rxInvert ? "yes" : "no"); LogInfo(" TX Invert: %s", txInvert ? "yes" : "no"); LogInfo(" PTT Invert: %s", pttInvert ? "yes" : "no"); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 63ba164..3ed61f9 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -187,7 +187,6 @@ - @@ -285,7 +284,6 @@ - diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 8dc6f12..704bf0b 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -275,9 +275,6 @@ Header Files - - Header Files - Header Files @@ -547,9 +544,6 @@ Source Files - - Source Files - Source Files diff --git a/Modem.cpp b/Modem.cpp index f648d22..cb2c18c 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -16,7 +16,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "SerialController.h" +#if defined(__linux__) #include "I2CController.h" +#endif #include "DStarDefines.h" #include "DMRDefines.h" #include "YSFDefines.h" @@ -224,9 +227,11 @@ CModem::~CModem() void CModem::setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) { // Create the serial controller instance according the protocol specified in conf. +#if defined(__linux__) if (protocol == "i2c") - m_serial = new CI2CController(m_port, speed, address, true); + m_serial = new CI2CController(m_port, address); else +#endif m_serial = new CSerialController(m_port, speed, true); } diff --git a/Modem.h b/Modem.h index 48d59b4..4c77d9f 100644 --- a/Modem.h +++ b/Modem.h @@ -19,7 +19,7 @@ #ifndef MODEM_H #define MODEM_H -#include "SerialController.h" +#include "SerialPort.h" #include "RingBuffer.h" #include "Defines.h" #include "Timer.h" @@ -156,7 +156,7 @@ private: bool m_fmEnabled; int m_rxDCOffset; int m_txDCOffset; - CSerialController* m_serial; + ISerialPort* m_serial; unsigned char* m_buffer; unsigned int m_length; unsigned int m_offset; From af34d9abc3de1cae6f19fe5934bbca12bb91d5cb Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 23 May 2020 16:54:11 +0100 Subject: [PATCH 032/115] Linux compile fix. --- I2CController.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/I2CController.h b/I2CController.h index 14bc81e..281c587 100644 --- a/I2CController.h +++ b/I2CController.h @@ -24,6 +24,8 @@ #include "SerialPort.h" +#include + class CI2CController : public ISerialPort { public: CI2CController(const std::string& device, unsigned int address = 0x22U); From ad843e72835e05f2a2b6b60ad42c7ec21770cd6b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 20 May 2020 18:07:57 +0200 Subject: [PATCH 033/115] do not write EOT when network is not set --- FMControl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 18d90c5..0867914 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -41,6 +41,9 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) assert(data != NULL); assert(length > 0U); + if (m_network == NULL) + return true; + if (data[0U] == TAG_HEADER) return true; @@ -50,8 +53,6 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (data[0U] != TAG_DATA) return false; - if (m_network == NULL) - return true; m_incomingRFAudio.addData(data + 1U, length - 1U); unsigned int bufferLength = m_incomingRFAudio.dataSize(); From ed3299a51376a46f5c9c8442c534ff19ea1437fc Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 07:43:22 +0200 Subject: [PATCH 034/115] Fix unpack, add audio dump --- FMControl.cpp | 37 ++++++++++++++++++++++++++++--------- FMControl.h | 5 +++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 0867914..5405a11 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -20,6 +20,11 @@ #include +#if defined(DUMP_RF_AUDIO) +#include +#include +#endif + const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis const unsigned int FM_MASK = 0x00000FFFU; @@ -38,6 +43,11 @@ CFMControl::~CFMControl() bool CFMControl::writeModem(const unsigned char* data, unsigned int length) { +#if defined(DUMP_RF_AUDIO) + std::ofstream audiofile; + audiofile.open("audiodump.bin", std::ios::out | std::ios::app | std::ios::binary); +#endif + assert(data != NULL); assert(length > 0U); @@ -69,28 +79,33 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) // Unpack the serial data into float values. for (unsigned int i = 0U; i < bufferLength; i += 3U) { - unsigned short sample1 = 0U; - unsigned short sample2 = 0U; + short sample1 = 0U; + short sample2 = 0U; unsigned int pack = 0U; unsigned char* packPointer = (unsigned char*)&pack; - packPointer[1U] = bufferData[i]; - packPointer[2U] = bufferData[i + 1U]; - packPointer[3U] = bufferData[i + 2U]; + packPointer[0U] = bufferData[i]; + packPointer[1U] = bufferData[i + 1U]; + packPointer[2U] = bufferData[i + 2U]; - sample2 = short(pack & FM_MASK); - sample1 = short(pack >> 12); + //extract unsigned 12 bit samples to 16 bit signed + sample2 = short(int(pack & FM_MASK) - 2048); + sample1 = short(int(pack >> 12) - 2048); // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) - samples[nSamples++] = (float(sample1) - 2048.0F) / 2048.0F; - samples[nSamples++] = (float(sample2) - 2048.0F) / 2048.0F; + samples[nSamples++] = float(sample1) / 2048.0F; + samples[nSamples++] = float(sample2) / 2048.0F; } //De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) for (unsigned int i = 0U; i < nSamples; i++) samples[i] = m_deemphasis.filter(samples[i]); +#if defined(DUMP_RF_AUDIO) + audiofile.write((char*)(void*)samples, nSamples * sizeof(float)); +#endif + unsigned short out[170U]; // 85 * 2 unsigned int nOut = 0U; @@ -104,6 +119,10 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) return m_network->writeData((unsigned char*)out, nOut); } +#if defined(DUMP_RF_AUDIO) + audiofile.close(); +#endif + return true; } diff --git a/FMControl.h b/FMControl.h index 5a4a8cd..9067d89 100644 --- a/FMControl.h +++ b/FMControl.h @@ -23,6 +23,11 @@ #include "Defines.h" #include "IIRDirectForm1Filter.h" +// Uncomment this to dump audio to a raw audio file +// The file will be written in same folder as executable +// Toplay the file : aplay -f FLOAT_LE -c1 -r8000 -t raw audiodump.bin +//#define DUMP_RF_AUDIO + class CFMControl { public: CFMControl(CFMNetwork* network); From c0a9bb81a30063c046ec80e5c76721094882785c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 08:00:27 +0200 Subject: [PATCH 035/115] Fix sample packing --- FMControl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 5405a11..79dbdcb 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -167,9 +167,9 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) pack = ((unsigned int)sample1) << 12; pack |= sample2; - data[j] = packPointer[1U]; - data[j + 1U] = packPointer[2U]; - data[j + 2U] = packPointer[3U]; + data[j] = packPointer[0U]; + data[j + 1U] = packPointer[1U]; + data[j + 2U] = packPointer[2U]; } return j;//return the number of bytes written From 8b31cb34fff4134f919919165e7b2c8bb7be58b8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 10:47:11 +0200 Subject: [PATCH 036/115] Use stdio instead of iostream, fix file not properly closed --- FMControl.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 79dbdcb..baa429c 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -21,8 +21,7 @@ #include #if defined(DUMP_RF_AUDIO) -#include -#include +#include #endif const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis @@ -43,11 +42,6 @@ CFMControl::~CFMControl() bool CFMControl::writeModem(const unsigned char* data, unsigned int length) { -#if defined(DUMP_RF_AUDIO) - std::ofstream audiofile; - audiofile.open("audiodump.bin", std::ios::out | std::ios::app | std::ios::binary); -#endif - assert(data != NULL); assert(length > 0U); @@ -70,6 +64,10 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) bufferLength = 255U; if (bufferLength >= 3U) { +#if defined(DUMP_RF_AUDIO) + FILE * audiofile = fopen("./audiodump.bin", "ab"); +#endif + bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 unsigned char bufferData[255U]; m_incomingRFAudio.getData(bufferData, bufferLength); @@ -103,7 +101,8 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) samples[i] = m_deemphasis.filter(samples[i]); #if defined(DUMP_RF_AUDIO) - audiofile.write((char*)(void*)samples, nSamples * sizeof(float)); + if(audiofile != NULL) + fwrite(samples, sizeof(float), nSamples, audiofile); #endif unsigned short out[170U]; // 85 * 2 @@ -116,13 +115,14 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) out[nOut++] = (sample >> 0) & 0xFFU; } +#if defined(DUMP_RF_AUDIO) + if(audiofile != NULL) + fclose(audiofile); +#endif + return m_network->writeData((unsigned char*)out, nOut); } -#if defined(DUMP_RF_AUDIO) - audiofile.close(); -#endif - return true; } From 1caffc1dad5702a5d1ecdbc418349383fe4a718c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 24 May 2020 14:26:24 +0100 Subject: [PATCH 037/115] Small cleanups. --- FMControl.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index baa429c..55477cd 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -21,7 +21,7 @@ #include #if defined(DUMP_RF_AUDIO) -#include +#include #endif const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis @@ -47,7 +47,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (m_network == NULL) return true; - + if (data[0U] == TAG_HEADER) return true; @@ -57,7 +57,6 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (data[0U] != TAG_DATA) return false; - m_incomingRFAudio.addData(data + 1U, length - 1U); unsigned int bufferLength = m_incomingRFAudio.dataSize(); if (bufferLength > 255U) @@ -65,9 +64,8 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (bufferLength >= 3U) { #if defined(DUMP_RF_AUDIO) - FILE * audiofile = fopen("./audiodump.bin", "ab"); + FILE* audiofile = ::fopen("./audiodump.bin", "ab"); #endif - bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 unsigned char bufferData[255U]; m_incomingRFAudio.getData(bufferData, bufferLength); @@ -101,10 +99,9 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) samples[i] = m_deemphasis.filter(samples[i]); #if defined(DUMP_RF_AUDIO) - if(audiofile != NULL) - fwrite(samples, sizeof(float), nSamples, audiofile); + if (audiofile != NULL) + ::fwrite(samples, sizeof(float), nSamples, audiofile); #endif - unsigned short out[170U]; // 85 * 2 unsigned int nOut = 0U; @@ -116,10 +113,11 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) } #if defined(DUMP_RF_AUDIO) - if(audiofile != NULL) - fclose(audiofile); + if (audiofile != NULL) { + ::fclose(audiofile); + audiofile = NULL; + } #endif - return m_network->writeData((unsigned char*)out, nOut); } @@ -134,7 +132,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) if (m_network == NULL) return 0U; - if(space > 252U) + if (space > 252U) space = 252U; unsigned char netData[168U];//84 * 2 modem can handle up to 84 samples (252 bytes) at a time @@ -150,7 +148,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) samples[nSamples++] = (float(sample) / 32767.0F) - 1.0F; } - //Pre-emphasise the data and other stuff. + // Pre-emphasise the data and other stuff. for (unsigned int i = 0U; i < nSamples; i++) samples[i] = m_preemphasis.filter(samples[i]); From 02d1e2f0ef89f7c9031a93c274ed599b6b3158f7 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 19:07:59 +0200 Subject: [PATCH 038/115] Add CTCSS removal --- FMControl.cpp | 33 +++++++++++++++++++++++++-------- FMControl.h | 9 ++++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index baa429c..72188dd 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -24,20 +24,36 @@ #include #endif -const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis -const unsigned int FM_MASK = 0x00000FFFU; +const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis +const float FILTER_GAIN_DB = 0.0F; +const unsigned int FM_MASK = 0x00000FFFU; CFMControl::CFMControl(CFMNetwork* network) : m_network(network), m_enabled(false), m_incomingRFAudio(1600U, "Incoming RF FM Audio"), -m_preemphasis(0.3889703155F, -0.32900055326F, 0.0F, 1.0F, 0.2820291817F, 0.0F, EMPHASIS_GAIN_DB), -m_deemphasis(1.0F, 0.2820291817F, 0.0F, 0.3889703155F, -0.32900055326F, 0.0F, EMPHASIS_GAIN_DB) +m_preemphasis (NULL), +m_deemphasis (NULL), +m_filterStage1(NULL), +m_filterStage2(NULL), +m_filterStage3(NULL) { + m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, EMPHASIS_GAIN_DB); + m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, EMPHASIS_GAIN_DB); + + 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); } CFMControl::~CFMControl() { + delete m_preemphasis ; + delete m_deemphasis ; + + delete m_filterStage1; + delete m_filterStage2; + delete m_filterStage3; } bool CFMControl::writeModem(const unsigned char* data, unsigned int length) @@ -57,7 +73,6 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (data[0U] != TAG_DATA) return false; - m_incomingRFAudio.addData(data + 1U, length - 1U); unsigned int bufferLength = m_incomingRFAudio.dataSize(); if (bufferLength > 255U) @@ -97,8 +112,10 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) } //De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) - for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_deemphasis.filter(samples[i]); + for (unsigned int i = 0U; i < nSamples; i++) { + samples[i] = m_deemphasis->filter(samples[i]); + samples[i] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(samples[i]))); + } #if defined(DUMP_RF_AUDIO) if(audiofile != NULL) @@ -152,7 +169,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) //Pre-emphasise the data and other stuff. for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_preemphasis.filter(samples[i]); + samples[i] = m_preemphasis->filter(samples[i]); // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; diff --git a/FMControl.h b/FMControl.h index 9067d89..c7af709 100644 --- a/FMControl.h +++ b/FMControl.h @@ -26,7 +26,7 @@ // Uncomment this to dump audio to a raw audio file // The file will be written in same folder as executable // Toplay the file : aplay -f FLOAT_LE -c1 -r8000 -t raw audiodump.bin -//#define DUMP_RF_AUDIO +// #define DUMP_RF_AUDIO class CFMControl { public: @@ -45,8 +45,11 @@ private: CFMNetwork* m_network; 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; }; #endif From a28aa7792749ecf49550e8f4ad5f0ed7514e25ae Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 07:31:48 +0200 Subject: [PATCH 039/115] Add deemphasis and remove CTCSS, emphasis temp deactivated --- FMControl.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 72188dd..fadf005 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -41,6 +41,7 @@ m_filterStage3(NULL) m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, EMPHASIS_GAIN_DB); m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, EMPHASIS_GAIN_DB); + //cheby 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); @@ -111,7 +112,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) samples[nSamples++] = float(sample2) / 2048.0F; } - //De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) + //De-emphasise the data and remove CTCSS for (unsigned int i = 0U; i < nSamples; i++) { samples[i] = m_deemphasis->filter(samples[i]); samples[i] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(samples[i]))); @@ -164,12 +165,12 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) for (unsigned int i = 0U; i < length; i += 2U) { unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; - samples[nSamples++] = (float(sample) / 32767.0F) - 1.0F; + samples[nSamples++] = (float(sample) / 32768.0F) - 1.0F; } //Pre-emphasise the data and other stuff. - for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_preemphasis->filter(samples[i]); + //for (unsigned int i = 0U; i < nSamples; i++) + // samples[i] = m_preemphasis->filter(samples[i]); // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; @@ -180,7 +181,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); - pack = 0; + pack = 0U; pack = ((unsigned int)sample1) << 12; pack |= sample2; From 0b8a9a1a4cef43202c42eb1f88c31f51d96f7569 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 07:32:09 +0200 Subject: [PATCH 040/115] Increase FM TX Buffer size --- Modem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modem.cpp b/Modem.cpp index cb2c18c..3a6974d 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -160,7 +160,7 @@ m_rxNXDNData(1000U, "Modem RX NXDN"), m_txNXDNData(1000U, "Modem TX NXDN"), m_txPOCSAGData(1000U, "Modem TX POCSAG"), m_rxFMData(1000U, "Modem RX FM"), -m_txFMData(1000U, "Modem TX FM"), +m_txFMData(5000U, "Modem TX FM"), m_rxTransparentData(1000U, "Modem RX Transparent"), m_txTransparentData(1000U, "Modem TX Transparent"), m_sendTransparentDataFrameType(0U), @@ -232,7 +232,7 @@ void CModem::setSerialParams(const std::string& protocol, unsigned int address, m_serial = new CI2CController(m_port, address); else #endif - m_serial = new CSerialController(m_port, speed, true); + m_serial = new CSerialController(m_port, speed, false); } void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) From 75d5083f8e20ad32a7e52c720a6c0fa86e0f3ef3 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 19:59:15 +0200 Subject: [PATCH 041/115] fixe network byte ordering, change audio dump to dumep 16 bit samples --- FMControl.cpp | 13 ++++++------- FMControl.h | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index fadf005..1e460b7 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -118,21 +118,20 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) samples[i] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(samples[i]))); } -#if defined(DUMP_RF_AUDIO) - if(audiofile != NULL) - fwrite(samples, sizeof(float), nSamples, audiofile); -#endif - unsigned short out[170U]; // 85 * 2 unsigned int nOut = 0U; // Repack the data (8-bit unsigned values containing unsigned 16-bit data) for (unsigned int i = 0U; i < nSamples; i++) { unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); - out[nOut++] = (sample >> 8) & 0xFFU; - out[nOut++] = (sample >> 0) & 0xFFU; + out[nOut++] = ((sample >> 8) & 0x00FFU) | ((sample << 8) & 0xFF00U);//change endianess to network order, transmit MSB first } +#if defined(DUMP_RF_AUDIO) + if(audiofile != NULL) + fwrite(out, sizeof(unsigned short), nOut, audiofile); +#endif + #if defined(DUMP_RF_AUDIO) if(audiofile != NULL) fclose(audiofile); diff --git a/FMControl.h b/FMControl.h index c7af709..1647010 100644 --- a/FMControl.h +++ b/FMControl.h @@ -25,7 +25,7 @@ // Uncomment this to dump audio to a raw audio file // The file will be written in same folder as executable -// Toplay the file : aplay -f FLOAT_LE -c1 -r8000 -t raw audiodump.bin +// Toplay the file : ffplay -autoexit -f u16be -ar 8000 audiodump.bin // #define DUMP_RF_AUDIO class CFMControl { From c2187fd6243683110f96161a993ac2fb6bbc2935 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 20:19:46 +0200 Subject: [PATCH 042/115] Add 460800 serial speed --- SerialController.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SerialController.cpp b/SerialController.cpp index aacc6c6..970501a 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -304,6 +304,10 @@ bool CSerialController::open() ::cfsetospeed(&termios, B230400); ::cfsetispeed(&termios, B230400); break; + case 460800U: + ::cfsetospeed(&termios, B460800); + ::cfsetispeed(&termios, B460800); + break; default: LogError("Unsupported serial port speed - %u", m_speed); ::close(m_fd); From 409e0de721c1ba615019aa3058cb1fde8c1b421e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 07:03:01 +0200 Subject: [PATCH 043/115] Send correct number of bytes --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index 1e460b7..b07206a 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -137,7 +137,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) fclose(audiofile); #endif - return m_network->writeData((unsigned char*)out, nOut); + return m_network->writeData((unsigned char*)out, nOut * sizeof(unsigned short)); } return true; From 8d4241d154e5e4d308d2f5087c04e7753c7ec437 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 08:20:39 +0200 Subject: [PATCH 044/115] Reenable RTS --- Modem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modem.cpp b/Modem.cpp index 3a6974d..e4dcb79 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -232,7 +232,7 @@ void CModem::setSerialParams(const std::string& protocol, unsigned int address, m_serial = new CI2CController(m_port, address); else #endif - m_serial = new CSerialController(m_port, speed, false); + m_serial = new CSerialController(m_port, speed, true); } void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) From eef364b1a97aec7749a9fcb32f35d66349cf092d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 08:38:17 +0200 Subject: [PATCH 045/115] Enable Pre emphasis --- FMControl.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index b07206a..f1dc045 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -24,9 +24,10 @@ #include #endif -const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis -const float FILTER_GAIN_DB = 0.0F; -const unsigned int FM_MASK = 0x00000FFFU; +const float DEEMPHASIS_GAIN_DB = 0.0F; +const float PREEMPHASIS_GAIN_DB = 30.0F; +const float FILTER_GAIN_DB = 0.0F; +const unsigned int FM_MASK = 0x00000FFFU; CFMControl::CFMControl(CFMNetwork* network) : m_network(network), @@ -38,8 +39,8 @@ m_filterStage1(NULL), m_filterStage2(NULL), m_filterStage3(NULL) { - m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, EMPHASIS_GAIN_DB); - m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, EMPHASIS_GAIN_DB); + m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, PREEMPHASIS_GAIN_DB); + m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, DEEMPHASIS_GAIN_DB); //cheby 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); @@ -168,8 +169,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) } //Pre-emphasise the data and other stuff. - //for (unsigned int i = 0U; i < nSamples; i++) - // samples[i] = m_preemphasis->filter(samples[i]); + for (unsigned int i = 0U; i < nSamples; i++) + samples[i] = m_preemphasis->filter(samples[i]); // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; From 98cd2404f56575c74975d9e7d770fe68671f3b04 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 09:17:45 +0200 Subject: [PATCH 046/115] Use GNU Radio emphasis filters, add filters generation scripts --- FMControl.cpp | 6 +++--- Tools/DeEmphasis.py | 43 +++++++++++++++++++++++++++++++++++++ Tools/PreEmphasis.py | 51 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 Tools/DeEmphasis.py create mode 100644 Tools/PreEmphasis.py diff --git a/FMControl.cpp b/FMControl.cpp index f1dc045..d558ac7 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -25,7 +25,7 @@ #endif const float DEEMPHASIS_GAIN_DB = 0.0F; -const float PREEMPHASIS_GAIN_DB = 30.0F; +const float PREEMPHASIS_GAIN_DB = 0.0F; const float FILTER_GAIN_DB = 0.0F; const unsigned int FM_MASK = 0x00000FFFU; @@ -39,8 +39,8 @@ m_filterStage1(NULL), m_filterStage2(NULL), m_filterStage3(NULL) { - m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, PREEMPHASIS_GAIN_DB); - m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, DEEMPHASIS_GAIN_DB); + 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); //cheby 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); diff --git a/Tools/DeEmphasis.py b/Tools/DeEmphasis.py new file mode 100644 index 0000000..44320c9 --- /dev/null +++ b/Tools/DeEmphasis.py @@ -0,0 +1,43 @@ +#based on https://github.com/gnuradio/gnuradio/blob/master/gr-analog/python/analog/fm_emph.py + +import math +import cmath +import numpy as np +import scipy.signal as signal +import pylab as pl + +tau = 750e-6 +fs = 8000 +fh = 2700 + +# Digital corner frequency +w_c = 1.0 / tau + +# Prewarped analog corner frequency +w_ca = 2.0 * fs * math.tan(w_c / (2.0 * fs)) + +# Resulting digital pole, zero, and gain term from the bilinear +# transformation of H(s) = w_ca / (s + w_ca) to +# H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1) +k = -w_ca / (2.0 * fs) +z1 = -1.0 +p1 = (1.0 + k) / (1.0 - k) +b0 = -k / (1.0 - k) + +btaps = [ b0 * 1.0, b0 * -z1, 0 ] +ataps = [ 1.0, -p1, 0 ] + +# Since H(s = 0) = 1.0, then H(z = 1) = 1.0 and has 0 dB gain at DC + + +taps = np.concatenate((btaps, ataps), axis=0) +print("Taps") +print(*taps, "", sep=",", end="\n") + +f,h = signal.freqz(btaps,ataps, fs=fs) +pl.plot(f, 20*np.log10(np.abs(h))) +pl.xlabel('frequency/Hz') +pl.ylabel('gain/dB') +pl.ylim(top=0,bottom=-30) +pl.xlim(left=0, right=fh*2.5) +pl.show() \ No newline at end of file diff --git a/Tools/PreEmphasis.py b/Tools/PreEmphasis.py new file mode 100644 index 0000000..22c81f6 --- /dev/null +++ b/Tools/PreEmphasis.py @@ -0,0 +1,51 @@ +#based on https://github.com/gnuradio/gnuradio/blob/master/gr-analog/python/analog/fm_emph.py + +import math +import cmath +import numpy as np +import scipy.signal as signal +import pylab as pl + +tau = 750e-6 +fs = 8000 +fh = 2700 + +# Digital corner frequencies +w_cl = 1.0 / tau +w_ch = 2.0 * math.pi * fh + +# Prewarped analog corner frequencies +w_cla = 2.0 * fs * math.tan(w_cl / (2.0 * fs)) +w_cha = 2.0 * fs * math.tan(w_ch / (2.0 * fs)) + +# Resulting digital pole, zero, and gain term from the bilinear +# transformation of H(s) = (s + w_cla) / (s + w_cha) to +# H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1) +kl = -w_cla / (2.0 * fs) +kh = -w_cha / (2.0 * fs) +z1 = (1.0 + kl) / (1.0 - kl) +p1 = (1.0 + kh) / (1.0 - kh) +b0 = (1.0 - kl) / (1.0 - kh) + +# Since H(s = infinity) = 1.0, then H(z = -1) = 1.0 and +# this filter has 0 dB gain at fs/2.0. +# That isn't what users are going to expect, so adjust with a +# gain, g, so that H(z = 1) = 1.0 for 0 dB gain at DC. +w_0dB = 2.0 * math.pi * 0.0 +g = abs(1.0 - p1 * cmath.rect(1.0, -w_0dB)) \ +/ (b0 * abs(1.0 - z1 * cmath.rect(1.0, -w_0dB))) + +btaps = [ g * b0 * 1.0, g * b0 * -z1, 0] +ataps = [ 1.0, -p1, 0] + +taps = np.concatenate((btaps, ataps), axis=0) +print("Taps") +print(*taps, "", sep=",", end="\n") + +f,h = signal.freqz(btaps,ataps, fs=fs) +pl.plot(f, 20*np.log10(np.abs(h))) +pl.xlabel('frequency/Hz') +pl.ylabel('gain/dB') +pl.ylim(top=30,bottom=0) +pl.xlim(left=0, right=fh*2.5) +pl.show() \ No newline at end of file From 015edf9b81c196ebbf7784db2ee2782932aafca7 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 11:01:53 +0200 Subject: [PATCH 047/115] Simplify readmodem, only one loop --- FMControl.cpp | 90 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index d558ac7..74b3537 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -24,6 +24,8 @@ #include #endif +#define SWAP_BYTES_16(a) (((a >> 8) & 0x00FFU) | ((a << 8) & 0xFF00U)) + const float DEEMPHASIS_GAIN_DB = 0.0F; const float PREEMPHASIS_GAIN_DB = 0.0F; const float FILTER_GAIN_DB = 0.0F; @@ -125,7 +127,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) // Repack the data (8-bit unsigned values containing unsigned 16-bit data) for (unsigned int i = 0U; i < nSamples; i++) { unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); - out[nOut++] = ((sample >> 8) & 0x00FFU) | ((sample << 8) & 0xFF00U);//change endianess to network order, transmit MSB first + out[nOut++] = SWAP_BYTES_16(sample);//change endianess to network order, transmit MSB first } #if defined(DUMP_RF_AUDIO) @@ -155,42 +157,74 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) if(space > 252U) space = 252U; - unsigned char netData[168U];//84 * 2 modem can handle up to 84 samples (252 bytes) at a time - unsigned int length = m_network->read(netData, 168U); + unsigned short netData[84U];//modem can handle up to 84 samples (252 bytes) at a time + unsigned int length = m_network->read((unsigned char*)netData, 84U * sizeof(unsigned short)); + length /= sizeof(unsigned short); if (length == 0U) return 0U; - float samples[84U]; - unsigned int nSamples = 0U; - // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) - for (unsigned int i = 0U; i < length; i += 2U) { - unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; - samples[nSamples++] = (float(sample) / 32768.0F) - 1.0F; - } - - //Pre-emphasise the data and other stuff. - for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_preemphasis->filter(samples[i]); - - // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; unsigned char* packPointer = (unsigned char*)&pack; - unsigned int j = 0U; - unsigned int i = 0U; - for (; i < nSamples && j < space; i += 2U, j += 3U) { - unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); - unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); + unsigned int nData = 0U; - pack = 0U; - pack = ((unsigned int)sample1) << 12; - pack |= sample2; + for(unsigned int i = 0; i < length; i++) { + unsigned short netSample = SWAP_BYTES_16(netData[i]);//((netData[i] << 8) & 0xFF00U)| ((netData[i] >> 8) & 0x00FFU); + // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) + float sampleFloat = (float(netSample) / 32768.0F) - 1.0F; - data[j] = packPointer[0U]; - data[j + 1U] = packPointer[1U]; - data[j + 2U] = packPointer[2U]; + //preemphasis + 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 = 0U; + pack = sample12bit << 12; + } else { + pack |= sample12bit; + + data[nData++] = packPointer[0U]; + data[nData++] = packPointer[1U]; + data[nData++] = packPointer[2U]; + } } - return j;//return the number of bytes written + return nData; + + + // float samples[84U]; + // unsigned int nSamples = 0U; + // // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) + // for (unsigned int i = 0U; i < length; i += 2U) { + // unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; + // samples[nSamples++] = (float(sample) / 32768.0F) - 1.0F; + // } + + // //Pre-emphasise the data and other stuff. + // for (unsigned int i = 0U; i < nSamples; i++) + // samples[i] = m_preemphasis->filter(samples[i]); + + // // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) + // unsigned int pack = 0U; + // unsigned char* packPointer = (unsigned char*)&pack; + // unsigned int j = 0U; + // unsigned int i = 0U; + // for (; i < nSamples && j < space; i += 2U, j += 3U) { + // unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); + // unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); + + // pack = 0U; + // pack = ((unsigned int)sample1) << 12; + // pack |= sample2; + + // data[j] = packPointer[0U]; + // data[j + 1U] = packPointer[1U]; + // data[j + 2U] = packPointer[2U]; + // } + + // return j;//return the number of bytes written } void CFMControl::clock(unsigned int ms) From bd1aa20803daebfbcfae32b45d3140ec2fe7cca8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 11:37:18 +0200 Subject: [PATCH 048/115] Simplify writeModem, only 2 loops --- FMControl.cpp | 69 +++++++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 74b3537..72e79a1 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -83,63 +83,46 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) bufferLength = 255U; if (bufferLength >= 3U) { -#if defined(DUMP_RF_AUDIO) - FILE * audiofile = fopen("./audiodump.bin", "ab"); -#endif - bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 unsigned char bufferData[255U]; m_incomingRFAudio.getData(bufferData, bufferLength); - - unsigned int nSamples = 0; - float samples[85U]; // 255 / 3; - // Unpack the serial data into float values. + unsigned int pack = 0U; + unsigned char* packPointer = (unsigned char*)&pack; + unsigned short out[168U]; // 84 * 2 + unsigned int nOut = 0U; + short unpackedSamples[2U]; + for (unsigned int i = 0U; i < bufferLength; i += 3U) { - short sample1 = 0U; - short sample2 = 0U; - - unsigned int pack = 0U; - unsigned char* packPointer = (unsigned char*)&pack; - + //extract unsigned 12 bit unsigned sample pairs pack into 3 bytes to 16 bit signed packPointer[0U] = bufferData[i]; packPointer[1U] = bufferData[i + 1U]; packPointer[2U] = bufferData[i + 2U]; + unpackedSamples[1U] = short(int(pack & FM_MASK) - 2048); + unpackedSamples[0U] = short(int(pack >> 12) - 2048); - //extract unsigned 12 bit samples to 16 bit signed - sample2 = short(int(pack & FM_MASK) - 2048); - sample1 = short(int(pack >> 12) - 2048); + //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; - // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) - samples[nSamples++] = float(sample1) / 2048.0F; - samples[nSamples++] = float(sample2) / 2048.0F; + //De-emphasise and remove CTCSS + sampleFloat = m_deemphasis->filter(sampleFloat); + sampleFloat = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(sampleFloat))); + + // Repack the float data to 16 bit unsigned + unsigned short sampleUShort = (unsigned short)((sampleFloat + 1.0F) * 32767.0F + 0.5F); + out[nOut++] = SWAP_BYTES_16(sampleUShort); + } } - //De-emphasise the data and remove CTCSS - for (unsigned int i = 0U; i < nSamples; i++) { - samples[i] = m_deemphasis->filter(samples[i]); - samples[i] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(samples[i]))); - } - - unsigned short out[170U]; // 85 * 2 - unsigned int nOut = 0U; - - // Repack the data (8-bit unsigned values containing unsigned 16-bit data) - for (unsigned int i = 0U; i < nSamples; i++) { - unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); - out[nOut++] = SWAP_BYTES_16(sample);//change endianess to network order, transmit MSB first - } - -#if defined(DUMP_RF_AUDIO) - if(audiofile != NULL) - fwrite(out, sizeof(unsigned short), nOut, audiofile); -#endif - #if defined(DUMP_RF_AUDIO) - if(audiofile != NULL) - fclose(audiofile); + FILE * audiofile = fopen("./audiodump.bin", "ab"); + if(audiofile != NULL) { + fwrite(out, sizeof(unsigned short), nOut, audiofile); + fclose(audiofile); + } #endif - return m_network->writeData((unsigned char*)out, nOut * sizeof(unsigned short)); } From af6b7d79da18f8c7f4f71f32f1fbc11e86ba70d8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 11:43:35 +0200 Subject: [PATCH 049/115] Adjust emphasis gains --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index 72e79a1..3f58cb4 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -27,7 +27,7 @@ #define SWAP_BYTES_16(a) (((a >> 8) & 0x00FFU) | ((a << 8) & 0xFF00U)) const float DEEMPHASIS_GAIN_DB = 0.0F; -const float PREEMPHASIS_GAIN_DB = 0.0F; +const float PREEMPHASIS_GAIN_DB = 13.0F; const float FILTER_GAIN_DB = 0.0F; const unsigned int FM_MASK = 0x00000FFFU; From 97a35e69a4215ee2ebefe39f1428f40a7136c4e8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 12:14:16 +0200 Subject: [PATCH 050/115] clean up --- FMControl.cpp | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 3f58cb4..8adc9c4 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -175,39 +175,6 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) } return nData; - - - // float samples[84U]; - // unsigned int nSamples = 0U; - // // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) - // for (unsigned int i = 0U; i < length; i += 2U) { - // unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; - // samples[nSamples++] = (float(sample) / 32768.0F) - 1.0F; - // } - - // //Pre-emphasise the data and other stuff. - // for (unsigned int i = 0U; i < nSamples; i++) - // samples[i] = m_preemphasis->filter(samples[i]); - - // // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) - // unsigned int pack = 0U; - // unsigned char* packPointer = (unsigned char*)&pack; - // unsigned int j = 0U; - // unsigned int i = 0U; - // for (; i < nSamples && j < space; i += 2U, j += 3U) { - // unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); - // unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); - - // pack = 0U; - // pack = ((unsigned int)sample1) << 12; - // pack |= sample2; - - // data[j] = packPointer[0U]; - // data[j + 1U] = packPointer[1U]; - // data[j + 2U] = packPointer[2U]; - // } - - // return j;//return the number of bytes written } void CFMControl::clock(unsigned int ms) From 17b49fde883ed2ac79a5720c4e8f9f20396b8e31 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 12:19:20 +0200 Subject: [PATCH 051/115] Typo --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index e8b4230..13c4132 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -94,7 +94,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) short unpackedSamples[2U]; for (unsigned int i = 0U; i < bufferLength; i += 3U) { - //extract unsigned 12 bit unsigned sample pairs pack into 3 bytes to 16 bit signed + //extract unsigned 12 bit unsigned sample pairs packed into 3 bytes to 16 bit signed packPointer[0U] = bufferData[i]; packPointer[1U] = bufferData[i + 1U]; packPointer[2U] = bufferData[i + 2U]; From 82c6f717cf706194a87bd77a2f6aad6ad83d7293 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 20:35:04 +0200 Subject: [PATCH 052/115] Remove 250 length check --- Modem.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Modem.cpp b/Modem.cpp index e4dcb79..3350a5c 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -1853,12 +1853,6 @@ RESP_TYPE_MMDVM CModem::getResponse() if (ret == 0) return RTM_TIMEOUT; - if (m_buffer[1U] >= 250U) { - LogError("Invalid length received from the modem - %u", m_buffer[1U]); - m_offset = 0U; - return RTM_ERROR; - } - m_length = m_buffer[1U]; m_offset = 2U; } From f01fc3e9fcc5fb2f0588c26eb04a272b3a02b7d1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 21:42:35 +0200 Subject: [PATCH 053/115] Ensure Modem FM frames are always 168 samples --- FMControl.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 13c4132..8a8f133 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -79,17 +79,17 @@ 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 > 255U) - bufferLength = 255U; + if (bufferLength > 252U)//168 samples 12-bit + bufferLength = 252U; if (bufferLength >= 3U) { bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 - unsigned char bufferData[255U]; + unsigned char bufferData[252U]; m_incomingRFAudio.getData(bufferData, bufferLength); unsigned int pack = 0U; unsigned char* packPointer = (unsigned char*)&pack; - unsigned short out[168U]; // 84 * 2 + unsigned short out[168U]; unsigned int nOut = 0U; short unpackedSamples[2U]; @@ -140,8 +140,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) if (space > 252U) space = 252U; - unsigned short netData[84U];//modem can handle up to 84 samples (252 bytes) at a time - unsigned int length = m_network->read((unsigned char*)netData, 84U * sizeof(unsigned short)); + unsigned short netData[168U];//modem can handle up to 168 samples at a time + unsigned int length = m_network->read((unsigned char*)netData, 168U * sizeof(unsigned short)); length /= sizeof(unsigned short); if (length == 0U) return 0U; @@ -151,7 +151,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) unsigned int nData = 0U; for(unsigned int i = 0; i < length; i++) { - unsigned short netSample = SWAP_BYTES_16(netData[i]);//((netData[i] << 8) & 0xFF00U)| ((netData[i] >> 8) & 0x00FFU); + unsigned short netSample = SWAP_BYTES_16(netData[i]); + // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) float sampleFloat = (float(netSample) / 32768.0F) - 1.0F; From dbe04c3c2f48ae5933014afb713c7b349af52696 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 8 Jun 2020 16:33:20 +0100 Subject: [PATCH 054/115] Initial code for AX.25 support. --- AX25Control.cpp | 97 +++++++++++++++++++++++++++++++++ AX25Control.h | 45 ++++++++++++++++ AX25Network.cpp | 111 ++++++++++++++++++++++++++++++++++++++ AX25Network.h | 51 ++++++++++++++++++ Conf.cpp | 67 ++++++++++++++++++++++- Conf.h | 20 +++++++ MMDVM.ini | 11 ++++ MMDVMHost.cpp | 76 ++++++++++++++++++++++++-- MMDVMHost.h | 6 +++ MMDVMHost.vcxproj | 4 ++ MMDVMHost.vcxproj.filters | 12 +++++ Makefile | 2 +- Makefile.Pi | 2 +- Makefile.Pi.Adafruit | 2 +- Makefile.Pi.HD44780 | 2 +- Makefile.Pi.OLED | 2 +- Makefile.Pi.PCF8574 | 2 +- Makefile.Solaris | 2 +- Modem.cpp | 37 ++++++++++++- Modem.h | 5 +- RemoteControl.cpp | 6 ++- RemoteControl.h | 4 +- 22 files changed, 549 insertions(+), 17 deletions(-) create mode 100644 AX25Control.cpp create mode 100644 AX25Control.h create mode 100644 AX25Network.cpp create mode 100644 AX25Network.h diff --git a/AX25Control.cpp b/AX25Control.cpp new file mode 100644 index 0000000..1f1b590 --- /dev/null +++ b/AX25Control.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 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; version 2 of the License. + * + * 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. + */ + +#include "AX25Control.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include +#include + +// #define DUMP_AX25 + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT1(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_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +CAX25Control::CAX25Control(CAX25Network* network) : +m_network(network), +m_enabled(true), +m_fp(NULL) +{ +} + +CAX25Control::~CAX25Control() +{ +} + +bool CAX25Control::writeModem(unsigned char *data, unsigned int len) +{ + assert(data != NULL); + + if (!m_enabled) + return false; + + unsigned char type = data[0U]; + + return true; +} + +bool CAX25Control::openFile() +{ + if (m_fp != NULL) + return true; + + time_t t; + ::time(&t); + + struct tm* tm = ::localtime(&t); + + char name[100U]; + ::sprintf(name, "AX25_%04d%02d%02d_%02d%02d%02d.ambe", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + + m_fp = ::fopen(name, "wb"); + if (m_fp == NULL) + return false; + + ::fwrite("AX25", 1U, 4U, m_fp); + + return true; +} + +bool CAX25Control::writeFile(const unsigned char* data, unsigned int length) +{ + if (m_fp == NULL) + return false; + + ::fwrite(&length, 1U, sizeof(unsigned int), m_fp); + ::fwrite(data, 1U, length, m_fp); + + return true; +} + +void CAX25Control::closeFile() +{ + if (m_fp != NULL) { + ::fclose(m_fp); + m_fp = NULL; + } +} + +void CAX25Control::enable(bool enabled) +{ + m_enabled = enabled; +} diff --git a/AX25Control.h b/AX25Control.h new file mode 100644 index 0000000..2f73874 --- /dev/null +++ b/AX25Control.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#if !defined(AX25Control_H) +#define AX25Control_H + +#include "AX25Network.h" + +#include + +class CAX25Control { +public: + CAX25Control(CAX25Network* network); + ~CAX25Control(); + + bool writeModem(unsigned char* data, unsigned int len); + + void enable(bool enabled); + +private: + CAX25Network* m_network; + bool m_enabled; + FILE* m_fp; + + bool openFile(); + bool writeFile(const unsigned char* data, unsigned int length); + void closeFile(); +}; + +#endif diff --git a/AX25Network.cpp b/AX25Network.cpp new file mode 100644 index 0000000..8123c51 --- /dev/null +++ b/AX25Network.cpp @@ -0,0 +1,111 @@ +/* + * 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 "AX25Network.h" +#include "Defines.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +const unsigned int BUFFER_LENGTH = 200U; + +CAX25Network::CAX25Network(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : +m_socket(localAddress, localPort), +m_address(), +m_port(gatewayPort), +m_debug(debug), +m_enabled(false) +{ + assert(gatewayPort > 0U); + assert(!gatewayAddress.empty()); + + m_address = CUDPSocket::lookup(gatewayAddress); +} + +CAX25Network::~CAX25Network() +{ +} + +bool CAX25Network::open() +{ + LogMessage("Opening AX25 network connection"); + + if (m_address.s_addr == INADDR_NONE) + return false; + + return m_socket.open(); +} + +bool CAX25Network::writeAX25(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + + unsigned char buffer[110U]; + ::memset(buffer, 0x00U, 110U); + + buffer[0U] = 'A'; + buffer[1U] = 'X'; + buffer[2U] = '2'; + buffer[3U] = '5'; + + ::memcpy(buffer + 4U, data, length); + + if (m_debug) + CUtils::dump(1U, "AX25 Network Data Sent", buffer, length + 4U); + + return m_socket.write(buffer, length + 4U, m_address, m_port); +} + +bool CAX25Network::writeMICE(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + + unsigned char buffer[110U]; + ::memset(buffer, 0x00U, 110U); + + buffer[0U] = 'M'; + buffer[1U] = 'I'; + buffer[2U] = 'C'; + buffer[3U] = 'E'; + + ::memcpy(buffer + 4U, data, length); + + if (m_debug) + CUtils::dump(1U, "AX25 Network Data Sent", buffer, length + 4U); + + return m_socket.write(buffer, length + 4U, m_address, m_port); +} + +void CAX25Network::reset() +{ +} + +void CAX25Network::close() +{ + m_socket.close(); + + LogMessage("Closing AX25 network connection"); +} + +void CAX25Network::enable(bool enabled) +{ + m_enabled = enabled; +} diff --git a/AX25Network.h b/AX25Network.h new file mode 100644 index 0000000..b171e6a --- /dev/null +++ b/AX25Network.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef AX25Network_H +#define AX25Network_H + +#include "UDPSocket.h" + +#include +#include + +class CAX25Network { +public: + CAX25Network(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug); + ~CAX25Network(); + + bool open(); + + void enable(bool enabled); + + bool writeAX25(const unsigned char* data, unsigned int length); + bool writeMICE(const unsigned char* data, unsigned int length); + + void reset(); + + void close(); + +private: + CUDPSocket m_socket; + in_addr m_address; + unsigned int m_port; + bool m_debug; + bool m_enabled; +}; + +#endif diff --git a/Conf.cpp b/Conf.cpp index ee4034b..47fe532 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -45,12 +45,14 @@ enum SECTION { SECTION_NXDN, SECTION_POCSAG, SECTION_FM, + SECTION_AX25, SECTION_DSTAR_NETWORK, SECTION_DMR_NETWORK, SECTION_FUSION_NETWORK, SECTION_P25_NETWORK, SECTION_NXDN_NETWORK, SECTION_POCSAG_NETWORK, + SECTION_AX25_NETWORK, SECTION_TFTSERIAL, SECTION_HD44780, SECTION_NEXTION, @@ -205,6 +207,7 @@ m_fmCOSInvert(false), m_fmRFAudioBoost(1U), m_fmMaxDevLevel(90.0F), m_fmExtAudioBoost(1U), +m_ax25Enabled(false), m_dstarNetworkEnabled(false), m_dstarGatewayAddress(), m_dstarGatewayPort(0U), @@ -249,6 +252,12 @@ m_pocsagLocalAddress(), m_pocsagLocalPort(0U), m_pocsagNetworkModeHang(3U), m_pocsagNetworkDebug(false), +m_ax25NetworkEnabled(false), +m_ax25GatewayAddress(), +m_ax25GatewayPort(0U), +m_ax25LocalAddress(), +m_ax25LocalPort(0U), +m_ax25NetworkDebug(false), m_tftSerialPort("/dev/ttyAMA0"), m_tftSerialBrightness(50U), m_hd44780Rows(2U), @@ -342,6 +351,8 @@ bool CConf::read() section = SECTION_POCSAG; else if (::strncmp(buffer, "[FM]", 4U) == 0) section = SECTION_FM; + else if (::strncmp(buffer, "[AX.25]", 7U) == 0) + section = SECTION_AX25; else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0) section = SECTION_DSTAR_NETWORK; else if (::strncmp(buffer, "[DMR Network]", 13U) == 0) @@ -354,6 +365,8 @@ bool CConf::read() section = SECTION_NXDN_NETWORK; else if (::strncmp(buffer, "[POCSAG Network]", 16U) == 0) section = SECTION_POCSAG_NETWORK; + else if (::strncmp(buffer, "[AX.25 Network]", 15U) == 0) + section = SECTION_AX25_NETWORK; else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0) section = SECTION_TFTSERIAL; else if (::strncmp(buffer, "[HD44780]", 9U) == 0) @@ -700,8 +713,7 @@ bool CConf::read() m_pocsagEnabled = ::atoi(value) == 1; else if (::strcmp(key, "Frequency") == 0) m_pocsagFrequency = (unsigned int)::atoi(value); - } - else if (section == SECTION_FM) { + } else if (section == SECTION_FM) { if (::strcmp(key, "Enable") == 0) m_fmEnabled = ::atoi(value) == 1; else if (::strcmp(key, "Callsign") == 0) { @@ -775,6 +787,9 @@ bool CConf::read() m_fmMaxDevLevel = float(::atof(value)); else if (::strcmp(key, "ExtAudioBoost") == 0) m_fmExtAudioBoost = (unsigned int)::atoi(value); + } else if (section == SECTION_AX25) { + if (::strcmp(key, "Enable") == 0) + m_ax25Enabled = ::atoi(value) == 1; } else if (section == SECTION_DSTAR_NETWORK) { if (::strcmp(key, "Enable") == 0) m_dstarNetworkEnabled = ::atoi(value) == 1; @@ -869,6 +884,19 @@ bool CConf::read() m_pocsagNetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) m_pocsagNetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_AX25_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_ax25NetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "LocalAddress") == 0) + m_ax25LocalAddress = value; + else if (::strcmp(key, "LocalPort") == 0) + m_ax25LocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "GatewayAddress") == 0) + m_ax25GatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_ax25GatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_ax25NetworkDebug = ::atoi(value) == 1; } else if (section == SECTION_TFTSERIAL) { if (::strcmp(key, "Port") == 0) m_tftSerialPort = value; @@ -1677,6 +1705,11 @@ unsigned int CConf::getFMExtAudioBoost() const return m_fmExtAudioBoost; } +bool CConf::getAX25Enabled() const +{ + return m_ax25Enabled; +} + bool CConf::getDStarNetworkEnabled() const { return m_dstarNetworkEnabled; @@ -1897,6 +1930,36 @@ bool CConf::getPOCSAGNetworkDebug() const return m_pocsagNetworkDebug; } +bool CConf::getAX25NetworkEnabled() const +{ + return m_ax25NetworkEnabled; +} + +std::string CConf::getAX25GatewayAddress() const +{ + return m_ax25GatewayAddress; +} + +unsigned int CConf::getAX25GatewayPort() const +{ + return m_ax25GatewayPort; +} + +std::string CConf::getAX25LocalAddress() const +{ + return m_ax25LocalAddress; +} + +unsigned int CConf::getAX25LocalPort() const +{ + return m_ax25LocalPort; +} + +bool CConf::getAX25NetworkDebug() const +{ + return m_ax25NetworkDebug; +} + std::string CConf::getTFTSerialPort() const { return m_tftSerialPort; diff --git a/Conf.h b/Conf.h index 40e81a0..91d7118 100644 --- a/Conf.h +++ b/Conf.h @@ -171,6 +171,9 @@ public: bool getPOCSAGEnabled() const; unsigned int getPOCSAGFrequency() const; + // The AX.25 section + bool getAX25Enabled() const; + // The FM Section bool getFMEnabled() const; std::string getFMCallsign() const; @@ -260,6 +263,14 @@ public: unsigned int getPOCSAGNetworkModeHang() const; bool getPOCSAGNetworkDebug() const; + // The AX.25 Network section + bool getAX25NetworkEnabled() const; + std::string getAX25GatewayAddress() const; + unsigned int getAX25GatewayPort() const; + std::string getAX25LocalAddress() const; + unsigned int getAX25LocalPort() const; + bool getAX25NetworkDebug() const; + // The TFTSERIAL section std::string getTFTSerialPort() const; unsigned int getTFTSerialBrightness() const; @@ -442,6 +453,8 @@ private: bool m_pocsagEnabled; unsigned int m_pocsagFrequency; + bool m_ax25Enabled; + bool m_fmEnabled; std::string m_fmCallsign; unsigned int m_fmCallsignSpeed; @@ -524,6 +537,13 @@ private: unsigned int m_pocsagNetworkModeHang; bool m_pocsagNetworkDebug; + bool m_ax25NetworkEnabled; + std::string m_ax25GatewayAddress; + unsigned int m_ax25GatewayPort; + std::string m_ax25LocalAddress; + unsigned int m_ax25LocalPort; + bool m_ax25NetworkDebug; + std::string m_tftSerialPort; unsigned int m_tftSerialBrightness; diff --git a/MMDVM.ini b/MMDVM.ini index 12f2b73..6f2b910 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -175,6 +175,9 @@ RFAudioBoost=1 MaxDevLevel=90 ExtAudioBoost=1 +[AX.25] +Enable=1 + [D-Star Network] Enable=1 GatewayAddress=127.0.0.1 @@ -231,6 +234,14 @@ GatewayPort=4800 # ModeHang=3 Debug=0 +[AX.25 Network] +Enable=1 +LocalAddress=127.0.0.1 +LocalPort=47325 +GatewayAddress=127.0.0.1 +GatewayPort=47326 +Debug=0 + [TFT Serial] # Port=modem Port=/dev/ttyAMA0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 924d4a9..b1f8353 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -119,12 +119,14 @@ m_ysf(NULL), m_p25(NULL), m_nxdn(NULL), m_pocsag(NULL), +m_ax25(NULL), m_dstarNetwork(NULL), m_dmrNetwork(NULL), m_ysfNetwork(NULL), m_p25Network(NULL), m_nxdnNetwork(NULL), m_pocsagNetwork(NULL), +m_ax25Network(NULL), m_display(NULL), m_ump(NULL), m_mode(MODE_IDLE), @@ -151,6 +153,7 @@ m_p25Enabled(false), m_nxdnEnabled(false), m_pocsagEnabled(false), m_fmEnabled(false), +m_ax25Enabled(false), m_cwIdTime(0U), m_dmrLookup(NULL), m_nxdnLookup(NULL), @@ -320,6 +323,12 @@ int CMMDVMHost::run() return 1; } + if (m_ax25Enabled && m_conf.getAX25NetworkEnabled()) { + ret = createAX25Network(); + if (!ret) + return 1; + } + in_addr transparentAddress; unsigned int transparentPort = 0U; CUDPSocket* transparentSocket = NULL; @@ -614,6 +623,9 @@ int CMMDVMHost::run() pocsagTimer.start(); } + if (m_ax25Enabled) + m_ax25 = new CAX25Control(m_ax25Network); + bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); if (remoteControlEnabled) { unsigned int port = m_conf.getRemoteControlPort(); @@ -806,6 +818,15 @@ int CMMDVMHost::run() } } + len = m_modem->readAX25Data(data); + if (m_ax25 != NULL && len > 0U) { + if (m_mode == MODE_IDLE || m_mode == MODE_FM) { + m_ax25->writeModem(data, len); + } else if (m_mode != MODE_LOCKOUT) { + LogWarning("NXDN modem data received when in mode %u", m_mode); + } + } + len = m_modem->readTransparentData(data); if (transparentSocket != NULL && len > 0U) transparentSocket->write(data, len, transparentAddress, transparentPort); @@ -1126,6 +1147,11 @@ int CMMDVMHost::run() delete m_pocsagNetwork; } + if (m_ax25Network != NULL) { + m_ax25Network->close(); + delete m_ax25Network; + } + if (transparentSocket != NULL) { transparentSocket->close(); delete transparentSocket; @@ -1142,6 +1168,7 @@ int CMMDVMHost::run() delete m_p25; delete m_nxdn; delete m_pocsag; + delete m_ax25; return 0; } @@ -1209,7 +1236,7 @@ bool CMMDVMHost::createModem() m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); m_modem->setSerialParams(protocol,address); - m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled); + m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled, m_ax25Enabled); m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel); m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency); m_modem->setDMRParams(colorCode); @@ -1531,6 +1558,34 @@ bool CMMDVMHost::createPOCSAGNetwork() return true; } +bool CMMDVMHost::createAX25Network() +{ + std::string gatewayAddress = m_conf.getAX25GatewayAddress(); + unsigned int gatewayPort = m_conf.getAX25GatewayPort(); + std::string localAddress = m_conf.getAX25LocalAddress(); + unsigned int localPort = m_conf.getAX25LocalPort(); + bool debug = m_conf.getAX25NetworkDebug(); + + LogInfo("AX.25 Network Parameters"); + LogInfo(" Gateway Address: %s", gatewayAddress.c_str()); + LogInfo(" Gateway Port: %u", gatewayPort); + LogInfo(" Local Address: %s", localAddress.c_str()); + LogInfo(" Local Port: %u", localPort); + + m_ax25Network = new CAX25Network(localAddress, localPort, gatewayAddress, gatewayPort, debug); + + bool ret = m_ax25Network->open(); + if (!ret) { + delete m_ax25Network; + m_ax25Network = NULL; + return false; + } + + m_ax25Network->enable(true); + + return true; +} + void CMMDVMHost::readParams() { m_dstarEnabled = m_conf.getDStarEnabled(); @@ -1540,6 +1595,7 @@ void CMMDVMHost::readParams() m_nxdnEnabled = m_conf.getNXDNEnabled(); m_pocsagEnabled = m_conf.getPOCSAGEnabled(); m_fmEnabled = m_conf.getFMEnabled(); + m_ax25Enabled = m_conf.getAX25Enabled(); m_duplex = m_conf.getDuplex(); m_callsign = m_conf.getCallsign(); m_id = m_conf.getId(); @@ -1557,8 +1613,10 @@ void CMMDVMHost::readParams() LogInfo(" NXDN: %s", m_nxdnEnabled ? "enabled" : "disabled"); LogInfo(" POCSAG: %s", m_pocsagEnabled ? "enabled" : "disabled"); LogInfo(" FM: %s", m_fmEnabled ? "enabled" : "disabled"); + LogInfo(" AX.25: %s", m_ax25Enabled ? "enabled" : "disabled"); } +// XXX AX.25 enabled/disabled void CMMDVMHost::setMode(unsigned char mode) { assert(m_modem != NULL); @@ -2016,9 +2074,13 @@ void CMMDVMHost::remoteControl() processEnableCommand(m_nxdnEnabled, true); break; case RCD_ENABLE_FM: - if (m_fmEnabled==false) + if (!m_fmEnabled) processEnableCommand(m_fmEnabled, true); break; + case RCD_ENABLE_AX25: + if (!m_ax25Enabled) + processEnableCommand(m_ax25Enabled, true); + break; case RCD_DISABLE_DSTAR: if (m_dstar != NULL && m_dstarEnabled==true) processEnableCommand(m_dstarEnabled, false); @@ -2043,6 +2105,10 @@ void CMMDVMHost::remoteControl() if (m_fmEnabled == true) processEnableCommand(m_fmEnabled, false); break; + case RCD_DISABLE_AX25: + if (m_ax25Enabled == true) + processEnableCommand(m_ax25Enabled, false); + break; case RCD_PAGE: if (m_pocsag != NULL) { unsigned int ric = m_remoteControl->getArgUInt(0U); @@ -2092,8 +2158,10 @@ void CMMDVMHost::processModeCommand(unsigned char mode, unsigned int timeout) void CMMDVMHost::processEnableCommand(bool& mode, bool enabled) { LogDebug("Setting mode current=%s new=%s",mode ? "true" : "false",enabled ? "true" : "false"); - mode=enabled; - m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled); + + mode = enabled; + + m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled, m_ax25Enabled); if (!m_modem->writeConfig()) LogError("Cannot write Config to MMDVM"); } diff --git a/MMDVMHost.h b/MMDVMHost.h index 17d6786..1a3f791 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -23,8 +23,10 @@ #include "POCSAGNetwork.h" #include "POCSAGControl.h" #include "DStarNetwork.h" +#include "AX25Network.h" #include "NXDNNetwork.h" #include "DStarControl.h" +#include "AX25Control.h" #include "DMRControl.h" #include "YSFControl.h" #include "P25Control.h" @@ -62,12 +64,14 @@ private: CP25Control* m_p25; CNXDNControl* m_nxdn; CPOCSAGControl* m_pocsag; + CAX25Control* m_ax25; CDStarNetwork* m_dstarNetwork; CDMRNetwork* m_dmrNetwork; CYSFNetwork* m_ysfNetwork; CP25Network* m_p25Network; CNXDNNetwork* m_nxdnNetwork; CPOCSAGNetwork* m_pocsagNetwork; + CAX25Network* m_ax25Network; CDisplay* m_display; CUMP* m_ump; unsigned char m_mode; @@ -94,6 +98,7 @@ private: bool m_nxdnEnabled; bool m_pocsagEnabled; bool m_fmEnabled; + bool m_ax25Enabled; unsigned int m_cwIdTime; CDMRLookup* m_dmrLookup; CNXDNLookup* m_nxdnLookup; @@ -114,6 +119,7 @@ private: bool createP25Network(); bool createNXDNNetwork(); bool createPOCSAGNetwork(); + bool createAX25Network(); void remoteControl(); void processModeCommand(unsigned char mode, unsigned int timeout); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 812c7a4..63b8aa6 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -153,6 +153,8 @@ + + @@ -251,6 +253,8 @@ + + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index fb8a362..b333302 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -299,6 +299,12 @@ Header Files + + Header Files + + + Header Files + @@ -562,5 +568,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index efdaba6..2ac2552 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lpthread LDFLAGS = -g -OBJECTS = \ +OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ diff --git a/Makefile.Pi b/Makefile.Pi index 640c07f..3a4c2c1 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -6,7 +6,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DRASPBERRY_PI -I/usr/local/include LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib -OBJECTS = \ +OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 24c2907..16775bb 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -7,7 +7,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/l LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib -OBJECTS = \ +OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index c2faad2..3d02d71 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -6,7 +6,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -I/usr/local/include LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib -OBJECTS = \ +OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index d2db40c..f4f2024 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -6,7 +6,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DOLED -I/usr/local/include LIBS = -lArduiPi_OLED -lwiringPi -lpthread LDFLAGS = -g -L/usr/local/lib -OBJECTS = \ +OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 4c5d3a3..3a70077 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -7,7 +7,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DPCF8574_DISPLAY -I/usr/lo LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib -OBJECTS = \ +OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ diff --git a/Makefile.Solaris b/Makefile.Solaris index c50d41e..d469fad 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -6,7 +6,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lpthread -lsocket LDFLAGS = -g -OBJECTS = \ +OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ diff --git a/Modem.cpp b/Modem.cpp index 93319be..0f0b0c1 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -76,6 +76,8 @@ const unsigned char MMDVM_NXDN_LOST = 0x41U; const unsigned char MMDVM_POCSAG_DATA = 0x50U; +const unsigned char MMDVM_AX25_DATA = 0x55U; + const unsigned char MMDVM_FM_PARAMS1 = 0x60U; const unsigned char MMDVM_FM_PARAMS2 = 0x61U; const unsigned char MMDVM_FM_PARAMS3 = 0x62U; @@ -133,6 +135,7 @@ m_p25Enabled(false), m_nxdnEnabled(false), m_pocsagEnabled(false), m_fmEnabled(false), +m_ax25Enabled(false), m_rxDCOffset(0), m_txDCOffset(0), m_serial(NULL), @@ -152,6 +155,7 @@ m_txP25Data(1000U, "Modem TX P25"), m_rxNXDNData(1000U, "Modem RX NXDN"), m_txNXDNData(1000U, "Modem TX NXDN"), m_txPOCSAGData(1000U, "Modem TX POCSAG"), +m_rxAX25Data(1000U, "Modem RX AX.25"), m_rxTransparentData(1000U, "Modem RX Transparent"), m_txTransparentData(1000U, "Modem TX Transparent"), m_sendTransparentDataFrameType(0U), @@ -230,7 +234,7 @@ void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int tx m_pocsagFrequency = pocsagFrequency + txOffset; } -void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled) +void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) { m_dstarEnabled = dstarEnabled; m_dmrEnabled = dmrEnabled; @@ -239,6 +243,7 @@ void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, m_nxdnEnabled = nxdnEnabled; m_pocsagEnabled = pocsagEnabled; m_fmEnabled = fmEnabled; + m_ax25Enabled = ax25Enabled; } void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel) @@ -585,6 +590,20 @@ void CModem::clock(unsigned int ms) } break; + case MMDVM_AX25_DATA: { + if (m_trace) + CUtils::dump(1U, "RX AX.25 Data", m_buffer, m_length); + + unsigned char data = m_length - 2U; + m_rxAX25Data.addData(&data, 1U); + + data = TAG_DATA; + m_rxAX25Data.addData(&data, 1U); + + m_rxAX25Data.addData(m_buffer + 3U, m_length - 3U); + } + break; + case MMDVM_GET_STATUS: { // if (m_trace) // CUtils::dump(1U, "GET_STATUS", m_buffer, m_length); @@ -941,6 +960,20 @@ unsigned int CModem::readNXDNData(unsigned char* data) return len; } +unsigned int CModem::readAX25Data(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxAX25Data.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxAX25Data.getData(&len, 1U); + m_rxAX25Data.getData(data, len); + + return len; +} + unsigned int CModem::readTransparentData(unsigned char* data) { assert(data != NULL); @@ -1552,6 +1585,8 @@ bool CModem::setConfig() buffer[4U] |= 0x20U; if (m_fmEnabled && m_duplex) buffer[4U] |= 0x40U; + if (m_ax25Enabled) + buffer[4U] |= 0x80U; buffer[5U] = m_txDelay / 10U; // In 10ms units diff --git a/Modem.h b/Modem.h index 069fe46..69228bb 100644 --- a/Modem.h +++ b/Modem.h @@ -39,7 +39,7 @@ public: virtual void setSerialParams(const std::string& protocol, unsigned int address); virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); - virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled); + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled); virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel); virtual void setDMRParams(unsigned int colorCode); virtual void setYSFParams(bool loDev, unsigned int txHang); @@ -59,6 +59,7 @@ public: virtual unsigned int readYSFData(unsigned char* data); virtual unsigned int readP25Data(unsigned char* data); virtual unsigned int readNXDNData(unsigned char* data); + virtual unsigned int readAX25Data(unsigned char* data); virtual unsigned int readTransparentData(unsigned char* data); virtual unsigned int readSerial(unsigned char* data, unsigned int length); @@ -150,6 +151,7 @@ private: bool m_nxdnEnabled; bool m_pocsagEnabled; bool m_fmEnabled; + bool m_ax25Enabled; int m_rxDCOffset; int m_txDCOffset; CSerialController* m_serial; @@ -169,6 +171,7 @@ private: CRingBuffer m_rxNXDNData; CRingBuffer m_txNXDNData; CRingBuffer m_txPOCSAGData; + CRingBuffer m_rxAX25Data; CRingBuffer m_rxTransparentData; CRingBuffer m_txTransparentData; unsigned int m_sendTransparentDataFrameType; diff --git a/RemoteControl.cpp b/RemoteControl.cpp index 15ac46c..bf400ad 100644 --- a/RemoteControl.cpp +++ b/RemoteControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Jonathan Naylor G4KLX + * Copyright (C) 2019,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 @@ -102,6 +102,8 @@ REMOTE_COMMAND CRemoteControl::getCommand() m_command = RCD_ENABLE_NXDN; else if (m_args.at(1U) == "fm") m_command = RCD_ENABLE_FM; + else if (m_args.at(1U) == "ax25") + m_command = RCD_ENABLE_AX25; } 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 +117,8 @@ REMOTE_COMMAND CRemoteControl::getCommand() m_command = RCD_DISABLE_NXDN; else if (m_args.at(1U) == "fm") m_command = RCD_DISABLE_FM; + else if (m_args.at(1U) == "ax25") + m_command = RCD_DISABLE_AX25; } else if (m_args.at(0U) == "page" && m_args.size() >= PAGE_ARGS) { // Page command is in the form of "page " m_command = RCD_PAGE; diff --git a/RemoteControl.h b/RemoteControl.h index 53b9820..3825dee 100644 --- a/RemoteControl.h +++ b/RemoteControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Jonathan Naylor G4KLX + * Copyright (C) 2019,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 @@ -40,12 +40,14 @@ enum REMOTE_COMMAND { RCD_ENABLE_P25, RCD_ENABLE_NXDN, RCD_ENABLE_FM, + RCD_ENABLE_AX25, RCD_DISABLE_DSTAR, RCD_DISABLE_DMR, RCD_DISABLE_YSF, RCD_DISABLE_P25, RCD_DISABLE_NXDN, RCD_DISABLE_FM, + RCD_DISABLE_AX25, RCD_PAGE, RCD_CW }; From d409700a313bcddafed901bf6522d351c573f1e3 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 9 Jun 2020 14:32:05 +0100 Subject: [PATCH 055/115] X25 cleanups. --- AX25Control.cpp | 2 +- MMDVMHost.cpp | 69 ++++++++++++++++++++++++++++++++++++++++--------- Modem.cpp | 5 +--- Version.h | 2 +- 4 files changed, 60 insertions(+), 18 deletions(-) diff --git a/AX25Control.cpp b/AX25Control.cpp index 1f1b590..d9f9a2f 100644 --- a/AX25Control.cpp +++ b/AX25Control.cpp @@ -45,7 +45,7 @@ bool CAX25Control::writeModem(unsigned char *data, unsigned int len) if (!m_enabled) return false; - unsigned char type = data[0U]; + CUtils::dump(1U, "AX.25 raw packet", data, len); return true; } diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index b1f8353..3cf60cb 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -623,8 +623,12 @@ int CMMDVMHost::run() pocsagTimer.start(); } - if (m_ax25Enabled) + if (m_ax25Enabled) { + LogInfo("AX.25 RF Parameters"); + LogInfo(" RXOnly: yes"); + m_ax25 = new CAX25Control(m_ax25Network); + } bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); if (remoteControlEnabled) { @@ -1616,7 +1620,6 @@ void CMMDVMHost::readParams() LogInfo(" AX.25: %s", m_ax25Enabled ? "enabled" : "disabled"); } -// XXX AX.25 enabled/disabled void CMMDVMHost::setMode(unsigned char mode) { assert(m_modem != NULL); @@ -1636,6 +1639,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_ax25Network != NULL) + m_ax25Network->enable(false); if (m_dstar != NULL) m_dstar->enable(true); if (m_dmr != NULL) @@ -1648,6 +1653,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_ax25 != NULL) + m_ax25->enable(false); m_modem->setMode(MODE_DSTAR); if (m_ump != NULL) m_ump->setMode(MODE_DSTAR); @@ -1670,6 +1677,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_ax25Network != NULL) + m_ax25Network->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1682,6 +1691,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_ax25 != NULL) + m_ax25->enable(false); m_modem->setMode(MODE_DMR); if (m_ump != NULL) m_ump->setMode(MODE_DMR); @@ -1708,6 +1719,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_ax25Network != NULL) + m_ax25Network->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1720,6 +1733,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_ax25 != NULL) + m_ax25->enable(false); m_modem->setMode(MODE_YSF); if (m_ump != NULL) m_ump->setMode(MODE_YSF); @@ -1742,6 +1757,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_ax25Network != NULL) + m_ax25Network->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1754,6 +1771,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_ax25 != NULL) + m_ax25->enable(false); m_modem->setMode(MODE_P25); if (m_ump != NULL) m_ump->setMode(MODE_P25); @@ -1776,6 +1795,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(true); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_ax25Network != NULL) + m_ax25Network->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1788,6 +1809,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(true); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_ax25 != NULL) + m_ax25->enable(false); m_modem->setMode(MODE_NXDN); if (m_ump != NULL) m_ump->setMode(MODE_NXDN); @@ -1810,6 +1833,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(true); + if (m_ax25Network != NULL) + m_ax25Network->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1822,6 +1847,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(true); + if (m_ax25 != NULL) + m_ax25->enable(false); m_modem->setMode(MODE_POCSAG); if (m_ump != NULL) m_ump->setMode(MODE_POCSAG); @@ -1844,6 +1871,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_ax25Network != NULL) + m_ax25Network->enable(true); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1856,6 +1885,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_ax25 != NULL) + m_ax25->enable(true); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -1882,6 +1913,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_ax25Network != NULL) + m_ax25Network->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1894,6 +1927,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_ax25 != NULL) + m_ax25->enable(false); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -1922,6 +1957,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(false); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(false); + if (m_ax25Network != NULL) + m_ax25Network->enable(false); if (m_dstar != NULL) m_dstar->enable(false); if (m_dmr != NULL) @@ -1934,6 +1971,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(false); if (m_pocsag != NULL) m_pocsag->enable(false); + if (m_ax25 != NULL) + m_ax25->enable(false); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -1960,6 +1999,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdnNetwork->enable(true); if (m_pocsagNetwork != NULL) m_pocsagNetwork->enable(true); + if (m_ax25Network != NULL) + m_ax25Network->enable(true); if (m_dstar != NULL) m_dstar->enable(true); if (m_dmr != NULL) @@ -1972,6 +2013,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_nxdn->enable(true); if (m_pocsag != NULL) m_pocsag->enable(true); + if (m_ax25 != NULL) + m_ax25->enable(true); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -2120,18 +2163,20 @@ void CMMDVMHost::remoteControl() } m_pocsag->sendPage(ric, text); } + break; case RCD_CW: setMode(MODE_IDLE); // Force the modem to go idle so that we can send the CW text. - if (!m_modem->hasTX()){ - std::string cwtext; - for (unsigned int i = 0U; i < m_remoteControl->getArgCount(); i++) { - if (i > 0U) - cwtext += " "; - cwtext += m_remoteControl->getArgString(i); - } - m_display->writeCW(); - m_modem->sendCWId(cwtext); - } + if (!m_modem->hasTX()) { + std::string cwtext; + for (unsigned int i = 0U; i < m_remoteControl->getArgCount(); i++) { + if (i > 0U) + cwtext += " "; + cwtext += m_remoteControl->getArgString(i); + } + m_display->writeCW(); + m_modem->sendCWId(cwtext); + } + break; default: break; } diff --git a/Modem.cpp b/Modem.cpp index 0f0b0c1..3a59fca 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -594,10 +594,7 @@ void CModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX AX.25 Data", m_buffer, m_length); - unsigned char data = m_length - 2U; - m_rxAX25Data.addData(&data, 1U); - - data = TAG_DATA; + unsigned char data = m_length - 3U; m_rxAX25Data.addData(&data, 1U); m_rxAX25Data.addData(m_buffer + 3U, m_length - 3U); diff --git a/Version.h b/Version.h index 101ca94..6b25bcc 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200608"; +const char* VERSION = "20200609"; #endif From d9e2940f08550cc8ed8000dfa27ff031f3cf5e69 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 18 Jun 2020 12:51:13 +0100 Subject: [PATCH 056/115] Add AX.25 packet tracking. --- AX25Control.cpp | 154 +++++++++++++++++++++++++++++++++++++++++++++++- AX25Control.h | 6 +- AX25Network.cpp | 20 ------- AX25Network.h | 1 - Conf.cpp | 12 +++- Conf.h | 2 + MMDVM.ini | 1 + MMDVMHost.cpp | 5 +- Version.h | 2 +- 9 files changed, 175 insertions(+), 28 deletions(-) diff --git a/AX25Control.cpp b/AX25Control.cpp index d9f9a2f..a6b89ea 100644 --- a/AX25Control.cpp +++ b/AX25Control.cpp @@ -27,8 +27,9 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04 #define WRITE_BIT1(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_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) -CAX25Control::CAX25Control(CAX25Network* network) : +CAX25Control::CAX25Control(CAX25Network* network, bool trace) : m_network(network), +m_trace(trace), m_enabled(true), m_fp(NULL) { @@ -45,7 +46,15 @@ bool CAX25Control::writeModem(unsigned char *data, unsigned int len) if (!m_enabled) return false; - CUtils::dump(1U, "AX.25 raw packet", data, len); + if (m_trace) + decode(data, len); + + CUtils::dump(1U, "AX.25 raw packet", data, len); + + if (m_network != NULL) { + if (isUI(data, len)) + m_network->writeAX25(data, len); + } return true; } @@ -95,3 +104,144 @@ void CAX25Control::enable(bool enabled) { m_enabled = enabled; } + +void CAX25Control::decode(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length >= 15U); + + std::string text; + + bool more = decodeAddress(data + 7U, text); + + text += '>'; + + decodeAddress(data + 0U, text); + + unsigned int n = 14U; + while (more && n < length) { + text += ','; + more = decodeAddress(data + n, text, true); + n += 7U; + } + + text += ' '; + + if ((data[n] & 0x01U) == 0x00U) { + // I frame + char t[20U]; + ::sprintf(t, "", (data[n] >> 1) & 0x07U, (data[n] >> 5) & 0x07U); + text += t; + } else { + if ((data[n] & 0x02U) == 0x00U) { + // S frame + char t[20U]; + switch (data[n] & 0x0FU) { + case 0x01U: + sprintf(t, "", (data[n] >> 5) & 0x07U); + break; + case 0x05U: + sprintf(t, "", (data[n] >> 5) & 0x07U); + break; + case 0x09U: + sprintf(t, "", (data[n] >> 5) & 0x07U); + break; + case 0x0DU: + sprintf(t, "", (data[n] >> 5) & 0x07U); + break; + default: + sprintf(t, "", (data[n] >> 5) & 0x07U); + break; + } + + text += t; + LogMessage("AX.25, %s", text.c_str()); + return; + } else { + // U frame + switch (data[n] & 0xEFU) { + case 0x6FU: + text += ""; + break; + case 0x2FU: + text += ""; + break; + case 0x43U: + text += ""; + break; + case 0x0FU: + text += ""; + break; + case 0x63U: + text += ""; + break; + case 0x87U: + text += ""; + break; + case 0x03U: + text += ""; + break; + case 0xAFU: + text += ""; + break; + case 0xE3U: + text += ""; + break; + default: + text += ""; + break; + } + + if ((data[n] & 0xEFU) != 0x03U) { + LogMessage("AX.25, %s", text.c_str()); + return; + } + } + } + + n += 2U; + + LogMessage("AX.25, %s %.*s", text.c_str(), length - n, data + n); +} + +bool CAX25Control::decodeAddress(const unsigned char* data, std::string& text, bool isDigi) const +{ + assert(data != NULL); + + for (unsigned int i = 0U; i < 6U; i++) { + char c = data[i] >> 1; + if (c != ' ') + text += c; + } + + unsigned char ssid = (data[6U] >> 1) & 0x0FU; + if (ssid > 0U) { + text += '-'; + if (ssid >= 10U) { + text += '1'; + text += '0' + ssid - 10U; + } + else { + text += '0' + ssid; + } + } + + if (isDigi) { + if ((data[6U] & 0x80U) == 0x80U) + text += '*'; + } + + return (data[6U] & 0x01U) == 0x00U; +} + +bool CAX25Control::isUI(const unsigned char* data, unsigned int length) const +{ + assert(data != NULL); + assert(length >= 15U); + + unsigned int n = 13U; + while ((data[n] & 0x01U) == 0x00U && n < length) + n += 7U; + + return (data[n + 1U] & 0xEFU) == 0x03U; +} diff --git a/AX25Control.h b/AX25Control.h index 2f73874..59b5688 100644 --- a/AX25Control.h +++ b/AX25Control.h @@ -25,7 +25,7 @@ class CAX25Control { public: - CAX25Control(CAX25Network* network); + CAX25Control(CAX25Network* network, bool trace); ~CAX25Control(); bool writeModem(unsigned char* data, unsigned int len); @@ -34,9 +34,13 @@ public: private: CAX25Network* m_network; + bool m_trace; bool m_enabled; FILE* m_fp; + bool isUI(const unsigned char* data, unsigned int length) const; + void decode(const unsigned char* data, unsigned int length); + bool decodeAddress(const unsigned char* data, std::string& text, bool isDigi = false) const; bool openFile(); bool writeFile(const unsigned char* data, unsigned int length); void closeFile(); diff --git a/AX25Network.cpp b/AX25Network.cpp index 8123c51..3f5ac49 100644 --- a/AX25Network.cpp +++ b/AX25Network.cpp @@ -74,26 +74,6 @@ bool CAX25Network::writeAX25(const unsigned char* data, unsigned int length) return m_socket.write(buffer, length + 4U, m_address, m_port); } -bool CAX25Network::writeMICE(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - - unsigned char buffer[110U]; - ::memset(buffer, 0x00U, 110U); - - buffer[0U] = 'M'; - buffer[1U] = 'I'; - buffer[2U] = 'C'; - buffer[3U] = 'E'; - - ::memcpy(buffer + 4U, data, length); - - if (m_debug) - CUtils::dump(1U, "AX25 Network Data Sent", buffer, length + 4U); - - return m_socket.write(buffer, length + 4U, m_address, m_port); -} - void CAX25Network::reset() { } diff --git a/AX25Network.h b/AX25Network.h index b171e6a..866ae7e 100644 --- a/AX25Network.h +++ b/AX25Network.h @@ -34,7 +34,6 @@ public: void enable(bool enabled); bool writeAX25(const unsigned char* data, unsigned int length); - bool writeMICE(const unsigned char* data, unsigned int length); void reset(); diff --git a/Conf.cpp b/Conf.cpp index 5e10a9f..1e14523 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -208,6 +208,7 @@ m_fmRFAudioBoost(1U), m_fmMaxDevLevel(90.0F), m_fmExtAudioBoost(1U), m_ax25Enabled(false), +m_ax25Trace(false), m_dstarNetworkEnabled(false), m_dstarGatewayAddress(), m_dstarGatewayPort(0U), @@ -789,8 +790,10 @@ bool CConf::read() else if (::strcmp(key, "ExtAudioBoost") == 0) m_fmExtAudioBoost = (unsigned int)::atoi(value); } else if (section == SECTION_AX25) { - if (::strcmp(key, "Enable") == 0) - m_ax25Enabled = ::atoi(value) == 1; + if (::strcmp(key, "Enable") == 0) + m_ax25Enabled = ::atoi(value) == 1; + else if (::strcmp(key, "Trace") == 0) + m_ax25Trace = ::atoi(value) == 1; } else if (section == SECTION_DSTAR_NETWORK) { if (::strcmp(key, "Enable") == 0) m_dstarNetworkEnabled = ::atoi(value) == 1; @@ -1713,6 +1716,11 @@ bool CConf::getAX25Enabled() const return m_ax25Enabled; } +bool CConf::getAX25Trace() const +{ + return m_ax25Trace; +} + bool CConf::getDStarNetworkEnabled() const { return m_dstarNetworkEnabled; diff --git a/Conf.h b/Conf.h index ef584c7..0d340f9 100644 --- a/Conf.h +++ b/Conf.h @@ -173,6 +173,7 @@ public: // The AX.25 section bool getAX25Enabled() const; + bool getAX25Trace() const; // The FM Section bool getFMEnabled() const; @@ -455,6 +456,7 @@ private: unsigned int m_pocsagFrequency; bool m_ax25Enabled; + bool m_ax25Trace; bool m_fmEnabled; std::string m_fmCallsign; diff --git a/MMDVM.ini b/MMDVM.ini index e6de0fb..de6408d 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -177,6 +177,7 @@ ExtAudioBoost=1 [AX.25] Enable=1 +Trace=1 [D-Star Network] Enable=1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index ebc5613..9c452dc 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -626,10 +626,13 @@ int CMMDVMHost::run() } if (m_ax25Enabled) { + bool trace = m_conf.getAX25Trace(); + LogInfo("AX.25 RF Parameters"); LogInfo(" RXOnly: yes"); + LogInfo(" Trace: %s", trace ? "yes" : "no"); - m_ax25 = new CAX25Control(m_ax25Network); + m_ax25 = new CAX25Control(m_ax25Network, trace); } bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); diff --git a/Version.h b/Version.h index 6b25bcc..279ecfd 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200609"; +const char* VERSION = "20200618"; #endif From e0f800ba98f575d137192fd2c1e977ddfb827e53 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 19 Jun 2020 15:09:21 +0100 Subject: [PATCH 057/115] Handle the new larger frame type. --- Modem.cpp | 150 ++++++++++++++++++++++++++++-------------------------- Modem.h | 10 ++++ Version.h | 2 +- 3 files changed, 89 insertions(+), 73 deletions(-) diff --git a/Modem.cpp b/Modem.cpp index 3a59fca..bcdde83 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -142,6 +142,8 @@ m_serial(NULL), m_buffer(NULL), m_length(0U), m_offset(0U), +m_state(SS_START), +m_type(0U), m_rxDStarData(1000U, "Modem RX D-Star"), m_txDStarData(1000U, "Modem TX D-Star"), m_rxDMRData1(1000U, "Modem RX DMR1"), @@ -387,7 +389,7 @@ void CModem::clock(unsigned int ms) // Nothing to do } else { // type == RTM_OK - switch (m_buffer[2U]) { + switch (m_type) { case MMDVM_DSTAR_HEADER: { if (m_trace) CUtils::dump(1U, "RX D-Star Header", m_buffer, m_length); @@ -398,7 +400,7 @@ void CModem::clock(unsigned int ms) data = TAG_HEADER; m_rxDStarData.addData(&data, 1U); - m_rxDStarData.addData(m_buffer + 3U, m_length - 3U); + m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -412,7 +414,7 @@ void CModem::clock(unsigned int ms) data = TAG_DATA; m_rxDStarData.addData(&data, 1U); - m_rxDStarData.addData(m_buffer + 3U, m_length - 3U); + m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -453,7 +455,7 @@ void CModem::clock(unsigned int ms) data = TAG_DATA; m_rxDMRData1.addData(&data, 1U); - m_rxDMRData1.addData(m_buffer + 3U, m_length - 3U); + m_rxDMRData1.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -470,7 +472,7 @@ void CModem::clock(unsigned int ms) data = TAG_DATA; m_rxDMRData2.addData(&data, 1U); - m_rxDMRData2.addData(m_buffer + 3U, m_length - 3U); + m_rxDMRData2.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -508,7 +510,7 @@ void CModem::clock(unsigned int ms) data = TAG_DATA; m_rxYSFData.addData(&data, 1U); - m_rxYSFData.addData(m_buffer + 3U, m_length - 3U); + m_rxYSFData.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -534,7 +536,7 @@ void CModem::clock(unsigned int ms) data = TAG_HEADER; m_rxP25Data.addData(&data, 1U); - m_rxP25Data.addData(m_buffer + 3U, m_length - 3U); + m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -548,7 +550,7 @@ void CModem::clock(unsigned int ms) data = TAG_DATA; m_rxP25Data.addData(&data, 1U); - m_rxP25Data.addData(m_buffer + 3U, m_length - 3U); + m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -574,7 +576,7 @@ void CModem::clock(unsigned int ms) data = TAG_DATA; m_rxNXDNData.addData(&data, 1U); - m_rxNXDNData.addData(m_buffer + 3U, m_length - 3U); + m_rxNXDNData.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -597,7 +599,7 @@ void CModem::clock(unsigned int ms) unsigned char data = m_length - 3U; m_rxAX25Data.addData(&data, 1U); - m_rxAX25Data.addData(m_buffer + 3U, m_length - 3U); + m_rxAX25Data.addData(m_buffer + m_offset, m_length - m_offset); } break; @@ -609,44 +611,44 @@ void CModem::clock(unsigned int ms) m_nxdnSpace = 0U; m_pocsagSpace = 0U; - m_mode = m_buffer[4U]; + m_mode = m_buffer[m_offset + 1U]; - m_tx = (m_buffer[5U] & 0x01U) == 0x01U; + m_tx = (m_buffer[m_offset + 2U] & 0x01U) == 0x01U; - bool adcOverflow = (m_buffer[5U] & 0x02U) == 0x02U; + bool adcOverflow = (m_buffer[m_offset + 2U] & 0x02U) == 0x02U; if (adcOverflow) LogError("MMDVM ADC levels have overflowed"); - bool rxOverflow = (m_buffer[5U] & 0x04U) == 0x04U; + bool rxOverflow = (m_buffer[m_offset + 2U] & 0x04U) == 0x04U; if (rxOverflow) LogError("MMDVM RX buffer has overflowed"); - bool txOverflow = (m_buffer[5U] & 0x08U) == 0x08U; + bool txOverflow = (m_buffer[m_offset + 2U] & 0x08U) == 0x08U; if (txOverflow) LogError("MMDVM TX buffer has overflowed"); - m_lockout = (m_buffer[5U] & 0x10U) == 0x10U; + m_lockout = (m_buffer[m_offset + 2U] & 0x10U) == 0x10U; - bool dacOverflow = (m_buffer[5U] & 0x20U) == 0x20U; + bool dacOverflow = (m_buffer[m_offset + 2U] & 0x20U) == 0x20U; if (dacOverflow) LogError("MMDVM DAC levels have overflowed"); - m_cd = (m_buffer[5U] & 0x40U) == 0x40U; + m_cd = (m_buffer[m_offset + 2U] & 0x40U) == 0x40U; - m_dstarSpace = m_buffer[6U]; - m_dmrSpace1 = m_buffer[7U]; - m_dmrSpace2 = m_buffer[8U]; - m_ysfSpace = m_buffer[9U]; + m_dstarSpace = m_buffer[m_offset + 3U]; + m_dmrSpace1 = m_buffer[m_offset + 4U]; + m_dmrSpace2 = m_buffer[m_offset + 5U]; + m_ysfSpace = m_buffer[m_offset + 6U]; - if (m_length > 10U) - m_p25Space = m_buffer[10U]; - if (m_length > 11U) - m_nxdnSpace = m_buffer[11U]; - if (m_length > 12U) - m_pocsagSpace = m_buffer[12U]; + if (m_length > (m_offset + 7U)) + m_p25Space = m_buffer[m_offset + 7U]; + if (m_length > (m_offset + 8U)) + m_nxdnSpace = m_buffer[m_offset + 8U]; + if (m_length > (m_offset + 9U)) + m_pocsagSpace = m_buffer[m_offset + 9U]; m_inactivityTimer.start(); - // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, int(m_lockout), int(m_cd)); + // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, int(m_lockout), int(m_cd)); } break; @@ -656,10 +658,10 @@ void CModem::clock(unsigned int ms) unsigned char offset = m_sendTransparentDataFrameType; if (offset > 1U) offset = 1U; - unsigned char data = m_length - 3U + offset; + unsigned char data = m_length - m_offset + offset; m_rxTransparentData.addData(&data, 1U); - m_rxTransparentData.addData(m_buffer + 3U - offset, m_length - 3U + offset); + m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); } break; @@ -669,7 +671,7 @@ void CModem::clock(unsigned int ms) break; case MMDVM_NAK: - LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[3U], m_buffer[4U]); + LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[m_offset], m_buffer[m_offset + 1U]); break; case MMDVM_DEBUG1: @@ -689,14 +691,14 @@ void CModem::clock(unsigned int ms) unsigned char offset = m_sendTransparentDataFrameType; if (offset > 1U) offset = 1U; - unsigned char data = m_length - 3U + offset; + unsigned char data = m_length - m_offset + offset; m_rxTransparentData.addData(&data, 1U); - m_rxTransparentData.addData(m_buffer + 3U - offset, m_length - 3U + offset); + m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); break; //only break when sendFrameType>0, else message is unknown } default: - LogMessage("Unknown message, type: %02X", m_buffer[2U]); + LogMessage("Unknown message, type: %02X", m_type); CUtils::dump("Buffer dump", m_buffer, m_length); break; } @@ -1729,7 +1731,7 @@ RESP_TYPE_MMDVM CModem::getResponse() { assert(m_serial != NULL); - if (m_offset == 0U) { + if (m_state == SS_START) { // Get the start of the frame or nothing at all int ret = m_serial->read(m_buffer + 0U, 1U); if (ret < 0) { @@ -1743,68 +1745,71 @@ RESP_TYPE_MMDVM CModem::getResponse() if (m_buffer[0U] != MMDVM_FRAME_START) return RTM_TIMEOUT; - m_offset = 1U; + m_state = SS_LENGTH1; + m_length = 1U; } - if (m_offset == 1U) { - // Get the length of the frame + if (m_state == SS_LENGTH1) { + // Get the length of the frame, 1/2 int ret = m_serial->read(m_buffer + 1U, 1U); if (ret < 0) { LogError("Error when reading from the modem"); - m_offset = 0U; + m_state = SS_START; return RTM_ERROR; } if (ret == 0) return RTM_TIMEOUT; - if (m_buffer[1U] >= 250U) { - LogError("Invalid length received from the modem - %u", m_buffer[1U]); - m_offset = 0U; - return RTM_ERROR; - } - m_length = m_buffer[1U]; m_offset = 2U; + + if (m_length == 0U) + m_state = SS_LENGTH2; + else + m_state = SS_TYPE; } - if (m_offset == 2U) { - // Get the frame type + if (m_state == SS_LENGTH2) { + // Get the length of the frane, 2/2 int ret = m_serial->read(m_buffer + 2U, 1U); if (ret < 0) { LogError("Error when reading from the modem"); - m_offset = 0U; + m_state = SS_START; return RTM_ERROR; } if (ret == 0) return RTM_TIMEOUT; + m_length = m_buffer[2U] + 255U; m_offset = 3U; + m_state = SS_TYPE; } - if (m_offset >= 3U) { - // Use later two byte length field - if (m_length == 0U) { - int ret = m_serial->read(m_buffer + 3U, 2U); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_offset = 0U; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - m_length = (m_buffer[3U] << 8) | m_buffer[4U]; - m_offset = 5U; + if (m_state == SS_TYPE) { + // Get the frame type + int ret = m_serial->read(&m_type, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; } + if (ret == 0) + return RTM_TIMEOUT; + + m_buffer[m_offset++] = m_type; + + m_state = SS_DATA; + } + + if (m_state == SS_DATA) { while (m_offset < m_length) { int ret = m_serial->read(m_buffer + m_offset, m_length - m_offset); if (ret < 0) { LogError("Error when reading from the modem"); - m_offset = 0U; + m_state = SS_START; return RTM_ERROR; } @@ -1816,10 +1821,11 @@ RESP_TYPE_MMDVM CModem::getResponse() } } - m_offset = 0U; - // CUtils::dump(1U, "Received", m_buffer, m_length); + m_offset = m_length > 255U ? 4U : 3U; + m_state = SS_START; + return RTM_OK; } @@ -2162,25 +2168,25 @@ bool CModem::setFMMiscParams() void CModem::printDebug() { if (m_buffer[2U] == MMDVM_DEBUG1) { - LogMessage("Debug: %.*s", m_length - 3U, m_buffer + 3U); + LogMessage("Debug: %.*s", m_length - m_offset - 0U, m_buffer + m_offset); } else if (m_buffer[2U] == MMDVM_DEBUG2) { short val1 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d", m_length - 5U, m_buffer + 3U, val1); + LogMessage("Debug: %.*s %d", m_length - m_offset - 2U, m_buffer + m_offset, val1); } else if (m_buffer[2U] == MMDVM_DEBUG3) { short val1 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; short val2 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d", m_length - 7U, m_buffer + 3U, val1, val2); + LogMessage("Debug: %.*s %d %d", m_length - m_offset - 4U, m_buffer + m_offset, val1, val2); } else if (m_buffer[2U] == MMDVM_DEBUG4) { short val1 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; short val2 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; short val3 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d %d", m_length - 9U, m_buffer + 3U, val1, val2, val3); + LogMessage("Debug: %.*s %d %d %d", m_length - m_offset - 6U, m_buffer + m_offset, val1, val2, val3); } else if (m_buffer[2U] == MMDVM_DEBUG5) { short val1 = (m_buffer[m_length - 8U] << 8) | m_buffer[m_length - 7U]; short val2 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; short val3 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; short val4 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d %d %d", m_length - 11U, m_buffer + 3U, val1, val2, val3, val4); + LogMessage("Debug: %.*s %d %d %d %d", m_length - m_offset - 8U, m_buffer + m_offset, val1, val2, val3, val4); } } diff --git a/Modem.h b/Modem.h index 69228bb..ea01945 100644 --- a/Modem.h +++ b/Modem.h @@ -32,6 +32,14 @@ enum RESP_TYPE_MMDVM { RTM_ERROR }; +enum SERIAL_STATE { + SS_START, + SS_LENGTH1, + SS_LENGTH2, + SS_TYPE, + SS_DATA +}; + class CModem { public: CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); @@ -158,6 +166,8 @@ private: unsigned char* m_buffer; unsigned int m_length; unsigned int m_offset; + SERIAL_STATE m_state; + unsigned char m_type; CRingBuffer m_rxDStarData; CRingBuffer m_txDStarData; CRingBuffer m_rxDMRData1; diff --git a/Version.h b/Version.h index 279ecfd..ffc27e8 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200618"; +const char* VERSION = "20200619"; #endif From d0878bbf7e3eb3b32dd8338d2482be8272a3e175 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 20 Jun 2020 20:06:48 +0100 Subject: [PATCH 058/115] Add new AX.25 parameters. --- MMDVM.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MMDVM.ini b/MMDVM.ini index de6408d..dcbb0b8 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -66,6 +66,7 @@ RFLevel=100 # NXDNTXLevel=50 # POCSAGTXLevel=50 # FMTXLevel=50 +# AX25TXLevel=50 RSSIMappingFile=RSSI.dat Trace=0 Debug=0 @@ -177,6 +178,9 @@ ExtAudioBoost=1 [AX.25] Enable=1 +TXTwist=6 +RXTwist=6 +Digipeat=1 Trace=1 [D-Star Network] From f936a6c5b640514954ca06cd12ec93f3e80c78ca Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 20 Jun 2020 20:44:02 +0100 Subject: [PATCH 059/115] Add the Kerchunk TX parameter. --- Conf.cpp | 8 ++++++++ Conf.h | 2 ++ MMDVM.ini | 1 + MMDVMHost.cpp | 4 +++- Modem.cpp | 7 ++++++- Modem.h | 3 ++- Version.h | 2 +- 7 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index eae0db6..5799323 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -201,6 +201,7 @@ m_fmCTCSSHighThreshold(30U), m_fmCTCSSLowThreshold(20U), m_fmCTCSSLevel(2.0F), m_fmKerchunkTime(0U), +m_fmKerchunkTX(true), m_fmHangTime(7U), m_fmUseCOS(true), m_fmCOSInvert(false), @@ -777,6 +778,8 @@ bool CConf::read() m_fmCTCSSLevel = float(::atof(value)); else if (::strcmp(key, "KerchunkTime") == 0) m_fmKerchunkTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "KerchunkTX") == 0) + m_fmKerchunkTX = ::atoi(value) == 1; else if (::strcmp(key, "HangTime") == 0) m_fmHangTime = (unsigned int)::atoi(value); else if (::strcmp(key, "UseCOS") == 0) @@ -1683,6 +1686,11 @@ unsigned int CConf::getFMKerchunkTime() const return m_fmKerchunkTime; } +bool CConf::getFMKerchunkTX() const +{ + return m_fmKerchunkTX; +} + unsigned int CConf::getFMHangTime() const { return m_fmHangTime; diff --git a/Conf.h b/Conf.h index b455a55..01e1f0b 100644 --- a/Conf.h +++ b/Conf.h @@ -198,6 +198,7 @@ public: unsigned int getFMCTCSSLowThreshold() const; float getFMCTCSSLevel() const; unsigned int getFMKerchunkTime() const; + bool getFMKerchunkTX() const; unsigned int getFMHangTime() const; bool getFMUseCOS() const; bool getFMCOSInvert() const; @@ -479,6 +480,7 @@ private: unsigned int m_fmCTCSSLowThreshold; float m_fmCTCSSLevel; unsigned int m_fmKerchunkTime; + bool m_fmKerchunkTX; unsigned int m_fmHangTime; bool m_fmUseCOS; bool m_fmCOSInvert; diff --git a/MMDVM.ini b/MMDVM.ini index c031c49..a323267 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -169,6 +169,7 @@ CTCSSThreshold=30 # CTCSSLowThreshold=20 CTCSSLevel=20 KerchunkTime=0 +KerchunkTX=1 HangTime=7 UseCOS=1 COSInvert=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index c28f17e..5c4a926 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1300,6 +1300,7 @@ bool CMMDVMHost::createModem() unsigned int ctcssLowThreshold = m_conf.getFMCTCSSLowThreshold(); float ctcssLevel = m_conf.getFMCTCSSLevel(); unsigned int kerchunkTime = m_conf.getFMKerchunkTime(); + bool kerchunkTX = m_conf.getFMKerchunkTX(); unsigned int hangTime = m_conf.getFMHangTime(); bool useCOS = m_conf.getFMUseCOS(); bool cosInvert = m_conf.getFMCOSInvert(); @@ -1331,6 +1332,7 @@ bool CMMDVMHost::createModem() LogInfo(" CTCSS Low Threshold: %u", ctcssLowThreshold); LogInfo(" CTCSS Level: %.1f%%", ctcssLevel); LogInfo(" Kerchunk Time: %us", kerchunkTime); + LogInfo(" Kerchunk TX: %s", kerchunkTX ? "yes" : "no"); LogInfo(" Hang Time: %us", hangTime); LogInfo(" Use COS: %s", useCOS ? "yes" : "no"); LogInfo(" COS Invert: %s", cosInvert ? "yes" : "no"); @@ -1340,7 +1342,7 @@ bool CMMDVMHost::createModem() m_modem->setFMCallsignParams(callsign, callsignSpeed, callsignFrequency, callsignTime, callsignHoldoff, callsignHighLevel, callsignLowLevel, callsignAtStart, callsignAtEnd, callsignAtLatch); m_modem->setFMAckParams(rfAck, ackSpeed, ackFrequency, ackMinTime, ackDelay, ackLevel); - m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel); + m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, kerchunkTX, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel); if (m_conf.getFMNetworkEnabled()) { std::string extAck = m_conf.getFMExtAck(); diff --git a/Modem.cpp b/Modem.cpp index 3350a5c..8dfb235 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -205,6 +205,7 @@ m_fmCtcssHighThreshold(30U), m_fmCtcssLowThreshold(20U), m_fmCtcssLevel(10.0F), m_fmKerchunkTime(0U), +m_fmKerchunkTX(true), m_fmHangTime(5U), m_fmUseCOS(true), m_fmCOSInvert(false), @@ -2051,7 +2052,7 @@ void CModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, uns m_fmAckLevel = ackLevel; } -void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) +void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) { m_fmTimeout = timeout; m_fmTimeoutLevel = timeoutLevel; @@ -2062,6 +2063,8 @@ void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctc m_fmCtcssLevel = ctcssLevel; m_fmKerchunkTime = kerchunkTime; + m_fmKerchunkTX = kerchunkTX; + m_fmHangTime = hangTime; m_fmUseCOS = useCOS; @@ -2217,6 +2220,8 @@ bool CModem::setFMMiscParams() buffer[11U] |= 0x01U; if (m_fmCOSInvert) buffer[11U] |= 0x02U; + if (m_fmKerchunkTX) + buffer[11U] |= 0x04U; buffer[12U] = m_fmRFAudioBoost; diff --git a/Modem.h b/Modem.h index 4c77d9f..6cbf683 100644 --- a/Modem.h +++ b/Modem.h @@ -49,7 +49,7 @@ public: virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost); virtual bool open(); @@ -220,6 +220,7 @@ private: unsigned int m_fmCtcssLowThreshold; float m_fmCtcssLevel; unsigned int m_fmKerchunkTime; + bool m_fmKerchunkTX; unsigned int m_fmHangTime; bool m_fmUseCOS; bool m_fmCOSInvert; diff --git a/Version.h b/Version.h index 46f5c4f..7cfe66a 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200523"; +const char* VERSION = "20200620"; #endif From fe77cbd68c7831a6f5f61d0cfd9926c1b46c5fcb Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 20 Jun 2020 21:28:39 +0100 Subject: [PATCH 060/115] Add the extra AX.25 parameters. --- Conf.cpp | 34 +++++++++++++++++++++++++++++++++- Conf.h | 8 ++++++++ MMDVMHost.cpp | 18 ++++++++++++++---- Version.h | 2 +- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 1e14523..85972c1 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -113,6 +113,7 @@ m_modemP25TXLevel(50.0F), m_modemNXDNTXLevel(50.0F), m_modemPOCSAGTXLevel(50.0F), m_modemFMTXLevel(50.0F), +m_modemAX25TXLevel(50.0F), m_modemRSSIMappingFile(), m_modemTrace(false), m_modemDebug(false), @@ -208,6 +209,9 @@ m_fmRFAudioBoost(1U), m_fmMaxDevLevel(90.0F), m_fmExtAudioBoost(1U), m_ax25Enabled(false), +m_ax25RXTwist(6), +m_ax25TXTwist(6), +m_ax25Digipeat(true), m_ax25Trace(false), m_dstarNetworkEnabled(false), m_dstarGatewayAddress(), @@ -508,7 +512,7 @@ bool CConf::read() else if (::strcmp(key, "RXLevel") == 0) m_modemRXLevel = float(::atof(value)); else if (::strcmp(key, "TXLevel") == 0) - m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value)); + m_modemAX25TXLevel = m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value)); else if (::strcmp(key, "CWIdTXLevel") == 0) m_modemCWIdTXLevel = float(::atof(value)); else if (::strcmp(key, "D-StarTXLevel") == 0) @@ -525,6 +529,8 @@ bool CConf::read() m_modemPOCSAGTXLevel = float(::atof(value)); else if (::strcmp(key, "FMTXLevel") == 0) m_modemFMTXLevel = float(::atof(value)); + else if (::strcmp(key, "AX25TXLevel") == 0) + m_modemAX25TXLevel = float(::atof(value)); else if (::strcmp(key, "RSSIMappingFile") == 0) m_modemRSSIMappingFile = value; else if (::strcmp(key, "Trace") == 0) @@ -792,6 +798,12 @@ bool CConf::read() } else if (section == SECTION_AX25) { if (::strcmp(key, "Enable") == 0) m_ax25Enabled = ::atoi(value) == 1; + else if (::strcmp(key, "RXTwist") == 0) + m_ax25RXTwist = ::atoi(value); + else if (::strcmp(key, "TXTwist") == 0) + m_ax25TXTwist = ::atoi(value); + else if (::strcmp(key, "Digipeat") == 0) + m_ax25Digipeat = ::atoi(value) == 1; else if (::strcmp(key, "Trace") == 0) m_ax25Trace = ::atoi(value) == 1; } else if (section == SECTION_DSTAR_NETWORK) { @@ -1241,6 +1253,11 @@ float CConf::getModemFMTXLevel() const return m_modemFMTXLevel; } +float CConf::getModemAX25TXLevel() const +{ + return m_modemAX25TXLevel; +} + std::string CConf::getModemRSSIMappingFile () const { return m_modemRSSIMappingFile; @@ -1716,6 +1733,21 @@ bool CConf::getAX25Enabled() const return m_ax25Enabled; } +int CConf::getAX25RXTwist() const +{ + return m_ax25RXTwist; +} + +int CConf::getAX25TXTwist() const +{ + return m_ax25TXTwist; +} + +bool CConf::getAX25Digipeat() const +{ + return m_ax25Digipeat; +} + bool CConf::getAX25Trace() const { return m_ax25Trace; diff --git a/Conf.h b/Conf.h index 0d340f9..8379061 100644 --- a/Conf.h +++ b/Conf.h @@ -91,6 +91,7 @@ public: float getModemNXDNTXLevel() const; float getModemPOCSAGTXLevel() const; float getModemFMTXLevel() const; + float getModemAX25TXLevel() const; std::string getModemRSSIMappingFile() const; bool getModemTrace() const; bool getModemDebug() const; @@ -173,6 +174,9 @@ public: // The AX.25 section bool getAX25Enabled() const; + int getAX25RXTwist() const; + int getAX25TXTwist() const; + bool getAX25Digipeat() const; bool getAX25Trace() const; // The FM Section @@ -383,6 +387,7 @@ private: float m_modemNXDNTXLevel; float m_modemPOCSAGTXLevel; float m_modemFMTXLevel; + float m_modemAX25TXLevel; std::string m_modemRSSIMappingFile; bool m_modemTrace; bool m_modemDebug; @@ -456,6 +461,9 @@ private: unsigned int m_pocsagFrequency; bool m_ax25Enabled; + int m_ax25RXTwist; + int m_ax25TXTwist; + bool m_ax25Digipeat; bool m_ax25Trace; bool m_fmEnabled; diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 9c452dc..db24632 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -626,13 +626,18 @@ int CMMDVMHost::run() } if (m_ax25Enabled) { - bool trace = m_conf.getAX25Trace(); + int rxTwist = m_conf.getAX25RXTwist(); + int txTwist = m_conf.getAX25TXTwist(); + bool digipeat = m_conf.getAX25Digipeat(); + bool trace = m_conf.getAX25Trace(); LogInfo("AX.25 RF Parameters"); - LogInfo(" RXOnly: yes"); + LogInfo(" RXTwist: %d", rxTwist); + LogInfo(" TXTwist: %d", txTwist); + LogInfo(" Digipeat: %s", digipeat ? "yes" : "no"); LogInfo(" Trace: %s", trace ? "yes" : "no"); - m_ax25 = new CAX25Control(m_ax25Network, trace); + m_ax25 = new CAX25Control(m_ax25Network, digipeat, trace); } bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); @@ -1201,6 +1206,7 @@ bool CMMDVMHost::createModem() float nxdnTXLevel = m_conf.getModemNXDNTXLevel(); float pocsagTXLevel = m_conf.getModemPOCSAGTXLevel(); float fmTXLevel = m_conf.getModemFMTXLevel(); + float ax25TXLevel = m_conf.getModemAX25TXLevel(); bool trace = m_conf.getModemTrace(); bool debug = m_conf.getModemDebug(); unsigned int colorCode = m_conf.getDMRColorCode(); @@ -1216,6 +1222,8 @@ bool CMMDVMHost::createModem() int rxDCOffset = m_conf.getModemRXDCOffset(); int txDCOffset = m_conf.getModemTXDCOffset(); float rfLevel = m_conf.getModemRFLevel(); + int rxTwist = m_conf.getAX25RXTwist(); + int txTwist = m_conf.getAX25TXTwist(); LogInfo("Modem Parameters"); LogInfo(" Port: %s", port.c_str()); @@ -1241,17 +1249,19 @@ bool CMMDVMHost::createModem() LogInfo(" NXDN TX Level: %.1f%%", nxdnTXLevel); LogInfo(" POCSAG TX Level: %.1f%%", pocsagTXLevel); LogInfo(" FM TX Level: %.1f%%", fmTXLevel); + LogInfo(" AX.25 TX Level: %.1f%%", ax25TXLevel); LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset); m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); m_modem->setSerialParams(protocol,address); m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled, m_ax25Enabled); - m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel); + m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel); m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency); m_modem->setDMRParams(colorCode); m_modem->setYSFParams(lowDeviation, ysfTXHang); m_modem->setP25Params(p25TXHang); m_modem->setNXDNParams(nxdnTXHang); + m_modem->setAX25Params(rxTwist, txTwist); if (m_fmEnabled) { std::string callsign = m_conf.getFMCallsign(); diff --git a/Version.h b/Version.h index ffc27e8..7cfe66a 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200619"; +const char* VERSION = "20200620"; #endif From 692d6519db4dd9644cb430bda117efdaeea59da5 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 21 Jun 2020 14:15:37 +0100 Subject: [PATCH 061/115] Add the AX.25 modem parameters and start reworking the AX,25 RX processing. --- AX25Control.cpp | 20 +++---------------- AX25Control.h | 1 - AX25Network.cpp | 30 +++++++++++++++------------- AX25Network.h | 22 +++++++++++++-------- Conf.cpp | 52 +++++++++++++------------------------------------ Conf.h | 14 ++++--------- MMDVM.ini | 7 ++----- MMDVMHost.cpp | 26 ++++++++++--------------- Modem.cpp | 45 +++++++++++++++++++++++++++++------------- Modem.h | 6 +++++- Version.h | 2 +- 11 files changed, 101 insertions(+), 124 deletions(-) diff --git a/AX25Control.cpp b/AX25Control.cpp index a6b89ea..563fa42 100644 --- a/AX25Control.cpp +++ b/AX25Control.cpp @@ -51,12 +51,10 @@ bool CAX25Control::writeModem(unsigned char *data, unsigned int len) CUtils::dump(1U, "AX.25 raw packet", data, len); - if (m_network != NULL) { - if (isUI(data, len)) - m_network->writeAX25(data, len); - } + if (m_network == NULL) + return true; - return true; + return m_network->write(data, len); } bool CAX25Control::openFile() @@ -233,15 +231,3 @@ bool CAX25Control::decodeAddress(const unsigned char* data, std::string& text, b return (data[6U] & 0x01U) == 0x00U; } - -bool CAX25Control::isUI(const unsigned char* data, unsigned int length) const -{ - assert(data != NULL); - assert(length >= 15U); - - unsigned int n = 13U; - while ((data[n] & 0x01U) == 0x00U && n < length) - n += 7U; - - return (data[n + 1U] & 0xEFU) == 0x03U; -} diff --git a/AX25Control.h b/AX25Control.h index 59b5688..b0217df 100644 --- a/AX25Control.h +++ b/AX25Control.h @@ -38,7 +38,6 @@ private: bool m_enabled; FILE* m_fp; - bool isUI(const unsigned char* data, unsigned int length) const; void decode(const unsigned char* data, unsigned int length); bool decodeAddress(const unsigned char* data, std::string& text, bool isDigi = false) const; bool openFile(); diff --git a/AX25Network.cpp b/AX25Network.cpp index 3f5ac49..5330ec8 100644 --- a/AX25Network.cpp +++ b/AX25Network.cpp @@ -27,34 +27,38 @@ const unsigned int BUFFER_LENGTH = 200U; -CAX25Network::CAX25Network(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : -m_socket(localAddress, localPort), -m_address(), -m_port(gatewayPort), +CAX25Network::CAX25Network(const std::string& port, unsigned int speed, bool debug) : +m_serial(port, SERIAL_SPEED(speed), false), // XXX +m_txData(NULL), +m_txLength(0U), +m_txOffset(0U), +m_rxData(NULL), +m_rxLength(0U), +m_rxComplete(false), m_debug(debug), m_enabled(false) { - assert(gatewayPort > 0U); - assert(!gatewayAddress.empty()); + assert(!port.empty()); + assert(speed > 0U); - m_address = CUDPSocket::lookup(gatewayAddress); + m_txData = new unsigned char[BUFFER_LENGTH]; + m_rxData = new unsigned char[BUFFER_LENGTH]; } CAX25Network::~CAX25Network() { + delete[] m_txData; + delete[] m_rxData; } bool CAX25Network::open() { LogMessage("Opening AX25 network connection"); - if (m_address.s_addr == INADDR_NONE) - return false; - - return m_socket.open(); + return m_serial.open(); } -bool CAX25Network::writeAX25(const unsigned char* data, unsigned int length) +bool CAX25Network::write(const unsigned char* data, unsigned int length) { assert(data != NULL); @@ -80,7 +84,7 @@ void CAX25Network::reset() void CAX25Network::close() { - m_socket.close(); + m_serial.close(); LogMessage("Closing AX25 network connection"); } diff --git a/AX25Network.h b/AX25Network.h index 866ae7e..9c9cecb 100644 --- a/AX25Network.h +++ b/AX25Network.h @@ -19,32 +19,38 @@ #ifndef AX25Network_H #define AX25Network_H -#include "UDPSocket.h" +#include "SerialController.h" #include #include class CAX25Network { public: - CAX25Network(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug); + CAX25Network(const std::string& port, unsigned int speed, bool debug); ~CAX25Network(); bool open(); void enable(bool enabled); - bool writeAX25(const unsigned char* data, unsigned int length); + bool write(const unsigned char* data, unsigned int length); + + unsigned int read(unsigned char* data, unsigned int length); void reset(); void close(); private: - CUDPSocket m_socket; - in_addr m_address; - unsigned int m_port; - bool m_debug; - bool m_enabled; + CSerialController m_serial; + unsigned char* m_txData; + unsigned int m_txLength; + unsigned int m_txOffset; + unsigned char* m_rxData; + unsigned int m_rxLength; + bool m_rxComplete; + bool m_debug; + bool m_enabled; }; #endif diff --git a/Conf.cpp b/Conf.cpp index 85972c1..0ef321f 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -211,7 +211,6 @@ m_fmExtAudioBoost(1U), m_ax25Enabled(false), m_ax25RXTwist(6), m_ax25TXTwist(6), -m_ax25Digipeat(true), m_ax25Trace(false), m_dstarNetworkEnabled(false), m_dstarGatewayAddress(), @@ -259,10 +258,8 @@ m_pocsagLocalPort(0U), m_pocsagNetworkModeHang(3U), m_pocsagNetworkDebug(false), m_ax25NetworkEnabled(false), -m_ax25GatewayAddress(), -m_ax25GatewayPort(0U), -m_ax25LocalAddress(), -m_ax25LocalPort(0U), +m_ax25NetworkPort(), +m_ax25NetworkSpeed(9600U), m_ax25NetworkDebug(false), m_tftSerialPort("/dev/ttyAMA0"), m_tftSerialBrightness(50U), @@ -802,8 +799,6 @@ bool CConf::read() m_ax25RXTwist = ::atoi(value); else if (::strcmp(key, "TXTwist") == 0) m_ax25TXTwist = ::atoi(value); - else if (::strcmp(key, "Digipeat") == 0) - m_ax25Digipeat = ::atoi(value) == 1; else if (::strcmp(key, "Trace") == 0) m_ax25Trace = ::atoi(value) == 1; } else if (section == SECTION_DSTAR_NETWORK) { @@ -903,18 +898,14 @@ bool CConf::read() else if (::strcmp(key, "Debug") == 0) m_pocsagNetworkDebug = ::atoi(value) == 1; } else if (section == SECTION_AX25_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_ax25NetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LocalAddress") == 0) - m_ax25LocalAddress = value; - else if (::strcmp(key, "LocalPort") == 0) - m_ax25LocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "GatewayAddress") == 0) - m_ax25GatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_ax25GatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_ax25NetworkDebug = ::atoi(value) == 1; + if (::strcmp(key, "Enable") == 0) + m_ax25NetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Port") == 0) + m_ax25NetworkPort = value; + else if (::strcmp(key, "Speed") == 0) + m_ax25NetworkSpeed = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_ax25NetworkDebug = ::atoi(value) == 1; } else if (section == SECTION_TFTSERIAL) { if (::strcmp(key, "Port") == 0) m_tftSerialPort = value; @@ -1743,11 +1734,6 @@ int CConf::getAX25TXTwist() const return m_ax25TXTwist; } -bool CConf::getAX25Digipeat() const -{ - return m_ax25Digipeat; -} - bool CConf::getAX25Trace() const { return m_ax25Trace; @@ -1983,24 +1969,14 @@ bool CConf::getAX25NetworkEnabled() const return m_ax25NetworkEnabled; } -std::string CConf::getAX25GatewayAddress() const +std::string CConf::getAX25NetworkPort() const { - return m_ax25GatewayAddress; + return m_ax25NetworkPort; } -unsigned int CConf::getAX25GatewayPort() const +unsigned int CConf::getAX25NetworkSpeed() const { - return m_ax25GatewayPort; -} - -std::string CConf::getAX25LocalAddress() const -{ - return m_ax25LocalAddress; -} - -unsigned int CConf::getAX25LocalPort() const -{ - return m_ax25LocalPort; + return m_ax25NetworkSpeed; } bool CConf::getAX25NetworkDebug() const diff --git a/Conf.h b/Conf.h index 8379061..335c1e3 100644 --- a/Conf.h +++ b/Conf.h @@ -176,7 +176,6 @@ public: bool getAX25Enabled() const; int getAX25RXTwist() const; int getAX25TXTwist() const; - bool getAX25Digipeat() const; bool getAX25Trace() const; // The FM Section @@ -271,10 +270,8 @@ public: // The AX.25 Network section bool getAX25NetworkEnabled() const; - std::string getAX25GatewayAddress() const; - unsigned int getAX25GatewayPort() const; - std::string getAX25LocalAddress() const; - unsigned int getAX25LocalPort() const; + std::string getAX25NetworkPort() const; + unsigned int getAX25NetworkSpeed() const; bool getAX25NetworkDebug() const; // The TFTSERIAL section @@ -463,7 +460,6 @@ private: bool m_ax25Enabled; int m_ax25RXTwist; int m_ax25TXTwist; - bool m_ax25Digipeat; bool m_ax25Trace; bool m_fmEnabled; @@ -550,10 +546,8 @@ private: bool m_pocsagNetworkDebug; bool m_ax25NetworkEnabled; - std::string m_ax25GatewayAddress; - unsigned int m_ax25GatewayPort; - std::string m_ax25LocalAddress; - unsigned int m_ax25LocalPort; + std::string m_ax25NetworkPort; + unsigned int m_ax25NetworkSpeed; bool m_ax25NetworkDebug; std::string m_tftSerialPort; diff --git a/MMDVM.ini b/MMDVM.ini index dcbb0b8..6b12fff 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -180,7 +180,6 @@ ExtAudioBoost=1 Enable=1 TXTwist=6 RXTwist=6 -Digipeat=1 Trace=1 [D-Star Network] @@ -242,10 +241,8 @@ Debug=0 [AX.25 Network] Enable=1 -LocalAddress=127.0.0.1 -LocalPort=47325 -GatewayAddress=127.0.0.1 -GatewayPort=47326 +Port=/dev/ttyp7 +Speed=9600 Debug=0 [TFT Serial] diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index db24632..12e71b5 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -626,18 +626,16 @@ int CMMDVMHost::run() } if (m_ax25Enabled) { - int rxTwist = m_conf.getAX25RXTwist(); - int txTwist = m_conf.getAX25TXTwist(); - bool digipeat = m_conf.getAX25Digipeat(); - bool trace = m_conf.getAX25Trace(); + int rxTwist = m_conf.getAX25RXTwist(); + int txTwist = m_conf.getAX25TXTwist(); + bool trace = m_conf.getAX25Trace(); LogInfo("AX.25 RF Parameters"); LogInfo(" RXTwist: %d", rxTwist); LogInfo(" TXTwist: %d", txTwist); - LogInfo(" Digipeat: %s", digipeat ? "yes" : "no"); LogInfo(" Trace: %s", trace ? "yes" : "no"); - m_ax25 = new CAX25Control(m_ax25Network, digipeat, trace); + m_ax25 = new CAX25Control(m_ax25Network, trace); } bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); @@ -1584,19 +1582,15 @@ bool CMMDVMHost::createPOCSAGNetwork() bool CMMDVMHost::createAX25Network() { - std::string gatewayAddress = m_conf.getAX25GatewayAddress(); - unsigned int gatewayPort = m_conf.getAX25GatewayPort(); - std::string localAddress = m_conf.getAX25LocalAddress(); - unsigned int localPort = m_conf.getAX25LocalPort(); - bool debug = m_conf.getAX25NetworkDebug(); + std::string port = m_conf.getAX25NetworkPort(); + unsigned int speed = m_conf.getAX25NetworkSpeed(); + bool debug = m_conf.getAX25NetworkDebug(); LogInfo("AX.25 Network Parameters"); - 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(" Port: %s", port.c_str()); + LogInfo(" Speed: %u", speed); - m_ax25Network = new CAX25Network(localAddress, localPort, gatewayAddress, gatewayPort, debug); + m_ax25Network = new CAX25Network(port, speed, debug); bool ret = m_ax25Network->open(); if (!ret) { diff --git a/Modem.cpp b/Modem.cpp index bcdde83..f1c6449 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -114,15 +114,17 @@ m_txInvert(txInvert), m_pttInvert(pttInvert), m_txDelay(txDelay), m_dmrDelay(dmrDelay), -m_rxLevel(0U), -m_cwIdTXLevel(0U), -m_dstarTXLevel(0U), -m_dmrTXLevel(0U), -m_ysfTXLevel(0U), -m_p25TXLevel(0U), -m_nxdnTXLevel(0U), -m_pocsagTXLevel(0U), -m_fmTXLevel(0U), +m_rxLevel(0.0F), +m_cwIdTXLevel(0.0F), +m_dstarTXLevel(0.0F), +m_dmrTXLevel(0.0F), +m_ysfTXLevel(0.0F), +m_p25TXLevel(0.0F), +m_nxdnTXLevel(0.0F), +m_pocsagTXLevel(0.0F), +m_fmTXLevel(0.0F), +m_ax25TXLevel(0.0F), +m_rfLevel(0.0F), m_trace(trace), m_debug(debug), m_rxFrequency(0U), @@ -177,6 +179,8 @@ m_lockout(false), m_error(false), m_mode(MODE_IDLE), m_hwType(HWT_UNKNOWN), +m_ax25RXTwist(0), +m_ax25TXTwist(0), m_fmCallsign(), m_fmCallsignSpeed(20U), m_fmCallsignFrequency(1000U), @@ -248,7 +252,7 @@ void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, m_ax25Enabled = ax25Enabled; } -void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel) +void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel, float ax25TXLevel) { m_rxLevel = rxLevel; m_cwIdTXLevel = cwIdTXLevel; @@ -259,6 +263,7 @@ void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, flo m_nxdnTXLevel = nxdnTXLevel; m_pocsagTXLevel = pocsagTXLevel; m_fmTXLevel = fmTXLevel; + m_ax25TXLevel = ax25TXLevel; } void CModem::setDMRParams(unsigned int colorCode) @@ -284,6 +289,12 @@ void CModem::setNXDNParams(unsigned int txHang) m_nxdnTXHang = txHang; } +void CModem::setAX25Params(int rxTwist, int txTwist) +{ + m_ax25RXTwist = rxTwist; + m_ax25TXTwist = txTwist; +} + void CModem::setTransparentDataParams(unsigned int sendFrameType) { m_sendTransparentDataFrameType = sendFrameType; @@ -1551,7 +1562,7 @@ bool CModem::setConfig() buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 24U; + buffer[1U] = 27U; buffer[2U] = MMDVM_SET_CONFIG; @@ -1621,10 +1632,16 @@ bool CModem::setConfig() buffer[23U] = (unsigned char)m_nxdnTXHang; - // CUtils::dump(1U, "Written", buffer, 24U); + buffer[24U] = (unsigned char)(m_ax25TXLevel * 2.55F + 0.5F); - int ret = m_serial->write(buffer, 24U); - if (ret != 24) + buffer[25U] = (unsigned char)(m_ax25RXTwist + 128); + + buffer[26U] = (unsigned char)(m_ax25TXTwist + 128); + + // CUtils::dump(1U, "Written", buffer, 27U); + + int ret = m_serial->write(buffer, 27U); + if (ret != 27) return false; unsigned int count = 0U; diff --git a/Modem.h b/Modem.h index ea01945..1f8b291 100644 --- a/Modem.h +++ b/Modem.h @@ -48,11 +48,12 @@ public: virtual void setSerialParams(const std::string& protocol, unsigned int address); virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled); - virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel); + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel); virtual void setDMRParams(unsigned int colorCode); virtual void setYSFParams(bool loDev, unsigned int txHang); virtual void setP25Params(unsigned int txHang); virtual void setNXDNParams(unsigned int txHang); + virtual void setAX25Params(int rxTwist, int txTwist); virtual void setTransparentDataParams(unsigned int sendFrameType); virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); @@ -146,6 +147,7 @@ private: float m_nxdnTXLevel; float m_pocsagTXLevel; float m_fmTXLevel; + float m_ax25TXLevel; float m_rfLevel; bool m_trace; bool m_debug; @@ -201,6 +203,8 @@ private: bool m_error; unsigned char m_mode; HW_TYPE m_hwType; + int m_ax25RXTwist; + int m_ax25TXTwist; std::string m_fmCallsign; unsigned int m_fmCallsignSpeed; diff --git a/Version.h b/Version.h index 7cfe66a..5f48e8f 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200620"; +const char* VERSION = "20200621"; #endif From 38f59236aeebac5415d01f28325cb43773966693 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 21 Jun 2020 14:28:40 +0100 Subject: [PATCH 062/115] Add the KISS encoding. --- AX25Network.cpp | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/AX25Network.cpp b/AX25Network.cpp index 5330ec8..82c341b 100644 --- a/AX25Network.cpp +++ b/AX25Network.cpp @@ -25,7 +25,14 @@ #include #include -const unsigned int BUFFER_LENGTH = 200U; +const unsigned int BUFFER_LENGTH = 500U; + +const unsigned char AX25_KISS_DATA = 0x00U; + +const unsigned char AX25_FEND = 0xC0U; +const unsigned char AX25_FESC = 0xDBU; +const unsigned char AX25_TFEND = 0xDCU; +const unsigned char AX25_TFESC = 0xDDU; CAX25Network::CAX25Network(const std::string& port, unsigned int speed, bool debug) : m_serial(port, SERIAL_SPEED(speed), false), // XXX @@ -62,20 +69,36 @@ bool CAX25Network::write(const unsigned char* data, unsigned int length) { assert(data != NULL); - unsigned char buffer[110U]; - ::memset(buffer, 0x00U, 110U); + m_txLength = 0U; + m_txOffset = 0U; - buffer[0U] = 'A'; - buffer[1U] = 'X'; - buffer[2U] = '2'; - buffer[3U] = '5'; + m_txData[m_txLength++] = AX25_FEND; + m_txData[m_txLength++] = AX25_KISS_DATA; - ::memcpy(buffer + 4U, data, length); + for (unsigned int i = 0U; i < length; i++) { + unsigned char c = data[i]; + + switch (c) { + case AX25_FEND: + m_txData[m_txLength++] = AX25_FESC; + m_txData[m_txLength++] = AX25_TFEND; + break; + case AX25_FESC: + m_txData[m_txLength++] = AX25_FESC; + m_txData[m_txLength++] = AX25_TFESC; + break; + default: + m_txData[m_txLength++] = c; + break; + } + } + + m_txData[m_txLength++] = AX25_FEND; if (m_debug) - CUtils::dump(1U, "AX25 Network Data Sent", buffer, length + 4U); + CUtils::dump(1U, "AX25 Network Data Sent", m_txData, m_txLength); - return m_socket.write(buffer, length + 4U, m_address, m_port); + return m_serial.write(m_txData, m_txLength); } void CAX25Network::reset() From 27c9ad43eccead2773013b8691789d49cb4170ff Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 21 Jun 2020 17:22:27 +0100 Subject: [PATCH 063/115] Add KISS receive. --- AX25Network.cpp | 100 ++++++++++++++++++++++++++++++++++++++++-------- AX25Network.h | 4 +- 2 files changed, 86 insertions(+), 18 deletions(-) diff --git a/AX25Network.cpp b/AX25Network.cpp index 82c341b..7da9a4c 100644 --- a/AX25Network.cpp +++ b/AX25Network.cpp @@ -37,11 +37,9 @@ const unsigned char AX25_TFESC = 0xDDU; CAX25Network::CAX25Network(const std::string& port, unsigned int speed, bool debug) : m_serial(port, SERIAL_SPEED(speed), false), // XXX m_txData(NULL), -m_txLength(0U), -m_txOffset(0U), m_rxData(NULL), m_rxLength(0U), -m_rxComplete(false), +m_rxLastChar(0U), m_debug(debug), m_enabled(false) { @@ -69,36 +67,103 @@ bool CAX25Network::write(const unsigned char* data, unsigned int length) { assert(data != NULL); - m_txLength = 0U; - m_txOffset = 0U; + if (!m_enabled) + return true; - m_txData[m_txLength++] = AX25_FEND; - m_txData[m_txLength++] = AX25_KISS_DATA; + unsigned int txLength = 0U; + + m_txData[txLength++] = AX25_FEND; + m_txData[txLength++] = AX25_KISS_DATA; for (unsigned int i = 0U; i < length; i++) { unsigned char c = data[i]; switch (c) { case AX25_FEND: - m_txData[m_txLength++] = AX25_FESC; - m_txData[m_txLength++] = AX25_TFEND; + m_txData[txLength++] = AX25_FESC; + m_txData[txLength++] = AX25_TFEND; break; case AX25_FESC: - m_txData[m_txLength++] = AX25_FESC; - m_txData[m_txLength++] = AX25_TFESC; + m_txData[txLength++] = AX25_FESC; + m_txData[txLength++] = AX25_TFESC; break; default: - m_txData[m_txLength++] = c; + m_txData[txLength++] = c; break; } } - m_txData[m_txLength++] = AX25_FEND; + m_txData[txLength++] = AX25_FEND; if (m_debug) - CUtils::dump(1U, "AX25 Network Data Sent", m_txData, m_txLength); + CUtils::dump(1U, "AX25 Network Data Sent", m_txData, txLength); - return m_serial.write(m_txData, m_txLength); + return m_serial.write(m_txData, txLength); +} + +unsigned int CAX25Network::read(unsigned char* data, unsigned int length) +{ + assert(data != NULL); + + bool complete = false; + + unsigned char c; + while (m_serial.read(&c, 1U) > 0U) { + if (m_rxLength == 0U && c == AX25_FEND) + m_rxData[m_rxLength++] = c; + else if (m_rxLength > 0U) + m_rxData[m_rxLength++] = c; + + if (m_rxLength > 1U && c == AX25_FEND) { + complete = true; + break; + } + } + + if (!m_enabled) + return 0U; + + if (!complete) + return 0U; + + if (m_rxLength == 0U) + return 0U; + + if (m_rxData[1U] != AX25_KISS_DATA) { + m_rxLength = 0U; + return 0U; + } + + complete = false; + + unsigned int dataLen = 0U; + for (unsigned int i = 2U; i < m_rxLength; i++) { + unsigned char c = m_rxData[i]; + + if (c == AX25_FEND) { + complete = true; + break; + } else if (c == AX25_TFEND && m_rxLastChar == AX25_FESC) { + data[dataLen++] = AX25_FEND; + } else if (c == AX25_TFESC && m_rxLastChar == AX25_FESC) { + data[dataLen++] = AX25_FESC; + } else if (c != AX25_FESC) { + data[dataLen++] = c; + } + + m_rxLastChar = c; + } + + if (!complete) + return 0U; + + if (m_debug) + CUtils::dump(1U, "AX25 Network Data Received", m_rxData, m_rxLength); + + m_rxLength = 0U; + m_rxLastChar = 0U; + + return dataLen; } void CAX25Network::reset() @@ -115,4 +180,9 @@ void CAX25Network::close() void CAX25Network::enable(bool enabled) { m_enabled = enabled; + + if (enabled && !m_enabled) { + m_rxLastChar = 0U; + m_rxLength = 0U; + } } diff --git a/AX25Network.h b/AX25Network.h index 9c9cecb..37804d6 100644 --- a/AX25Network.h +++ b/AX25Network.h @@ -44,11 +44,9 @@ public: private: CSerialController m_serial; unsigned char* m_txData; - unsigned int m_txLength; - unsigned int m_txOffset; unsigned char* m_rxData; unsigned int m_rxLength; - bool m_rxComplete; + unsigned char m_rxLastChar; bool m_debug; bool m_enabled; }; From c026471aec8b5618b806a1f3c1a1c907200b2c7a Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 21 Jun 2020 18:53:38 +0100 Subject: [PATCH 064/115] Start the AX.25 transmit path development. --- AX25Control.cpp | 20 +++++++++++++++++++- AX25Control.h | 2 ++ AX25Network.cpp | 2 +- MMDVMHost.cpp | 16 +++++++++++++++- Modem.h | 2 ++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/AX25Control.cpp b/AX25Control.cpp index 563fa42..00cfc0d 100644 --- a/AX25Control.cpp +++ b/AX25Control.cpp @@ -49,7 +49,7 @@ bool CAX25Control::writeModem(unsigned char *data, unsigned int len) if (m_trace) decode(data, len); - CUtils::dump(1U, "AX.25 raw packet", data, len); + CUtils::dump(1U, "AX.25 received packet", data, len); if (m_network == NULL) return true; @@ -57,6 +57,24 @@ bool CAX25Control::writeModem(unsigned char *data, unsigned int len) return m_network->write(data, len); } +unsigned int CAX25Control::readModem(unsigned char* data) +{ + assert(data != NULL); + + if (m_network == NULL) + return 0U; + + if (!m_enabled) + return 0U; + + unsigned int length = m_network->read(data, 500U); + + if (length > 0U) + CUtils::dump(1U, "AX.25 transmitted packet", data, length); + + return length; +} + bool CAX25Control::openFile() { if (m_fp != NULL) diff --git a/AX25Control.h b/AX25Control.h index b0217df..b4fed2a 100644 --- a/AX25Control.h +++ b/AX25Control.h @@ -30,6 +30,8 @@ public: bool writeModem(unsigned char* data, unsigned int len); + unsigned int readModem(unsigned char* data); + void enable(bool enabled); private: diff --git a/AX25Network.cpp b/AX25Network.cpp index 7da9a4c..806844f 100644 --- a/AX25Network.cpp +++ b/AX25Network.cpp @@ -181,7 +181,7 @@ void CAX25Network::enable(bool enabled) { m_enabled = enabled; - if (enabled && !m_enabled) { + if (enabled != m_enabled) { m_rxLastChar = 0U; m_rxLength = 0U; } diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 12e71b5..6c10567 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -688,7 +688,7 @@ int CMMDVMHost::run() m_ump->setCD(cd); } - unsigned char data[220U]; + unsigned char data[500U]; unsigned int len; bool ret; @@ -989,6 +989,20 @@ int CMMDVMHost::run() } } + if (m_ax25 != NULL) { + ret = m_modem->hasAX25Space(); + if (ret) { + len = m_ax25->readModem(data); + if (len > 0U) { + if (m_mode == MODE_IDLE || m_mode == MODE_FM) { + m_modem->writeAX25Data(data, len); + } else if (m_mode != MODE_LOCKOUT) { + LogWarning("AX.25 data received when in mode %u", m_mode); + } + } + } + } + if (transparentSocket != NULL) { in_addr address; unsigned int port = 0U; diff --git a/Modem.h b/Modem.h index 1f8b291..29ecbe4 100644 --- a/Modem.h +++ b/Modem.h @@ -80,6 +80,7 @@ public: virtual bool hasP25Space() const; virtual bool hasNXDNSpace() const; virtual bool hasPOCSAGSpace() const; + virtual bool hasAX25Space() const; virtual bool hasTX() const; virtual bool hasCD() const; @@ -95,6 +96,7 @@ public: virtual bool writeP25Data(const unsigned char* data, unsigned int length); virtual bool writeNXDNData(const unsigned char* data, unsigned int length); virtual bool writePOCSAGData(const unsigned char* data, unsigned int length); + virtual bool writeAX25Data(const unsigned char* data, unsigned int length); virtual bool writeTransparentData(const unsigned char* data, unsigned int length); From 92ceba052a996b7925b28c17ee28447939744324 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 21 Jun 2020 21:16:31 +0100 Subject: [PATCH 065/115] Add AX.25 transmit functionality to the modem handler. --- AX25Control.cpp | 1 + AX25Defines.h | 39 +++++++++++++++++++++++++ AX25Network.cpp | 7 +---- MMDVMHost.vcxproj | 1 + MMDVMHost.vcxproj.filters | 3 ++ Modem.cpp | 61 ++++++++++++++++++++++++++++++++++++++- Modem.h | 2 ++ 7 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 AX25Defines.h diff --git a/AX25Control.cpp b/AX25Control.cpp index 00cfc0d..3b108fc 100644 --- a/AX25Control.cpp +++ b/AX25Control.cpp @@ -12,6 +12,7 @@ */ #include "AX25Control.h" +#include "AX25Defines.h" #include "Utils.h" #include "Log.h" diff --git a/AX25Defines.h b/AX25Defines.h new file mode 100644 index 0000000..1cb145e --- /dev/null +++ b/AX25Defines.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#if !defined(AX25Defines_H) +#define AX25Defines_H + +const unsigned int AX25_CALLSIGN_TEXT_LENGTH = 6U; +const unsigned int AX25_SSID_LENGTH = 1U; +const unsigned int AX25_CALLSIGN_LENGTH = 7U; + +const unsigned int AX25_MAX_DIGIPEATERS = 6U; + +const unsigned char AX25_PID_NOL3 = 0xF0U; + +const unsigned int AX25_MAX_FRAME_LENGTH_BYTES = 300U; + +const unsigned char AX25_KISS_DATA = 0x00U; + +const unsigned char AX25_FEND = 0xC0U; +const unsigned char AX25_FESC = 0xDBU; +const unsigned char AX25_TFEND = 0xDCU; +const unsigned char AX25_TFESC = 0xDDU; + +#endif diff --git a/AX25Network.cpp b/AX25Network.cpp index 806844f..2f25a47 100644 --- a/AX25Network.cpp +++ b/AX25Network.cpp @@ -17,6 +17,7 @@ */ #include "AX25Network.h" +#include "AX25Defines.h" #include "Defines.h" #include "Utils.h" #include "Log.h" @@ -27,12 +28,6 @@ const unsigned int BUFFER_LENGTH = 500U; -const unsigned char AX25_KISS_DATA = 0x00U; - -const unsigned char AX25_FEND = 0xC0U; -const unsigned char AX25_FESC = 0xDBU; -const unsigned char AX25_TFEND = 0xDCU; -const unsigned char AX25_TFESC = 0xDDU; CAX25Network::CAX25Network(const std::string& port, unsigned int speed, bool debug) : m_serial(port, SERIAL_SPEED(speed), false), // XXX diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 693adb1..535e686 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -154,6 +154,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index b4bee02..d5c8464 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -311,6 +311,9 @@ Header Files + + Header Files + diff --git a/Modem.cpp b/Modem.cpp index f1c6449..1ed2dee 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -22,6 +22,7 @@ #include "YSFDefines.h" #include "P25Defines.h" #include "NXDNDefines.h" +#include "AX25Defines.h" #include "POCSAGDefines.h" #include "Thread.h" #include "Modem.h" @@ -160,6 +161,7 @@ m_rxNXDNData(1000U, "Modem RX NXDN"), m_txNXDNData(1000U, "Modem TX NXDN"), m_txPOCSAGData(1000U, "Modem TX POCSAG"), m_rxAX25Data(1000U, "Modem RX AX.25"), +m_txAX25Data(1000U, "Modem TX AX.25"), m_rxTransparentData(1000U, "Modem RX Transparent"), m_txTransparentData(1000U, "Modem TX Transparent"), m_sendTransparentDataFrameType(0U), @@ -173,6 +175,7 @@ m_ysfSpace(0U), m_p25Space(0U), m_nxdnSpace(0U), m_pocsagSpace(0U), +m_ax25Space(0U), m_tx(false), m_cd(false), m_lockout(false), @@ -621,6 +624,7 @@ void CModem::clock(unsigned int ms) m_p25Space = 0U; m_nxdnSpace = 0U; m_pocsagSpace = 0U; + m_ax25Space = 0U; m_mode = m_buffer[m_offset + 1U]; @@ -657,9 +661,11 @@ void CModem::clock(unsigned int ms) m_nxdnSpace = m_buffer[m_offset + 8U]; if (m_length > (m_offset + 9U)) m_pocsagSpace = m_buffer[m_offset + 9U]; + if (m_length > (m_offset + 10U)) + m_ax25Space = m_buffer[m_offset + 10U] * 8U; m_inactivityTimer.start(); - // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, int(m_lockout), int(m_cd)); + // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, m_ax25Space, int(m_lockout), int(m_cd)); } break; @@ -863,6 +869,23 @@ void CModem::clock(unsigned int ms) m_pocsagSpace--; } + if (m_ax25Space > 1U && !m_txAX25Data.isEmpty()) { + unsigned char len = 0U; + m_txAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); + m_txAX25Data.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX AX.25 Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing AX.25 data to the MMDVM"); + + m_playoutTimer.start(); + + m_ax25Space -= len; + } + if (!m_txTransparentData.isEmpty()) { unsigned char len = 0U; m_txTransparentData.getData(&len, 1U); @@ -1225,6 +1248,42 @@ bool CModem::writePOCSAGData(const unsigned char* data, unsigned int length) return true; } +bool CModem::hasAX25Space() const +{ + unsigned int space = m_txAX25Data.freeSpace() / (AX25_MAX_FRAME_LENGTH_BYTES + 5U); + + return space > 1U; +} + +bool CModem::writeAX25Data(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[500U]; + + unsigned int len; + if (length > 252U) { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 0U; + buffer[2U] = (length + 4U) - 255U; + buffer[3U] = MMDVM_AX25_DATA; + ::memcpy(buffer + 4U, data, length); + len = length + 4U; + } else { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_AX25_DATA; + ::memcpy(buffer + 3U, data, length); + len = length + 3U; + } + + m_txAX25Data.addData((unsigned char*)&len, sizeof(unsigned int)); + m_txAX25Data.addData(buffer, len); + + return true; +} + bool CModem::writeTransparentData(const unsigned char* data, unsigned int length) { assert(data != NULL); diff --git a/Modem.h b/Modem.h index 29ecbe4..a6e711e 100644 --- a/Modem.h +++ b/Modem.h @@ -186,6 +186,7 @@ private: CRingBuffer m_txNXDNData; CRingBuffer m_txPOCSAGData; CRingBuffer m_rxAX25Data; + CRingBuffer m_txAX25Data; CRingBuffer m_rxTransparentData; CRingBuffer m_txTransparentData; unsigned int m_sendTransparentDataFrameType; @@ -199,6 +200,7 @@ private: unsigned int m_p25Space; unsigned int m_nxdnSpace; unsigned int m_pocsagSpace; + unsigned int m_ax25Space; bool m_tx; bool m_cd; bool m_lockout; From d8716adc434f3a254d62439aac677ca02584d276 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 24 Jun 2020 11:18:12 +0100 Subject: [PATCH 066/115] Change the free space handling for AX25. --- Modem.cpp | 4 ++-- Version.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modem.cpp b/Modem.cpp index 1ed2dee..daee6c3 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -869,7 +869,7 @@ void CModem::clock(unsigned int ms) m_pocsagSpace--; } - if (m_ax25Space > 1U && !m_txAX25Data.isEmpty()) { + if (m_ax25Space > 0U && !m_txAX25Data.isEmpty()) { unsigned char len = 0U; m_txAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); m_txAX25Data.getData(m_buffer, len); @@ -883,7 +883,7 @@ void CModem::clock(unsigned int ms) m_playoutTimer.start(); - m_ax25Space -= len; + m_ax25Space = 0U; } if (!m_txTransparentData.isEmpty()) { diff --git a/Version.h b/Version.h index 5f48e8f..9bb9c4a 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200621"; +const char* VERSION = "20200624"; #endif From 96a8ec0e354d1844648ce1f0900759e9bd651b89 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 24 Jun 2020 13:22:55 +0100 Subject: [PATCH 067/115] Change the maximum packet length. --- AX25Defines.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AX25Defines.h b/AX25Defines.h index 1cb145e..a0f4c80 100644 --- a/AX25Defines.h +++ b/AX25Defines.h @@ -27,8 +27,8 @@ const unsigned int AX25_MAX_DIGIPEATERS = 6U; const unsigned char AX25_PID_NOL3 = 0xF0U; -const unsigned int AX25_MAX_FRAME_LENGTH_BYTES = 300U; - +const unsigned int AX25_MAX_FRAME_LENGTH_BYTES = 330U; // Callsign (7) + Callsign (7) + 8 Digipeaters (56) + + // Control (1) + PID (1) + Data (256) + Checksum (2) const unsigned char AX25_KISS_DATA = 0x00U; const unsigned char AX25_FEND = 0xC0U; From aec1ae74f799aad24d771ad1b2e9951252cc4532 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 25 Jun 2020 20:40:13 +0200 Subject: [PATCH 068/115] add missing files in makefile --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8b7136f..985ab3c 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,9 @@ OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o From 63215634968f2fae813b4b2f4e6924254f338489 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 25 Jun 2020 21:13:28 +0200 Subject: [PATCH 069/115] add missing files in makefiles --- Makefile.Pi | 6 +++--- Makefile.Pi.Adafruit | 4 ++-- Makefile.Pi.HD44780 | 4 ++-- Makefile.Pi.OLED | 4 ++-- Makefile.Pi.PCF8574 | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Makefile.Pi b/Makefile.Pi index c4aea75..5631c0b 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -10,9 +10,9 @@ OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 1c98ef2..4a28051 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -11,8 +11,8 @@ OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 3ade129..f5b6dc0 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -10,8 +10,8 @@ OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 3de00ec..d49d135 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -11,8 +11,8 @@ OBJECTS = AX25Control.o AX25Network.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 OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + NXDNLayer3.o NXDNIcomNetwork.o NXDNKenwoodNetwork.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index c58b728..8e9518a 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -11,8 +11,8 @@ OBJECTS = AX25Control.o AX25Network.o \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o From cb51a145753870699a2c725dc711f2233e47ed73 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 25 Jun 2020 21:17:38 +0100 Subject: [PATCH 070/115] Create a pseudo TTY for the AX25 Network. --- AX25Network.h | 16 ++-- MMDVMHost.vcxproj | 2 + MMDVMHost.vcxproj.filters | 6 ++ Makefile | 2 +- PseudoTTYController.cpp | 161 ++++++++++++++++++++++++++++++++++++++ PseudoTTYController.h | 40 ++++++++++ 6 files changed, 218 insertions(+), 9 deletions(-) create mode 100644 PseudoTTYController.cpp create mode 100644 PseudoTTYController.h diff --git a/AX25Network.h b/AX25Network.h index 37804d6..34aa43b 100644 --- a/AX25Network.h +++ b/AX25Network.h @@ -19,7 +19,7 @@ #ifndef AX25Network_H #define AX25Network_H -#include "SerialController.h" +#include "PseudoTTYController.h" #include #include @@ -42,13 +42,13 @@ public: void close(); private: - CSerialController m_serial; - unsigned char* m_txData; - unsigned char* m_rxData; - unsigned int m_rxLength; - unsigned char m_rxLastChar; - bool m_debug; - bool m_enabled; + CPseudoTTYController m_serial; + unsigned char* m_txData; + unsigned char* m_rxData; + unsigned int m_rxLength; + unsigned char m_rxLastChar; + bool m_debug; + bool m_enabled; }; #endif diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 8c3375b..7f64db6 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -227,6 +227,7 @@ + @@ -326,6 +327,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index a144fce..00ed473 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -320,6 +320,9 @@ Header Files + + Header Files + @@ -601,5 +604,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index 985ab3c..3f34ccd 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ OBJECTS = AX25Control.o AX25Network.o \ DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/PseudoTTYController.cpp b/PseudoTTYController.cpp new file mode 100644 index 0000000..a21fb3d --- /dev/null +++ b/PseudoTTYController.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2002-2004,2007-2011,2013,2014-2017,2019,2020 by Jonathan Naylor G4KLX + * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX + * + * 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. + */ + +#if !defined(_WIN32) && !defined(_WIN64) + +#include "SerialController.h" +#include "Log.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +CPseudoTTYController::CPseudoTTYController(const std::string& device, unsigned int speed, bool assertRTS) : +CSerialController(device, speed, assertRTS) +{ +} + +CPseudoTTYController::~CPseudoTTYController() +{ +} + +bool CPseudoTTYController::open() +{ + assert(m_fd == -1); + + m_fd = ::posix_openpt(O_RDWR | O_NOCTTY | O_NDELAY); + if (m_fd < 0) { + LogError("Cannot open device - %s", m_device.c_str()); + return false; + } + + std::string slave = std::string(::ptsname(m_fd)); + + // Remove any previous stale symlink + ::unlink(m_device.c_str()); + + int ret = ::symlink(slave.c_str(), m_device.c_str()); + if (ret != 0) { + LogError("Cannot make symlink to %s with %s", slave.c_str(), m_device.c_str()); + close(); + return false; + } + + m_device = std::string(::ttyname(m_fd)); + + if (::isatty(m_fd)) { + termios termios; + if (::tcgetattr(m_fd, &termios) < 0) { + LogError("Cannot get the attributes for %s", m_device.c_str()); + ::close(m_fd); + return false; + } + + termios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK); + termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL); + termios.c_iflag &= ~(IXON | IXOFF | IXANY); + termios.c_oflag &= ~(OPOST); + termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS); + termios.c_cflag |= (CS8 | CLOCAL | CREAD); + termios.c_lflag &= ~(ISIG | ICANON | IEXTEN); + termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); + termios.c_cc[VMIN] = 0; + termios.c_cc[VTIME] = 10; + + switch (m_speed) { + case 1200U: + ::cfsetospeed(&termios, B1200); + ::cfsetispeed(&termios, B1200); + break; + case 2400U: + ::cfsetospeed(&termios, B2400); + ::cfsetispeed(&termios, B2400); + break; + case 4800U: + ::cfsetospeed(&termios, B4800); + ::cfsetispeed(&termios, B4800); + break; + case 9600U: + ::cfsetospeed(&termios, B9600); + ::cfsetispeed(&termios, B9600); + break; + case 19200U: + ::cfsetospeed(&termios, B19200); + ::cfsetispeed(&termios, B19200); + break; + case 38400U: + ::cfsetospeed(&termios, B38400); + ::cfsetispeed(&termios, B38400); + break; + case 115200U: + ::cfsetospeed(&termios, B115200); + ::cfsetispeed(&termios, B115200); + break; + case 230400U: + ::cfsetospeed(&termios, B230400); + ::cfsetispeed(&termios, B230400); + break; + case 460800U: + ::cfsetospeed(&termios, B460800); + ::cfsetispeed(&termios, B460800); + break; + default: + LogError("Unsupported serial port speed - %u", m_speed); + ::close(m_fd); + return false; + } + + if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) { + LogError("Cannot set the attributes for %s", m_device.c_str()); + ::close(m_fd); + return false; + } + + if (m_assertRTS) { + unsigned int y; + if (::ioctl(m_fd, TIOCMGET, &y) < 0) { + LogError("Cannot get the control attributes for %s", m_device.c_str()); + ::close(m_fd); + return false; + } + + y |= TIOCM_RTS; + + if (::ioctl(m_fd, TIOCMSET, &y) < 0) { + LogError("Cannot set the control attributes for %s", m_device.c_str()); + ::close(m_fd); + return false; + } + } + } + + return true; +} + +#endif + diff --git a/PseudoTTYController.h b/PseudoTTYController.h new file mode 100644 index 0000000..9f9a921 --- /dev/null +++ b/PseudoTTYController.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef PseudoTTYController_H +#define PseudoTTYController_H + +#if !defined(_WIN32) && !defined(_WIN64) + +#include + +#include "SerialController.h" + +class CPseudoTTYController : public CSerialController { +public: + CPseudoTTYController(const std::string& device, unsigned int speed, bool assertRTS = false); + virtual ~CPseudoTTYController(); + + virtual bool open(); + +protected: +}; + +#endif + +#endif From e164538b09ef4bcd4dc86fdaf208ebda8a412271 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 25 Jun 2020 21:23:43 +0100 Subject: [PATCH 071/115] Fix compilation bugs. --- AX25Network.cpp | 2 +- Conf.h | 10 +++++----- PseudoTTYController.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/AX25Network.cpp b/AX25Network.cpp index 192b6df..dec4ea3 100644 --- a/AX25Network.cpp +++ b/AX25Network.cpp @@ -103,7 +103,7 @@ unsigned int CAX25Network::read(unsigned char* data, unsigned int length) bool complete = false; unsigned char c; - while (m_serial.read(&c, 1U) > 0U) { + while (m_serial.read(&c, 1U) > 0) { if (m_rxLength == 0U && c == AX25_FEND) m_rxData[m_rxLength++] = c; else if (m_rxLength > 0U) diff --git a/Conf.h b/Conf.h index c3c0c16..04c2be8 100644 --- a/Conf.h +++ b/Conf.h @@ -470,11 +470,6 @@ private: bool m_pocsagEnabled; unsigned int m_pocsagFrequency; - bool m_ax25Enabled; - int m_ax25RXTwist; - int m_ax25TXTwist; - bool m_ax25Trace; - bool m_fmEnabled; std::string m_fmCallsign; unsigned int m_fmCallsignSpeed; @@ -509,6 +504,11 @@ private: unsigned int m_fmExtAudioBoost; unsigned int m_fmModeHang; + bool m_ax25Enabled; + int m_ax25RXTwist; + int m_ax25TXTwist; + bool m_ax25Trace; + bool m_dstarNetworkEnabled; std::string m_dstarGatewayAddress; unsigned int m_dstarGatewayPort; diff --git a/PseudoTTYController.cpp b/PseudoTTYController.cpp index a21fb3d..e853c52 100644 --- a/PseudoTTYController.cpp +++ b/PseudoTTYController.cpp @@ -19,7 +19,7 @@ #if !defined(_WIN32) && !defined(_WIN64) -#include "SerialController.h" +#include "PseudoTTYController.h" #include "Log.h" #include From f151ca6c1ae21e0ea8c6dbc37294b4f56c461fab Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 26 Jun 2020 21:17:14 +0200 Subject: [PATCH 072/115] Make pty work --- Makefile | 2 +- PseudoTTYController.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 3f34ccd..bd07c05 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC = cc CXX = c++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -LIBS = -lpthread +LIBS = -lpthread -lutil LDFLAGS = -g OBJECTS = AX25Control.o AX25Network.o \ diff --git a/PseudoTTYController.cpp b/PseudoTTYController.cpp index e853c52..71196bd 100644 --- a/PseudoTTYController.cpp +++ b/PseudoTTYController.cpp @@ -33,6 +33,7 @@ #include #include #include +#include CPseudoTTYController::CPseudoTTYController(const std::string& device, unsigned int speed, bool assertRTS) : @@ -48,9 +49,11 @@ bool CPseudoTTYController::open() { assert(m_fd == -1); - m_fd = ::posix_openpt(O_RDWR | O_NOCTTY | O_NDELAY); - if (m_fd < 0) { - LogError("Cannot open device - %s", m_device.c_str()); + int slavefd; + char buf[300]; + int result = ::openpty(&m_fd, &slavefd, buf, NULL,NULL); + if (result < 0) { + LogError("Cannot open device - %s - Errno : %d", m_device.c_str(), errno); return false; } From d1a809808b5c686e708c47d8e9a660eb9f928edd Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 27 Jun 2020 22:33:24 +0100 Subject: [PATCH 073/115] Rationalise the pseudo tty handling. --- PseudoTTYController.cpp | 112 ++++------------------- PseudoTTYController.h | 5 +- SerialController.cpp | 190 +++++++++++++++++++++------------------- SerialController.h | 1 + 4 files changed, 120 insertions(+), 188 deletions(-) diff --git a/PseudoTTYController.cpp b/PseudoTTYController.cpp index 71196bd..67df4a4 100644 --- a/PseudoTTYController.cpp +++ b/PseudoTTYController.cpp @@ -36,8 +36,9 @@ #include -CPseudoTTYController::CPseudoTTYController(const std::string& device, unsigned int speed, bool assertRTS) : -CSerialController(device, speed, assertRTS) +CPseudoTTYController::CPseudoTTYController(const std::string& symlink, unsigned int speed, bool assertRTS) : +CSerialController("", speed, assertRTS), +m_symlink(symlink) { } @@ -50,114 +51,35 @@ bool CPseudoTTYController::open() assert(m_fd == -1); int slavefd; - char buf[300]; - int result = ::openpty(&m_fd, &slavefd, buf, NULL,NULL); + char slave[300]; + int result = ::openpty(&m_fd, &slavefd, slave, NULL, NULL); if (result < 0) { - LogError("Cannot open device - %s - Errno : %d", m_device.c_str(), errno); + LogError("Cannot open the pseudo tty - errno : %d", errno); return false; } - std::string slave = std::string(::ptsname(m_fd)); - // Remove any previous stale symlink - ::unlink(m_device.c_str()); + ::unlink(m_symlink.c_str()); - int ret = ::symlink(slave.c_str(), m_device.c_str()); + int ret = ::symlink(slave, m_symlink.c_str()); if (ret != 0) { - LogError("Cannot make symlink to %s with %s", slave.c_str(), m_device.c_str()); + LogError("Cannot make symlink to %s with %s", slave, m_symlink.c_str()); close(); return false; } + LogMessage("Made symbolic link from %s to %s", slave, m_symlink.c_str()); + m_device = std::string(::ttyname(m_fd)); - if (::isatty(m_fd)) { - termios termios; - if (::tcgetattr(m_fd, &termios) < 0) { - LogError("Cannot get the attributes for %s", m_device.c_str()); - ::close(m_fd); - return false; - } + return setRaw(); +} - termios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK); - termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL); - termios.c_iflag &= ~(IXON | IXOFF | IXANY); - termios.c_oflag &= ~(OPOST); - termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS); - termios.c_cflag |= (CS8 | CLOCAL | CREAD); - termios.c_lflag &= ~(ISIG | ICANON | IEXTEN); - termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); - termios.c_cc[VMIN] = 0; - termios.c_cc[VTIME] = 10; +void CPseudoTTYController::close() +{ + CSerialController::close(); - switch (m_speed) { - case 1200U: - ::cfsetospeed(&termios, B1200); - ::cfsetispeed(&termios, B1200); - break; - case 2400U: - ::cfsetospeed(&termios, B2400); - ::cfsetispeed(&termios, B2400); - break; - case 4800U: - ::cfsetospeed(&termios, B4800); - ::cfsetispeed(&termios, B4800); - break; - case 9600U: - ::cfsetospeed(&termios, B9600); - ::cfsetispeed(&termios, B9600); - break; - case 19200U: - ::cfsetospeed(&termios, B19200); - ::cfsetispeed(&termios, B19200); - break; - case 38400U: - ::cfsetospeed(&termios, B38400); - ::cfsetispeed(&termios, B38400); - break; - case 115200U: - ::cfsetospeed(&termios, B115200); - ::cfsetispeed(&termios, B115200); - break; - case 230400U: - ::cfsetospeed(&termios, B230400); - ::cfsetispeed(&termios, B230400); - break; - case 460800U: - ::cfsetospeed(&termios, B460800); - ::cfsetispeed(&termios, B460800); - break; - default: - LogError("Unsupported serial port speed - %u", m_speed); - ::close(m_fd); - return false; - } - - if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) { - LogError("Cannot set the attributes for %s", m_device.c_str()); - ::close(m_fd); - return false; - } - - if (m_assertRTS) { - unsigned int y; - if (::ioctl(m_fd, TIOCMGET, &y) < 0) { - LogError("Cannot get the control attributes for %s", m_device.c_str()); - ::close(m_fd); - return false; - } - - y |= TIOCM_RTS; - - if (::ioctl(m_fd, TIOCMSET, &y) < 0) { - LogError("Cannot set the control attributes for %s", m_device.c_str()); - ::close(m_fd); - return false; - } - } - } - - return true; + ::unlink(m_symlink.c_str()); } #endif diff --git a/PseudoTTYController.h b/PseudoTTYController.h index 9f9a921..ccf6ba1 100644 --- a/PseudoTTYController.h +++ b/PseudoTTYController.h @@ -27,12 +27,15 @@ class CPseudoTTYController : public CSerialController { public: - CPseudoTTYController(const std::string& device, unsigned int speed, bool assertRTS = false); + CPseudoTTYController(const std::string& symlink, unsigned int speed, bool assertRTS = false); virtual ~CPseudoTTYController(); virtual bool open(); + virtual void close(); + protected: + std::string m_symlink; }; #endif diff --git a/SerialController.cpp b/SerialController.cpp index 970501a..10c634a 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -247,101 +247,107 @@ bool CSerialController::open() return false; } - if (::isatty(m_fd)) { - termios termios; - if (::tcgetattr(m_fd, &termios) < 0) { - LogError("Cannot get the attributes for %s", m_device.c_str()); - ::close(m_fd); - return false; - } + if (::isatty(m_fd)) + return setRaw(); + + return true; +} - termios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK); - termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL); - termios.c_iflag &= ~(IXON | IXOFF | IXANY); - termios.c_oflag &= ~(OPOST); - termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS); - termios.c_cflag |= (CS8 | CLOCAL | CREAD); - termios.c_lflag &= ~(ISIG | ICANON | IEXTEN); - termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); -#if defined(__APPLE__) - termios.c_cc[VMIN] = 1; - termios.c_cc[VTIME] = 1; -#else - termios.c_cc[VMIN] = 0; - termios.c_cc[VTIME] = 10; -#endif - - switch (m_speed) { - case 1200U: - ::cfsetospeed(&termios, B1200); - ::cfsetispeed(&termios, B1200); - break; - case 2400U: - ::cfsetospeed(&termios, B2400); - ::cfsetispeed(&termios, B2400); - break; - case 4800U: - ::cfsetospeed(&termios, B4800); - ::cfsetispeed(&termios, B4800); - break; - case 9600U: - ::cfsetospeed(&termios, B9600); - ::cfsetispeed(&termios, B9600); - break; - case 19200U: - ::cfsetospeed(&termios, B19200); - ::cfsetispeed(&termios, B19200); - break; - case 38400U: - ::cfsetospeed(&termios, B38400); - ::cfsetispeed(&termios, B38400); - break; - case 115200U: - ::cfsetospeed(&termios, B115200); - ::cfsetispeed(&termios, B115200); - break; - case 230400U: - ::cfsetospeed(&termios, B230400); - ::cfsetispeed(&termios, B230400); - break; - case 460800U: - ::cfsetospeed(&termios, B460800); - ::cfsetispeed(&termios, B460800); - break; - default: - LogError("Unsupported serial port speed - %u", m_speed); - ::close(m_fd); - return false; - } - - if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) { - LogError("Cannot set the attributes for %s", m_device.c_str()); - ::close(m_fd); - return false; - } - - if (m_assertRTS) { - unsigned int y; - if (::ioctl(m_fd, TIOCMGET, &y) < 0) { - LogError("Cannot get the control attributes for %s", m_device.c_str()); - ::close(m_fd); - return false; - } - - y |= TIOCM_RTS; - - if (::ioctl(m_fd, TIOCMSET, &y) < 0) { - LogError("Cannot set the control attributes for %s", m_device.c_str()); - ::close(m_fd); - return false; - } - } - -#if defined(__APPLE__) - setNonblock(false); -#endif +bool CSerialController::setRaw() +{ + termios termios; + if (::tcgetattr(m_fd, &termios) < 0) { + LogError("Cannot get the attributes for %s", m_device.c_str()); + ::close(m_fd); + return false; } + termios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK); + termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL); + termios.c_iflag &= ~(IXON | IXOFF | IXANY); + termios.c_oflag &= ~(OPOST); + termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS); + termios.c_cflag |= (CS8 | CLOCAL | CREAD); + termios.c_lflag &= ~(ISIG | ICANON | IEXTEN); + termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); +#if defined(__APPLE__) + termios.c_cc[VMIN] = 1; + termios.c_cc[VTIME] = 1; +#else + termios.c_cc[VMIN] = 0; + termios.c_cc[VTIME] = 10; +#endif + + switch (m_speed) { + case 1200U: + ::cfsetospeed(&termios, B1200); + ::cfsetispeed(&termios, B1200); + break; + case 2400U: + ::cfsetospeed(&termios, B2400); + ::cfsetispeed(&termios, B2400); + break; + case 4800U: + ::cfsetospeed(&termios, B4800); + ::cfsetispeed(&termios, B4800); + break; + case 9600U: + ::cfsetospeed(&termios, B9600); + ::cfsetispeed(&termios, B9600); + break; + case 19200U: + ::cfsetospeed(&termios, B19200); + ::cfsetispeed(&termios, B19200); + break; + case 38400U: + ::cfsetospeed(&termios, B38400); + ::cfsetispeed(&termios, B38400); + break; + case 115200U: + ::cfsetospeed(&termios, B115200); + ::cfsetispeed(&termios, B115200); + break; + case 230400U: + ::cfsetospeed(&termios, B230400); + ::cfsetispeed(&termios, B230400); + break; + case 460800U: + ::cfsetospeed(&termios, B460800); + ::cfsetispeed(&termios, B460800); + break; + default: + LogError("Unsupported serial port speed - %u", m_speed); + ::close(m_fd); + return false; + } + + if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) { + LogError("Cannot set the attributes for %s", m_device.c_str()); + ::close(m_fd); + return false; + } + + if (m_assertRTS) { + unsigned int y; + if (::ioctl(m_fd, TIOCMGET, &y) < 0) { + LogError("Cannot get the control attributes for %s", m_device.c_str()); + ::close(m_fd); + return false; + } + + y |= TIOCM_RTS; + + if (::ioctl(m_fd, TIOCMSET, &y) < 0) { + LogError("Cannot set the control attributes for %s", m_device.c_str()); + ::close(m_fd); + return false; + } + } + +#if defined(__APPLE__) + setNonblock(false); +#endif + return true; } diff --git a/SerialController.h b/SerialController.h index c7f97eb..d4cb519 100644 --- a/SerialController.h +++ b/SerialController.h @@ -59,6 +59,7 @@ protected: int readNonblock(unsigned char* buffer, unsigned int length); #else bool canWrite(); + bool setRaw(); #endif }; From 97f1ebb25fb69ff7c9bff817b10dee5f18f6ae67 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 27 Jun 2020 22:47:54 +0100 Subject: [PATCH 074/115] Convert TXTwist to TXDelay. --- Conf.cpp | 12 ++++++------ Conf.h | 4 ++-- MMDVM.ini | 2 +- MMDVMHost.cpp | 14 +++++++------- Modem.cpp | 8 ++++---- Modem.h | 4 ++-- NullModem.h | 1 + Version.h | 2 +- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index fc6dad7..fae8b95 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -214,7 +214,7 @@ m_fmExtAudioBoost(1U), m_fmModeHang(10U), m_ax25Enabled(false), m_ax25RXTwist(6), -m_ax25TXTwist(6), +m_ax25TXDelay(300U), m_ax25Trace(false), m_dstarNetworkEnabled(false), m_dstarGatewayAddress(), @@ -508,7 +508,7 @@ bool CConf::read() else if (::strcmp(key, "PTTInvert") == 0) m_modemPTTInvert = ::atoi(value) == 1; else if (::strcmp(key, "TXDelay") == 0) - m_modemTXDelay = (unsigned int)::atoi(value); + m_ax25TXDelay = m_modemTXDelay = (unsigned int)::atoi(value); else if (::strcmp(key, "DMRDelay") == 0) m_modemDMRDelay = (unsigned int)::atoi(value); else if (::strcmp(key, "RXOffset") == 0) @@ -817,8 +817,8 @@ bool CConf::read() m_ax25Enabled = ::atoi(value) == 1; else if (::strcmp(key, "RXTwist") == 0) m_ax25RXTwist = ::atoi(value); - else if (::strcmp(key, "TXTwist") == 0) - m_ax25TXTwist = ::atoi(value); + else if (::strcmp(key, "TXDelay") == 0) + m_ax25TXDelay = (unsigned int)::atoi(value); else if (::strcmp(key, "Trace") == 0) m_ax25Trace = ::atoi(value) == 1; } else if (section == SECTION_DSTAR_NETWORK) { @@ -1777,9 +1777,9 @@ int CConf::getAX25RXTwist() const return m_ax25RXTwist; } -int CConf::getAX25TXTwist() const +unsigned int CConf::getAX25TXDelay() const { - return m_ax25TXTwist; + return m_ax25TXDelay; } bool CConf::getAX25Trace() const diff --git a/Conf.h b/Conf.h index 04c2be8..c87c730 100644 --- a/Conf.h +++ b/Conf.h @@ -176,7 +176,7 @@ public: // The AX.25 section bool getAX25Enabled() const; int getAX25RXTwist() const; - int getAX25TXTwist() const; + unsigned int getAX25TXDelay() const; bool getAX25Trace() const; // The FM Section @@ -506,7 +506,7 @@ private: bool m_ax25Enabled; int m_ax25RXTwist; - int m_ax25TXTwist; + unsigned int m_ax25TXDelay; bool m_ax25Trace; bool m_dstarNetworkEnabled; diff --git a/MMDVM.ini b/MMDVM.ini index 0ae670f..6cb0a9c 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -181,7 +181,7 @@ ExtAudioBoost=1 [AX.25] Enable=1 -TXTwist=6 +TXDelay=300 RXTwist=6 Trace=1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 8e95fec..b8d94a2 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -636,13 +636,13 @@ int CMMDVMHost::run() } if (m_ax25Enabled) { - int rxTwist = m_conf.getAX25RXTwist(); - int txTwist = m_conf.getAX25TXTwist(); - bool trace = m_conf.getAX25Trace(); + int rxTwist = m_conf.getAX25RXTwist(); + unsigned int txDelay = m_conf.getAX25TXDelay(); + bool trace = m_conf.getAX25Trace(); LogInfo("AX.25 RF Parameters"); - LogInfo(" RXTwist: %d", rxTwist); - LogInfo(" TXTwist: %d", txTwist); + LogInfo(" RX Twist: %d", rxTwist); + LogInfo(" TX Delay: %ums", txDelay); LogInfo(" Trace: %s", trace ? "yes" : "no"); m_ax25 = new CAX25Control(m_ax25Network, trace); @@ -1293,7 +1293,7 @@ bool CMMDVMHost::createModem() int txDCOffset = m_conf.getModemTXDCOffset(); float rfLevel = m_conf.getModemRFLevel(); int rxTwist = m_conf.getAX25RXTwist(); - int txTwist = m_conf.getAX25TXTwist(); + unsigned int ax25TXDelay = m_conf.getAX25TXDelay(); LogInfo("Modem Parameters"); LogInfo(" Port: %s", port.c_str()); @@ -1335,7 +1335,7 @@ bool CMMDVMHost::createModem() m_modem->setYSFParams(lowDeviation, ysfTXHang); m_modem->setP25Params(p25TXHang); m_modem->setNXDNParams(nxdnTXHang); - m_modem->setAX25Params(rxTwist, txTwist); + m_modem->setAX25Params(rxTwist, ax25TXDelay); if (m_fmEnabled) { std::string callsign = m_conf.getFMCallsign(); diff --git a/Modem.cpp b/Modem.cpp index 3b412b9..9591b0f 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -193,7 +193,7 @@ m_error(false), m_mode(MODE_IDLE), m_hwType(HWT_UNKNOWN), m_ax25RXTwist(0), -m_ax25TXTwist(0), +m_ax25TXDelay(300U), m_fmCallsign(), m_fmCallsignSpeed(20U), m_fmCallsignFrequency(1000U), @@ -308,10 +308,10 @@ void CModem::setNXDNParams(unsigned int txHang) m_nxdnTXHang = txHang; } -void CModem::setAX25Params(int rxTwist, int txTwist) +void CModem::setAX25Params(int rxTwist, unsigned int txDelay) { m_ax25RXTwist = rxTwist; - m_ax25TXTwist = txTwist; + m_ax25TXDelay = txDelay; } void CModem::setTransparentDataParams(unsigned int sendFrameType) @@ -1831,7 +1831,7 @@ bool CModem::setConfig() buffer[25U] = (unsigned char)(m_ax25RXTwist + 128); - buffer[26U] = (unsigned char)(m_ax25TXTwist + 128); + buffer[26U] = m_ax25TXDelay / 10U; // In 10ms units // CUtils::dump(1U, "Written", buffer, 27U); diff --git a/Modem.h b/Modem.h index c794477..822d50f 100644 --- a/Modem.h +++ b/Modem.h @@ -53,7 +53,7 @@ public: virtual void setYSFParams(bool loDev, unsigned int txHang); virtual void setP25Params(unsigned int txHang); virtual void setNXDNParams(unsigned int txHang); - virtual void setAX25Params(int rxTwist, int txTwist); + virtual void setAX25Params(int rxTwist, unsigned int txDelay); virtual void setTransparentDataParams(unsigned int sendFrameType); virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); @@ -215,7 +215,7 @@ private: unsigned char m_mode; HW_TYPE m_hwType; int m_ax25RXTwist; - int m_ax25TXTwist; + unsigned int m_ax25TXDelay; std::string m_fmCallsign; unsigned int m_fmCallsignSpeed; diff --git a/NullModem.h b/NullModem.h index a7ec68f..ec8757a 100644 --- a/NullModem.h +++ b/NullModem.h @@ -36,6 +36,7 @@ public: virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel){}; virtual void setDMRParams(unsigned int colorCode){}; virtual void setYSFParams(bool loDev, unsigned int txHang){}; + virtual void setAX25Params(int rxTwist, unsigned int txDelay){}; virtual void setTransparentDataParams(unsigned int sendFrameType){}; virtual bool open(); diff --git a/Version.h b/Version.h index 4559871..dc5e793 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200625"; +const char* VERSION = "20200627"; #endif From 648426f44ce076d9d8ea8bdbd96c442103bba2fc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 27 Jun 2020 22:58:37 +0100 Subject: [PATCH 075/115] Allow Windows compilation. --- AX25Network.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/AX25Network.h b/AX25Network.h index 34aa43b..f46de15 100644 --- a/AX25Network.h +++ b/AX25Network.h @@ -19,7 +19,11 @@ #ifndef AX25Network_H #define AX25Network_H +#if defined(_WIN32) || defined(_WIN64) +#include "SerialController.h" +#else #include "PseudoTTYController.h" +#endif #include #include @@ -42,7 +46,11 @@ public: void close(); private: +#if defined(_WIN32) || defined(_WIN64) + CSerialController m_serial; +#else CPseudoTTYController m_serial; +#endif unsigned char* m_txData; unsigned char* m_rxData; unsigned int m_rxLength; From 93a0b9793bf82a518cb18637966c418822711954 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 27 Jun 2020 23:01:00 +0100 Subject: [PATCH 076/115] Update the other Makefiles. --- Makefile.Pi | 2 +- Makefile.Pi.Adafruit | 2 +- Makefile.Pi.HD44780 | 2 +- Makefile.Pi.OLED | 2 +- Makefile.Pi.PCF8574 | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.Pi b/Makefile.Pi index 5631c0b..2e7fb1c 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -12,7 +12,7 @@ OBJECTS = AX25Control.o AX25Network.o \ DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 4a28051..1f274ef 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -13,7 +13,7 @@ OBJECTS = AX25Control.o AX25Network.o \ DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index f5b6dc0..3adaeab 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -12,7 +12,7 @@ OBJECTS = AX25Control.o AX25Network.o \ DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index d49d135..79d1f6e 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -12,7 +12,7 @@ OBJECTS = AX25Control.o AX25Network.o \ DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \ NXDNLayer3.o NXDNIcomNetwork.o NXDNKenwoodNetwork.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 8e9518a..81871cc 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -13,7 +13,7 @@ OBJECTS = AX25Control.o AX25Network.o \ DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o From d4c7f20696e9a70e7b2924b7da84cd046308280d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 28 Jun 2020 11:22:54 +0200 Subject: [PATCH 077/115] Fix assertion in PseudoTTY --- SerialController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialController.cpp b/SerialController.cpp index 10c634a..f48cf70 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -226,7 +226,6 @@ m_speed(speed), m_assertRTS(assertRTS), m_fd(-1) { - assert(!device.empty()); } CSerialController::~CSerialController() @@ -235,6 +234,7 @@ CSerialController::~CSerialController() bool CSerialController::open() { + assert(!m_device.empty()); assert(m_fd == -1); #if defined(__APPLE__) From 30098a5d3897167c70f1a7a54095d1cefa263970 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 28 Jun 2020 15:23:56 +0100 Subject: [PATCH 078/115] Fix SerialController being used by PseudoTTYController. --- PseudoTTYController.cpp | 2 +- SerialController.cpp | 16 ++++++++++++++++ SerialController.h | 2 ++ Version.h | 2 +- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/PseudoTTYController.cpp b/PseudoTTYController.cpp index 67df4a4..52a4ac9 100644 --- a/PseudoTTYController.cpp +++ b/PseudoTTYController.cpp @@ -37,7 +37,7 @@ CPseudoTTYController::CPseudoTTYController(const std::string& symlink, unsigned int speed, bool assertRTS) : -CSerialController("", speed, assertRTS), +CSerialController(speed, assertRTS), m_symlink(symlink) { } diff --git a/SerialController.cpp b/SerialController.cpp index 10c634a..99fe576 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -48,6 +48,14 @@ m_handle(INVALID_HANDLE_VALUE) assert(!device.empty()); } +CSerialController::CSerialController(unsigned int speed, bool assertRTS) : +m_device(), +m_speed(speed), +m_assertRTS(assertRTS), +m_handle(INVALID_HANDLE_VALUE) +{ +} + CSerialController::~CSerialController() { } @@ -229,6 +237,14 @@ m_fd(-1) assert(!device.empty()); } +CSerialController::CSerialController(unsigned int speed, bool assertRTS) : +m_device(), +m_speed(speed), +m_assertRTS(assertRTS), +m_fd(-1) +{ +} + CSerialController::~CSerialController() { } diff --git a/SerialController.h b/SerialController.h index d4cb519..e4adb7d 100644 --- a/SerialController.h +++ b/SerialController.h @@ -46,6 +46,8 @@ public: #endif protected: + CSerialController(unsigned int speed, bool assertRTS = false); + std::string m_device; unsigned int m_speed; bool m_assertRTS; diff --git a/Version.h b/Version.h index dc5e793..d3f9fbf 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200627"; +const char* VERSION = "20200628"; #endif From fab4dc227eaa96f1cf1437a1c1e029a271dc5d5d Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 28 Jun 2020 15:41:41 +0100 Subject: [PATCH 079/115] Fix NullModem.h --- NullModem.h | 74 +++++++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/NullModem.h b/NullModem.h index ec8757a..e44a352 100644 --- a/NullModem.h +++ b/NullModem.h @@ -30,48 +30,56 @@ public: CNullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); virtual ~CNullModem(); - virtual void setSerialParams(const std::string& protocol, unsigned int address){}; - virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency){}; - virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled){}; - virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel){}; - virtual void setDMRParams(unsigned int colorCode){}; - virtual void setYSFParams(bool loDev, unsigned int txHang){}; - virtual void setAX25Params(int rxTwist, unsigned int txDelay){}; - virtual void setTransparentDataParams(unsigned int sendFrameType){}; + virtual void setSerialParams(const std::string& protocol, unsigned int address) {}; + virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) {}; + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled) {}; + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel) {}; + virtual void setDMRParams(unsigned int colorCode) {}; + virtual void setYSFParams(bool loDev, unsigned int txHang) {}; + virtual void setP25Params(unsigned int txHang) {}; + virtual void setNXDNParams(unsigned int txHang) {}; + virtual void setAX25Params(int rxTwist, unsigned int txDelay) {}; + virtual void setTransparentDataParams(unsigned int sendFrameType) {}; virtual bool open(); - virtual unsigned int readDStarData(unsigned char* data){return 0;}; - virtual unsigned int readDMRData1(unsigned char* data){return 0;}; - virtual unsigned int readDMRData2(unsigned char* data){return 0;}; - virtual unsigned int readYSFData(unsigned char* data){return 0;}; - virtual unsigned int readP25Data(unsigned char* data){return 0;}; - virtual unsigned int readNXDNData(unsigned char* data){return 0;}; - virtual unsigned int readTransparentData(unsigned char* data){return 0;}; + virtual unsigned int readDStarData(unsigned char* data) { return 0U; }; + virtual unsigned int readDMRData1(unsigned char* data) { return 0U; }; + virtual unsigned int readDMRData2(unsigned char* data) { return 0U; }; + virtual unsigned int readYSFData(unsigned char* data) { return 0U; }; + virtual unsigned int readP25Data(unsigned char* data) { return 0U; }; + virtual unsigned int readNXDNData(unsigned char* data) { return 0U; }; + virtual unsigned int readFMData(unsigned char* data) { return 0U; }; + virtual unsigned int readAX25Data(unsigned char* data) { return 0U; }; + virtual unsigned int readTransparentData(unsigned char* data) { return 0U; }; virtual unsigned int readSerial(unsigned char* data, unsigned int length){return 0;}; - virtual bool hasDStarSpace()const {return true;}; - virtual bool hasDMRSpace1() const {return true;}; - virtual bool hasDMRSpace2() const {return true;}; - virtual bool hasYSFSpace() const {return true;}; - virtual bool hasP25Space() const {return true;}; - virtual bool hasNXDNSpace() const {return true;}; - virtual bool hasPOCSAGSpace() const{return true;}; + virtual bool hasDStarSpace()const { return true; }; + virtual bool hasDMRSpace1() const { return true; }; + virtual bool hasDMRSpace2() const { return true; }; + virtual bool hasYSFSpace() const { return true; }; + virtual bool hasP25Space() const { return true; }; + virtual bool hasNXDNSpace() const { return true; }; + virtual bool hasPOCSAGSpace() const { return true; }; + virtual unsigned int getFMSpace() const { return true; }; + virtual bool hasAX25Space() const { return true; }; - virtual bool hasTX() const {return false;}; - virtual bool hasCD() const {return false;}; + virtual bool hasTX() const { return false; }; + virtual bool hasCD() const { return false; }; - virtual bool hasLockout() const {return false;}; - virtual bool hasError() const {return false;}; + virtual bool hasLockout() const { return false; }; + virtual bool hasError() const { return false; }; - virtual bool writeDStarData(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeDMRData1(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeDMRData2(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeYSFData(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeP25Data(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeNXDNData(const unsigned char* data, unsigned int length){return true;}; - virtual bool writePOCSAGData(const unsigned char* data, unsigned int length){return true;}; + virtual bool writeDStarData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeDMRData1(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeDMRData2(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeYSFData(const unsigned char* data, unsigned int length) {return true; }; + virtual bool writeP25Data(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeNXDNData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writePOCSAGData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeFMData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeAX25Data(const unsigned char* data, unsigned int length) { return true; }; virtual bool writeTransparentData(const unsigned char* data, unsigned int length){return true;}; From 4ee32a506f3656595ef2047b2a56a0484b88ffde Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Jun 2020 11:46:30 +0100 Subject: [PATCH 080/115] Fix the NullModem. --- NullModem.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NullModem.h b/NullModem.h index e44a352..49dd3ec 100644 --- a/NullModem.h +++ b/NullModem.h @@ -41,6 +41,11 @@ public: virtual void setAX25Params(int rxTwist, unsigned int txDelay) {}; virtual void setTransparentDataParams(unsigned int sendFrameType) {}; + virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) {}; + virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) {}; + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) {}; + virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost) {}; + virtual bool open(); virtual unsigned int readDStarData(unsigned char* data) { return 0U; }; From 5dbf916db039d686f234b8047862ac6f48883825 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Jun 2020 11:53:54 +0100 Subject: [PATCH 081/115] Fix Windows compilation. --- MMDVMHost.vcxproj | 4 ++-- MMDVMHost.vcxproj.filters | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 7f64db6..befb54e 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -188,13 +188,13 @@ + - @@ -291,12 +291,12 @@ + - diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 00ed473..ecb892d 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -275,9 +275,6 @@ Header Files - - Header Files - Header Files @@ -323,6 +320,9 @@ Header Files + + Header Files + @@ -562,9 +562,6 @@ Source Files - - Source Files - Source Files @@ -607,5 +604,8 @@ Source Files + + Source Files + \ No newline at end of file From 8383c7d320e53ad6863e6538b0a118e63e9a6bec Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Jun 2020 12:11:01 +0100 Subject: [PATCH 082/115] Clean up the Makefiles. --- Makefile | 19 ++++++++++--------- Makefile.Pi | 19 ++++++++++--------- Makefile.Pi.Adafruit | 19 ++++++++++--------- Makefile.Pi.HD44780 | 19 ++++++++++--------- Makefile.Pi.OLED | 19 ++++++++++--------- Makefile.Pi.PCF8574 | 19 ++++++++++--------- 6 files changed, 60 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index f9699c9..6af3151 100644 --- a/Makefile +++ b/Makefile @@ -13,15 +13,16 @@ LIBS = -lpthread -lutil LDFLAGS = -g -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +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 DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ + UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi b/Makefile.Pi index f46272d..9e6fe90 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -12,15 +12,16 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +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 DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ + UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 84bd1fc..ab3279b 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -13,15 +13,16 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +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 DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ + UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index a1e86cd..659b6fd 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -13,15 +13,16 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o HD44780.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +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 DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o HD44780.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ + UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index af780eb..61b2626 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -13,15 +13,16 @@ LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lutil LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \ - NXDNLayer3.o NXDNIcomNetwork.o NXDNKenwoodNetwork.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +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 DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o \ + NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNIcomNetwork.o NXDNKenwoodNetwork.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ + UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 94d3aaf..d037b95 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -14,15 +14,16 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +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 DMREMB.o DMREmbeddedData.o DMRFullLC.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 GPSD.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o \ + UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand From aa8b78a31125869c46a035e0658fe7746c38f25d Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jun 2020 12:35:03 +0100 Subject: [PATCH 083/115] Refactor the Modem class hierarchy. --- CASTInfo.cpp | 2 +- CASTInfo.h | 4 +- DMRControl.cpp | 2 +- DMRControl.h | 4 +- DMRSlot.cpp | 4 +- DMRSlot.h | 6 +- Display.cpp | 6 +- Display.h | 5 +- MMDVMHost.cpp | 8 +- MMDVMHost.h | 2 +- MMDVMHost.vcxproj | 2 + MMDVMHost.vcxproj.filters | 12 +- Makefile | 4 +- Makefile.Pi | 4 +- Makefile.Pi.Adafruit | 4 +- Makefile.Pi.HD44780 | 4 +- Makefile.Pi.OLED | 4 +- Makefile.Pi.PCF8574 | 4 +- Modem.cpp | 2453 +----------------------------------- Modem.h | 286 +---- ModemSerialPort.cpp | 14 +- ModemSerialPort.h | 10 +- NullModem.cpp | 12 +- NullModem.h | 54 +- SerialModem.cpp | 2465 +++++++++++++++++++++++++++++++++++++ SerialModem.h | 267 ++++ 26 files changed, 2891 insertions(+), 2751 deletions(-) create mode 100644 SerialModem.cpp create mode 100644 SerialModem.h diff --git a/CASTInfo.cpp b/CASTInfo.cpp index cce34d8..4821251 100644 --- a/CASTInfo.cpp +++ b/CASTInfo.cpp @@ -21,7 +21,7 @@ static bool networkInfoInitialized = false; static unsigned char passCounter = 0; -CCASTInfo::CCASTInfo(CModem* modem) : +CCASTInfo::CCASTInfo(IModem* modem) : CDisplay(), m_modem(modem), m_ipaddress() diff --git a/CASTInfo.h b/CASTInfo.h index 9254995..4651cf0 100644 --- a/CASTInfo.h +++ b/CASTInfo.h @@ -28,7 +28,7 @@ class CCASTInfo : public CDisplay { public: - CCASTInfo(CModem* modem); + CCASTInfo(IModem* modem); virtual ~CCASTInfo(); virtual bool open(); @@ -64,7 +64,7 @@ protected: virtual void clearCWInt(); private: - CModem* m_modem; + IModem* m_modem; std::string m_ipaddress; }; diff --git a/DMRControl.cpp b/DMRControl.cpp index bd07082..4ec1a4c 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -21,7 +21,7 @@ #include #include -CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) : +CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, IModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) : m_colorCode(colorCode), m_modem(modem), m_network(network), diff --git a/DMRControl.h b/DMRControl.h index 4d2597e..5a8d7de 100644 --- a/DMRControl.h +++ b/DMRControl.h @@ -31,7 +31,7 @@ class CDMRControl { public: - CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm); + CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, IModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm); ~CDMRControl(); bool processWakeup(const unsigned char* data); @@ -50,7 +50,7 @@ public: private: unsigned int m_colorCode; - CModem* m_modem; + IModem* m_modem; CDMRNetwork* m_network; CDMRSlot m_slot1; CDMRSlot m_slot2; diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 1cfecab..5554328 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -37,7 +37,7 @@ unsigned int CDMRSlot::m_colorCode = 0U; bool CDMRSlot::m_embeddedLCOnly = false; bool CDMRSlot::m_dumpTAData = true; -CModem* CDMRSlot::m_modem = NULL; +IModem* CDMRSlot::m_modem = NULL; CDMRNetwork* CDMRSlot::m_network = NULL; CDisplay* CDMRSlot::m_display = NULL; bool CDMRSlot::m_duplex = true; @@ -1896,7 +1896,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data) m_queue.addData(data, len); } -void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm) +void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, IModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm) { assert(modem != NULL); assert(display != NULL); diff --git a/DMRSlot.h b/DMRSlot.h index 1e95dc2..f50596b 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015-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 @@ -62,7 +62,7 @@ public: void enable(bool enabled); - static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm); + static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, IModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm); private: unsigned int m_slotNo; @@ -117,7 +117,7 @@ private: static bool m_embeddedLCOnly; static bool m_dumpTAData; - static CModem* m_modem; + static IModem* m_modem; static CDMRNetwork* m_network; static CDisplay* m_display; static bool m_duplex; diff --git a/Display.cpp b/Display.cpp index 22bc953..ce19ce5 100644 --- a/Display.cpp +++ b/Display.cpp @@ -490,7 +490,7 @@ int CDisplay::writeNXDNIntEx(const class CUserDBentry& source, bool group, unsig /* Factory method extracted from MMDVMHost.cpp - BG5HHP */ -CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) +CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, IModem* modem) { CDisplay *display = NULL; @@ -509,7 +509,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) ISerialPort* serial = NULL; if (port == "modem") - serial = new CModemSerialPort(modem); + serial = new IModemSerialPort(modem); else serial = new CSerialController(port, (type == "TFT Serial") ? 9600U : 115200U); @@ -555,7 +555,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) } if (port == "modem") { - ISerialPort* serial = new CModemSerialPort(modem); + ISerialPort* serial = new IModemSerialPort(modem); display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation()); } else if (port == "ump") { if (ump != NULL) { diff --git a/Display.h b/Display.h index 17caa41..c4937d2 100644 --- a/Display.h +++ b/Display.h @@ -21,13 +21,14 @@ #include "Timer.h" #include "UserDBentry.h" +#include "Modem.h" #include #include class CConf; -class CModem; +class IModem; class CUMP; class CDisplay @@ -81,7 +82,7 @@ public: void clock(unsigned int ms); - static CDisplay* createDisplay(const CConf& conf, CUMP* ump, CModem* modem); + static CDisplay* createDisplay(const CConf& conf, CUMP* ump, IModem* modem); protected: virtual void setIdleInt() = 0; diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 5e6940b..93ee9f7 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -21,6 +21,8 @@ #include "NXDNIcomNetwork.h" #include "RSSIInterpolator.h" #include "SerialController.h" +#include "SerialModem.h" +#include "NullModem.h" #include "Version.h" #include "StopWatch.h" #include "Defines.h" @@ -514,7 +516,6 @@ int CMMDVMHost::run() else if (ovcm == DMR_OVCM_ON) LogInfo(" OVCM: on"); - switch (dmrBeacons) { case DMR_BEACONS_NETWORK: { unsigned int dmrBeaconDuration = m_conf.getDMRBeaconDuration(); @@ -1332,7 +1333,10 @@ bool CMMDVMHost::createModem() LogInfo(" AX.25 TX Level: %.1f%%", ax25TXLevel); LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset); - m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); + if (port == "NullModem") + m_modem = new CNullModem; + else + m_modem = new CSerialModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); m_modem->setSerialParams(protocol, address, speed); m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled, m_ax25Enabled); m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel); diff --git a/MMDVMHost.h b/MMDVMHost.h index d7f3e84..9cb28cb 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -59,7 +59,7 @@ public: private: CConf m_conf; - CModem* m_modem; + IModem* m_modem; CDStarControl* m_dstar; CDMRControl* m_dmr; CYSFControl* m_ysf; diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index befb54e..96f4c96 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -236,6 +236,7 @@ + @@ -334,6 +335,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 32cca98..0757e74 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -275,9 +275,6 @@ Header Files - - Header Files - Header Files @@ -326,6 +323,9 @@ Header Files + + Header Files + @@ -565,9 +565,6 @@ Source Files - - Source Files - Source Files @@ -613,5 +610,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index 5ab488b..91fcf2d 100644 --- a/Makefile +++ b/Makefile @@ -21,8 +21,8 @@ OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Con 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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ - SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ - UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi b/Makefile.Pi index f936cad..62e27aa 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -20,8 +20,8 @@ OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Con 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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ - SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ - UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 928937e..2915c69 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -21,8 +21,8 @@ OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Con 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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ - SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ - UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index d6a7241..c00e58f 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -21,8 +21,8 @@ OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Con 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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ - SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ - UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 61b2626..41e837e 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -21,8 +21,8 @@ OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Con NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNIcomNetwork.o NXDNKenwoodNetwork.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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ - SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o \ - UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index f06d5c4..37de0b1 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -22,8 +22,8 @@ OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Con 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 POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ - SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o \ - UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Modem.cpp b/Modem.cpp index 9591b0f..75c65dc 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-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 @@ -16,2457 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "SerialController.h" -#if defined(__linux__) -#include "I2CController.h" -#endif -#include "DStarDefines.h" -#include "DMRDefines.h" -#include "YSFDefines.h" -#include "P25Defines.h" -#include "NXDNDefines.h" -#include "AX25Defines.h" -#include "POCSAGDefines.h" -#include "Thread.h" #include "Modem.h" -#include "NullModem.h" -#include "Utils.h" -#include "Log.h" -#include -#include -#include -#include -#include - -#if defined(_WIN32) || defined(_WIN64) -#include -#else -#include -#endif - -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_SEND_CWID = 0x0AU; - -const unsigned char MMDVM_DSTAR_HEADER = 0x10U; -const unsigned char MMDVM_DSTAR_DATA = 0x11U; -const unsigned char MMDVM_DSTAR_LOST = 0x12U; -const unsigned char MMDVM_DSTAR_EOT = 0x13U; - -const unsigned char MMDVM_DMR_DATA1 = 0x18U; -const unsigned char MMDVM_DMR_LOST1 = 0x19U; -const unsigned char MMDVM_DMR_DATA2 = 0x1AU; -const unsigned char MMDVM_DMR_LOST2 = 0x1BU; -const unsigned char MMDVM_DMR_SHORTLC = 0x1CU; -const unsigned char MMDVM_DMR_START = 0x1DU; -const unsigned char MMDVM_DMR_ABORT = 0x1EU; - -const unsigned char MMDVM_YSF_DATA = 0x20U; -const unsigned char MMDVM_YSF_LOST = 0x21U; - -const unsigned char MMDVM_P25_HDR = 0x30U; -const unsigned char MMDVM_P25_LDU = 0x31U; -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_POCSAG_DATA = 0x50U; - -const unsigned char MMDVM_AX25_DATA = 0x55U; - -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_FM_DATA = 0x65U; -const unsigned char MMDVM_FM_CONTROL = 0x66U; -const unsigned char MMDVM_FM_EOT = 0x67U; - -const unsigned char MMDVM_ACK = 0x70U; -const unsigned char MMDVM_NAK = 0x7FU; - -const unsigned char MMDVM_SERIAL = 0x80U; - -const unsigned char MMDVM_TRANSPARENT = 0x90U; -const unsigned char MMDVM_QSO_INFO = 0x91U; - -const unsigned char MMDVM_DEBUG1 = 0xF1U; -const unsigned char MMDVM_DEBUG2 = 0xF2U; -const unsigned char MMDVM_DEBUG3 = 0xF3U; -const unsigned char MMDVM_DEBUG4 = 0xF4U; -const unsigned char MMDVM_DEBUG5 = 0xF5U; - -const unsigned int MAX_RESPONSES = 30U; - -const unsigned int BUFFER_LENGTH = 2000U; - - -CModem::CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug) : -m_port(port), -m_dmrColorCode(0U), -m_ysfLoDev(false), -m_ysfTXHang(4U), -m_p25TXHang(5U), -m_nxdnTXHang(5U), -m_duplex(duplex), -m_rxInvert(rxInvert), -m_txInvert(txInvert), -m_pttInvert(pttInvert), -m_txDelay(txDelay), -m_dmrDelay(dmrDelay), -m_rxLevel(0.0F), -m_cwIdTXLevel(0.0F), -m_dstarTXLevel(0.0F), -m_dmrTXLevel(0.0F), -m_ysfTXLevel(0.0F), -m_p25TXLevel(0.0F), -m_nxdnTXLevel(0.0F), -m_pocsagTXLevel(0.0F), -m_fmTXLevel(0.0F), -m_ax25TXLevel(0.0F), -m_rfLevel(0.0F), -m_trace(trace), -m_debug(debug), -m_rxFrequency(0U), -m_txFrequency(0U), -m_pocsagFrequency(0U), -m_dstarEnabled(false), -m_dmrEnabled(false), -m_ysfEnabled(false), -m_p25Enabled(false), -m_nxdnEnabled(false), -m_pocsagEnabled(false), -m_fmEnabled(false), -m_ax25Enabled(false), -m_rxDCOffset(0), -m_txDCOffset(0), -m_serial(NULL), -m_buffer(NULL), -m_length(0U), -m_offset(0U), -m_state(SS_START), -m_type(0U), -m_rxDStarData(1000U, "Modem RX D-Star"), -m_txDStarData(1000U, "Modem TX D-Star"), -m_rxDMRData1(1000U, "Modem RX DMR1"), -m_rxDMRData2(1000U, "Modem RX DMR2"), -m_txDMRData1(1000U, "Modem TX DMR1"), -m_txDMRData2(1000U, "Modem TX DMR2"), -m_rxYSFData(1000U, "Modem RX YSF"), -m_txYSFData(1000U, "Modem TX YSF"), -m_rxP25Data(1000U, "Modem RX P25"), -m_txP25Data(1000U, "Modem TX P25"), -m_rxNXDNData(1000U, "Modem RX NXDN"), -m_txNXDNData(1000U, "Modem TX NXDN"), -m_txPOCSAGData(1000U, "Modem TX POCSAG"), -m_rxFMData(5000U, "Modem RX FM"), -m_txFMData(5000U, "Modem TX FM"), -m_rxAX25Data(1000U, "Modem RX AX.25"), -m_txAX25Data(1000U, "Modem TX AX.25"), -m_rxTransparentData(1000U, "Modem RX Transparent"), -m_txTransparentData(1000U, "Modem TX Transparent"), -m_sendTransparentDataFrameType(0U), -m_statusTimer(1000U, 0U, 250U), -m_inactivityTimer(1000U, 2U), -m_playoutTimer(1000U, 0U, 10U), -m_dstarSpace(0U), -m_dmrSpace1(0U), -m_dmrSpace2(0U), -m_ysfSpace(0U), -m_p25Space(0U), -m_nxdnSpace(0U), -m_pocsagSpace(0U), -m_fmSpace(0U), -m_ax25Space(0U), -m_tx(false), -m_cd(false), -m_lockout(false), -m_error(false), -m_mode(MODE_IDLE), -m_hwType(HWT_UNKNOWN), -m_ax25RXTwist(0), -m_ax25TXDelay(300U), -m_fmCallsign(), -m_fmCallsignSpeed(20U), -m_fmCallsignFrequency(1000U), -m_fmCallsignTime(600U), -m_fmCallsignHoldoff(0U), -m_fmCallsignHighLevel(35.0F), -m_fmCallsignLowLevel(15.0F), -m_fmCallsignAtStart(true), -m_fmCallsignAtEnd(true), -m_fmCallsignAtLatch(true), -m_fmRfAck("K"), -m_fmExtAck("N"), -m_fmAckSpeed(20U), -m_fmAckFrequency(1750U), -m_fmAckMinTime(4U), -m_fmAckDelay(1000U), -m_fmAckLevel(80.0F), -m_fmTimeout(120U), -m_fmTimeoutLevel(80.0F), -m_fmCtcssFrequency(88.4F), -m_fmCtcssHighThreshold(30U), -m_fmCtcssLowThreshold(20U), -m_fmCtcssLevel(10.0F), -m_fmKerchunkTime(0U), -m_fmKerchunkTX(true), -m_fmHangTime(5U), -m_fmUseCOS(true), -m_fmCOSInvert(false), -m_fmRFAudioBoost(1U), -m_fmExtAudioBoost(1U), -m_fmMaxDevLevel(90.0F), -m_fmExtEnable(false) -{ - m_buffer = new unsigned char[BUFFER_LENGTH]; - - assert(!port.empty()); -} - -CModem::~CModem() -{ - delete m_serial; - delete[] m_buffer; -} - -void CModem::setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) -{ - // Create the serial controller instance according the protocol specified in conf. -#if defined(__linux__) - if (protocol == "i2c") - m_serial = new CI2CController(m_port, address); - else -#endif - m_serial = new CSerialController(m_port, speed, true); -} - -void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) -{ - m_rxFrequency = rxFrequency + rxOffset; - m_txFrequency = txFrequency + txOffset; - m_txDCOffset = txDCOffset; - m_rxDCOffset = rxDCOffset; - m_rfLevel = rfLevel; - m_pocsagFrequency = pocsagFrequency + txOffset; -} - -void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) -{ - m_dstarEnabled = dstarEnabled; - m_dmrEnabled = dmrEnabled; - m_ysfEnabled = ysfEnabled; - m_p25Enabled = p25Enabled; - m_nxdnEnabled = nxdnEnabled; - m_pocsagEnabled = pocsagEnabled; - m_fmEnabled = fmEnabled; - m_ax25Enabled = ax25Enabled; -} - -void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel, float ax25TXLevel) -{ - m_rxLevel = rxLevel; - m_cwIdTXLevel = cwIdTXLevel; - m_dstarTXLevel = dstarTXLevel; - m_dmrTXLevel = dmrTXLevel; - m_ysfTXLevel = ysfTXLevel; - m_p25TXLevel = p25TXLevel; - m_nxdnTXLevel = nxdnTXLevel; - m_pocsagTXLevel = pocsagTXLevel; - m_fmTXLevel = fmTXLevel; - m_ax25TXLevel = ax25TXLevel; -} - -void CModem::setDMRParams(unsigned int colorCode) -{ - assert(colorCode < 16U); - - m_dmrColorCode = colorCode; -} - -void CModem::setYSFParams(bool loDev, unsigned int txHang) -{ - m_ysfLoDev = loDev; - m_ysfTXHang = txHang; -} - -void CModem::setP25Params(unsigned int txHang) -{ - m_p25TXHang = txHang; -} - -void CModem::setNXDNParams(unsigned int txHang) -{ - m_nxdnTXHang = txHang; -} - -void CModem::setAX25Params(int rxTwist, unsigned int txDelay) -{ - m_ax25RXTwist = rxTwist; - m_ax25TXDelay = txDelay; -} - -void CModem::setTransparentDataParams(unsigned int sendFrameType) -{ - m_sendTransparentDataFrameType = sendFrameType; -} - -bool CModem::open() -{ - ::LogMessage("Opening the MMDVM"); - - bool ret = m_serial->open(); - if (!ret) - return false; - - ret = readVersion(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } else { - /* Stopping the inactivity timer here when a firmware version has been - successfuly read prevents the death spiral of "no reply from modem..." */ - m_inactivityTimer.stop(); - } - - ret = setFrequency(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - ret = setConfig(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - if (m_fmEnabled && m_duplex) { - ret = setFMCallsignParams(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - ret = setFMAckParams(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - ret = setFMMiscParams(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - if (m_fmExtEnable) { - ret = setFMExtParams(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - } - } - - m_statusTimer.start(); - - m_error = false; - m_offset = 0U; - - return true; -} - -void CModem::clock(unsigned int ms) -{ - assert(m_serial != NULL); - - // Poll the modem status every 250ms - m_statusTimer.clock(ms); - if (m_statusTimer.hasExpired()) { - readStatus(); - m_statusTimer.start(); - } - - m_inactivityTimer.clock(ms); - if (m_inactivityTimer.hasExpired()) { - LogError("No reply from the modem for some time, resetting it"); - m_error = true; - close(); - - CThread::sleep(2000U); // 2s - while (!open()) - CThread::sleep(5000U); // 5s - } - - RESP_TYPE_MMDVM type = getResponse(); - - if (type == RTM_TIMEOUT) { - // Nothing to do - } else if (type == RTM_ERROR) { - // Nothing to do - } else { - // type == RTM_OK - switch (m_type) { - case MMDVM_DSTAR_HEADER: { - if (m_trace) - CUtils::dump(1U, "RX D-Star Header", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxDStarData.addData(&data, 1U); - - data = TAG_HEADER; - m_rxDStarData.addData(&data, 1U); - - m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_DSTAR_DATA: { - if (m_trace) - CUtils::dump(1U, "RX D-Star Data", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxDStarData.addData(&data, 1U); - - data = TAG_DATA; - m_rxDStarData.addData(&data, 1U); - - m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_DSTAR_LOST: { - if (m_trace) - CUtils::dump(1U, "RX D-Star Lost", m_buffer, m_length); - - unsigned char data = 1U; - m_rxDStarData.addData(&data, 1U); - - data = TAG_LOST; - m_rxDStarData.addData(&data, 1U); - } - break; - - case MMDVM_DSTAR_EOT: { - if (m_trace) - CUtils::dump(1U, "RX D-Star EOT", m_buffer, m_length); - - unsigned char data = 1U; - m_rxDStarData.addData(&data, 1U); - - data = TAG_EOT; - m_rxDStarData.addData(&data, 1U); - } - break; - - case MMDVM_DMR_DATA1: { - if (m_trace) - CUtils::dump(1U, "RX DMR Data 1", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxDMRData1.addData(&data, 1U); - - if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) - data = TAG_EOT; - else - data = TAG_DATA; - m_rxDMRData1.addData(&data, 1U); - - m_rxDMRData1.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_DMR_DATA2: { - if (m_trace) - CUtils::dump(1U, "RX DMR Data 2", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxDMRData2.addData(&data, 1U); - - if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) - data = TAG_EOT; - else - data = TAG_DATA; - m_rxDMRData2.addData(&data, 1U); - - m_rxDMRData2.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_DMR_LOST1: { - if (m_trace) - CUtils::dump(1U, "RX DMR Lost 1", m_buffer, m_length); - - unsigned char data = 1U; - m_rxDMRData1.addData(&data, 1U); - - data = TAG_LOST; - m_rxDMRData1.addData(&data, 1U); - } - break; - - case MMDVM_DMR_LOST2: { - if (m_trace) - CUtils::dump(1U, "RX DMR Lost 2", m_buffer, m_length); - - unsigned char data = 1U; - m_rxDMRData2.addData(&data, 1U); - - data = TAG_LOST; - m_rxDMRData2.addData(&data, 1U); - } - break; - - case MMDVM_YSF_DATA: { - if (m_trace) - CUtils::dump(1U, "RX YSF Data", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxYSFData.addData(&data, 1U); - - data = TAG_DATA; - m_rxYSFData.addData(&data, 1U); - - m_rxYSFData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_YSF_LOST: { - if (m_trace) - CUtils::dump(1U, "RX YSF Lost", m_buffer, m_length); - - unsigned char data = 1U; - m_rxYSFData.addData(&data, 1U); - - data = TAG_LOST; - m_rxYSFData.addData(&data, 1U); - } - break; - - case MMDVM_P25_HDR: { - if (m_trace) - CUtils::dump(1U, "RX P25 Header", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxP25Data.addData(&data, 1U); - - data = TAG_HEADER; - m_rxP25Data.addData(&data, 1U); - - m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_P25_LDU: { - if (m_trace) - CUtils::dump(1U, "RX P25 LDU", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxP25Data.addData(&data, 1U); - - data = TAG_DATA; - m_rxP25Data.addData(&data, 1U); - - m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_P25_LOST: { - if (m_trace) - CUtils::dump(1U, "RX P25 Lost", m_buffer, m_length); - - unsigned char data = 1U; - m_rxP25Data.addData(&data, 1U); - - data = TAG_LOST; - m_rxP25Data.addData(&data, 1U); - } - break; - - case MMDVM_NXDN_DATA: { - if (m_trace) - CUtils::dump(1U, "RX NXDN Data", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxNXDNData.addData(&data, 1U); - - data = TAG_DATA; - m_rxNXDNData.addData(&data, 1U); - - m_rxNXDNData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_NXDN_LOST: { - if (m_trace) - CUtils::dump(1U, "RX NXDN Lost", m_buffer, m_length); - - unsigned char data = 1U; - m_rxNXDNData.addData(&data, 1U); - - data = TAG_LOST; - m_rxNXDNData.addData(&data, 1U); - } - break; - - case MMDVM_FM_DATA: { - if (m_trace) - CUtils::dump(1U, "RX FM Data", m_buffer, m_length); - - unsigned int data1 = m_length - m_offset + 1U; - m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); - - unsigned char data2 = TAG_DATA; - m_rxFMData.addData(&data2, 1U); - - m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_FM_CONTROL: { - if (m_trace) - CUtils::dump(1U, "RX FM Control", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxFMData.addData(&data, 1U); - - data = TAG_HEADER; - m_rxFMData.addData(&data, 1U); - - m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_FM_EOT: { - if(m_trace) - CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxFMData.addData(&data, 1U); - - data = TAG_EOT; - m_rxFMData.addData(&data, 1U); - - m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_AX25_DATA: { - if (m_trace) - CUtils::dump(1U, "RX AX.25 Data", m_buffer, m_length); - - unsigned int data = m_length - m_offset; - m_rxAX25Data.addData((unsigned char*)&data, sizeof(unsigned int)); - - m_rxAX25Data.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_GET_STATUS: { - // if (m_trace) - // CUtils::dump(1U, "GET_STATUS", m_buffer, m_length); - - m_p25Space = 0U; - m_nxdnSpace = 0U; - m_pocsagSpace = 0U; - m_fmSpace = 0U; - m_ax25Space = 0U; - - m_mode = m_buffer[m_offset + 1U]; - - m_tx = (m_buffer[m_offset + 2U] & 0x01U) == 0x01U; - - bool adcOverflow = (m_buffer[m_offset + 2U] & 0x02U) == 0x02U; - if (adcOverflow) - LogError("MMDVM ADC levels have overflowed"); - - bool rxOverflow = (m_buffer[m_offset + 2U] & 0x04U) == 0x04U; - if (rxOverflow) - LogError("MMDVM RX buffer has overflowed"); - - bool txOverflow = (m_buffer[m_offset + 2U] & 0x08U) == 0x08U; - if (txOverflow) - LogError("MMDVM TX buffer has overflowed"); - - m_lockout = (m_buffer[m_offset + 2U] & 0x10U) == 0x10U; - - bool dacOverflow = (m_buffer[m_offset + 2U] & 0x20U) == 0x20U; - if (dacOverflow) - LogError("MMDVM DAC levels have overflowed"); - - m_cd = (m_buffer[m_offset + 2U] & 0x40U) == 0x40U; - - m_dstarSpace = m_buffer[m_offset + 3U]; - m_dmrSpace1 = m_buffer[m_offset + 4U]; - m_dmrSpace2 = m_buffer[m_offset + 5U]; - m_ysfSpace = m_buffer[m_offset + 6U]; - - if (m_length > (m_offset + 7U)) - m_p25Space = m_buffer[m_offset + 7U]; - if (m_length > (m_offset + 8U)) - m_nxdnSpace = m_buffer[m_offset + 8U]; - if (m_length > (m_offset + 9U)) - m_pocsagSpace = m_buffer[m_offset + 9U]; - if (m_length > (m_offset + 10U)) - m_fmSpace = m_buffer[m_offset + 10U]; - if (m_length > (m_offset + 11U)) - m_ax25Space = m_buffer[m_offset + 11U]; - - m_inactivityTimer.start(); - // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, m_fmSpace, m_ax25Space, int(m_lockout), int(m_cd)); - } - break; - - case MMDVM_TRANSPARENT: { - if (m_trace) - CUtils::dump(1U, "RX Transparent Data", m_buffer, m_length); - - unsigned char offset = m_sendTransparentDataFrameType; - if (offset > 1U) offset = 1U; - unsigned char data = m_length - m_offset + offset; - m_rxTransparentData.addData(&data, 1U); - - m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); - } - break; - - // These should not be received, but don't complain if we do - case MMDVM_GET_VERSION: - case MMDVM_ACK: - break; - - case MMDVM_NAK: - LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[m_offset], m_buffer[m_offset + 1U]); - break; - - case MMDVM_DEBUG1: - case MMDVM_DEBUG2: - case MMDVM_DEBUG3: - case MMDVM_DEBUG4: - case MMDVM_DEBUG5: - printDebug(); - break; - - case MMDVM_SERIAL: - //MMDVMHost does not process serial data from the display, - // so we send it to the transparent port if sendFrameType==1 - if (m_sendTransparentDataFrameType > 0U) { - if (m_trace) - CUtils::dump(1U, "RX Serial Data", m_buffer, m_length); - - unsigned char offset = m_sendTransparentDataFrameType; - if (offset > 1U) offset = 1U; - unsigned char data = m_length - m_offset + offset; - m_rxTransparentData.addData(&data, 1U); - - m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); - break; //only break when sendFrameType>0, else message is unknown - } - default: - LogMessage("Unknown message, type: %02X", m_type); - CUtils::dump("Buffer dump", m_buffer, m_length); - break; - } - } - - // Only feed data to the modem if the playout timer has expired - m_playoutTimer.clock(ms); - if (!m_playoutTimer.hasExpired()) - return; - - if (m_dstarSpace > 1U && !m_txDStarData.isEmpty()) { - unsigned char buffer[4U]; - m_txDStarData.peek(buffer, 4U); - - if ((buffer[3U] == MMDVM_DSTAR_HEADER && m_dstarSpace > 4U) || - (buffer[3U] == MMDVM_DSTAR_DATA && m_dstarSpace > 1U) || - (buffer[3U] == MMDVM_DSTAR_EOT && m_dstarSpace > 1U)) { - unsigned char len = 0U; - m_txDStarData.getData(&len, 1U); - m_txDStarData.getData(m_buffer, len); - - switch (buffer[3U]) { - case MMDVM_DSTAR_HEADER: - if (m_trace) - CUtils::dump(1U, "TX D-Star Header", m_buffer, len); - m_dstarSpace -= 4U; - break; - case MMDVM_DSTAR_DATA: - if (m_trace) - CUtils::dump(1U, "TX D-Star Data", m_buffer, len); - m_dstarSpace -= 1U; - break; - default: - if (m_trace) - CUtils::dump(1U, "TX D-Star EOT", m_buffer, len); - m_dstarSpace -= 1U; - break; - } - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing D-Star data to the MMDVM"); - - m_playoutTimer.start(); - } - } - - if (m_dmrSpace1 > 1U && !m_txDMRData1.isEmpty()) { - unsigned char len = 0U; - m_txDMRData1.getData(&len, 1U); - m_txDMRData1.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX DMR Data 1", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing DMR data to the MMDVM"); - - m_playoutTimer.start(); - - m_dmrSpace1--; - } - - if (m_dmrSpace2 > 1U && !m_txDMRData2.isEmpty()) { - unsigned char len = 0U; - m_txDMRData2.getData(&len, 1U); - m_txDMRData2.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX DMR Data 2", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing DMR data to the MMDVM"); - - m_playoutTimer.start(); - - m_dmrSpace2--; - } - - if (m_ysfSpace > 1U && !m_txYSFData.isEmpty()) { - unsigned char len = 0U; - m_txYSFData.getData(&len, 1U); - m_txYSFData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX YSF Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing YSF data to the MMDVM"); - - m_playoutTimer.start(); - - m_ysfSpace--; - } - - if (m_p25Space > 1U && !m_txP25Data.isEmpty()) { - unsigned char len = 0U; - m_txP25Data.getData(&len, 1U); - m_txP25Data.getData(m_buffer, len); - - if (m_trace) { - if (m_buffer[2U] == MMDVM_P25_HDR) - CUtils::dump(1U, "TX P25 HDR", m_buffer, len); - else - CUtils::dump(1U, "TX P25 LDU", m_buffer, len); - } - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing P25 data to the MMDVM"); - - m_playoutTimer.start(); - - m_p25Space--; - } - - if (m_nxdnSpace > 1U && !m_txNXDNData.isEmpty()) { - unsigned char len = 0U; - m_txNXDNData.getData(&len, 1U); - m_txNXDNData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX NXDN Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing NXDN data to the MMDVM"); - - m_playoutTimer.start(); - - m_nxdnSpace--; - } - - if (m_pocsagSpace > 1U && !m_txPOCSAGData.isEmpty()) { - unsigned char len = 0U; - m_txPOCSAGData.getData(&len, 1U); - m_txPOCSAGData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX POCSAG Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing POCSAG data to the MMDVM"); - - m_playoutTimer.start(); - - m_pocsagSpace--; - } - - if (m_fmSpace > 1U && !m_txFMData.isEmpty()) { - unsigned char len = 0U; - m_txFMData.getData(&len, 1U); - m_txFMData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX FM Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing FM data to the MMDVM"); - - m_playoutTimer.start(); - - m_fmSpace--; - } - - if (m_ax25Space > 0U && !m_txAX25Data.isEmpty()) { - unsigned char len = 0U; - m_txAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); - m_txAX25Data.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX AX.25 Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing AX.25 data to the MMDVM"); - - m_playoutTimer.start(); - - m_ax25Space = 0U; - } - - if (!m_txTransparentData.isEmpty()) { - unsigned char len = 0U; - m_txTransparentData.getData(&len, 1U); - m_txTransparentData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX Transparent Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing Transparent data to the MMDVM"); - } -} - -void CModem::close() -{ - assert(m_serial != NULL); - - ::LogMessage("Closing the MMDVM"); - - m_serial->close(); -} - -unsigned int CModem::readDStarData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxDStarData.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxDStarData.getData(&len, 1U); - m_rxDStarData.getData(data, len); - - return len; -} - -unsigned int CModem::readDMRData1(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxDMRData1.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxDMRData1.getData(&len, 1U); - m_rxDMRData1.getData(data, len); - - return len; -} - -unsigned int CModem::readDMRData2(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxDMRData2.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxDMRData2.getData(&len, 1U); - m_rxDMRData2.getData(data, len); - - return len; -} - -unsigned int CModem::readYSFData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxYSFData.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxYSFData.getData(&len, 1U); - m_rxYSFData.getData(data, len); - - return len; -} - -unsigned int CModem::readP25Data(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxP25Data.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxP25Data.getData(&len, 1U); - m_rxP25Data.getData(data, len); - - return len; -} - -unsigned int CModem::readNXDNData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxNXDNData.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxNXDNData.getData(&len, 1U); - m_rxNXDNData.getData(data, len); - - return len; -} - -unsigned int CModem::readFMData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxFMData.isEmpty()) - return 0U; - - unsigned int len = 0U; - m_rxFMData.getData((unsigned char*)&len, sizeof(unsigned int)); - m_rxFMData.getData(data, len); - - return len; -} - -unsigned int CModem::readAX25Data(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxAX25Data.isEmpty()) - return 0U; - - unsigned int len = 0U; - m_rxAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); - m_rxAX25Data.getData(data, len); - - return len; -} - -unsigned int CModem::readTransparentData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxTransparentData.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxTransparentData.getData(&len, 1U); - m_rxTransparentData.getData(data, len); - - return len; -} - -// To be implemented later if needed -unsigned int CModem::readSerial(unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - return 0U; -} - -bool CModem::hasDStarSpace() const -{ - unsigned int space = m_txDStarData.freeSpace() / (DSTAR_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::writeDStarData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[50U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - - switch (data[0U]) { - case TAG_HEADER: - buffer[2U] = MMDVM_DSTAR_HEADER; - break; - case TAG_DATA: - buffer[2U] = MMDVM_DSTAR_DATA; - break; - case TAG_EOT: - buffer[2U] = MMDVM_DSTAR_EOT; - break; - default: - CUtils::dump(2U, "Unknown D-Star packet type", data, length); - return false; - } - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txDStarData.addData(&len, 1U); - m_txDStarData.addData(buffer, len); - - return true; -} - -bool CModem::hasDMRSpace1() const -{ - unsigned int space = m_txDMRData1.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::hasDMRSpace2() const -{ - unsigned int space = m_txDMRData2.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -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) - return false; - - unsigned char buffer[40U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = MMDVM_DMR_DATA1; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txDMRData1.addData(&len, 1U); - m_txDMRData1.addData(buffer, len); - - return true; -} - -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) - return false; - - unsigned char buffer[40U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = MMDVM_DMR_DATA2; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txDMRData2.addData(&len, 1U); - m_txDMRData2.addData(buffer, len); - - return true; -} - -bool CModem::hasYSFSpace() const -{ - unsigned int space = m_txYSFData.freeSpace() / (YSF_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -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) - return false; - - unsigned char buffer[130U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = MMDVM_YSF_DATA; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txYSFData.addData(&len, 1U); - m_txYSFData.addData(buffer, len); - - return true; -} - -bool CModem::hasP25Space() const -{ - unsigned int space = m_txP25Data.freeSpace() / (P25_LDU_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -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) - return false; - - unsigned char buffer[250U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = (data[0U] == TAG_HEADER) ? MMDVM_P25_HDR : MMDVM_P25_LDU; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txP25Data.addData(&len, 1U); - m_txP25Data.addData(buffer, len); - - return true; -} - -bool CModem::hasNXDNSpace() const -{ - unsigned int space = m_txNXDNData.freeSpace() / (NXDN_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -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) - return false; - - unsigned char buffer[130U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = MMDVM_NXDN_DATA; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txNXDNData.addData(&len, 1U); - m_txNXDNData.addData(buffer, len); - - return true; -} - -bool CModem::hasPOCSAGSpace() const -{ - unsigned int space = m_txPOCSAGData.freeSpace() / (POCSAG_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::writePOCSAGData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[130U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_POCSAG_DATA; - - ::memcpy(buffer + 3U, data, length); - - unsigned char len = length + 3U; - m_txPOCSAGData.addData(&len, 1U); - m_txPOCSAGData.addData(buffer, len); - - return true; -} - -unsigned int CModem::getFMSpace() const -{ - return m_txFMData.freeSpace(); -} - -bool CModem::writeFMData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[500U]; - - unsigned int len; - if (length > 252U) { - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 0U; - buffer[2U] = (length + 4U) - 255U; - buffer[3U] = MMDVM_FM_DATA; - ::memcpy(buffer + 4U, data, length); - len = length + 4U; - } else { - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_FM_DATA; - ::memcpy(buffer + 3U, data, length); - len = length + 3U; - } - - m_txFMData.addData((unsigned char*)&len, sizeof(unsigned int)); - m_txFMData.addData(buffer, len); - - return true; -} - -bool CModem::hasAX25Space() const -{ - unsigned int space = m_txAX25Data.freeSpace() / (AX25_MAX_FRAME_LENGTH_BYTES + 5U); - - return space > 1U; -} - -bool CModem::writeAX25Data(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[500U]; - - unsigned int len; - if (length > 252U) { - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 0U; - buffer[2U] = (length + 4U) - 255U; - buffer[3U] = MMDVM_AX25_DATA; - ::memcpy(buffer + 4U, data, length); - len = length + 4U; - } else { - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_AX25_DATA; - ::memcpy(buffer + 3U, data, length); - len = length + 3U; - } - - m_txAX25Data.addData((unsigned char*)&len, sizeof(unsigned int)); - m_txAX25Data.addData(buffer, len); - - return true; -} - -bool CModem::writeTransparentData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[250U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_TRANSPARENT; - - if (m_sendTransparentDataFrameType > 0U) { - ::memcpy(buffer + 2U, data, length); - length--; - buffer[1U]--; - - //when sendFrameType==1 , only 0x80 and 0x90 (MMDVM_SERIAL and MMDVM_TRANSPARENT) are allowed - // and reverted to default (MMDVM_TRANSPARENT) for any other value - //when >1, frame type is not checked - if (m_sendTransparentDataFrameType == 1U) { - if ((buffer[2U] & 0xE0) != 0x80) - buffer[2U] = MMDVM_TRANSPARENT; - } - } else { - ::memcpy(buffer + 3U, data, length); - } - - unsigned char len = length + 3U; - m_txTransparentData.addData(&len, 1U); - m_txTransparentData.addData(buffer, len); - - return true; -} - -bool CModem::writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) -{ - assert(m_serial != NULL); - assert(my1 != NULL); - assert(my2 != NULL); - assert(your != NULL); - assert(type != NULL); - assert(reflector != NULL); - - unsigned char buffer[50U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 33U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_DSTAR; - - ::memcpy(buffer + 4U, my1, DSTAR_LONG_CALLSIGN_LENGTH); - ::memcpy(buffer + 12U, my2, DSTAR_SHORT_CALLSIGN_LENGTH); - - ::memcpy(buffer + 16U, your, DSTAR_LONG_CALLSIGN_LENGTH); - - ::memcpy(buffer + 24U, type, 1U); - - ::memcpy(buffer + 25U, reflector, DSTAR_LONG_CALLSIGN_LENGTH); - - return m_serial->write(buffer, 33U) != 33; -} - -bool CModem::writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dest, const char* type) -{ - assert(m_serial != NULL); - assert(type != NULL); - - unsigned char buffer[50U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 47U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_DMR; - - buffer[4U] = slotNo; - - ::sprintf((char*)(buffer + 5U), "%20.20s", src.c_str()); - - buffer[25U] = group ? 'G' : 'I'; - - ::sprintf((char*)(buffer + 26U), "%20.20s", dest.c_str()); - - ::memcpy(buffer + 46U, type, 1U); - - return m_serial->write(buffer, 47U) != 47; -} - -bool CModem::writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin) -{ - assert(m_serial != NULL); - assert(source != NULL); - assert(dest != NULL); - assert(type != NULL); - assert(origin != NULL); - - unsigned char buffer[50U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 35U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_YSF; - - ::memcpy(buffer + 4U, source, YSF_CALLSIGN_LENGTH); - ::memcpy(buffer + 14U, dest, YSF_CALLSIGN_LENGTH); - - ::memcpy(buffer + 24U, type, 1U); - - ::memcpy(buffer + 25U, origin, YSF_CALLSIGN_LENGTH); - - return m_serial->write(buffer, 35U) != 35; -} - -bool CModem::writeP25Info(const char* source, bool group, unsigned int dest, const char* type) -{ - assert(m_serial != NULL); - assert(source != NULL); - assert(type != NULL); - - unsigned char buffer[40U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 31U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_DMR; - - ::sprintf((char*)(buffer + 4U), "%20.20s", source); - - buffer[24U] = group ? 'G' : 'I'; - - ::sprintf((char*)(buffer + 25U), "%05u", dest); // 16-bits - - ::memcpy(buffer + 30U, type, 1U); - - return m_serial->write(buffer, 31U) != 31; -} - -bool CModem::writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type) -{ - assert(m_serial != NULL); - assert(source != NULL); - assert(type != NULL); - - unsigned char buffer[40U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 31U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_NXDN; - - ::sprintf((char*)(buffer + 4U), "%20.20s", source); - - buffer[24U] = group ? 'G' : 'I'; - - ::sprintf((char*)(buffer + 25U), "%05u", dest); // 16-bits - - ::memcpy(buffer + 30U, type, 1U); - - return m_serial->write(buffer, 31U) != 31; -} - -bool CModem::writePOCSAGInfo(unsigned int ric, const std::string& message) -{ - assert(m_serial != NULL); - - size_t length = message.size(); - - unsigned char buffer[250U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 11U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_POCSAG; - - ::sprintf((char*)(buffer + 4U), "%07u", ric); // 21-bits - - ::memcpy(buffer + 11U, message.c_str(), length); - - int ret = m_serial->write(buffer, length + 11U); - - return ret != int(length + 11U); -} - -bool CModem::writeIPInfo(const std::string& address) -{ - assert(m_serial != NULL); - - size_t length = address.size(); - - unsigned char buffer[25U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 4U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = 250U; - - ::memcpy(buffer + 4U, address.c_str(), length); - - int ret = m_serial->write(buffer, length + 4U); - - return ret != int(length + 4U); -} - -bool CModem::writeSerial(const unsigned char* data, unsigned int length) -{ - assert(m_serial != NULL); - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[250U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_SERIAL; - - ::memcpy(buffer + 3U, data, length); - - int ret = m_serial->write(buffer, length + 3U); - - return ret != int(length + 3U); -} - -bool CModem::hasTX() const -{ - return m_tx; -} - -bool CModem::hasCD() const -{ - return m_cd; -} - -bool CModem::hasLockout() const -{ - return m_lockout; -} - -bool CModem::hasError() const -{ - return m_error; -} - -bool CModem::readVersion() -{ - assert(m_serial != NULL); - - CThread::sleep(2000U); // 2s - - for (unsigned int i = 0U; i < 6U; i++) { - unsigned char buffer[3U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 3U; - buffer[2U] = MMDVM_GET_VERSION; - - // CUtils::dump(1U, "Written", buffer, 3U); - - int ret = m_serial->write(buffer, 3U); - if (ret != 3) - return false; - -#if defined(__APPLE__) - m_serial->setNonblock(true); -#endif - - for (unsigned int count = 0U; count < MAX_RESPONSES; count++) { - CThread::sleep(10U); - RESP_TYPE_MMDVM resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] == MMDVM_GET_VERSION) { - if (::memcmp(m_buffer + 4U, "MMDVM ", 6U) == 0) - m_hwType = HWT_MMDVM; - else if (::memcmp(m_buffer + 4U, "DVMEGA", 6U) == 0) - m_hwType = HWT_DVMEGA; - else if (::memcmp(m_buffer + 4U, "ZUMspot", 7U) == 0) - m_hwType = HWT_MMDVM_ZUMSPOT; - else if (::memcmp(m_buffer + 4U, "MMDVM_HS_Hat", 12U) == 0) - m_hwType = HWT_MMDVM_HS_HAT; - else if (::memcmp(m_buffer + 4U, "MMDVM_HS_Dual_Hat", 17U) == 0) - m_hwType = HWT_MMDVM_HS_DUAL_HAT; - else if (::memcmp(m_buffer + 4U, "Nano_hotSPOT", 12U) == 0) - m_hwType = HWT_NANO_HOTSPOT; - else if (::memcmp(m_buffer + 4U, "Nano_DV", 7U) == 0) - m_hwType = HWT_NANO_DV; - else if (::memcmp(m_buffer + 4U, "D2RG_MMDVM_HS", 13U) == 0) - m_hwType = HWT_D2RG_MMDVM_HS; - else if (::memcmp(m_buffer + 4U, "MMDVM_HS-", 9U) == 0) - m_hwType = HWT_MMDVM_HS; - else if (::memcmp(m_buffer + 4U, "OpenGD77_HS", 11U) == 0) - m_hwType = HWT_OPENGD77_HS; - - LogInfo("MMDVM protocol version: %u, description: %.*s", m_buffer[3U], m_length - 4U, m_buffer + 4U); - return true; - } - } - - CThread::sleep(1500U); - } - - LogError("Unable to read the firmware version after six attempts"); - - return false; -} - -bool CModem::readStatus() -{ - assert(m_serial != NULL); - - unsigned char buffer[3U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 3U; - buffer[2U] = MMDVM_GET_STATUS; - - // CUtils::dump(1U, "Written", buffer, 3U); - - return m_serial->write(buffer, 3U) == 3; -} - -bool CModem::writeConfig() -{ - return setConfig(); -} - -bool CModem::setConfig() -{ - assert(m_serial != NULL); - - unsigned char buffer[30U]; - - buffer[0U] = MMDVM_FRAME_START; - - buffer[1U] = 27U; - - buffer[2U] = MMDVM_SET_CONFIG; - - buffer[3U] = 0x00U; - if (m_rxInvert) - buffer[3U] |= 0x01U; - if (m_txInvert) - buffer[3U] |= 0x02U; - if (m_pttInvert) - buffer[3U] |= 0x04U; - if (m_ysfLoDev) - buffer[3U] |= 0x08U; - if (m_debug) - buffer[3U] |= 0x10U; - if (!m_duplex) - buffer[3U] |= 0x80U; - - buffer[4U] = 0x00U; - if (m_dstarEnabled) - buffer[4U] |= 0x01U; - if (m_dmrEnabled) - buffer[4U] |= 0x02U; - if (m_ysfEnabled) - buffer[4U] |= 0x04U; - if (m_p25Enabled) - buffer[4U] |= 0x08U; - if (m_nxdnEnabled) - buffer[4U] |= 0x10U; - if (m_pocsagEnabled) - buffer[4U] |= 0x20U; - if (m_fmEnabled && m_duplex) - buffer[4U] |= 0x40U; - if (m_ax25Enabled) - buffer[4U] |= 0x80U; - - buffer[5U] = m_txDelay / 10U; // In 10ms units - - buffer[6U] = MODE_IDLE; - - buffer[7U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); - - buffer[8U] = (unsigned char)(m_cwIdTXLevel * 2.55F + 0.5F); - - buffer[9U] = m_dmrColorCode; - - buffer[10U] = m_dmrDelay; - - buffer[11U] = 128U; // Was OscOffset - - buffer[12U] = (unsigned char)(m_dstarTXLevel * 2.55F + 0.5F); - buffer[13U] = (unsigned char)(m_dmrTXLevel * 2.55F + 0.5F); - buffer[14U] = (unsigned char)(m_ysfTXLevel * 2.55F + 0.5F); - buffer[15U] = (unsigned char)(m_p25TXLevel * 2.55F + 0.5F); - - buffer[16U] = (unsigned char)(m_txDCOffset + 128); - buffer[17U] = (unsigned char)(m_rxDCOffset + 128); - - buffer[18U] = (unsigned char)(m_nxdnTXLevel * 2.55F + 0.5F); - - buffer[19U] = (unsigned char)m_ysfTXHang; - - buffer[20U] = (unsigned char)(m_pocsagTXLevel * 2.55F + 0.5F); - - buffer[21U] = (unsigned char)(m_fmTXLevel * 2.55F + 0.5F); - - buffer[22U] = (unsigned char)m_p25TXHang; - - buffer[23U] = (unsigned char)m_nxdnTXHang; - - buffer[24U] = (unsigned char)(m_ax25TXLevel * 2.55F + 0.5F); - - buffer[25U] = (unsigned char)(m_ax25RXTwist + 128); - - buffer[26U] = m_ax25TXDelay / 10U; // In 10ms units - - // CUtils::dump(1U, "Written", buffer, 27U); - - int ret = m_serial->write(buffer, 27U); - if (ret != 27) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_CONFIG command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_CONFIG command from the modem"); - return false; - } - - m_playoutTimer.start(); - - return true; -} - -bool CModem::setFrequency() -{ - assert(m_serial != NULL); - - unsigned char buffer[20U]; - unsigned char len; - unsigned int pocsagFrequency = 433000000U; - - if (m_pocsagEnabled) - pocsagFrequency = m_pocsagFrequency; - - if (m_hwType == HWT_DVMEGA) - len = 12U; - else { - buffer[12U] = (unsigned char)(m_rfLevel * 2.55F + 0.5F); - - buffer[13U] = (pocsagFrequency >> 0) & 0xFFU; - buffer[14U] = (pocsagFrequency >> 8) & 0xFFU; - buffer[15U] = (pocsagFrequency >> 16) & 0xFFU; - buffer[16U] = (pocsagFrequency >> 24) & 0xFFU; - - len = 17U; - } - - buffer[0U] = MMDVM_FRAME_START; - - buffer[1U] = len; - - buffer[2U] = MMDVM_SET_FREQ; - - buffer[3U] = 0x00U; - - buffer[4U] = (m_rxFrequency >> 0) & 0xFFU; - buffer[5U] = (m_rxFrequency >> 8) & 0xFFU; - buffer[6U] = (m_rxFrequency >> 16) & 0xFFU; - buffer[7U] = (m_rxFrequency >> 24) & 0xFFU; - - buffer[8U] = (m_txFrequency >> 0) & 0xFFU; - buffer[9U] = (m_txFrequency >> 8) & 0xFFU; - buffer[10U] = (m_txFrequency >> 16) & 0xFFU; - buffer[11U] = (m_txFrequency >> 24) & 0xFFU; - - // CUtils::dump(1U, "Written", buffer, len); - - int ret = m_serial->write(buffer, len); - if (ret != len) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FREQ command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FREQ command from the modem"); - return false; - } - - return true; -} - -RESP_TYPE_MMDVM CModem::getResponse() -{ - assert(m_serial != NULL); - - if (m_state == SS_START) { - // Get the start of the frame or nothing at all - int ret = m_serial->read(m_buffer + 0U, 1U); - if (ret < 0) { - LogError("Error when reading from the modem"); - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - if (m_buffer[0U] != MMDVM_FRAME_START) - return RTM_TIMEOUT; - - m_state = SS_LENGTH1; - m_length = 1U; - } - - if (m_state == SS_LENGTH1) { - // Get the length of the frame, 1/2 - int ret = m_serial->read(m_buffer + 1U, 1U); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_state = SS_START; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - m_length = m_buffer[1U]; - m_offset = 2U; - - if (m_length == 0U) - m_state = SS_LENGTH2; - else - m_state = SS_TYPE; - } - - if (m_state == SS_LENGTH2) { - // Get the length of the frane, 2/2 - int ret = m_serial->read(m_buffer + 2U, 1U); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_state = SS_START; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - m_length = m_buffer[2U] + 255U; - m_offset = 3U; - m_state = SS_TYPE; - } - - if (m_state == SS_TYPE) { - // Get the frame type - int ret = m_serial->read(&m_type, 1U); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_state = SS_START; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - m_buffer[m_offset++] = m_type; - - m_state = SS_DATA; - } - - if (m_state == SS_DATA) { - while (m_offset < m_length) { - int ret = m_serial->read(m_buffer + m_offset, m_length - m_offset); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_state = SS_START; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - if (ret > 0) - m_offset += ret; - } - } - - // CUtils::dump(1U, "Received", m_buffer, m_length); - - m_offset = m_length > 255U ? 4U : 3U; - m_state = SS_START; - - return RTM_OK; -} - -HW_TYPE CModem::getHWType() const -{ - return m_hwType; -} - -unsigned char CModem::getMode() const -{ - return m_mode; -} - -bool CModem::setMode(unsigned char mode) -{ - assert(m_serial != NULL); - - unsigned char buffer[4U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 4U; - buffer[2U] = MMDVM_SET_MODE; - buffer[3U] = mode; - - // CUtils::dump(1U, "Written", buffer, 4U); - - return m_serial->write(buffer, 4U) == 4; -} - -bool CModem::sendCWId(const std::string& callsign) -{ - assert(m_serial != NULL); - - unsigned int length = callsign.length(); - if (length > 200U) - length = 200U; - - unsigned char buffer[205U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_SEND_CWID; - - for (unsigned int i = 0U; i < length; i++) - buffer[i + 3U] = callsign.at(i); - - // CUtils::dump(1U, "Written", buffer, length + 3U); - - return m_serial->write(buffer, length + 3U) == int(length + 3U); -} - -bool CModem::writeDMRStart(bool tx) -{ - assert(m_serial != NULL); - - if (tx && m_tx) - return true; - if (!tx && !m_tx) - return true; - - unsigned char buffer[4U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 4U; - buffer[2U] = MMDVM_DMR_START; - buffer[3U] = tx ? 0x01U : 0x00U; - - // CUtils::dump(1U, "Written", buffer, 4U); - - return m_serial->write(buffer, 4U) == 4; -} - -bool CModem::writeDMRAbort(unsigned int slotNo) -{ - assert(m_serial != NULL); - - if (slotNo == 1U) - m_txDMRData1.clear(); - else - m_txDMRData2.clear(); - - unsigned char buffer[4U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 4U; - buffer[2U] = MMDVM_DMR_ABORT; - buffer[3U] = slotNo; - - // CUtils::dump(1U, "Written", buffer, 4U); - - return m_serial->write(buffer, 4U) == 4; -} - -bool CModem::writeDMRShortLC(const unsigned char* lc) -{ - assert(m_serial != NULL); - assert(lc != NULL); - - unsigned char buffer[12U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 12U; - buffer[2U] = MMDVM_DMR_SHORTLC; - buffer[3U] = lc[0U]; - buffer[4U] = lc[1U]; - buffer[5U] = lc[2U]; - buffer[6U] = lc[3U]; - buffer[7U] = lc[4U]; - buffer[8U] = lc[5U]; - buffer[9U] = lc[6U]; - buffer[10U] = lc[7U]; - buffer[11U] = lc[8U]; - - // CUtils::dump(1U, "Written", buffer, 12U); - - return m_serial->write(buffer, 12U) == 12; -} - -void CModem::setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) -{ - m_fmCallsign = callsign; - m_fmCallsignSpeed = callsignSpeed; - m_fmCallsignFrequency = callsignFrequency; - m_fmCallsignTime = callsignTime; - m_fmCallsignHoldoff = callsignHoldoff; - m_fmCallsignHighLevel = callsignHighLevel; - m_fmCallsignLowLevel = callsignLowLevel; - m_fmCallsignAtStart = callsignAtStart; - m_fmCallsignAtEnd = callsignAtEnd; - m_fmCallsignAtLatch = callsignAtLatch; -} - -void CModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) -{ - m_fmRfAck = rfAck; - m_fmAckSpeed = ackSpeed; - m_fmAckFrequency = ackFrequency; - m_fmAckMinTime = ackMinTime; - m_fmAckDelay = ackDelay; - m_fmAckLevel = ackLevel; -} - -void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) -{ - m_fmTimeout = timeout; - m_fmTimeoutLevel = timeoutLevel; - - m_fmCtcssFrequency = ctcssFrequency; - m_fmCtcssHighThreshold = ctcssHighThreshold; - m_fmCtcssLowThreshold = ctcssLowThreshold; - m_fmCtcssLevel = ctcssLevel; - - m_fmKerchunkTime = kerchunkTime; - m_fmKerchunkTX = kerchunkTX; - - m_fmHangTime = hangTime; - - m_fmUseCOS = useCOS; - m_fmCOSInvert = cosInvert; - - m_fmRFAudioBoost = rfAudioBoost; - m_fmMaxDevLevel = maxDevLevel; -} - -void CModem::setFMExtParams(const std::string& ack, unsigned int audioBoost) -{ - m_fmExtAck = ack; - m_fmExtAudioBoost = audioBoost; - m_fmExtEnable = true; -} - -bool CModem::setFMCallsignParams() -{ - assert(m_serial != NULL); - - unsigned char buffer[80U]; - unsigned char len = 10U + m_fmCallsign.size(); - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = len; - buffer[2U] = MMDVM_FM_PARAMS1; - - buffer[3U] = m_fmCallsignSpeed; - buffer[4U] = m_fmCallsignFrequency / 10U; - buffer[5U] = m_fmCallsignTime; - buffer[6U] = m_fmCallsignHoldoff; - - buffer[7U] = (unsigned char)(m_fmCallsignHighLevel * 2.55F + 0.5F); - buffer[8U] = (unsigned char)(m_fmCallsignLowLevel * 2.55F + 0.5F); - - buffer[9U] = 0x00U; - if (m_fmCallsignAtStart) - buffer[9U] |= 0x01U; - if (m_fmCallsignAtEnd) - buffer[9U] |= 0x02U; - if (m_fmCallsignAtLatch) - buffer[9U] |= 0x04U; - - for (unsigned int i = 0U; i < m_fmCallsign.size(); i++) - buffer[10U + i] = m_fmCallsign.at(i); - - // CUtils::dump(1U, "Written", buffer, len); - - int ret = m_serial->write(buffer, len); - if (ret != len) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FM_PARAMS1 command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FM_PARAMS1 command from the modem"); - return false; - } - - return true; -} - -bool CModem::setFMAckParams() -{ - assert(m_serial != NULL); - - unsigned char buffer[80U]; - unsigned char len = 8U + m_fmRfAck.size(); - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = len; - buffer[2U] = MMDVM_FM_PARAMS2; - - buffer[3U] = m_fmAckSpeed; - buffer[4U] = m_fmAckFrequency / 10U; - buffer[5U] = m_fmAckMinTime; - buffer[6U] = m_fmAckDelay / 10U; - - buffer[7U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); - - for (unsigned int i = 0U; i < m_fmRfAck.size(); i++) - buffer[8U + i] = m_fmRfAck.at(i); - - // CUtils::dump(1U, "Written", buffer, len); - - int ret = m_serial->write(buffer, len); - if (ret != len) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FM_PARAMS2 command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FM_PARAMS2 command from the modem"); - return false; - } - - return true; -} - -bool CModem::setFMMiscParams() -{ - assert(m_serial != NULL); - - unsigned char buffer[20U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 15U; - buffer[2U] = MMDVM_FM_PARAMS3; - - buffer[3U] = m_fmTimeout / 5U; - buffer[4U] = (unsigned char)(m_fmTimeoutLevel * 2.55F + 0.5F); - - buffer[5U] = (unsigned char)m_fmCtcssFrequency; - buffer[6U] = m_fmCtcssHighThreshold; - buffer[7U] = m_fmCtcssLowThreshold; - buffer[8U] = (unsigned char)(m_fmCtcssLevel * 2.55F + 0.5F); - - buffer[9U] = m_fmKerchunkTime; - buffer[10U] = m_fmHangTime; - - buffer[11U] = 0x00U; - if (m_fmUseCOS) - buffer[11U] |= 0x01U; - if (m_fmCOSInvert) - buffer[11U] |= 0x02U; - if (m_fmKerchunkTX) - buffer[11U] |= 0x04U; - - buffer[12U] = m_fmRFAudioBoost; - - buffer[13U] = (unsigned char)(m_fmMaxDevLevel * 2.55F + 0.5F); - - buffer[14U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); - - // CUtils::dump(1U, "Written", buffer, 15U); - - int ret = m_serial->write(buffer, 15U); - if (ret != 15) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FM_PARAMS3 command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FM_PARAMS3 command from the modem"); - return false; - } - - return true; -} - -bool CModem::setFMExtParams() -{ - assert(m_serial != NULL); - - unsigned char buffer[80U]; - unsigned char len = 7U + m_fmExtAck.size(); - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = len; - buffer[2U] = MMDVM_FM_PARAMS4; - - buffer[3U] = m_fmExtAudioBoost; - buffer[4U] = m_fmAckSpeed; - buffer[5U] = m_fmAckFrequency / 10U; - - buffer[6U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); - - for (unsigned int i = 0U; i < m_fmExtAck.size(); i++) - buffer[7U + i] = m_fmExtAck.at(i); - - // CUtils::dump(1U, "Written", buffer, len); - - int ret = m_serial->write(buffer, len); - if (ret != len) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FM_PARAMS4 command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FM_PARAMS4 command from the modem"); - return false; - } - - return true; -} - -void CModem::printDebug() +IModem::~IModem() { - if (m_buffer[2U] == MMDVM_DEBUG1) { - LogMessage("Debug: %.*s", m_length - m_offset - 0U, m_buffer + m_offset); - } else if (m_buffer[2U] == MMDVM_DEBUG2) { - short val1 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d", m_length - m_offset - 2U, m_buffer + m_offset, val1); - } else if (m_buffer[2U] == MMDVM_DEBUG3) { - short val1 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; - short val2 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d", m_length - m_offset - 4U, m_buffer + m_offset, val1, val2); - } else if (m_buffer[2U] == MMDVM_DEBUG4) { - short val1 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; - short val2 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; - short val3 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d %d", m_length - m_offset - 6U, m_buffer + m_offset, val1, val2, val3); - } else if (m_buffer[2U] == MMDVM_DEBUG5) { - short val1 = (m_buffer[m_length - 8U] << 8) | m_buffer[m_length - 7U]; - short val2 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; - short val3 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; - short val4 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d %d %d", m_length - m_offset - 8U, m_buffer + m_offset, val1, val2, val3, val4); - } -} - -CModem* CModem::createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug){ - if (port == "NullModem") - return new CNullModem(port, duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); - else - return new CModem(port, duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); } diff --git a/Modem.h b/Modem.h index 822d50f..c408f01 100644 --- a/Modem.h +++ b/Modem.h @@ -19,249 +19,99 @@ #ifndef MODEM_H #define MODEM_H -#include "SerialPort.h" -#include "RingBuffer.h" #include "Defines.h" -#include "Timer.h" #include -enum RESP_TYPE_MMDVM { - RTM_OK, - RTM_TIMEOUT, - RTM_ERROR -}; - -enum SERIAL_STATE { - SS_START, - SS_LENGTH1, - SS_LENGTH2, - SS_TYPE, - SS_DATA -}; - -class CModem { +class IModem { public: - CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); - virtual ~CModem(); + virtual ~IModem() = 0; - virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed); - virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); - virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled); - virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel); - virtual void setDMRParams(unsigned int colorCode); - virtual void setYSFParams(bool loDev, unsigned int txHang); - virtual void setP25Params(unsigned int txHang); - virtual void setNXDNParams(unsigned int txHang); - virtual void setAX25Params(int rxTwist, unsigned int txDelay); - virtual void setTransparentDataParams(unsigned int sendFrameType); + virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) = 0; + virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) = 0; + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) = 0; + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel) = 0; + virtual void setDMRParams(unsigned int colorCode) = 0; + virtual void setYSFParams(bool loDev, unsigned int txHang) = 0; + virtual void setP25Params(unsigned int txHang) = 0; + virtual void setNXDNParams(unsigned int txHang) = 0; + virtual void setAX25Params(int rxTwist, unsigned int txDelay) = 0; + virtual void setTransparentDataParams(unsigned int sendFrameType) = 0; - virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); - virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); - virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost); + virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) = 0; + virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) = 0; + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) = 0; + virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost) = 0; - virtual bool open(); + virtual bool open() = 0; - virtual unsigned int readDStarData(unsigned char* data); - virtual unsigned int readDMRData1(unsigned char* data); - virtual unsigned int readDMRData2(unsigned char* data); - virtual unsigned int readYSFData(unsigned char* data); - virtual unsigned int readP25Data(unsigned char* data); - virtual unsigned int readNXDNData(unsigned char* data); - virtual unsigned int readFMData(unsigned char* data); - virtual unsigned int readAX25Data(unsigned char* data); - virtual unsigned int readTransparentData(unsigned char* data); + virtual unsigned int readDStarData(unsigned char* data) = 0; + virtual unsigned int readDMRData1(unsigned char* data) = 0; + virtual unsigned int readDMRData2(unsigned char* data) = 0; + virtual unsigned int readYSFData(unsigned char* data) = 0; + virtual unsigned int readP25Data(unsigned char* data) = 0; + virtual unsigned int readNXDNData(unsigned char* data) = 0; + virtual unsigned int readFMData(unsigned char* data) = 0; + virtual unsigned int readAX25Data(unsigned char* data) = 0; + virtual unsigned int readTransparentData(unsigned char* data) = 0; - virtual unsigned int readSerial(unsigned char* data, unsigned int length); + virtual unsigned int readSerial(unsigned char* data, unsigned int length) = 0; - virtual bool hasDStarSpace() const; - virtual bool hasDMRSpace1() const; - virtual bool hasDMRSpace2() const; - virtual bool hasYSFSpace() const; - virtual bool hasP25Space() const; - virtual bool hasNXDNSpace() const; - virtual bool hasPOCSAGSpace() const; - virtual unsigned int getFMSpace() const; - virtual bool hasAX25Space() const; + virtual bool hasDStarSpace() const = 0; + virtual bool hasDMRSpace1() const = 0; + virtual bool hasDMRSpace2() const = 0; + virtual bool hasYSFSpace() const = 0; + virtual bool hasP25Space() const = 0; + virtual bool hasNXDNSpace() const = 0; + virtual bool hasPOCSAGSpace() const = 0; + virtual unsigned int getFMSpace() const = 0; + virtual bool hasAX25Space() const = 0; - virtual bool hasTX() const; - virtual bool hasCD() const; + virtual bool hasTX() const = 0; + virtual bool hasCD() const = 0; - virtual bool hasLockout() const; - virtual bool hasError() const; + virtual bool hasLockout() const = 0; + virtual bool hasError() const = 0; - virtual bool writeConfig(); - virtual bool writeDStarData(const unsigned char* data, unsigned int length); - virtual bool writeDMRData1(const unsigned char* data, unsigned int length); - virtual bool writeDMRData2(const unsigned char* data, unsigned int length); - virtual bool writeYSFData(const unsigned char* data, unsigned int length); - virtual bool writeP25Data(const unsigned char* data, unsigned int length); - virtual bool writeNXDNData(const unsigned char* data, unsigned int length); - virtual bool writePOCSAGData(const unsigned char* data, unsigned int length); - virtual bool writeFMData(const unsigned char* data, unsigned int length); - virtual bool writeAX25Data(const unsigned char* data, unsigned int length); + virtual bool writeConfig() = 0; + virtual bool writeDStarData(const unsigned char* data, unsigned int length) = 0; + virtual bool writeDMRData1(const unsigned char* data, unsigned int length) = 0; + virtual bool writeDMRData2(const unsigned char* data, unsigned int length) = 0; + virtual bool writeYSFData(const unsigned char* data, unsigned int length) = 0; + virtual bool writeP25Data(const unsigned char* data, unsigned int length) = 0; + virtual bool writeNXDNData(const unsigned char* data, unsigned int length) = 0; + virtual bool writePOCSAGData(const unsigned char* data, unsigned int length) = 0; + virtual bool writeFMData(const unsigned char* data, unsigned int length) = 0; + virtual bool writeAX25Data(const unsigned char* data, unsigned int length) = 0; - virtual bool writeTransparentData(const unsigned char* data, unsigned int length); + virtual bool writeTransparentData(const unsigned char* data, unsigned int length) = 0; - virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); - virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type); - virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin); - virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type); - virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type); - virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message); - virtual bool writeIPInfo(const std::string& address); + virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0; + virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) = 0; + virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin) = 0; + virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type) = 0; + virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type) = 0; + virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message) = 0; + virtual bool writeIPInfo(const std::string& address) = 0; - virtual bool writeDMRStart(bool tx); - virtual bool writeDMRShortLC(const unsigned char* lc); - virtual bool writeDMRAbort(unsigned int slotNo); + virtual bool writeDMRStart(bool tx) = 0; + virtual bool writeDMRShortLC(const unsigned char* lc) = 0; + virtual bool writeDMRAbort(unsigned int slotNo) = 0; - virtual bool writeSerial(const unsigned char* data, unsigned int length); + virtual bool writeSerial(const unsigned char* data, unsigned int length) = 0; - virtual unsigned char getMode() const; - virtual bool setMode(unsigned char mode); + virtual unsigned char getMode() const = 0; + virtual bool setMode(unsigned char mode) = 0; - virtual bool sendCWId(const std::string& callsign); + virtual bool sendCWId(const std::string& callsign) = 0; - virtual HW_TYPE getHWType() const; + virtual HW_TYPE getHWType() const = 0; - virtual void clock(unsigned int ms); + virtual void clock(unsigned int ms) = 0; - virtual void close(); - - static CModem* createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); + virtual void close() = 0; private: - std::string m_port; - unsigned int m_dmrColorCode; - bool m_ysfLoDev; - unsigned int m_ysfTXHang; - unsigned int m_p25TXHang; - unsigned int m_nxdnTXHang; - bool m_duplex; - bool m_rxInvert; - bool m_txInvert; - bool m_pttInvert; - unsigned int m_txDelay; - unsigned int m_dmrDelay; - float m_rxLevel; - float m_cwIdTXLevel; - float m_dstarTXLevel; - float m_dmrTXLevel; - float m_ysfTXLevel; - float m_p25TXLevel; - float m_nxdnTXLevel; - float m_pocsagTXLevel; - float m_fmTXLevel; - float m_ax25TXLevel; - float m_rfLevel; - bool m_trace; - bool m_debug; - unsigned int m_rxFrequency; - unsigned int m_txFrequency; - unsigned int m_pocsagFrequency; - bool m_dstarEnabled; - bool m_dmrEnabled; - bool m_ysfEnabled; - bool m_p25Enabled; - bool m_nxdnEnabled; - bool m_pocsagEnabled; - bool m_fmEnabled; - bool m_ax25Enabled; - int m_rxDCOffset; - int m_txDCOffset; - ISerialPort* m_serial; - unsigned char* m_buffer; - unsigned int m_length; - unsigned int m_offset; - SERIAL_STATE m_state; - unsigned char m_type; - CRingBuffer m_rxDStarData; - CRingBuffer m_txDStarData; - CRingBuffer m_rxDMRData1; - CRingBuffer m_rxDMRData2; - CRingBuffer m_txDMRData1; - CRingBuffer m_txDMRData2; - CRingBuffer m_rxYSFData; - CRingBuffer m_txYSFData; - CRingBuffer m_rxP25Data; - CRingBuffer m_txP25Data; - CRingBuffer m_rxNXDNData; - CRingBuffer m_txNXDNData; - CRingBuffer m_txPOCSAGData; - CRingBuffer m_rxFMData; - CRingBuffer m_txFMData; - CRingBuffer m_rxAX25Data; - CRingBuffer m_txAX25Data; - CRingBuffer m_rxTransparentData; - CRingBuffer m_txTransparentData; - unsigned int m_sendTransparentDataFrameType; - CTimer m_statusTimer; - CTimer m_inactivityTimer; - CTimer m_playoutTimer; - unsigned int m_dstarSpace; - unsigned int m_dmrSpace1; - unsigned int m_dmrSpace2; - unsigned int m_ysfSpace; - unsigned int m_p25Space; - unsigned int m_nxdnSpace; - unsigned int m_pocsagSpace; - unsigned int m_fmSpace; - unsigned int m_ax25Space; - bool m_tx; - bool m_cd; - bool m_lockout; - bool m_error; - unsigned char m_mode; - HW_TYPE m_hwType; - int m_ax25RXTwist; - unsigned int m_ax25TXDelay; - - std::string m_fmCallsign; - unsigned int m_fmCallsignSpeed; - unsigned int m_fmCallsignFrequency; - unsigned int m_fmCallsignTime; - unsigned int m_fmCallsignHoldoff; - float m_fmCallsignHighLevel; - float m_fmCallsignLowLevel; - bool m_fmCallsignAtStart; - bool m_fmCallsignAtEnd; - bool m_fmCallsignAtLatch; - std::string m_fmRfAck; - std::string m_fmExtAck; - unsigned int m_fmAckSpeed; - unsigned int m_fmAckFrequency; - unsigned int m_fmAckMinTime; - unsigned int m_fmAckDelay; - float m_fmAckLevel; - unsigned int m_fmTimeout; - float m_fmTimeoutLevel; - float m_fmCtcssFrequency; - unsigned int m_fmCtcssHighThreshold; - unsigned int m_fmCtcssLowThreshold; - float m_fmCtcssLevel; - unsigned int m_fmKerchunkTime; - bool m_fmKerchunkTX; - unsigned int m_fmHangTime; - bool m_fmUseCOS; - bool m_fmCOSInvert; - unsigned int m_fmRFAudioBoost; - unsigned int m_fmExtAudioBoost; - float m_fmMaxDevLevel; - bool m_fmExtEnable; - - bool readVersion(); - bool readStatus(); - bool setConfig(); - bool setFrequency(); - bool setFMCallsignParams(); - bool setFMAckParams(); - bool setFMMiscParams(); - bool setFMExtParams(); - - void printDebug(); - - RESP_TYPE_MMDVM getResponse(); }; #endif diff --git a/ModemSerialPort.cpp b/ModemSerialPort.cpp index 51ba01d..c34cb3d 100644 --- a/ModemSerialPort.cpp +++ b/ModemSerialPort.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2016,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 @@ -21,22 +21,22 @@ #include #include -CModemSerialPort::CModemSerialPort(CModem* modem) : +IModemSerialPort::IModemSerialPort(IModem* modem) : m_modem(modem) { assert(modem != NULL); } -CModemSerialPort::~CModemSerialPort() +IModemSerialPort::~IModemSerialPort() { } -bool CModemSerialPort::open() +bool IModemSerialPort::open() { return true; } -int CModemSerialPort::write(const unsigned char* data, unsigned int length) +int IModemSerialPort::write(const unsigned char* data, unsigned int length) { assert(data != NULL); assert(length > 0U); @@ -46,7 +46,7 @@ int CModemSerialPort::write(const unsigned char* data, unsigned int length) return ret ? int(length) : -1; } -int CModemSerialPort::read(unsigned char* data, unsigned int length) +int IModemSerialPort::read(unsigned char* data, unsigned int length) { assert(data != NULL); assert(length > 0U); @@ -54,6 +54,6 @@ int CModemSerialPort::read(unsigned char* data, unsigned int length) return m_modem->readSerial(data, length); } -void CModemSerialPort::close() +void IModemSerialPort::close() { } diff --git a/ModemSerialPort.h b/ModemSerialPort.h index d6761ce..6de56a7 100644 --- a/ModemSerialPort.h +++ b/ModemSerialPort.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2016,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 @@ -22,10 +22,10 @@ #include "SerialPort.h" #include "Modem.h" -class CModemSerialPort : public ISerialPort { +class IModemSerialPort : public ISerialPort { public: - CModemSerialPort(CModem* modem); - virtual ~CModemSerialPort(); + IModemSerialPort(IModem* modem); + virtual ~IModemSerialPort(); virtual bool open(); @@ -36,7 +36,7 @@ public: virtual void close(); private: - CModem* m_modem; + IModem* m_modem; }; #endif diff --git a/NullModem.cpp b/NullModem.cpp index 8539f1b..40e3fdd 100644 --- a/NullModem.cpp +++ b/NullModem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 by Jonathan Naylor G4KLX + * Copyright (C) 2011-2018,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 @@ -19,9 +19,7 @@ #include "NullModem.h" #include "Log.h" -CNullModem::CNullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug) : -CModem(port, duplex,rxInvert, txInvert,pttInvert,txDelay, dmrDelay, trace, debug), -m_hwType(HWT_MMDVM) +CNullModem::CNullModem() { } @@ -29,7 +27,9 @@ CNullModem::~CNullModem() { } -bool CNullModem::open(){ +bool CNullModem::open() +{ ::LogMessage("Opening the MMDVM Null Modem"); + return true; -} \ No newline at end of file +} diff --git a/NullModem.h b/NullModem.h index 49dd3ec..12ae460 100644 --- a/NullModem.h +++ b/NullModem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 by Jonathan Naylor G4KLX + * Copyright (C) 2011-2018,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 @@ -24,16 +24,15 @@ #include - -class CNullModem : public CModem { +class CNullModem : public IModem { public: - CNullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); + CNullModem(); virtual ~CNullModem(); - virtual void setSerialParams(const std::string& protocol, unsigned int address) {}; + virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) {}; virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) {}; - virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled) {}; - virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel) {}; + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) {}; + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel) {}; virtual void setDMRParams(unsigned int colorCode) {}; virtual void setYSFParams(bool loDev, unsigned int txHang) {}; virtual void setP25Params(unsigned int txHang) {}; @@ -58,7 +57,7 @@ public: virtual unsigned int readAX25Data(unsigned char* data) { return 0U; }; virtual unsigned int readTransparentData(unsigned char* data) { return 0U; }; - virtual unsigned int readSerial(unsigned char* data, unsigned int length){return 0;}; + virtual unsigned int readSerial(unsigned char* data, unsigned int length) { return 0; }; virtual bool hasDStarSpace()const { return true; }; virtual bool hasDMRSpace1() const { return true; }; @@ -79,41 +78,42 @@ public: virtual bool writeDStarData(const unsigned char* data, unsigned int length) { return true; }; virtual bool writeDMRData1(const unsigned char* data, unsigned int length) { return true; }; virtual bool writeDMRData2(const unsigned char* data, unsigned int length) { return true; }; - virtual bool writeYSFData(const unsigned char* data, unsigned int length) {return true; }; + virtual bool writeYSFData(const unsigned char* data, unsigned int length) { return true; }; virtual bool writeP25Data(const unsigned char* data, unsigned int length) { return true; }; virtual bool writeNXDNData(const unsigned char* data, unsigned int length) { return true; }; virtual bool writePOCSAGData(const unsigned char* data, unsigned int length) { return true; }; virtual bool writeFMData(const unsigned char* data, unsigned int length) { return true; }; virtual bool writeAX25Data(const unsigned char* data, unsigned int length) { return true; }; - virtual bool writeTransparentData(const unsigned char* data, unsigned int length){return true;}; + virtual bool writeTransparentData(const unsigned char* data, unsigned int length) { return true; }; - virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector){return true;}; - virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type){return true;}; - virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin){return true;}; - virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type){return true;}; - virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type){return true;}; - virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message){return true;}; - virtual bool writeIPInfo(const std::string& address){return true;}; + virtual bool writeConfig() { return true; }; + virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { return true; }; + virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) { return true; }; + virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin) { return true; }; + virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type) { return true; }; + virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type) { return true; }; + virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message) { return true; }; + virtual bool writeIPInfo(const std::string& address) { return true; }; - virtual bool writeDMRStart(bool tx){return true;}; - virtual bool writeDMRShortLC(const unsigned char* lc){return true;}; - virtual bool writeDMRAbort(unsigned int slotNo){return true;}; + virtual bool writeDMRStart(bool tx) { return true; }; + virtual bool writeDMRShortLC(const unsigned char* lc) { return true; }; + virtual bool writeDMRAbort(unsigned int slotNo) { return true; }; - virtual bool writeSerial(const unsigned char* data, unsigned int length){return true;}; + virtual bool writeSerial(const unsigned char* data, unsigned int length) { return true; }; - virtual bool setMode(unsigned char mode){return true;}; + virtual unsigned char getMode() const { return MODE_IDLE; }; + virtual bool setMode(unsigned char mode) { return true; }; - virtual bool sendCWId(const std::string& callsign){return true;}; + virtual bool sendCWId(const std::string& callsign) { return true; }; - virtual HW_TYPE getHWType() const {return m_hwType;}; + virtual HW_TYPE getHWType() const { return HWT_MMDVM; }; - virtual void clock(unsigned int ms){}; + virtual void clock(unsigned int ms) {}; - virtual void close(){}; + virtual void close() {}; private: - HW_TYPE m_hwType; }; #endif diff --git a/SerialModem.cpp b/SerialModem.cpp new file mode 100644 index 0000000..10ddefa --- /dev/null +++ b/SerialModem.cpp @@ -0,0 +1,2465 @@ +/* + * Copyright (C) 2011-2018,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 "SerialController.h" +#if defined(__linux__) +#include "I2CController.h" +#endif +#include "DStarDefines.h" +#include "DMRDefines.h" +#include "YSFDefines.h" +#include "P25Defines.h" +#include "NXDNDefines.h" +#include "AX25Defines.h" +#include "POCSAGDefines.h" +#include "Thread.h" +#include "SerialModem.h" +#include "NullModem.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include +#include +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +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_SEND_CWID = 0x0AU; + +const unsigned char MMDVM_DSTAR_HEADER = 0x10U; +const unsigned char MMDVM_DSTAR_DATA = 0x11U; +const unsigned char MMDVM_DSTAR_LOST = 0x12U; +const unsigned char MMDVM_DSTAR_EOT = 0x13U; + +const unsigned char MMDVM_DMR_DATA1 = 0x18U; +const unsigned char MMDVM_DMR_LOST1 = 0x19U; +const unsigned char MMDVM_DMR_DATA2 = 0x1AU; +const unsigned char MMDVM_DMR_LOST2 = 0x1BU; +const unsigned char MMDVM_DMR_SHORTLC = 0x1CU; +const unsigned char MMDVM_DMR_START = 0x1DU; +const unsigned char MMDVM_DMR_ABORT = 0x1EU; + +const unsigned char MMDVM_YSF_DATA = 0x20U; +const unsigned char MMDVM_YSF_LOST = 0x21U; + +const unsigned char MMDVM_P25_HDR = 0x30U; +const unsigned char MMDVM_P25_LDU = 0x31U; +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_POCSAG_DATA = 0x50U; + +const unsigned char MMDVM_AX25_DATA = 0x55U; + +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_FM_DATA = 0x65U; +const unsigned char MMDVM_FM_CONTROL = 0x66U; +const unsigned char MMDVM_FM_EOT = 0x67U; + +const unsigned char MMDVM_ACK = 0x70U; +const unsigned char MMDVM_NAK = 0x7FU; + +const unsigned char MMDVM_SERIAL = 0x80U; + +const unsigned char MMDVM_TRANSPARENT = 0x90U; +const unsigned char MMDVM_QSO_INFO = 0x91U; + +const unsigned char MMDVM_DEBUG1 = 0xF1U; +const unsigned char MMDVM_DEBUG2 = 0xF2U; +const unsigned char MMDVM_DEBUG3 = 0xF3U; +const unsigned char MMDVM_DEBUG4 = 0xF4U; +const unsigned char MMDVM_DEBUG5 = 0xF5U; + +const unsigned int MAX_RESPONSES = 30U; + +const unsigned int BUFFER_LENGTH = 2000U; + + +CSerialModem::CSerialModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug) : +m_port(port), +m_dmrColorCode(0U), +m_ysfLoDev(false), +m_ysfTXHang(4U), +m_p25TXHang(5U), +m_nxdnTXHang(5U), +m_duplex(duplex), +m_rxInvert(rxInvert), +m_txInvert(txInvert), +m_pttInvert(pttInvert), +m_txDelay(txDelay), +m_dmrDelay(dmrDelay), +m_rxLevel(0.0F), +m_cwIdTXLevel(0.0F), +m_dstarTXLevel(0.0F), +m_dmrTXLevel(0.0F), +m_ysfTXLevel(0.0F), +m_p25TXLevel(0.0F), +m_nxdnTXLevel(0.0F), +m_pocsagTXLevel(0.0F), +m_fmTXLevel(0.0F), +m_ax25TXLevel(0.0F), +m_rfLevel(0.0F), +m_trace(trace), +m_debug(debug), +m_rxFrequency(0U), +m_txFrequency(0U), +m_pocsagFrequency(0U), +m_dstarEnabled(false), +m_dmrEnabled(false), +m_ysfEnabled(false), +m_p25Enabled(false), +m_nxdnEnabled(false), +m_pocsagEnabled(false), +m_fmEnabled(false), +m_ax25Enabled(false), +m_rxDCOffset(0), +m_txDCOffset(0), +m_serial(NULL), +m_buffer(NULL), +m_length(0U), +m_offset(0U), +m_state(SS_START), +m_type(0U), +m_rxDStarData(1000U, "Modem RX D-Star"), +m_txDStarData(1000U, "Modem TX D-Star"), +m_rxDMRData1(1000U, "Modem RX DMR1"), +m_rxDMRData2(1000U, "Modem RX DMR2"), +m_txDMRData1(1000U, "Modem TX DMR1"), +m_txDMRData2(1000U, "Modem TX DMR2"), +m_rxYSFData(1000U, "Modem RX YSF"), +m_txYSFData(1000U, "Modem TX YSF"), +m_rxP25Data(1000U, "Modem RX P25"), +m_txP25Data(1000U, "Modem TX P25"), +m_rxNXDNData(1000U, "Modem RX NXDN"), +m_txNXDNData(1000U, "Modem TX NXDN"), +m_txPOCSAGData(1000U, "Modem TX POCSAG"), +m_rxFMData(5000U, "Modem RX FM"), +m_txFMData(5000U, "Modem TX FM"), +m_rxAX25Data(1000U, "Modem RX AX.25"), +m_txAX25Data(1000U, "Modem TX AX.25"), +m_rxTransparentData(1000U, "Modem RX Transparent"), +m_txTransparentData(1000U, "Modem TX Transparent"), +m_sendTransparentDataFrameType(0U), +m_statusTimer(1000U, 0U, 250U), +m_inactivityTimer(1000U, 2U), +m_playoutTimer(1000U, 0U, 10U), +m_dstarSpace(0U), +m_dmrSpace1(0U), +m_dmrSpace2(0U), +m_ysfSpace(0U), +m_p25Space(0U), +m_nxdnSpace(0U), +m_pocsagSpace(0U), +m_fmSpace(0U), +m_ax25Space(0U), +m_tx(false), +m_cd(false), +m_lockout(false), +m_error(false), +m_mode(MODE_IDLE), +m_hwType(HWT_UNKNOWN), +m_ax25RXTwist(0), +m_ax25TXDelay(300U), +m_fmCallsign(), +m_fmCallsignSpeed(20U), +m_fmCallsignFrequency(1000U), +m_fmCallsignTime(600U), +m_fmCallsignHoldoff(0U), +m_fmCallsignHighLevel(35.0F), +m_fmCallsignLowLevel(15.0F), +m_fmCallsignAtStart(true), +m_fmCallsignAtEnd(true), +m_fmCallsignAtLatch(true), +m_fmRfAck("K"), +m_fmExtAck("N"), +m_fmAckSpeed(20U), +m_fmAckFrequency(1750U), +m_fmAckMinTime(4U), +m_fmAckDelay(1000U), +m_fmAckLevel(80.0F), +m_fmTimeout(120U), +m_fmTimeoutLevel(80.0F), +m_fmCtcssFrequency(88.4F), +m_fmCtcssHighThreshold(30U), +m_fmCtcssLowThreshold(20U), +m_fmCtcssLevel(10.0F), +m_fmKerchunkTime(0U), +m_fmKerchunkTX(true), +m_fmHangTime(5U), +m_fmUseCOS(true), +m_fmCOSInvert(false), +m_fmRFAudioBoost(1U), +m_fmExtAudioBoost(1U), +m_fmMaxDevLevel(90.0F), +m_fmExtEnable(false) +{ + m_buffer = new unsigned char[BUFFER_LENGTH]; + + assert(!port.empty()); +} + +CSerialModem::~CSerialModem() +{ + delete m_serial; + delete[] m_buffer; +} + +void CSerialModem::setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) +{ + // Create the serial controller instance according the protocol specified in conf. +#if defined(__linux__) + if (protocol == "i2c") + m_serial = new CI2CController(m_port, address); + else +#endif + m_serial = new CSerialController(m_port, speed, true); +} + +void CSerialModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) +{ + m_rxFrequency = rxFrequency + rxOffset; + m_txFrequency = txFrequency + txOffset; + m_txDCOffset = txDCOffset; + m_rxDCOffset = rxDCOffset; + m_rfLevel = rfLevel; + m_pocsagFrequency = pocsagFrequency + txOffset; +} + +void CSerialModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) +{ + m_dstarEnabled = dstarEnabled; + m_dmrEnabled = dmrEnabled; + m_ysfEnabled = ysfEnabled; + m_p25Enabled = p25Enabled; + m_nxdnEnabled = nxdnEnabled; + m_pocsagEnabled = pocsagEnabled; + m_fmEnabled = fmEnabled; + m_ax25Enabled = ax25Enabled; +} + +void CSerialModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel, float ax25TXLevel) +{ + m_rxLevel = rxLevel; + m_cwIdTXLevel = cwIdTXLevel; + m_dstarTXLevel = dstarTXLevel; + m_dmrTXLevel = dmrTXLevel; + m_ysfTXLevel = ysfTXLevel; + m_p25TXLevel = p25TXLevel; + m_nxdnTXLevel = nxdnTXLevel; + m_pocsagTXLevel = pocsagTXLevel; + m_fmTXLevel = fmTXLevel; + m_ax25TXLevel = ax25TXLevel; +} + +void CSerialModem::setDMRParams(unsigned int colorCode) +{ + assert(colorCode < 16U); + + m_dmrColorCode = colorCode; +} + +void CSerialModem::setYSFParams(bool loDev, unsigned int txHang) +{ + m_ysfLoDev = loDev; + m_ysfTXHang = txHang; +} + +void CSerialModem::setP25Params(unsigned int txHang) +{ + m_p25TXHang = txHang; +} + +void CSerialModem::setNXDNParams(unsigned int txHang) +{ + m_nxdnTXHang = txHang; +} + +void CSerialModem::setAX25Params(int rxTwist, unsigned int txDelay) +{ + m_ax25RXTwist = rxTwist; + m_ax25TXDelay = txDelay; +} + +void CSerialModem::setTransparentDataParams(unsigned int sendFrameType) +{ + m_sendTransparentDataFrameType = sendFrameType; +} + +bool CSerialModem::open() +{ + ::LogMessage("Opening the MMDVM"); + + bool ret = m_serial->open(); + if (!ret) + return false; + + ret = readVersion(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } else { + /* Stopping the inactivity timer here when a firmware version has been + successfuly read prevents the death spiral of "no reply from modem..." */ + m_inactivityTimer.stop(); + } + + ret = setFrequency(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + ret = setConfig(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + if (m_fmEnabled && m_duplex) { + ret = setFMCallsignParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + ret = setFMAckParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + ret = setFMMiscParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + if (m_fmExtEnable) { + ret = setFMExtParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + } + } + + m_statusTimer.start(); + + m_error = false; + m_offset = 0U; + + return true; +} + +void CSerialModem::clock(unsigned int ms) +{ + assert(m_serial != NULL); + + // Poll the modem status every 250ms + m_statusTimer.clock(ms); + if (m_statusTimer.hasExpired()) { + readStatus(); + m_statusTimer.start(); + } + + m_inactivityTimer.clock(ms); + if (m_inactivityTimer.hasExpired()) { + LogError("No reply from the modem for some time, resetting it"); + m_error = true; + close(); + + CThread::sleep(2000U); // 2s + while (!open()) + CThread::sleep(5000U); // 5s + } + + RESP_TYPE_MMDVM type = getResponse(); + + if (type == RTM_TIMEOUT) { + // Nothing to do + } else if (type == RTM_ERROR) { + // Nothing to do + } else { + // type == RTM_OK + switch (m_type) { + case MMDVM_DSTAR_HEADER: { + if (m_trace) + CUtils::dump(1U, "RX D-Star Header", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxDStarData.addData(&data, 1U); + + data = TAG_HEADER; + m_rxDStarData.addData(&data, 1U); + + m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_DSTAR_DATA: { + if (m_trace) + CUtils::dump(1U, "RX D-Star Data", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxDStarData.addData(&data, 1U); + + data = TAG_DATA; + m_rxDStarData.addData(&data, 1U); + + m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_DSTAR_LOST: { + if (m_trace) + CUtils::dump(1U, "RX D-Star Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxDStarData.addData(&data, 1U); + + data = TAG_LOST; + m_rxDStarData.addData(&data, 1U); + } + break; + + case MMDVM_DSTAR_EOT: { + if (m_trace) + CUtils::dump(1U, "RX D-Star EOT", m_buffer, m_length); + + unsigned char data = 1U; + m_rxDStarData.addData(&data, 1U); + + data = TAG_EOT; + m_rxDStarData.addData(&data, 1U); + } + break; + + case MMDVM_DMR_DATA1: { + if (m_trace) + CUtils::dump(1U, "RX DMR Data 1", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxDMRData1.addData(&data, 1U); + + if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) + data = TAG_EOT; + else + data = TAG_DATA; + m_rxDMRData1.addData(&data, 1U); + + m_rxDMRData1.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_DMR_DATA2: { + if (m_trace) + CUtils::dump(1U, "RX DMR Data 2", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxDMRData2.addData(&data, 1U); + + if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) + data = TAG_EOT; + else + data = TAG_DATA; + m_rxDMRData2.addData(&data, 1U); + + m_rxDMRData2.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_DMR_LOST1: { + if (m_trace) + CUtils::dump(1U, "RX DMR Lost 1", m_buffer, m_length); + + unsigned char data = 1U; + m_rxDMRData1.addData(&data, 1U); + + data = TAG_LOST; + m_rxDMRData1.addData(&data, 1U); + } + break; + + case MMDVM_DMR_LOST2: { + if (m_trace) + CUtils::dump(1U, "RX DMR Lost 2", m_buffer, m_length); + + unsigned char data = 1U; + m_rxDMRData2.addData(&data, 1U); + + data = TAG_LOST; + m_rxDMRData2.addData(&data, 1U); + } + break; + + case MMDVM_YSF_DATA: { + if (m_trace) + CUtils::dump(1U, "RX YSF Data", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxYSFData.addData(&data, 1U); + + data = TAG_DATA; + m_rxYSFData.addData(&data, 1U); + + m_rxYSFData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_YSF_LOST: { + if (m_trace) + CUtils::dump(1U, "RX YSF Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxYSFData.addData(&data, 1U); + + data = TAG_LOST; + m_rxYSFData.addData(&data, 1U); + } + break; + + case MMDVM_P25_HDR: { + if (m_trace) + CUtils::dump(1U, "RX P25 Header", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_HEADER; + m_rxP25Data.addData(&data, 1U); + + m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_P25_LDU: { + if (m_trace) + CUtils::dump(1U, "RX P25 LDU", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_DATA; + m_rxP25Data.addData(&data, 1U); + + m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_P25_LOST: { + if (m_trace) + CUtils::dump(1U, "RX P25 Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_LOST; + m_rxP25Data.addData(&data, 1U); + } + break; + + case MMDVM_NXDN_DATA: { + if (m_trace) + CUtils::dump(1U, "RX NXDN Data", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxNXDNData.addData(&data, 1U); + + data = TAG_DATA; + m_rxNXDNData.addData(&data, 1U); + + m_rxNXDNData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_NXDN_LOST: { + if (m_trace) + CUtils::dump(1U, "RX NXDN Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxNXDNData.addData(&data, 1U); + + data = TAG_LOST; + m_rxNXDNData.addData(&data, 1U); + } + break; + + case MMDVM_FM_DATA: { + if (m_trace) + CUtils::dump(1U, "RX FM Data", m_buffer, m_length); + + unsigned int data1 = m_length - m_offset + 1U; + m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); + + unsigned char data2 = TAG_DATA; + m_rxFMData.addData(&data2, 1U); + + m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_FM_CONTROL: { + if (m_trace) + CUtils::dump(1U, "RX FM Control", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxFMData.addData(&data, 1U); + + data = TAG_HEADER; + m_rxFMData.addData(&data, 1U); + + m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_FM_EOT: { + if(m_trace) + CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxFMData.addData(&data, 1U); + + data = TAG_EOT; + m_rxFMData.addData(&data, 1U); + + m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_AX25_DATA: { + if (m_trace) + CUtils::dump(1U, "RX AX.25 Data", m_buffer, m_length); + + unsigned int data = m_length - m_offset; + m_rxAX25Data.addData((unsigned char*)&data, sizeof(unsigned int)); + + m_rxAX25Data.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_GET_STATUS: { + // if (m_trace) + // CUtils::dump(1U, "GET_STATUS", m_buffer, m_length); + + m_p25Space = 0U; + m_nxdnSpace = 0U; + m_pocsagSpace = 0U; + m_fmSpace = 0U; + m_ax25Space = 0U; + + m_mode = m_buffer[m_offset + 1U]; + + m_tx = (m_buffer[m_offset + 2U] & 0x01U) == 0x01U; + + bool adcOverflow = (m_buffer[m_offset + 2U] & 0x02U) == 0x02U; + if (adcOverflow) + LogError("MMDVM ADC levels have overflowed"); + + bool rxOverflow = (m_buffer[m_offset + 2U] & 0x04U) == 0x04U; + if (rxOverflow) + LogError("MMDVM RX buffer has overflowed"); + + bool txOverflow = (m_buffer[m_offset + 2U] & 0x08U) == 0x08U; + if (txOverflow) + LogError("MMDVM TX buffer has overflowed"); + + m_lockout = (m_buffer[m_offset + 2U] & 0x10U) == 0x10U; + + bool dacOverflow = (m_buffer[m_offset + 2U] & 0x20U) == 0x20U; + if (dacOverflow) + LogError("MMDVM DAC levels have overflowed"); + + m_cd = (m_buffer[m_offset + 2U] & 0x40U) == 0x40U; + + m_dstarSpace = m_buffer[m_offset + 3U]; + m_dmrSpace1 = m_buffer[m_offset + 4U]; + m_dmrSpace2 = m_buffer[m_offset + 5U]; + m_ysfSpace = m_buffer[m_offset + 6U]; + + if (m_length > (m_offset + 7U)) + m_p25Space = m_buffer[m_offset + 7U]; + if (m_length > (m_offset + 8U)) + m_nxdnSpace = m_buffer[m_offset + 8U]; + if (m_length > (m_offset + 9U)) + m_pocsagSpace = m_buffer[m_offset + 9U]; + if (m_length > (m_offset + 10U)) + m_fmSpace = m_buffer[m_offset + 10U]; + if (m_length > (m_offset + 11U)) + m_ax25Space = m_buffer[m_offset + 11U]; + + m_inactivityTimer.start(); + // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, m_fmSpace, m_ax25Space, int(m_lockout), int(m_cd)); + } + break; + + case MMDVM_TRANSPARENT: { + if (m_trace) + CUtils::dump(1U, "RX Transparent Data", m_buffer, m_length); + + unsigned char offset = m_sendTransparentDataFrameType; + if (offset > 1U) offset = 1U; + unsigned char data = m_length - m_offset + offset; + m_rxTransparentData.addData(&data, 1U); + + m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); + } + break; + + // These should not be received, but don't complain if we do + case MMDVM_GET_VERSION: + case MMDVM_ACK: + break; + + case MMDVM_NAK: + LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[m_offset], m_buffer[m_offset + 1U]); + break; + + case MMDVM_DEBUG1: + case MMDVM_DEBUG2: + case MMDVM_DEBUG3: + case MMDVM_DEBUG4: + case MMDVM_DEBUG5: + printDebug(); + break; + + case MMDVM_SERIAL: + //MMDVMHost does not process serial data from the display, + // so we send it to the transparent port if sendFrameType==1 + if (m_sendTransparentDataFrameType > 0U) { + if (m_trace) + CUtils::dump(1U, "RX Serial Data", m_buffer, m_length); + + unsigned char offset = m_sendTransparentDataFrameType; + if (offset > 1U) offset = 1U; + unsigned char data = m_length - m_offset + offset; + m_rxTransparentData.addData(&data, 1U); + + m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); + break; //only break when sendFrameType>0, else message is unknown + } + default: + LogMessage("Unknown message, type: %02X", m_type); + CUtils::dump("Buffer dump", m_buffer, m_length); + break; + } + } + + // Only feed data to the modem if the playout timer has expired + m_playoutTimer.clock(ms); + if (!m_playoutTimer.hasExpired()) + return; + + if (m_dstarSpace > 1U && !m_txDStarData.isEmpty()) { + unsigned char buffer[4U]; + m_txDStarData.peek(buffer, 4U); + + if ((buffer[3U] == MMDVM_DSTAR_HEADER && m_dstarSpace > 4U) || + (buffer[3U] == MMDVM_DSTAR_DATA && m_dstarSpace > 1U) || + (buffer[3U] == MMDVM_DSTAR_EOT && m_dstarSpace > 1U)) { + unsigned char len = 0U; + m_txDStarData.getData(&len, 1U); + m_txDStarData.getData(m_buffer, len); + + switch (buffer[3U]) { + case MMDVM_DSTAR_HEADER: + if (m_trace) + CUtils::dump(1U, "TX D-Star Header", m_buffer, len); + m_dstarSpace -= 4U; + break; + case MMDVM_DSTAR_DATA: + if (m_trace) + CUtils::dump(1U, "TX D-Star Data", m_buffer, len); + m_dstarSpace -= 1U; + break; + default: + if (m_trace) + CUtils::dump(1U, "TX D-Star EOT", m_buffer, len); + m_dstarSpace -= 1U; + break; + } + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing D-Star data to the MMDVM"); + + m_playoutTimer.start(); + } + } + + if (m_dmrSpace1 > 1U && !m_txDMRData1.isEmpty()) { + unsigned char len = 0U; + m_txDMRData1.getData(&len, 1U); + m_txDMRData1.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX DMR Data 1", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing DMR data to the MMDVM"); + + m_playoutTimer.start(); + + m_dmrSpace1--; + } + + if (m_dmrSpace2 > 1U && !m_txDMRData2.isEmpty()) { + unsigned char len = 0U; + m_txDMRData2.getData(&len, 1U); + m_txDMRData2.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX DMR Data 2", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing DMR data to the MMDVM"); + + m_playoutTimer.start(); + + m_dmrSpace2--; + } + + if (m_ysfSpace > 1U && !m_txYSFData.isEmpty()) { + unsigned char len = 0U; + m_txYSFData.getData(&len, 1U); + m_txYSFData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX YSF Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing YSF data to the MMDVM"); + + m_playoutTimer.start(); + + m_ysfSpace--; + } + + if (m_p25Space > 1U && !m_txP25Data.isEmpty()) { + unsigned char len = 0U; + m_txP25Data.getData(&len, 1U); + m_txP25Data.getData(m_buffer, len); + + if (m_trace) { + if (m_buffer[2U] == MMDVM_P25_HDR) + CUtils::dump(1U, "TX P25 HDR", m_buffer, len); + else + CUtils::dump(1U, "TX P25 LDU", m_buffer, len); + } + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing P25 data to the MMDVM"); + + m_playoutTimer.start(); + + m_p25Space--; + } + + if (m_nxdnSpace > 1U && !m_txNXDNData.isEmpty()) { + unsigned char len = 0U; + m_txNXDNData.getData(&len, 1U); + m_txNXDNData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX NXDN Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing NXDN data to the MMDVM"); + + m_playoutTimer.start(); + + m_nxdnSpace--; + } + + if (m_pocsagSpace > 1U && !m_txPOCSAGData.isEmpty()) { + unsigned char len = 0U; + m_txPOCSAGData.getData(&len, 1U); + m_txPOCSAGData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX POCSAG Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing POCSAG data to the MMDVM"); + + m_playoutTimer.start(); + + m_pocsagSpace--; + } + + if (m_fmSpace > 1U && !m_txFMData.isEmpty()) { + unsigned char len = 0U; + m_txFMData.getData(&len, 1U); + m_txFMData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX FM Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing FM data to the MMDVM"); + + m_playoutTimer.start(); + + m_fmSpace--; + } + + if (m_ax25Space > 0U && !m_txAX25Data.isEmpty()) { + unsigned char len = 0U; + m_txAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); + m_txAX25Data.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX AX.25 Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing AX.25 data to the MMDVM"); + + m_playoutTimer.start(); + + m_ax25Space = 0U; + } + + if (!m_txTransparentData.isEmpty()) { + unsigned char len = 0U; + m_txTransparentData.getData(&len, 1U); + m_txTransparentData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX Transparent Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing Transparent data to the MMDVM"); + } +} + +void CSerialModem::close() +{ + assert(m_serial != NULL); + + ::LogMessage("Closing the MMDVM"); + + m_serial->close(); +} + +unsigned int CSerialModem::readDStarData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxDStarData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxDStarData.getData(&len, 1U); + m_rxDStarData.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readDMRData1(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxDMRData1.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxDMRData1.getData(&len, 1U); + m_rxDMRData1.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readDMRData2(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxDMRData2.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxDMRData2.getData(&len, 1U); + m_rxDMRData2.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readYSFData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxYSFData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxYSFData.getData(&len, 1U); + m_rxYSFData.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readP25Data(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxP25Data.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxP25Data.getData(&len, 1U); + m_rxP25Data.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readNXDNData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxNXDNData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxNXDNData.getData(&len, 1U); + m_rxNXDNData.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readFMData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxFMData.isEmpty()) + return 0U; + + unsigned int len = 0U; + m_rxFMData.getData((unsigned char*)&len, sizeof(unsigned int)); + m_rxFMData.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readAX25Data(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxAX25Data.isEmpty()) + return 0U; + + unsigned int len = 0U; + m_rxAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); + m_rxAX25Data.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readTransparentData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxTransparentData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxTransparentData.getData(&len, 1U); + m_rxTransparentData.getData(data, len); + + return len; +} + +// To be implemented later if needed +unsigned int CSerialModem::readSerial(unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + return 0U; +} + +bool CSerialModem::hasDStarSpace() const +{ + unsigned int space = m_txDStarData.freeSpace() / (DSTAR_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeDStarData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[50U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + + switch (data[0U]) { + case TAG_HEADER: + buffer[2U] = MMDVM_DSTAR_HEADER; + break; + case TAG_DATA: + buffer[2U] = MMDVM_DSTAR_DATA; + break; + case TAG_EOT: + buffer[2U] = MMDVM_DSTAR_EOT; + break; + default: + CUtils::dump(2U, "Unknown D-Star packet type", data, length); + return false; + } + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txDStarData.addData(&len, 1U); + m_txDStarData.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasDMRSpace1() const +{ + unsigned int space = m_txDMRData1.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::hasDMRSpace2() const +{ + unsigned int space = m_txDMRData2.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeDMRData1(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[40U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = MMDVM_DMR_DATA1; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txDMRData1.addData(&len, 1U); + m_txDMRData1.addData(buffer, len); + + return true; +} + +bool CSerialModem::writeDMRData2(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[40U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = MMDVM_DMR_DATA2; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txDMRData2.addData(&len, 1U); + m_txDMRData2.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasYSFSpace() const +{ + unsigned int space = m_txYSFData.freeSpace() / (YSF_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeYSFData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[130U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = MMDVM_YSF_DATA; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txYSFData.addData(&len, 1U); + m_txYSFData.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasP25Space() const +{ + unsigned int space = m_txP25Data.freeSpace() / (P25_LDU_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::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) + return false; + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = (data[0U] == TAG_HEADER) ? MMDVM_P25_HDR : MMDVM_P25_LDU; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txP25Data.addData(&len, 1U); + m_txP25Data.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasNXDNSpace() const +{ + unsigned int space = m_txNXDNData.freeSpace() / (NXDN_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeNXDNData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[130U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = MMDVM_NXDN_DATA; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txNXDNData.addData(&len, 1U); + m_txNXDNData.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasPOCSAGSpace() const +{ + unsigned int space = m_txPOCSAGData.freeSpace() / (POCSAG_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writePOCSAGData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[130U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_POCSAG_DATA; + + ::memcpy(buffer + 3U, data, length); + + unsigned char len = length + 3U; + m_txPOCSAGData.addData(&len, 1U); + m_txPOCSAGData.addData(buffer, len); + + return true; +} + +unsigned int CSerialModem::getFMSpace() const +{ + return m_txFMData.freeSpace(); +} + +bool CSerialModem::writeFMData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[500U]; + + unsigned int len; + if (length > 252U) { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 0U; + buffer[2U] = (length + 4U) - 255U; + buffer[3U] = MMDVM_FM_DATA; + ::memcpy(buffer + 4U, data, length); + len = length + 4U; + } else { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_FM_DATA; + ::memcpy(buffer + 3U, data, length); + len = length + 3U; + } + + m_txFMData.addData((unsigned char*)&len, sizeof(unsigned int)); + m_txFMData.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasAX25Space() const +{ + unsigned int space = m_txAX25Data.freeSpace() / (AX25_MAX_FRAME_LENGTH_BYTES + 5U); + + return space > 1U; +} + +bool CSerialModem::writeAX25Data(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[500U]; + + unsigned int len; + if (length > 252U) { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 0U; + buffer[2U] = (length + 4U) - 255U; + buffer[3U] = MMDVM_AX25_DATA; + ::memcpy(buffer + 4U, data, length); + len = length + 4U; + } else { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_AX25_DATA; + ::memcpy(buffer + 3U, data, length); + len = length + 3U; + } + + m_txAX25Data.addData((unsigned char*)&len, sizeof(unsigned int)); + m_txAX25Data.addData(buffer, len); + + return true; +} + +bool CSerialModem::writeTransparentData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_TRANSPARENT; + + if (m_sendTransparentDataFrameType > 0U) { + ::memcpy(buffer + 2U, data, length); + length--; + buffer[1U]--; + + //when sendFrameType==1 , only 0x80 and 0x90 (MMDVM_SERIAL and MMDVM_TRANSPARENT) are allowed + // and reverted to default (MMDVM_TRANSPARENT) for any other value + //when >1, frame type is not checked + if (m_sendTransparentDataFrameType == 1U) { + if ((buffer[2U] & 0xE0) != 0x80) + buffer[2U] = MMDVM_TRANSPARENT; + } + } else { + ::memcpy(buffer + 3U, data, length); + } + + unsigned char len = length + 3U; + m_txTransparentData.addData(&len, 1U); + m_txTransparentData.addData(buffer, len); + + return true; +} + +bool CSerialModem::writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) +{ + assert(m_serial != NULL); + assert(my1 != NULL); + assert(my2 != NULL); + assert(your != NULL); + assert(type != NULL); + assert(reflector != NULL); + + unsigned char buffer[50U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 33U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_DSTAR; + + ::memcpy(buffer + 4U, my1, DSTAR_LONG_CALLSIGN_LENGTH); + ::memcpy(buffer + 12U, my2, DSTAR_SHORT_CALLSIGN_LENGTH); + + ::memcpy(buffer + 16U, your, DSTAR_LONG_CALLSIGN_LENGTH); + + ::memcpy(buffer + 24U, type, 1U); + + ::memcpy(buffer + 25U, reflector, DSTAR_LONG_CALLSIGN_LENGTH); + + return m_serial->write(buffer, 33U) != 33; +} + +bool CSerialModem::writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dest, const char* type) +{ + assert(m_serial != NULL); + assert(type != NULL); + + unsigned char buffer[50U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 47U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_DMR; + + buffer[4U] = slotNo; + + ::sprintf((char*)(buffer + 5U), "%20.20s", src.c_str()); + + buffer[25U] = group ? 'G' : 'I'; + + ::sprintf((char*)(buffer + 26U), "%20.20s", dest.c_str()); + + ::memcpy(buffer + 46U, type, 1U); + + return m_serial->write(buffer, 47U) != 47; +} + +bool CSerialModem::writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin) +{ + assert(m_serial != NULL); + assert(source != NULL); + assert(dest != NULL); + assert(type != NULL); + assert(origin != NULL); + + unsigned char buffer[50U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 35U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_YSF; + + ::memcpy(buffer + 4U, source, YSF_CALLSIGN_LENGTH); + ::memcpy(buffer + 14U, dest, YSF_CALLSIGN_LENGTH); + + ::memcpy(buffer + 24U, type, 1U); + + ::memcpy(buffer + 25U, origin, YSF_CALLSIGN_LENGTH); + + return m_serial->write(buffer, 35U) != 35; +} + +bool CSerialModem::writeP25Info(const char* source, bool group, unsigned int dest, const char* type) +{ + assert(m_serial != NULL); + assert(source != NULL); + assert(type != NULL); + + unsigned char buffer[40U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 31U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_DMR; + + ::sprintf((char*)(buffer + 4U), "%20.20s", source); + + buffer[24U] = group ? 'G' : 'I'; + + ::sprintf((char*)(buffer + 25U), "%05u", dest); // 16-bits + + ::memcpy(buffer + 30U, type, 1U); + + return m_serial->write(buffer, 31U) != 31; +} + +bool CSerialModem::writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type) +{ + assert(m_serial != NULL); + assert(source != NULL); + assert(type != NULL); + + unsigned char buffer[40U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 31U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_NXDN; + + ::sprintf((char*)(buffer + 4U), "%20.20s", source); + + buffer[24U] = group ? 'G' : 'I'; + + ::sprintf((char*)(buffer + 25U), "%05u", dest); // 16-bits + + ::memcpy(buffer + 30U, type, 1U); + + return m_serial->write(buffer, 31U) != 31; +} + +bool CSerialModem::writePOCSAGInfo(unsigned int ric, const std::string& message) +{ + assert(m_serial != NULL); + + size_t length = message.size(); + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 11U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_POCSAG; + + ::sprintf((char*)(buffer + 4U), "%07u", ric); // 21-bits + + ::memcpy(buffer + 11U, message.c_str(), length); + + int ret = m_serial->write(buffer, length + 11U); + + return ret != int(length + 11U); +} + +bool CSerialModem::writeIPInfo(const std::string& address) +{ + assert(m_serial != NULL); + + size_t length = address.size(); + + unsigned char buffer[25U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 4U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = 250U; + + ::memcpy(buffer + 4U, address.c_str(), length); + + int ret = m_serial->write(buffer, length + 4U); + + return ret != int(length + 4U); +} + +bool CSerialModem::writeSerial(const unsigned char* data, unsigned int length) +{ + assert(m_serial != NULL); + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_SERIAL; + + ::memcpy(buffer + 3U, data, length); + + int ret = m_serial->write(buffer, length + 3U); + + return ret != int(length + 3U); +} + +bool CSerialModem::hasTX() const +{ + return m_tx; +} + +bool CSerialModem::hasCD() const +{ + return m_cd; +} + +bool CSerialModem::hasLockout() const +{ + return m_lockout; +} + +bool CSerialModem::hasError() const +{ + return m_error; +} + +bool CSerialModem::readVersion() +{ + assert(m_serial != NULL); + + CThread::sleep(2000U); // 2s + + for (unsigned int i = 0U; i < 6U; i++) { + unsigned char buffer[3U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 3U; + buffer[2U] = MMDVM_GET_VERSION; + + // CUtils::dump(1U, "Written", buffer, 3U); + + int ret = m_serial->write(buffer, 3U); + if (ret != 3) + return false; + +#if defined(__APPLE__) + m_serial->setNonblock(true); +#endif + + for (unsigned int count = 0U; count < MAX_RESPONSES; count++) { + CThread::sleep(10U); + RESP_TYPE_MMDVM resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] == MMDVM_GET_VERSION) { + if (::memcmp(m_buffer + 4U, "MMDVM ", 6U) == 0) + m_hwType = HWT_MMDVM; + else if (::memcmp(m_buffer + 4U, "DVMEGA", 6U) == 0) + m_hwType = HWT_DVMEGA; + else if (::memcmp(m_buffer + 4U, "ZUMspot", 7U) == 0) + m_hwType = HWT_MMDVM_ZUMSPOT; + else if (::memcmp(m_buffer + 4U, "MMDVM_HS_Hat", 12U) == 0) + m_hwType = HWT_MMDVM_HS_HAT; + else if (::memcmp(m_buffer + 4U, "MMDVM_HS_Dual_Hat", 17U) == 0) + m_hwType = HWT_MMDVM_HS_DUAL_HAT; + else if (::memcmp(m_buffer + 4U, "Nano_hotSPOT", 12U) == 0) + m_hwType = HWT_NANO_HOTSPOT; + else if (::memcmp(m_buffer + 4U, "Nano_DV", 7U) == 0) + m_hwType = HWT_NANO_DV; + else if (::memcmp(m_buffer + 4U, "D2RG_MMDVM_HS", 13U) == 0) + m_hwType = HWT_D2RG_MMDVM_HS; + else if (::memcmp(m_buffer + 4U, "MMDVM_HS-", 9U) == 0) + m_hwType = HWT_MMDVM_HS; + else if (::memcmp(m_buffer + 4U, "OpenGD77_HS", 11U) == 0) + m_hwType = HWT_OPENGD77_HS; + + LogInfo("MMDVM protocol version: %u, description: %.*s", m_buffer[3U], m_length - 4U, m_buffer + 4U); + return true; + } + } + + CThread::sleep(1500U); + } + + LogError("Unable to read the firmware version after six attempts"); + + return false; +} + +bool CSerialModem::readStatus() +{ + assert(m_serial != NULL); + + unsigned char buffer[3U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 3U; + buffer[2U] = MMDVM_GET_STATUS; + + // CUtils::dump(1U, "Written", buffer, 3U); + + return m_serial->write(buffer, 3U) == 3; +} + +bool CSerialModem::writeConfig() +{ + return setConfig(); +} + +bool CSerialModem::setConfig() +{ + assert(m_serial != NULL); + + unsigned char buffer[30U]; + + buffer[0U] = MMDVM_FRAME_START; + + buffer[1U] = 27U; + + buffer[2U] = MMDVM_SET_CONFIG; + + buffer[3U] = 0x00U; + if (m_rxInvert) + buffer[3U] |= 0x01U; + if (m_txInvert) + buffer[3U] |= 0x02U; + if (m_pttInvert) + buffer[3U] |= 0x04U; + if (m_ysfLoDev) + buffer[3U] |= 0x08U; + if (m_debug) + buffer[3U] |= 0x10U; + if (!m_duplex) + buffer[3U] |= 0x80U; + + buffer[4U] = 0x00U; + if (m_dstarEnabled) + buffer[4U] |= 0x01U; + if (m_dmrEnabled) + buffer[4U] |= 0x02U; + if (m_ysfEnabled) + buffer[4U] |= 0x04U; + if (m_p25Enabled) + buffer[4U] |= 0x08U; + if (m_nxdnEnabled) + buffer[4U] |= 0x10U; + if (m_pocsagEnabled) + buffer[4U] |= 0x20U; + if (m_fmEnabled && m_duplex) + buffer[4U] |= 0x40U; + if (m_ax25Enabled) + buffer[4U] |= 0x80U; + + buffer[5U] = m_txDelay / 10U; // In 10ms units + + buffer[6U] = MODE_IDLE; + + buffer[7U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); + + buffer[8U] = (unsigned char)(m_cwIdTXLevel * 2.55F + 0.5F); + + buffer[9U] = m_dmrColorCode; + + buffer[10U] = m_dmrDelay; + + buffer[11U] = 128U; // Was OscOffset + + buffer[12U] = (unsigned char)(m_dstarTXLevel * 2.55F + 0.5F); + buffer[13U] = (unsigned char)(m_dmrTXLevel * 2.55F + 0.5F); + buffer[14U] = (unsigned char)(m_ysfTXLevel * 2.55F + 0.5F); + buffer[15U] = (unsigned char)(m_p25TXLevel * 2.55F + 0.5F); + + buffer[16U] = (unsigned char)(m_txDCOffset + 128); + buffer[17U] = (unsigned char)(m_rxDCOffset + 128); + + buffer[18U] = (unsigned char)(m_nxdnTXLevel * 2.55F + 0.5F); + + buffer[19U] = (unsigned char)m_ysfTXHang; + + buffer[20U] = (unsigned char)(m_pocsagTXLevel * 2.55F + 0.5F); + + buffer[21U] = (unsigned char)(m_fmTXLevel * 2.55F + 0.5F); + + buffer[22U] = (unsigned char)m_p25TXHang; + + buffer[23U] = (unsigned char)m_nxdnTXHang; + + buffer[24U] = (unsigned char)(m_ax25TXLevel * 2.55F + 0.5F); + + buffer[25U] = (unsigned char)(m_ax25RXTwist + 128); + + buffer[26U] = m_ax25TXDelay / 10U; // In 10ms units + + // CUtils::dump(1U, "Written", buffer, 27U); + + int ret = m_serial->write(buffer, 27U); + if (ret != 27) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_CONFIG command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_CONFIG command from the modem"); + return false; + } + + m_playoutTimer.start(); + + return true; +} + +bool CSerialModem::setFrequency() +{ + assert(m_serial != NULL); + + unsigned char buffer[20U]; + unsigned char len; + unsigned int pocsagFrequency = 433000000U; + + if (m_pocsagEnabled) + pocsagFrequency = m_pocsagFrequency; + + if (m_hwType == HWT_DVMEGA) + len = 12U; + else { + buffer[12U] = (unsigned char)(m_rfLevel * 2.55F + 0.5F); + + buffer[13U] = (pocsagFrequency >> 0) & 0xFFU; + buffer[14U] = (pocsagFrequency >> 8) & 0xFFU; + buffer[15U] = (pocsagFrequency >> 16) & 0xFFU; + buffer[16U] = (pocsagFrequency >> 24) & 0xFFU; + + len = 17U; + } + + buffer[0U] = MMDVM_FRAME_START; + + buffer[1U] = len; + + buffer[2U] = MMDVM_SET_FREQ; + + buffer[3U] = 0x00U; + + buffer[4U] = (m_rxFrequency >> 0) & 0xFFU; + buffer[5U] = (m_rxFrequency >> 8) & 0xFFU; + buffer[6U] = (m_rxFrequency >> 16) & 0xFFU; + buffer[7U] = (m_rxFrequency >> 24) & 0xFFU; + + buffer[8U] = (m_txFrequency >> 0) & 0xFFU; + buffer[9U] = (m_txFrequency >> 8) & 0xFFU; + buffer[10U] = (m_txFrequency >> 16) & 0xFFU; + buffer[11U] = (m_txFrequency >> 24) & 0xFFU; + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FREQ command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FREQ command from the modem"); + return false; + } + + return true; +} + +RESP_TYPE_MMDVM CSerialModem::getResponse() +{ + assert(m_serial != NULL); + + if (m_state == SS_START) { + // Get the start of the frame or nothing at all + int ret = m_serial->read(m_buffer + 0U, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + if (m_buffer[0U] != MMDVM_FRAME_START) + return RTM_TIMEOUT; + + m_state = SS_LENGTH1; + m_length = 1U; + } + + if (m_state == SS_LENGTH1) { + // Get the length of the frame, 1/2 + int ret = m_serial->read(m_buffer + 1U, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + m_length = m_buffer[1U]; + m_offset = 2U; + + if (m_length == 0U) + m_state = SS_LENGTH2; + else + m_state = SS_TYPE; + } + + if (m_state == SS_LENGTH2) { + // Get the length of the frane, 2/2 + int ret = m_serial->read(m_buffer + 2U, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + m_length = m_buffer[2U] + 255U; + m_offset = 3U; + m_state = SS_TYPE; + } + + if (m_state == SS_TYPE) { + // Get the frame type + int ret = m_serial->read(&m_type, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + m_buffer[m_offset++] = m_type; + + m_state = SS_DATA; + } + + if (m_state == SS_DATA) { + while (m_offset < m_length) { + int ret = m_serial->read(m_buffer + m_offset, m_length - m_offset); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + if (ret > 0) + m_offset += ret; + } + } + + // CUtils::dump(1U, "Received", m_buffer, m_length); + + m_offset = m_length > 255U ? 4U : 3U; + m_state = SS_START; + + return RTM_OK; +} + +HW_TYPE CSerialModem::getHWType() const +{ + return m_hwType; +} + +unsigned char CSerialModem::getMode() const +{ + return m_mode; +} + +bool CSerialModem::setMode(unsigned char mode) +{ + assert(m_serial != NULL); + + unsigned char buffer[4U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 4U; + buffer[2U] = MMDVM_SET_MODE; + buffer[3U] = mode; + + // CUtils::dump(1U, "Written", buffer, 4U); + + return m_serial->write(buffer, 4U) == 4; +} + +bool CSerialModem::sendCWId(const std::string& callsign) +{ + assert(m_serial != NULL); + + unsigned int length = callsign.length(); + if (length > 200U) + length = 200U; + + unsigned char buffer[205U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_SEND_CWID; + + for (unsigned int i = 0U; i < length; i++) + buffer[i + 3U] = callsign.at(i); + + // CUtils::dump(1U, "Written", buffer, length + 3U); + + return m_serial->write(buffer, length + 3U) == int(length + 3U); +} + +bool CSerialModem::writeDMRStart(bool tx) +{ + assert(m_serial != NULL); + + if (tx && m_tx) + return true; + if (!tx && !m_tx) + return true; + + unsigned char buffer[4U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 4U; + buffer[2U] = MMDVM_DMR_START; + buffer[3U] = tx ? 0x01U : 0x00U; + + // CUtils::dump(1U, "Written", buffer, 4U); + + return m_serial->write(buffer, 4U) == 4; +} + +bool CSerialModem::writeDMRAbort(unsigned int slotNo) +{ + assert(m_serial != NULL); + + if (slotNo == 1U) + m_txDMRData1.clear(); + else + m_txDMRData2.clear(); + + unsigned char buffer[4U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 4U; + buffer[2U] = MMDVM_DMR_ABORT; + buffer[3U] = slotNo; + + // CUtils::dump(1U, "Written", buffer, 4U); + + return m_serial->write(buffer, 4U) == 4; +} + +bool CSerialModem::writeDMRShortLC(const unsigned char* lc) +{ + assert(m_serial != NULL); + assert(lc != NULL); + + unsigned char buffer[12U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 12U; + buffer[2U] = MMDVM_DMR_SHORTLC; + buffer[3U] = lc[0U]; + buffer[4U] = lc[1U]; + buffer[5U] = lc[2U]; + buffer[6U] = lc[3U]; + buffer[7U] = lc[4U]; + buffer[8U] = lc[5U]; + buffer[9U] = lc[6U]; + buffer[10U] = lc[7U]; + buffer[11U] = lc[8U]; + + // CUtils::dump(1U, "Written", buffer, 12U); + + return m_serial->write(buffer, 12U) == 12; +} + +void CSerialModem::setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) +{ + m_fmCallsign = callsign; + m_fmCallsignSpeed = callsignSpeed; + m_fmCallsignFrequency = callsignFrequency; + m_fmCallsignTime = callsignTime; + m_fmCallsignHoldoff = callsignHoldoff; + m_fmCallsignHighLevel = callsignHighLevel; + m_fmCallsignLowLevel = callsignLowLevel; + m_fmCallsignAtStart = callsignAtStart; + m_fmCallsignAtEnd = callsignAtEnd; + m_fmCallsignAtLatch = callsignAtLatch; +} + +void CSerialModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) +{ + m_fmRfAck = rfAck; + m_fmAckSpeed = ackSpeed; + m_fmAckFrequency = ackFrequency; + m_fmAckMinTime = ackMinTime; + m_fmAckDelay = ackDelay; + m_fmAckLevel = ackLevel; +} + +void CSerialModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) +{ + m_fmTimeout = timeout; + m_fmTimeoutLevel = timeoutLevel; + + m_fmCtcssFrequency = ctcssFrequency; + m_fmCtcssHighThreshold = ctcssHighThreshold; + m_fmCtcssLowThreshold = ctcssLowThreshold; + m_fmCtcssLevel = ctcssLevel; + + m_fmKerchunkTime = kerchunkTime; + m_fmKerchunkTX = kerchunkTX; + + m_fmHangTime = hangTime; + + m_fmUseCOS = useCOS; + m_fmCOSInvert = cosInvert; + + m_fmRFAudioBoost = rfAudioBoost; + m_fmMaxDevLevel = maxDevLevel; +} + +void CSerialModem::setFMExtParams(const std::string& ack, unsigned int audioBoost) +{ + m_fmExtAck = ack; + m_fmExtAudioBoost = audioBoost; + m_fmExtEnable = true; +} + +bool CSerialModem::setFMCallsignParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 10U + m_fmCallsign.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS1; + + buffer[3U] = m_fmCallsignSpeed; + buffer[4U] = m_fmCallsignFrequency / 10U; + buffer[5U] = m_fmCallsignTime; + buffer[6U] = m_fmCallsignHoldoff; + + buffer[7U] = (unsigned char)(m_fmCallsignHighLevel * 2.55F + 0.5F); + buffer[8U] = (unsigned char)(m_fmCallsignLowLevel * 2.55F + 0.5F); + + buffer[9U] = 0x00U; + if (m_fmCallsignAtStart) + buffer[9U] |= 0x01U; + if (m_fmCallsignAtEnd) + buffer[9U] |= 0x02U; + if (m_fmCallsignAtLatch) + buffer[9U] |= 0x04U; + + for (unsigned int i = 0U; i < m_fmCallsign.size(); i++) + buffer[10U + i] = m_fmCallsign.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS1 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS1 command from the modem"); + return false; + } + + return true; +} + +bool CSerialModem::setFMAckParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 8U + m_fmRfAck.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS2; + + buffer[3U] = m_fmAckSpeed; + buffer[4U] = m_fmAckFrequency / 10U; + buffer[5U] = m_fmAckMinTime; + buffer[6U] = m_fmAckDelay / 10U; + + buffer[7U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); + + for (unsigned int i = 0U; i < m_fmRfAck.size(); i++) + buffer[8U + i] = m_fmRfAck.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS2 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS2 command from the modem"); + return false; + } + + return true; +} + +bool CSerialModem::setFMMiscParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[20U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 15U; + buffer[2U] = MMDVM_FM_PARAMS3; + + buffer[3U] = m_fmTimeout / 5U; + buffer[4U] = (unsigned char)(m_fmTimeoutLevel * 2.55F + 0.5F); + + buffer[5U] = (unsigned char)m_fmCtcssFrequency; + buffer[6U] = m_fmCtcssHighThreshold; + buffer[7U] = m_fmCtcssLowThreshold; + buffer[8U] = (unsigned char)(m_fmCtcssLevel * 2.55F + 0.5F); + + buffer[9U] = m_fmKerchunkTime; + buffer[10U] = m_fmHangTime; + + buffer[11U] = 0x00U; + if (m_fmUseCOS) + buffer[11U] |= 0x01U; + if (m_fmCOSInvert) + buffer[11U] |= 0x02U; + if (m_fmKerchunkTX) + buffer[11U] |= 0x04U; + + buffer[12U] = m_fmRFAudioBoost; + + buffer[13U] = (unsigned char)(m_fmMaxDevLevel * 2.55F + 0.5F); + + buffer[14U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); + + // CUtils::dump(1U, "Written", buffer, 15U); + + int ret = m_serial->write(buffer, 15U); + if (ret != 15) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS3 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS3 command from the modem"); + return false; + } + + return true; +} + +bool CSerialModem::setFMExtParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 7U + m_fmExtAck.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS4; + + buffer[3U] = m_fmExtAudioBoost; + buffer[4U] = m_fmAckSpeed; + buffer[5U] = m_fmAckFrequency / 10U; + + buffer[6U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); + + for (unsigned int i = 0U; i < m_fmExtAck.size(); i++) + buffer[7U + i] = m_fmExtAck.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS4 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS4 command from the modem"); + return false; + } + + return true; +} + +void CSerialModem::printDebug() +{ + if (m_buffer[2U] == MMDVM_DEBUG1) { + LogMessage("Debug: %.*s", m_length - m_offset - 0U, m_buffer + m_offset); + } else if (m_buffer[2U] == MMDVM_DEBUG2) { + short val1 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; + LogMessage("Debug: %.*s %d", m_length - m_offset - 2U, m_buffer + m_offset, val1); + } else if (m_buffer[2U] == MMDVM_DEBUG3) { + short val1 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; + short val2 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; + LogMessage("Debug: %.*s %d %d", m_length - m_offset - 4U, m_buffer + m_offset, val1, val2); + } else if (m_buffer[2U] == MMDVM_DEBUG4) { + short val1 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; + short val2 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; + short val3 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; + LogMessage("Debug: %.*s %d %d %d", m_length - m_offset - 6U, m_buffer + m_offset, val1, val2, val3); + } else if (m_buffer[2U] == MMDVM_DEBUG5) { + short val1 = (m_buffer[m_length - 8U] << 8) | m_buffer[m_length - 7U]; + short val2 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; + short val3 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; + short val4 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; + LogMessage("Debug: %.*s %d %d %d %d", m_length - m_offset - 8U, m_buffer + m_offset, val1, val2, val3, val4); + } +} diff --git a/SerialModem.h b/SerialModem.h new file mode 100644 index 0000000..e1ef578 --- /dev/null +++ b/SerialModem.h @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2011-2018,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. + */ + +#ifndef SERIALMODEM_H +#define SERIALMODEM_H + +#include "Modem.h" + +#include "SerialPort.h" +#include "RingBuffer.h" +#include "Defines.h" +#include "Timer.h" + +#include + +enum RESP_TYPE_MMDVM { + RTM_OK, + RTM_TIMEOUT, + RTM_ERROR +}; + +enum SERIAL_STATE { + SS_START, + SS_LENGTH1, + SS_LENGTH2, + SS_TYPE, + SS_DATA +}; + +class CSerialModem : public IModem { +public: + CSerialModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); + virtual ~CSerialModem(); + + virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed); + virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled); + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel); + virtual void setDMRParams(unsigned int colorCode); + virtual void setYSFParams(bool loDev, unsigned int txHang); + virtual void setP25Params(unsigned int txHang); + virtual void setNXDNParams(unsigned int txHang); + virtual void setAX25Params(int rxTwist, unsigned int txDelay); + virtual void setTransparentDataParams(unsigned int sendFrameType); + + virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); + virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); + virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost); + + virtual bool open(); + + virtual unsigned int readDStarData(unsigned char* data); + virtual unsigned int readDMRData1(unsigned char* data); + virtual unsigned int readDMRData2(unsigned char* data); + virtual unsigned int readYSFData(unsigned char* data); + virtual unsigned int readP25Data(unsigned char* data); + virtual unsigned int readNXDNData(unsigned char* data); + virtual unsigned int readFMData(unsigned char* data); + virtual unsigned int readAX25Data(unsigned char* data); + virtual unsigned int readTransparentData(unsigned char* data); + + virtual unsigned int readSerial(unsigned char* data, unsigned int length); + + virtual bool hasDStarSpace() const; + virtual bool hasDMRSpace1() const; + virtual bool hasDMRSpace2() const; + virtual bool hasYSFSpace() const; + virtual bool hasP25Space() const; + virtual bool hasNXDNSpace() const; + virtual bool hasPOCSAGSpace() const; + virtual unsigned int getFMSpace() const; + virtual bool hasAX25Space() const; + + virtual bool hasTX() const; + virtual bool hasCD() const; + + virtual bool hasLockout() const; + virtual bool hasError() const; + + virtual bool writeConfig(); + virtual bool writeDStarData(const unsigned char* data, unsigned int length); + virtual bool writeDMRData1(const unsigned char* data, unsigned int length); + virtual bool writeDMRData2(const unsigned char* data, unsigned int length); + virtual bool writeYSFData(const unsigned char* data, unsigned int length); + virtual bool writeP25Data(const unsigned char* data, unsigned int length); + virtual bool writeNXDNData(const unsigned char* data, unsigned int length); + virtual bool writePOCSAGData(const unsigned char* data, unsigned int length); + virtual bool writeFMData(const unsigned char* data, unsigned int length); + virtual bool writeAX25Data(const unsigned char* data, unsigned int length); + + virtual bool writeTransparentData(const unsigned char* data, unsigned int length); + + virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); + virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type); + virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin); + virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type); + virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type); + virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message); + virtual bool writeIPInfo(const std::string& address); + + virtual bool writeDMRStart(bool tx); + virtual bool writeDMRShortLC(const unsigned char* lc); + virtual bool writeDMRAbort(unsigned int slotNo); + + virtual bool writeSerial(const unsigned char* data, unsigned int length); + + virtual unsigned char getMode() const; + virtual bool setMode(unsigned char mode); + + virtual bool sendCWId(const std::string& callsign); + + virtual HW_TYPE getHWType() const; + + virtual void clock(unsigned int ms); + + virtual void close(); + +private: + std::string m_port; + unsigned int m_dmrColorCode; + bool m_ysfLoDev; + unsigned int m_ysfTXHang; + unsigned int m_p25TXHang; + unsigned int m_nxdnTXHang; + bool m_duplex; + bool m_rxInvert; + bool m_txInvert; + bool m_pttInvert; + unsigned int m_txDelay; + unsigned int m_dmrDelay; + float m_rxLevel; + float m_cwIdTXLevel; + float m_dstarTXLevel; + float m_dmrTXLevel; + float m_ysfTXLevel; + float m_p25TXLevel; + float m_nxdnTXLevel; + float m_pocsagTXLevel; + float m_fmTXLevel; + float m_ax25TXLevel; + float m_rfLevel; + bool m_trace; + bool m_debug; + unsigned int m_rxFrequency; + unsigned int m_txFrequency; + unsigned int m_pocsagFrequency; + bool m_dstarEnabled; + bool m_dmrEnabled; + bool m_ysfEnabled; + bool m_p25Enabled; + bool m_nxdnEnabled; + bool m_pocsagEnabled; + bool m_fmEnabled; + bool m_ax25Enabled; + int m_rxDCOffset; + int m_txDCOffset; + ISerialPort* m_serial; + unsigned char* m_buffer; + unsigned int m_length; + unsigned int m_offset; + SERIAL_STATE m_state; + unsigned char m_type; + CRingBuffer m_rxDStarData; + CRingBuffer m_txDStarData; + CRingBuffer m_rxDMRData1; + CRingBuffer m_rxDMRData2; + CRingBuffer m_txDMRData1; + CRingBuffer m_txDMRData2; + CRingBuffer m_rxYSFData; + CRingBuffer m_txYSFData; + CRingBuffer m_rxP25Data; + CRingBuffer m_txP25Data; + CRingBuffer m_rxNXDNData; + CRingBuffer m_txNXDNData; + CRingBuffer m_txPOCSAGData; + CRingBuffer m_rxFMData; + CRingBuffer m_txFMData; + CRingBuffer m_rxAX25Data; + CRingBuffer m_txAX25Data; + CRingBuffer m_rxTransparentData; + CRingBuffer m_txTransparentData; + unsigned int m_sendTransparentDataFrameType; + CTimer m_statusTimer; + CTimer m_inactivityTimer; + CTimer m_playoutTimer; + unsigned int m_dstarSpace; + unsigned int m_dmrSpace1; + unsigned int m_dmrSpace2; + unsigned int m_ysfSpace; + unsigned int m_p25Space; + unsigned int m_nxdnSpace; + unsigned int m_pocsagSpace; + unsigned int m_fmSpace; + unsigned int m_ax25Space; + bool m_tx; + bool m_cd; + bool m_lockout; + bool m_error; + unsigned char m_mode; + HW_TYPE m_hwType; + int m_ax25RXTwist; + unsigned int m_ax25TXDelay; + + std::string m_fmCallsign; + unsigned int m_fmCallsignSpeed; + unsigned int m_fmCallsignFrequency; + unsigned int m_fmCallsignTime; + unsigned int m_fmCallsignHoldoff; + float m_fmCallsignHighLevel; + float m_fmCallsignLowLevel; + bool m_fmCallsignAtStart; + bool m_fmCallsignAtEnd; + bool m_fmCallsignAtLatch; + std::string m_fmRfAck; + std::string m_fmExtAck; + unsigned int m_fmAckSpeed; + unsigned int m_fmAckFrequency; + unsigned int m_fmAckMinTime; + unsigned int m_fmAckDelay; + float m_fmAckLevel; + unsigned int m_fmTimeout; + float m_fmTimeoutLevel; + float m_fmCtcssFrequency; + unsigned int m_fmCtcssHighThreshold; + unsigned int m_fmCtcssLowThreshold; + float m_fmCtcssLevel; + unsigned int m_fmKerchunkTime; + bool m_fmKerchunkTX; + unsigned int m_fmHangTime; + bool m_fmUseCOS; + bool m_fmCOSInvert; + unsigned int m_fmRFAudioBoost; + unsigned int m_fmExtAudioBoost; + float m_fmMaxDevLevel; + bool m_fmExtEnable; + + bool readVersion(); + bool readStatus(); + bool setConfig(); + bool setFrequency(); + bool setFMCallsignParams(); + bool setFMAckParams(); + bool setFMMiscParams(); + bool setFMExtParams(); + + void printDebug(); + + RESP_TYPE_MMDVM getResponse(); +}; + +#endif From 4ae141f59463f8a59d555ed44dd5d2f1bc782f90 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 30 Jun 2020 23:11:00 +0200 Subject: [PATCH 084/115] Fix KISS --- AX25Network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AX25Network.cpp b/AX25Network.cpp index dec4ea3..d7f876d 100644 --- a/AX25Network.cpp +++ b/AX25Network.cpp @@ -142,7 +142,7 @@ unsigned int CAX25Network::read(unsigned char* data, unsigned int length) data[dataLen++] = AX25_FEND; } else if (c == AX25_TFESC && m_rxLastChar == AX25_FESC) { data[dataLen++] = AX25_FESC; - } else if (c != AX25_FESC) { + } else { data[dataLen++] = c; } From 5f0ee739e134772b0b1e0201a23a9dbc3e67a266 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 30 Jun 2020 23:19:26 +0200 Subject: [PATCH 085/115] Use correct file --- SerialController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialController.cpp b/SerialController.cpp index 6352743..99fe576 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -234,6 +234,7 @@ m_speed(speed), m_assertRTS(assertRTS), m_fd(-1) { + assert(!device.empty()); } CSerialController::CSerialController(unsigned int speed, bool assertRTS) : @@ -250,7 +251,6 @@ CSerialController::~CSerialController() bool CSerialController::open() { - assert(!m_device.empty()); assert(m_fd == -1); #if defined(__APPLE__) From d2be9202546e28fa316dcba7f8ca7f0c414ff487 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 1 Jul 2020 10:59:46 +0100 Subject: [PATCH 086/115] Add AX25 SlotTime and P-Persist parameters. --- Conf.cpp | 26 +++++++++++++++++++++----- Conf.h | 8 ++++++-- MMDVM.ini | 2 ++ MMDVMHost.cpp | 16 +++++++++++----- Modem.h | 2 +- NullModem.h | 2 +- SerialModem.cpp | 24 ++++++++++++++---------- SerialModem.h | 4 +++- Version.h | 2 +- 9 files changed, 60 insertions(+), 26 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 36c8ce3..ae7037a 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -213,8 +213,10 @@ m_fmMaxDevLevel(90.0F), m_fmExtAudioBoost(1U), m_fmModeHang(10U), m_ax25Enabled(false), -m_ax25RXTwist(6), m_ax25TXDelay(300U), +m_ax25RXTwist(6), +m_ax25SlotTime(30U), +m_ax25PPersist(128U), m_ax25Trace(false), m_dstarNetworkEnabled(false), m_dstarGatewayAddress(), @@ -815,10 +817,14 @@ bool CConf::read() } else if (section == SECTION_AX25) { if (::strcmp(key, "Enable") == 0) m_ax25Enabled = ::atoi(value) == 1; - else if (::strcmp(key, "RXTwist") == 0) - m_ax25RXTwist = ::atoi(value); else if (::strcmp(key, "TXDelay") == 0) m_ax25TXDelay = (unsigned int)::atoi(value); + else if (::strcmp(key, "RXTwist") == 0) + m_ax25RXTwist = ::atoi(value); + else if (::strcmp(key, "SlotTime") == 0) + m_ax25SlotTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "PPersist") == 0) + m_ax25PPersist = (unsigned int)::atoi(value); else if (::strcmp(key, "Trace") == 0) m_ax25Trace = ::atoi(value) == 1; } else if (section == SECTION_DSTAR_NETWORK) { @@ -1772,14 +1778,24 @@ bool CConf::getAX25Enabled() const return m_ax25Enabled; } +unsigned int CConf::getAX25TXDelay() const +{ + return m_ax25TXDelay; +} + int CConf::getAX25RXTwist() const { return m_ax25RXTwist; } -unsigned int CConf::getAX25TXDelay() const +unsigned int CConf::getAX25SlotTime() const { - return m_ax25TXDelay; + return m_ax25SlotTime; +} + +unsigned int CConf::getAX25PPersist() const +{ + return m_ax25PPersist; } bool CConf::getAX25Trace() const diff --git a/Conf.h b/Conf.h index cbae96c..dd830c3 100644 --- a/Conf.h +++ b/Conf.h @@ -175,8 +175,10 @@ public: // The AX.25 section bool getAX25Enabled() const; - int getAX25RXTwist() const; unsigned int getAX25TXDelay() const; + int getAX25RXTwist() const; + unsigned int getAX25SlotTime() const; + unsigned int getAX25PPersist() const; bool getAX25Trace() const; // The FM Section @@ -505,8 +507,10 @@ private: unsigned int m_fmModeHang; bool m_ax25Enabled; - int m_ax25RXTwist; unsigned int m_ax25TXDelay; + int m_ax25RXTwist; + unsigned int m_ax25SlotTime; + unsigned int m_ax25PPersist; bool m_ax25Trace; bool m_dstarNetworkEnabled; diff --git a/MMDVM.ini b/MMDVM.ini index 474bcbb..1435956 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -183,6 +183,8 @@ ExtAudioBoost=1 Enable=1 TXDelay=300 RXTwist=6 +SlotTime=30 +PPersist=128 Trace=1 [D-Star Network] diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 93ee9f7..6703f90 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -639,13 +639,17 @@ int CMMDVMHost::run() } if (m_ax25Enabled) { - int rxTwist = m_conf.getAX25RXTwist(); - unsigned int txDelay = m_conf.getAX25TXDelay(); - bool trace = m_conf.getAX25Trace(); + unsigned int txDelay = m_conf.getAX25TXDelay(); + int rxTwist = m_conf.getAX25RXTwist(); + unsigned int slotTime = m_conf.getAX25SlotTime(); + unsigned int pPersist = m_conf.getAX25PPersist(); + bool trace = m_conf.getAX25Trace(); LogInfo("AX.25 RF Parameters"); - LogInfo(" RX Twist: %d", rxTwist); LogInfo(" TX Delay: %ums", txDelay); + LogInfo(" RX Twist: %d", rxTwist); + LogInfo(" Slot Time: %ums", slotTime); + LogInfo(" P-Persist: %u", pPersist); LogInfo(" Trace: %s", trace ? "yes" : "no"); m_ax25 = new CAX25Control(m_ax25Network, trace); @@ -1301,6 +1305,8 @@ bool CMMDVMHost::createModem() float rfLevel = m_conf.getModemRFLevel(); int rxTwist = m_conf.getAX25RXTwist(); unsigned int ax25TXDelay = m_conf.getAX25TXDelay(); + unsigned int ax25SlotTime = m_conf.getAX25SlotTime(); + unsigned int ax25PPersist = m_conf.getAX25PPersist(); LogInfo("Modem Parameters"); LogInfo(" Port: %s", port.c_str()); @@ -1345,7 +1351,7 @@ bool CMMDVMHost::createModem() m_modem->setYSFParams(lowDeviation, ysfTXHang); m_modem->setP25Params(p25TXHang); m_modem->setNXDNParams(nxdnTXHang); - m_modem->setAX25Params(rxTwist, ax25TXDelay); + m_modem->setAX25Params(rxTwist, ax25TXDelay, ax25SlotTime, ax25PPersist); if (m_fmEnabled) { std::string callsign = m_conf.getFMCallsign(); diff --git a/Modem.h b/Modem.h index c408f01..d5fc4b3 100644 --- a/Modem.h +++ b/Modem.h @@ -35,7 +35,7 @@ public: virtual void setYSFParams(bool loDev, unsigned int txHang) = 0; virtual void setP25Params(unsigned int txHang) = 0; virtual void setNXDNParams(unsigned int txHang) = 0; - virtual void setAX25Params(int rxTwist, unsigned int txDelay) = 0; + virtual void setAX25Params(int rxTwist, unsigned int txDelay, unsigned int slotTime, unsigned int pPersist) = 0; virtual void setTransparentDataParams(unsigned int sendFrameType) = 0; virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) = 0; diff --git a/NullModem.h b/NullModem.h index 12ae460..5ab0dd0 100644 --- a/NullModem.h +++ b/NullModem.h @@ -37,7 +37,7 @@ public: virtual void setYSFParams(bool loDev, unsigned int txHang) {}; virtual void setP25Params(unsigned int txHang) {}; virtual void setNXDNParams(unsigned int txHang) {}; - virtual void setAX25Params(int rxTwist, unsigned int txDelay) {}; + virtual void setAX25Params(int rxTwist, unsigned int txDelay, unsigned int slotTime, unsigned int pPersist) {}; virtual void setTransparentDataParams(unsigned int sendFrameType) {}; virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) {}; diff --git a/SerialModem.cpp b/SerialModem.cpp index 10ddefa..95f5765 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -194,6 +194,8 @@ m_mode(MODE_IDLE), m_hwType(HWT_UNKNOWN), m_ax25RXTwist(0), m_ax25TXDelay(300U), +m_ax25SlotTime(30U), +m_ax25PPersist(128U), m_fmCallsign(), m_fmCallsignSpeed(20U), m_fmCallsignFrequency(1000U), @@ -308,10 +310,12 @@ void CSerialModem::setNXDNParams(unsigned int txHang) m_nxdnTXHang = txHang; } -void CSerialModem::setAX25Params(int rxTwist, unsigned int txDelay) +void CSerialModem::setAX25Params(int rxTwist, unsigned int txDelay, unsigned int slotTime, unsigned int pPersist) { - m_ax25RXTwist = rxTwist; - m_ax25TXDelay = txDelay; + m_ax25RXTwist = rxTwist; + m_ax25TXDelay = txDelay; + m_ax25SlotTime = slotTime; + m_ax25PPersist = pPersist; } void CSerialModem::setTransparentDataParams(unsigned int sendFrameType) @@ -1757,7 +1761,7 @@ bool CSerialModem::setConfig() buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 27U; + buffer[1U] = 29U; buffer[2U] = MMDVM_SET_CONFIG; @@ -1788,7 +1792,7 @@ bool CSerialModem::setConfig() buffer[4U] |= 0x10U; if (m_pocsagEnabled) buffer[4U] |= 0x20U; - if (m_fmEnabled && m_duplex) + if (m_fmEnabled) buffer[4U] |= 0x40U; if (m_ax25Enabled) buffer[4U] |= 0x80U; @@ -1828,15 +1832,15 @@ bool CSerialModem::setConfig() buffer[23U] = (unsigned char)m_nxdnTXHang; buffer[24U] = (unsigned char)(m_ax25TXLevel * 2.55F + 0.5F); - buffer[25U] = (unsigned char)(m_ax25RXTwist + 128); - buffer[26U] = m_ax25TXDelay / 10U; // In 10ms units + buffer[27U] = m_ax25SlotTime / 10U; // In 10ms units + buffer[28U] = m_ax25PPersist; - // CUtils::dump(1U, "Written", buffer, 27U); + // CUtils::dump(1U, "Written", buffer, 29U); - int ret = m_serial->write(buffer, 27U); - if (ret != 27) + int ret = m_serial->write(buffer, 29U); + if (ret != 29) return false; unsigned int count = 0U; diff --git a/SerialModem.h b/SerialModem.h index e1ef578..9ec4d85 100644 --- a/SerialModem.h +++ b/SerialModem.h @@ -55,7 +55,7 @@ public: virtual void setYSFParams(bool loDev, unsigned int txHang); virtual void setP25Params(unsigned int txHang); virtual void setNXDNParams(unsigned int txHang); - virtual void setAX25Params(int rxTwist, unsigned int txDelay); + virtual void setAX25Params(int rxTwist, unsigned int txDelay, unsigned int slotTime, unsigned int pPersist); virtual void setTransparentDataParams(unsigned int sendFrameType); virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); @@ -216,6 +216,8 @@ private: HW_TYPE m_hwType; int m_ax25RXTwist; unsigned int m_ax25TXDelay; + unsigned int m_ax25SlotTime; + unsigned int m_ax25PPersist; std::string m_fmCallsign; unsigned int m_fmCallsignSpeed; diff --git a/Version.h b/Version.h index bb444d2..9a9d6e3 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200630"; +const char* VERSION = "20200701"; #endif From 192e8e24356cdd247ca4ca11416a9df37a62603f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 4 Jul 2020 13:04:24 +0200 Subject: [PATCH 087/115] Fix buffer underrun in FM --- SerialModem.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/SerialModem.cpp b/SerialModem.cpp index 95f5765..25a4ed5 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -248,7 +248,7 @@ void CSerialModem::setSerialParams(const std::string& protocol, unsigned int add m_serial = new CI2CController(m_port, address); else #endif - m_serial = new CSerialController(m_port, speed, true); + m_serial = new CSerialController(m_port, speed, false); } void CSerialModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) @@ -640,7 +640,7 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Data", m_buffer, m_length); - unsigned int data1 = m_length - m_offset + 1U; + unsigned int data1 = m_length - m_offset; m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); unsigned char data2 = TAG_DATA; @@ -654,11 +654,11 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Control", m_buffer, m_length); - unsigned char data = m_length - m_offset + 1U; - m_rxFMData.addData(&data, 1U); + unsigned int data1 = m_length - m_offset; + m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); - data = TAG_HEADER; - m_rxFMData.addData(&data, 1U); + unsigned char data2 = TAG_DATA; + m_rxFMData.addData(&data2, 1U); m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); } @@ -668,7 +668,7 @@ void CSerialModem::clock(unsigned int ms) if(m_trace) CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); - unsigned char data = m_length - m_offset + 1U; + unsigned char data = m_length - m_offset; m_rxFMData.addData(&data, 1U); data = TAG_EOT; From 183430593f085c643f0b168609914c74e45b8a68 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 4 Jul 2020 14:21:11 +0200 Subject: [PATCH 088/115] Revert "Fix buffer underrun in FM" This reverts commit 192e8e24356cdd247ca4ca11416a9df37a62603f. --- SerialModem.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/SerialModem.cpp b/SerialModem.cpp index 25a4ed5..95f5765 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -248,7 +248,7 @@ void CSerialModem::setSerialParams(const std::string& protocol, unsigned int add m_serial = new CI2CController(m_port, address); else #endif - m_serial = new CSerialController(m_port, speed, false); + m_serial = new CSerialController(m_port, speed, true); } void CSerialModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) @@ -640,7 +640,7 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Data", m_buffer, m_length); - unsigned int data1 = m_length - m_offset; + unsigned int data1 = m_length - m_offset + 1U; m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); unsigned char data2 = TAG_DATA; @@ -654,11 +654,11 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Control", m_buffer, m_length); - unsigned int data1 = m_length - m_offset; - m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); + unsigned char data = m_length - m_offset + 1U; + m_rxFMData.addData(&data, 1U); - unsigned char data2 = TAG_DATA; - m_rxFMData.addData(&data2, 1U); + data = TAG_HEADER; + m_rxFMData.addData(&data, 1U); m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); } @@ -668,7 +668,7 @@ void CSerialModem::clock(unsigned int ms) if(m_trace) CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); - unsigned char data = m_length - m_offset; + unsigned char data = m_length - m_offset + 1U; m_rxFMData.addData(&data, 1U); data = TAG_EOT; From f42f6f07c432efc470044443756cbc03854f192c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Jul 2020 10:16:06 +0100 Subject: [PATCH 089/115] Fix bug. --- SerialModem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SerialModem.cpp b/SerialModem.cpp index 95f5765..d745e0a 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -945,7 +945,7 @@ void CSerialModem::clock(unsigned int ms) } if (m_fmSpace > 1U && !m_txFMData.isEmpty()) { - unsigned char len = 0U; + unsigned int len = 0U; m_txFMData.getData(&len, 1U); m_txFMData.getData(m_buffer, len); @@ -962,7 +962,7 @@ void CSerialModem::clock(unsigned int ms) } if (m_ax25Space > 0U && !m_txAX25Data.isEmpty()) { - unsigned char len = 0U; + unsigned int len = 0U; m_txAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); m_txAX25Data.getData(m_buffer, len); From 3cc77c5c577fe994373cf33ce029021e1a16d6fd Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Jul 2020 10:20:40 +0100 Subject: [PATCH 090/115] Fix bug in bug. --- SerialModem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialModem.cpp b/SerialModem.cpp index d745e0a..6cc873b 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -946,7 +946,7 @@ void CSerialModem::clock(unsigned int ms) if (m_fmSpace > 1U && !m_txFMData.isEmpty()) { unsigned int len = 0U; - m_txFMData.getData(&len, 1U); + m_txFMData.getData((unsigned char*)&len, sizeof(unsigned int)); m_txFMData.getData(m_buffer, len); if (m_trace) From 954231ccbc331c8b9659cdfe9491ae2d2041e8ed Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Jul 2020 10:22:00 +0100 Subject: [PATCH 091/115] Bump the version date. --- Version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version.h b/Version.h index 9a9d6e3..c634cfc 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200701"; +const char* VERSION = "20200706"; #endif From 41dc96affeb03ba6086f6f51571b4e0e3c311916 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 4 Jul 2020 13:04:24 +0200 Subject: [PATCH 092/115] Fix buffer underrun in FM --- SerialModem.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/SerialModem.cpp b/SerialModem.cpp index 6cc873b..3d0cce9 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -248,7 +248,7 @@ void CSerialModem::setSerialParams(const std::string& protocol, unsigned int add m_serial = new CI2CController(m_port, address); else #endif - m_serial = new CSerialController(m_port, speed, true); + m_serial = new CSerialController(m_port, speed, false); } void CSerialModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) @@ -640,7 +640,7 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Data", m_buffer, m_length); - unsigned int data1 = m_length - m_offset + 1U; + unsigned int data1 = m_length - m_offset; m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); unsigned char data2 = TAG_DATA; @@ -654,11 +654,11 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Control", m_buffer, m_length); - unsigned char data = m_length - m_offset + 1U; - m_rxFMData.addData(&data, 1U); + unsigned int data1 = m_length - m_offset; + m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); - data = TAG_HEADER; - m_rxFMData.addData(&data, 1U); + unsigned char data2 = TAG_DATA; + m_rxFMData.addData(&data2, 1U); m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); } @@ -668,7 +668,7 @@ void CSerialModem::clock(unsigned int ms) if(m_trace) CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); - unsigned char data = m_length - m_offset + 1U; + unsigned char data = m_length - m_offset; m_rxFMData.addData(&data, 1U); data = TAG_EOT; From 40a974d7cbf8b880900ca8f08f8c0c4b5a403d27 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 4 Jul 2020 14:21:11 +0200 Subject: [PATCH 093/115] Revert "Fix buffer underrun in FM" This reverts commit 192e8e24356cdd247ca4ca11416a9df37a62603f. --- SerialModem.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/SerialModem.cpp b/SerialModem.cpp index 3d0cce9..6cc873b 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -248,7 +248,7 @@ void CSerialModem::setSerialParams(const std::string& protocol, unsigned int add m_serial = new CI2CController(m_port, address); else #endif - m_serial = new CSerialController(m_port, speed, false); + m_serial = new CSerialController(m_port, speed, true); } void CSerialModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) @@ -640,7 +640,7 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Data", m_buffer, m_length); - unsigned int data1 = m_length - m_offset; + unsigned int data1 = m_length - m_offset + 1U; m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); unsigned char data2 = TAG_DATA; @@ -654,11 +654,11 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Control", m_buffer, m_length); - unsigned int data1 = m_length - m_offset; - m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); + unsigned char data = m_length - m_offset + 1U; + m_rxFMData.addData(&data, 1U); - unsigned char data2 = TAG_DATA; - m_rxFMData.addData(&data2, 1U); + data = TAG_HEADER; + m_rxFMData.addData(&data, 1U); m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); } @@ -668,7 +668,7 @@ void CSerialModem::clock(unsigned int ms) if(m_trace) CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); - unsigned char data = m_length - m_offset; + unsigned char data = m_length - m_offset + 1U; m_rxFMData.addData(&data, 1U); data = TAG_EOT; From 4d6f64a51eacc60c831051800cf2163313503f9b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 6 Jul 2020 19:44:55 +0200 Subject: [PATCH 094/115] Write FM control length as integer, since we always read it as int --- SerialModem.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SerialModem.cpp b/SerialModem.cpp index 6cc873b..ef29423 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -654,11 +654,11 @@ void CSerialModem::clock(unsigned int ms) if (m_trace) CUtils::dump(1U, "RX FM Control", m_buffer, m_length); - unsigned char data = m_length - m_offset + 1U; - m_rxFMData.addData(&data, 1U); + unsigned int data1 = m_length - m_offset + 1U; + m_rxFMData.addData((unsigned char *)&data1, sizeof(unsigned int)); - data = TAG_HEADER; - m_rxFMData.addData(&data, 1U); + unsigned char data2= TAG_HEADER; + m_rxFMData.addData(&data2, 1U); m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); } From 009f50a9138f3f6e478d1e59c73380787009e620 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 6 Jul 2020 19:52:16 +0200 Subject: [PATCH 095/115] Write FM_EOT as uint --- SerialModem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SerialModem.cpp b/SerialModem.cpp index ef29423..5fe164b 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -655,7 +655,7 @@ void CSerialModem::clock(unsigned int ms) CUtils::dump(1U, "RX FM Control", m_buffer, m_length); unsigned int data1 = m_length - m_offset + 1U; - m_rxFMData.addData((unsigned char *)&data1, sizeof(unsigned int)); + m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); unsigned char data2= TAG_HEADER; m_rxFMData.addData(&data2, 1U); @@ -668,11 +668,11 @@ void CSerialModem::clock(unsigned int ms) if(m_trace) CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); - unsigned char data = m_length - m_offset + 1U; - m_rxFMData.addData(&data, 1U); + unsigned int data1 = m_length - m_offset + 1U; + m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); - data = TAG_EOT; - m_rxFMData.addData(&data, 1U); + unsigned char data2 = TAG_EOT; + m_rxFMData.addData(&data2, 1U); m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); } From 1e833d78cfd6dfc227ed7cf5ce7c8f2997f57a10 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 7 Jul 2020 17:54:46 +0100 Subject: [PATCH 096/115] Remove KerchunkTX. --- Conf.cpp | 8 -------- Conf.h | 2 -- MMDVM.ini | 1 - MMDVMHost.cpp | 4 +--- Modem.h | 2 +- NullModem.h | 2 +- SerialModem.cpp | 6 +----- SerialModem.h | 3 +-- Version.h | 2 +- 9 files changed, 6 insertions(+), 24 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 71976d8..961959e 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -204,7 +204,6 @@ m_fmCTCSSHighThreshold(30U), m_fmCTCSSLowThreshold(20U), m_fmCTCSSLevel(2.0F), m_fmKerchunkTime(0U), -m_fmKerchunkTX(true), m_fmHangTime(7U), m_fmUseCOS(true), m_fmCOSInvert(false), @@ -801,8 +800,6 @@ bool CConf::read() m_fmCTCSSLevel = float(::atof(value)); else if (::strcmp(key, "KerchunkTime") == 0) m_fmKerchunkTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "KerchunkTX") == 0) - m_fmKerchunkTX = ::atoi(value) == 1; else if (::strcmp(key, "HangTime") == 0) m_fmHangTime = (unsigned int)::atoi(value); else if (::strcmp(key, "UseCOS") == 0) @@ -1736,11 +1733,6 @@ unsigned int CConf::getFMKerchunkTime() const return m_fmKerchunkTime; } -bool CConf::getFMKerchunkTX() const -{ - return m_fmKerchunkTX; -} - unsigned int CConf::getFMHangTime() const { return m_fmHangTime; diff --git a/Conf.h b/Conf.h index dd830c3..49ec140 100644 --- a/Conf.h +++ b/Conf.h @@ -207,7 +207,6 @@ public: unsigned int getFMCTCSSLowThreshold() const; float getFMCTCSSLevel() const; unsigned int getFMKerchunkTime() const; - bool getFMKerchunkTX() const; unsigned int getFMHangTime() const; bool getFMUseCOS() const; bool getFMCOSInvert() const; @@ -497,7 +496,6 @@ private: unsigned int m_fmCTCSSLowThreshold; float m_fmCTCSSLevel; unsigned int m_fmKerchunkTime; - bool m_fmKerchunkTX; unsigned int m_fmHangTime; bool m_fmUseCOS; bool m_fmCOSInvert; diff --git a/MMDVM.ini b/MMDVM.ini index 1435956..0439646 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -170,7 +170,6 @@ CTCSSThreshold=30 # CTCSSLowThreshold=20 CTCSSLevel=20 KerchunkTime=0 -KerchunkTX=1 HangTime=7 UseCOS=1 COSInvert=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 6703f90..714699a 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1377,7 +1377,6 @@ bool CMMDVMHost::createModem() unsigned int ctcssLowThreshold = m_conf.getFMCTCSSLowThreshold(); float ctcssLevel = m_conf.getFMCTCSSLevel(); unsigned int kerchunkTime = m_conf.getFMKerchunkTime(); - bool kerchunkTX = m_conf.getFMKerchunkTX(); unsigned int hangTime = m_conf.getFMHangTime(); bool useCOS = m_conf.getFMUseCOS(); bool cosInvert = m_conf.getFMCOSInvert(); @@ -1409,7 +1408,6 @@ bool CMMDVMHost::createModem() LogInfo(" CTCSS Low Threshold: %u", ctcssLowThreshold); LogInfo(" CTCSS Level: %.1f%%", ctcssLevel); LogInfo(" Kerchunk Time: %us", kerchunkTime); - LogInfo(" Kerchunk TX: %s", kerchunkTX ? "yes" : "no"); LogInfo(" Hang Time: %us", hangTime); LogInfo(" Use COS: %s", useCOS ? "yes" : "no"); LogInfo(" COS Invert: %s", cosInvert ? "yes" : "no"); @@ -1419,7 +1417,7 @@ bool CMMDVMHost::createModem() m_modem->setFMCallsignParams(callsign, callsignSpeed, callsignFrequency, callsignTime, callsignHoldoff, callsignHighLevel, callsignLowLevel, callsignAtStart, callsignAtEnd, callsignAtLatch); m_modem->setFMAckParams(rfAck, ackSpeed, ackFrequency, ackMinTime, ackDelay, ackLevel); - m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, kerchunkTX, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel); + m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel); if (m_conf.getFMNetworkEnabled()) { std::string extAck = m_conf.getFMExtAck(); diff --git a/Modem.h b/Modem.h index d5fc4b3..4fba648 100644 --- a/Modem.h +++ b/Modem.h @@ -40,7 +40,7 @@ public: virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) = 0; virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) = 0; - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) = 0; + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) = 0; virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost) = 0; virtual bool open() = 0; diff --git a/NullModem.h b/NullModem.h index 5ab0dd0..3f73083 100644 --- a/NullModem.h +++ b/NullModem.h @@ -42,7 +42,7 @@ public: virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) {}; virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) {}; - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) {}; + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) {}; virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost) {}; virtual bool open(); diff --git a/SerialModem.cpp b/SerialModem.cpp index 5fe164b..37e87dc 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -220,7 +220,6 @@ m_fmCtcssHighThreshold(30U), m_fmCtcssLowThreshold(20U), m_fmCtcssLevel(10.0F), m_fmKerchunkTime(0U), -m_fmKerchunkTX(true), m_fmHangTime(5U), m_fmUseCOS(true), m_fmCOSInvert(false), @@ -2184,7 +2183,7 @@ void CSerialModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpee m_fmAckLevel = ackLevel; } -void CSerialModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) +void CSerialModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) { m_fmTimeout = timeout; m_fmTimeoutLevel = timeoutLevel; @@ -2195,7 +2194,6 @@ void CSerialModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, flo m_fmCtcssLevel = ctcssLevel; m_fmKerchunkTime = kerchunkTime; - m_fmKerchunkTX = kerchunkTX; m_fmHangTime = hangTime; @@ -2352,8 +2350,6 @@ bool CSerialModem::setFMMiscParams() buffer[11U] |= 0x01U; if (m_fmCOSInvert) buffer[11U] |= 0x02U; - if (m_fmKerchunkTX) - buffer[11U] |= 0x04U; buffer[12U] = m_fmRFAudioBoost; diff --git a/SerialModem.h b/SerialModem.h index 9ec4d85..9befe26 100644 --- a/SerialModem.h +++ b/SerialModem.h @@ -60,7 +60,7 @@ public: virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost); virtual bool open(); @@ -243,7 +243,6 @@ private: unsigned int m_fmCtcssLowThreshold; float m_fmCtcssLevel; unsigned int m_fmKerchunkTime; - bool m_fmKerchunkTX; unsigned int m_fmHangTime; bool m_fmUseCOS; bool m_fmCOSInvert; diff --git a/Version.h b/Version.h index c634cfc..a235cfe 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200706"; +const char* VERSION = "20200707"; #endif From c80894ddaa4a75481d8ba5df7519c15de801b5a8 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 15 Jul 2020 12:31:48 +0100 Subject: [PATCH 097/115] Fix the configuration source file. --- Conf.cpp | 431 ------------------------------------------------------- 1 file changed, 431 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index e19f3e6..380dcea 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -486,181 +486,6 @@ bool CConf::read() for (unsigned int i = 0U; value[i] != 0; i++) value[i] = ::toupper(value[i]); m_cwIdCallsign = value; - } - } else if (section == SECTION_DMRID_LOOKUP) { - if (::strcmp(key, "File") == 0) - m_dmrIdLookupFile = value; - else if (::strcmp(key, "Time") == 0) - m_dmrIdLookupTime = (unsigned int)::atoi(value); - } else if (section == SECTION_NXDNID_LOOKUP) { - if (::strcmp(key, "File") == 0) - m_nxdnIdLookupFile = value; - else if (::strcmp(key, "Time") == 0) - m_nxdnIdLookupTime = (unsigned int)::atoi(value); - } else if (section == SECTION_MODEM) { - if (::strcmp(key, "Port") == 0) - m_modemPort = value; - else if (::strcmp(key, "Protocol") == 0) - m_modemProtocol = value; - else if (::strcmp(key, "Address") == 0) - m_modemAddress = (unsigned int)::strtoul(value, NULL, 16); - else if (::strcmp(key, "RXInvert") == 0) - m_modemRXInvert = ::atoi(value) == 1; - else if (::strcmp(key, "TXInvert") == 0) - m_modemTXInvert = ::atoi(value) == 1; - else if (::strcmp(key, "PTTInvert") == 0) - m_modemPTTInvert = ::atoi(value) == 1; - else if (::strcmp(key, "TXDelay") == 0) - m_modemTXDelay = (unsigned int)::atoi(value); - else if (::strcmp(key, "DMRDelay") == 0) - m_modemDMRDelay = (unsigned int)::atoi(value); - else if (::strcmp(key, "RXOffset") == 0) - m_modemRXOffset = ::atoi(value); - else if (::strcmp(key, "TXOffset") == 0) - m_modemTXOffset = ::atoi(value); - else if (::strcmp(key, "RXDCOffset") == 0) - m_modemRXDCOffset = ::atoi(value); - else if (::strcmp(key, "TXDCOffset") == 0) - m_modemTXDCOffset = ::atoi(value); - else if (::strcmp(key, "RFLevel") == 0) - m_modemRFLevel = float(::atof(value)); - else if (::strcmp(key, "RXLevel") == 0) - m_modemRXLevel = float(::atof(value)); - else if (::strcmp(key, "TXLevel") == 0) - m_modemAX25TXLevel = m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value)); - else if (::strcmp(key, "CWIdTXLevel") == 0) - m_modemCWIdTXLevel = float(::atof(value)); - else if (::strcmp(key, "D-StarTXLevel") == 0) - m_modemDStarTXLevel = float(::atof(value)); - else if (::strcmp(key, "DMRTXLevel") == 0) - m_modemDMRTXLevel = float(::atof(value)); - else if (::strcmp(key, "YSFTXLevel") == 0) - m_modemYSFTXLevel = float(::atof(value)); - else if (::strcmp(key, "P25TXLevel") == 0) - m_modemP25TXLevel = float(::atof(value)); - else if (::strcmp(key, "NXDNTXLevel") == 0) - m_modemNXDNTXLevel = float(::atof(value)); - else if (::strcmp(key, "POCSAGTXLevel") == 0) - m_modemPOCSAGTXLevel = float(::atof(value)); - else if (::strcmp(key, "FMTXLevel") == 0) - m_modemFMTXLevel = float(::atof(value)); - else if (::strcmp(key, "RSSIMappingFile") == 0) - m_modemRSSIMappingFile = value; - else if (::strcmp(key, "UseCOSAsLockout") == 0) - m_modemUseCOSAsLockout = ::atoi(value) == 1; - else if (::strcmp(key, "Trace") == 0) - m_modemTrace = ::atoi(value) == 1; - else if (::strcmp(key, "Debug") == 0) - m_modemDebug = ::atoi(value) == 1; - } else if (section == SECTION_TRANSPARENT) { - if (::strcmp(key, "Enable") == 0) - m_transparentEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "RemoteAddress") == 0) - m_transparentRemoteAddress = value; - else if (::strcmp(key, "RemotePort") == 0) - m_transparentRemotePort = (unsigned int)::atoi(value); - else if (::strcmp(key, "LocalPort") == 0) - m_transparentLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "SendFrameType") == 0) - m_transparentSendFrameType = (unsigned int)::atoi(value); - } else if (section == SECTION_UMP) { - if (::strcmp(key, "Enable") == 0) - m_umpEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Port") == 0) - m_umpPort = value; - } else if (section == SECTION_DSTAR) { - if (::strcmp(key, "Enable") == 0) - m_dstarEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Module") == 0) { - // Convert the module to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_dstarModule = value; - } else if (::strcmp(key, "SelfOnly") == 0) - m_dstarSelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "BlackList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - if (::strlen(p) > 0U) { - for (unsigned int i = 0U; p[i] != 0; i++) - p[i] = ::toupper(p[i]); - std::string callsign = std::string(p); - callsign.resize(DSTAR_LONG_CALLSIGN_LENGTH, ' '); - m_dstarBlackList.push_back(callsign); - } - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "AckReply") == 0) - m_dstarAckReply = ::atoi(value) == 1; - else if (::strcmp(key, "AckTime") == 0) - m_dstarAckTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckMessage") == 0) - m_dstarAckMessage = ::atoi(value) == 1; - else if (::strcmp(key, "ErrorReply") == 0) - m_dstarErrorReply = ::atoi(value) == 1; - else if (::strcmp(key, "RemoteGateway") == 0) - m_dstarRemoteGateway = ::atoi(value) == 1; - else if (::strcmp(key, "ModeHang") == 0) - m_dstarModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_DMR) { - if (::strcmp(key, "Enable") == 0) - m_dmrEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Beacons") == 0) - m_dmrBeacons = ::atoi(value) == 1 ? DMR_BEACONS_NETWORK : DMR_BEACONS_OFF; - else if (::strcmp(key, "BeaconInterval") == 0) { - m_dmrBeacons = m_dmrBeacons != DMR_BEACONS_OFF ? DMR_BEACONS_TIMED : DMR_BEACONS_OFF; - m_dmrBeaconInterval = (unsigned int)::atoi(value); - } else if (::strcmp(key, "BeaconDuration") == 0) - m_dmrBeaconDuration = (unsigned int)::atoi(value); - else if (::strcmp(key, "Id") == 0) - m_dmrId = (unsigned int)::atoi(value); - else if (::strcmp(key, "ColorCode") == 0) - m_dmrColorCode = (unsigned int)::atoi(value); - else if (::strcmp(key, "SelfOnly") == 0) - m_dmrSelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "EmbeddedLCOnly") == 0) - m_dmrEmbeddedLCOnly = ::atoi(value) == 1; - else if (::strcmp(key, "DumpTAData") == 0) - m_dmrDumpTAData = ::atoi(value) == 1; - else if (::strcmp(key, "Prefixes") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int prefix = (unsigned int)::atoi(p); - if (prefix > 0U && prefix <= 999U) - m_dmrPrefixes.push_back(prefix); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "BlackList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int id = (unsigned int)::atoi(p); - if (id > 0U) - m_dmrBlackList.push_back(id); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "WhiteList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int id = (unsigned int)::atoi(p); - if (id > 0U) - m_dmrWhiteList.push_back(id); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "Slot1TGWhiteList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int id = (unsigned int)::atoi(p); - if (id > 0U) - m_dmrSlot1TGWhiteList.push_back(id); - p = ::strtok(NULL, ",\r\n"); - } - } else if (::strcmp(key, "Slot2TGWhiteList") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int id = (unsigned int)::atoi(p); - if (id > 0U) - m_dmrSlot2TGWhiteList.push_back(id); - p = ::strtok(NULL, ",\r\n"); } } else if (section == SECTION_DMRID_LOOKUP) { if (::strcmp(key, "File") == 0) @@ -1152,262 +977,6 @@ bool CConf::read() m_hd44780Pins.push_back(pin); p = ::strtok(NULL, ",\r\n"); } - - } else if (section == SECTION_FUSION) { - if (::strcmp(key, "Enable") == 0) - m_fusionEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LowDeviation") == 0) - m_fusionLowDeviation = ::atoi(value) == 1; - else if (::strcmp(key, "DGID") == 0) { - m_fusionDGIdEnabled = true; - m_fusionDGId = (unsigned int)::atoi(value); - } else if (::strcmp(key, "RemoteGateway") == 0) - m_fusionRemoteGateway = ::atoi(value) == 1; - else if (::strcmp(key, "SelfOnly") == 0) - m_fusionSelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "TXHang") == 0) - m_fusionTXHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_fusionModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_P25) { - if (::strcmp(key, "Enable") == 0) - m_p25Enabled = ::atoi(value) == 1; - else if (::strcmp(key, "Id") == 0) - m_p25Id = (unsigned int)::atoi(value); - else if (::strcmp(key, "NAC") == 0) - m_p25NAC = (unsigned int)::strtoul(value, NULL, 16); - else if (::strcmp(key, "OverrideUIDCheck") == 0) - m_p25OverrideUID = ::atoi(value) == 1; - else if (::strcmp(key, "SelfOnly") == 0) - m_p25SelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "RemoteGateway") == 0) - m_p25RemoteGateway = ::atoi(value) == 1; - else if (::strcmp(key, "TXHang") == 0) - m_p25TXHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_p25ModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_NXDN) { - if (::strcmp(key, "Enable") == 0) - m_nxdnEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Id") == 0) - m_nxdnId = (unsigned int)::atoi(value); - else if (::strcmp(key, "RAN") == 0) - m_nxdnRAN = (unsigned int)::atoi(value); - else if (::strcmp(key, "SelfOnly") == 0) - m_nxdnSelfOnly = ::atoi(value) == 1; - else if (::strcmp(key, "RemoteGateway") == 0) - m_nxdnRemoteGateway = ::atoi(value) == 1; - else if (::strcmp(key, "TXHang") == 0) - m_nxdnTXHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_nxdnModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_POCSAG) { - if (::strcmp(key, "Enable") == 0) - m_pocsagEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Frequency") == 0) - m_pocsagFrequency = (unsigned int)::atoi(value); - } - else if (section == SECTION_FM) { - if (::strcmp(key, "Enable") == 0) - m_fmEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Callsign") == 0) { - // Convert the callsign to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_fmCallsign = value; - } else if (::strcmp(key, "CallsignSpeed") == 0) - m_fmCallsignSpeed = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallsignFrequency") == 0) - m_fmCallsignFrequency = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallsignTime") == 0) - m_fmCallsignTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallsignHoldoff") == 0) - m_fmCallsignHoldoff = (unsigned int)::atoi(value); - else if (::strcmp(key, "CallsignHighLevel") == 0) - m_fmCallsignHighLevel = float(::atof(value)); - else if (::strcmp(key, "CallsignLowLevel") == 0) - m_fmCallsignLowLevel = float(::atof(value)); - else if (::strcmp(key, "CallsignAtStart") == 0) - m_fmCallsignAtStart = ::atoi(value) == 1; - else if (::strcmp(key, "CallsignAtEnd") == 0) - m_fmCallsignAtEnd = ::atoi(value) == 1; - else if (::strcmp(key, "CallsignAtLatch") == 0) - m_fmCallsignAtLatch = ::atoi(value) == 1; - else if (::strcmp(key, "RFAck") == 0) { - // Convert the ack to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_fmRFAck = value; - } else if (::strcmp(key, "ExtAck") == 0) { - // Convert the ack to upper case - for (unsigned int i = 0U; value[i] != 0; i++) - value[i] = ::toupper(value[i]); - m_fmExtAck = value; - } else if (::strcmp(key, "AckSpeed") == 0) - m_fmAckSpeed = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckFrequency") == 0) - m_fmAckFrequency = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckMinTime") == 0) - m_fmAckMinTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckDelay") == 0) - m_fmAckDelay = (unsigned int)::atoi(value); - else if (::strcmp(key, "AckLevel") == 0) - m_fmAckLevel = float(::atof(value)); - else if (::strcmp(key, "Timeout") == 0) - m_fmTimeout = (unsigned int)::atoi(value); - else if (::strcmp(key, "TimeoutLevel") == 0) - m_fmTimeoutLevel = float(::atof(value)); - else if (::strcmp(key, "CTCSSFrequency") == 0) - m_fmCTCSSFrequency = float(::atof(value)); - else if (::strcmp(key, "CTCSSThreshold") == 0) - m_fmCTCSSHighThreshold = m_fmCTCSSLowThreshold = (unsigned int)::atoi(value); - else if (::strcmp(key, "CTCSSHighThreshold") == 0) - m_fmCTCSSHighThreshold = (unsigned int)::atoi(value); - else if (::strcmp(key, "CTCSSLowThreshold") == 0) - m_fmCTCSSLowThreshold = (unsigned int)::atoi(value); - else if (::strcmp(key, "CTCSSLevel") == 0) - m_fmCTCSSLevel = float(::atof(value)); - else if (::strcmp(key, "KerchunkTime") == 0) - m_fmKerchunkTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "HangTime") == 0) - m_fmHangTime = (unsigned int)::atoi(value); - else if (::strcmp(key, "AccessMode") == 0) - m_fmAccessMode = (unsigned int)::atoi(value); - else if (::strcmp(key, "COSInvert") == 0) - m_fmCOSInvert = ::atoi(value) == 1; - else if (::strcmp(key, "RFAudioBoost") == 0) - m_fmRFAudioBoost = (unsigned int)::atoi(value); - else if (::strcmp(key, "MaxDevLevel") == 0) - m_fmMaxDevLevel = float(::atof(value)); - else if (::strcmp(key, "ExtAudioBoost") == 0) - m_fmExtAudioBoost = (unsigned int)::atoi(value); - } else if (section == SECTION_DSTAR_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_dstarNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "GatewayAddress") == 0) - m_dstarGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_dstarGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "LocalPort") == 0) - m_dstarLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_dstarNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_dstarNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_DMR_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_dmrNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Address") == 0) - m_dmrNetworkAddress = value; - else if (::strcmp(key, "Port") == 0) - m_dmrNetworkPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "Local") == 0) - m_dmrNetworkLocal = (unsigned int)::atoi(value); - else if (::strcmp(key, "Password") == 0) - m_dmrNetworkPassword = value; - else if (::strcmp(key, "Options") == 0) - m_dmrNetworkOptions = value; - else if (::strcmp(key, "Debug") == 0) - m_dmrNetworkDebug = ::atoi(value) == 1; - else if (::strcmp(key, "Jitter") == 0) - m_dmrNetworkJitter = (unsigned int)::atoi(value); - else if (::strcmp(key, "Slot1") == 0) - m_dmrNetworkSlot1 = ::atoi(value) == 1; - else if (::strcmp(key, "Slot2") == 0) - m_dmrNetworkSlot2 = ::atoi(value) == 1; - else if (::strcmp(key, "ModeHang") == 0) - m_dmrNetworkModeHang = (unsigned int)::atoi(value); - } else if (section == SECTION_FUSION_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_fusionNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LocalAddress") == 0) - m_fusionNetworkMyAddress = value; - else if (::strcmp(key, "LocalPort") == 0) - m_fusionNetworkMyPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "GatewayAddress") == 0) - m_fusionNetworkGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_fusionNetworkGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_fusionNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_fusionNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_P25_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_p25NetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "GatewayAddress") == 0) - m_p25GatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_p25GatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "LocalPort") == 0) - m_p25LocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_p25NetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_p25NetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_NXDN_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_nxdnNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Protocol") == 0) - m_nxdnNetworkProtocol = value; - else if (::strcmp(key, "LocalAddress") == 0) - m_nxdnLocalAddress = value; - else if (::strcmp(key, "LocalPort") == 0) - m_nxdnLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "GatewayAddress") == 0) - m_nxdnGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_nxdnGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_nxdnNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_nxdnNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_POCSAG_NETWORK) { - if (::strcmp(key, "Enable") == 0) - m_pocsagNetworkEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "LocalAddress") == 0) - m_pocsagLocalAddress = value; - else if (::strcmp(key, "LocalPort") == 0) - m_pocsagLocalPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "GatewayAddress") == 0) - m_pocsagGatewayAddress = value; - else if (::strcmp(key, "GatewayPort") == 0) - m_pocsagGatewayPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "ModeHang") == 0) - m_pocsagNetworkModeHang = (unsigned int)::atoi(value); - else if (::strcmp(key, "Debug") == 0) - m_pocsagNetworkDebug = ::atoi(value) == 1; - } else if (section == SECTION_TFTSERIAL) { - if (::strcmp(key, "Port") == 0) - m_tftSerialPort = value; - else if (::strcmp(key, "Brightness") == 0) - m_tftSerialBrightness = (unsigned int)::atoi(value); - } else if (section == SECTION_HD44780) { - if (::strcmp(key, "Rows") == 0) - m_hd44780Rows = (unsigned int)::atoi(value); - else if (::strcmp(key, "Columns") == 0) - m_hd44780Columns = (unsigned int)::atoi(value); - else if (::strcmp(key, "I2CAddress") == 0) - m_hd44780i2cAddress = (unsigned int)::strtoul(value, NULL, 16); - else if (::strcmp(key, "PWM") == 0) - m_hd44780PWM = ::atoi(value) == 1; - else if (::strcmp(key, "PWMPin") == 0) - m_hd44780PWMPin = (unsigned int)::atoi(value); - else if (::strcmp(key, "PWMBright") == 0) - m_hd44780PWMBright = (unsigned int)::atoi(value); - else if (::strcmp(key, "PWMDim") == 0) - m_hd44780PWMDim = (unsigned int)::atoi(value); - else if (::strcmp(key, "DisplayClock") == 0) - m_hd44780DisplayClock = ::atoi(value) == 1; - else if (::strcmp(key, "UTC") == 0) - m_hd44780UTC = ::atoi(value) == 1; - else if (::strcmp(key, "Pins") == 0) { - char* p = ::strtok(value, ",\r\n"); - while (p != NULL) { - unsigned int pin = (unsigned int)::atoi(p); - m_hd44780Pins.push_back(pin); - p = ::strtok(NULL, ",\r\n"); - } } else if (section == SECTION_NEXTION) { if (::strcmp(key, "Port") == 0) From 87b7a7c48a7b8b8942debf6fc4bdf84ef43cc62b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 18 Jul 2020 17:36:54 +0200 Subject: [PATCH 098/115] Moved existing scripts to pi-star folder --- linux/{ => pi-star}/init/README.md | 0 linux/{ => pi-star}/init/mmdvmhost | 0 linux/{ => pi-star}/systemd/README.md | 0 linux/{ => pi-star}/systemd/mmdvmhost.service | 0 linux/{ => pi-star}/systemd/mmdvmhost.timer | 0 linux/{ => pi-star}/systemd/mmdvmhost_service | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename linux/{ => pi-star}/init/README.md (100%) rename linux/{ => pi-star}/init/mmdvmhost (100%) rename linux/{ => pi-star}/systemd/README.md (100%) rename linux/{ => pi-star}/systemd/mmdvmhost.service (100%) rename linux/{ => pi-star}/systemd/mmdvmhost.timer (100%) rename linux/{ => pi-star}/systemd/mmdvmhost_service (100%) diff --git a/linux/init/README.md b/linux/pi-star/init/README.md similarity index 100% rename from linux/init/README.md rename to linux/pi-star/init/README.md diff --git a/linux/init/mmdvmhost b/linux/pi-star/init/mmdvmhost similarity index 100% rename from linux/init/mmdvmhost rename to linux/pi-star/init/mmdvmhost diff --git a/linux/systemd/README.md b/linux/pi-star/systemd/README.md similarity index 100% rename from linux/systemd/README.md rename to linux/pi-star/systemd/README.md diff --git a/linux/systemd/mmdvmhost.service b/linux/pi-star/systemd/mmdvmhost.service similarity index 100% rename from linux/systemd/mmdvmhost.service rename to linux/pi-star/systemd/mmdvmhost.service diff --git a/linux/systemd/mmdvmhost.timer b/linux/pi-star/systemd/mmdvmhost.timer similarity index 100% rename from linux/systemd/mmdvmhost.timer rename to linux/pi-star/systemd/mmdvmhost.timer diff --git a/linux/systemd/mmdvmhost_service b/linux/pi-star/systemd/mmdvmhost_service similarity index 100% rename from linux/systemd/mmdvmhost_service rename to linux/pi-star/systemd/mmdvmhost_service From 76033dd30174f8c7ab3f4378ca1eecf6556bf287 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 18 Jul 2020 18:07:10 +0200 Subject: [PATCH 099/115] Add systemd unit --- linux/systemd/mmdvmhost.service | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 linux/systemd/mmdvmhost.service diff --git a/linux/systemd/mmdvmhost.service b/linux/systemd/mmdvmhost.service new file mode 100644 index 0000000..0587683 --- /dev/null +++ b/linux/systemd/mmdvmhost.service @@ -0,0 +1,12 @@ +[Unit] +Description=MMDVMHost Radio Servce +After=syslog.target network.target + +[Service] +User=mmdvm +Type=forking +ExecStart=/usr/bin/local/MMDVMHost +Restart=on-abnormal + +[Install] +WantedBy=multi-user.target From ba9c97289fbb9b4b800971543bc44be2088dd573 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 18 Jul 2020 18:07:21 +0200 Subject: [PATCH 100/115] add install targets --- Makefile | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 91fcf2d..ccc4eef 100644 --- a/Makefile +++ b/Makefile @@ -35,10 +35,31 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h From bb1a542fe1ba0372f1fc7c2a9425cb76c432b52d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 20 Jul 2020 08:06:29 +0200 Subject: [PATCH 101/115] delete unit file on uninstall --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index ccc4eef..96a6b3e 100644 --- a/Makefile +++ b/Makefile @@ -55,10 +55,12 @@ install-service: install /etc/MMDVM.ini @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini @chown mmdvm:mmdvm /etc/MMDVM.ini +.PHONY uninstall-service: uninstall-service: @systemctl stop mmdvmhost.service || true @systemctl disable mmdvmhost.service || true @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h From 49a4e2ad0d5880cced428289ecec45017adf3702 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 20 Jul 2020 08:13:27 +0200 Subject: [PATCH 102/115] fix typo in executable path --- linux/systemd/mmdvmhost.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/systemd/mmdvmhost.service b/linux/systemd/mmdvmhost.service index 0587683..7ab6aa1 100644 --- a/linux/systemd/mmdvmhost.service +++ b/linux/systemd/mmdvmhost.service @@ -5,7 +5,7 @@ After=syslog.target network.target [Service] User=mmdvm Type=forking -ExecStart=/usr/bin/local/MMDVMHost +ExecStart=/usr/local/bin/MMDVMHost Restart=on-abnormal [Install] From fa7be67d9c920aa62f8499b8fe3f7f41cef04c5a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 20 Jul 2020 08:36:22 +0200 Subject: [PATCH 103/115] Add install service to othe rmakefiles --- Makefile.Pi | 25 ++++++++++++++++++++++++- Makefile.Pi.Adafruit | 25 ++++++++++++++++++++++++- Makefile.Pi.HD44780 | 25 ++++++++++++++++++++++++- Makefile.Pi.OLED | 25 ++++++++++++++++++++++++- Makefile.Pi.PCF8574 | 25 ++++++++++++++++++++++++- 5 files changed, 120 insertions(+), 5 deletions(-) diff --git a/Makefile.Pi b/Makefile.Pi index 62e27aa..7909ef4 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -34,10 +34,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 2915c69..9af13af 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -35,10 +35,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index c00e58f..eae303b 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -35,10 +35,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 41e837e..08ec63f 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -35,10 +35,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 37de0b1..4ebf3fc 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -36,10 +36,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h From 801ba04e0d7a01ac440142d614eed0e51876ddf3 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 20 Jul 2020 09:08:58 +0200 Subject: [PATCH 104/115] Correct typo --- linux/systemd/mmdvmhost.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/systemd/mmdvmhost.service b/linux/systemd/mmdvmhost.service index 7ab6aa1..27ca4ee 100644 --- a/linux/systemd/mmdvmhost.service +++ b/linux/systemd/mmdvmhost.service @@ -1,5 +1,5 @@ [Unit] -Description=MMDVMHost Radio Servce +Description=MMDVMHost Radio Service After=syslog.target network.target [Service] From da077c73f8ef929eb6e7616a723687e1cd93a808 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 27 Jul 2020 10:38:07 +0100 Subject: [PATCH 105/115] Allow the FM network sample rate to be specified. --- Conf.cpp | 8 ++++ Conf.h | 2 + FMControl.cpp | 22 ++++------ FMControl.h | 10 ++--- FMNetwork.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++-------- FMNetwork.h | 11 +++-- MMDVM.ini | 1 + MMDVMHost.cpp | 4 +- Version.h | 2 +- 9 files changed, 134 insertions(+), 41 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 380dcea..1ea5cc5 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -268,6 +268,7 @@ m_fmGatewayAddress(), m_fmGatewayPort(0U), m_fmLocalAddress(), m_fmLocalPort(0U), +m_fmSampleRate(8000U), m_fmNetworkModeHang(3U), m_fmNetworkDebug(false), m_ax25NetworkEnabled(false), @@ -933,6 +934,8 @@ bool CConf::read() m_fmGatewayAddress = value; else if (::strcmp(key, "GatewayPort") == 0) m_fmGatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "SampleRate") == 0) + m_fmSampleRate = (unsigned int)::atoi(value); else if (::strcmp(key, "ModeHang") == 0) m_fmNetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) @@ -2054,6 +2057,11 @@ unsigned int CConf::getFMLocalPort() const return m_fmLocalPort; } +unsigned int CConf::getFMSampleRate() const +{ + return m_fmSampleRate; +} + unsigned int CConf::getFMNetworkModeHang() const { return m_fmNetworkModeHang; diff --git a/Conf.h b/Conf.h index 095915d..01ef9f5 100644 --- a/Conf.h +++ b/Conf.h @@ -279,6 +279,7 @@ public: unsigned int getFMGatewayPort() const; std::string getFMLocalAddress() const; unsigned int getFMLocalPort() const; + unsigned int getFMSampleRate() const; unsigned int getFMNetworkModeHang() const; bool getFMNetworkDebug() const; @@ -569,6 +570,7 @@ private: unsigned int m_fmGatewayPort; std::string m_fmLocalAddress; unsigned int m_fmLocalPort; + unsigned int m_fmSampleRate; unsigned int m_fmNetworkModeHang; bool m_fmNetworkDebug; diff --git a/FMControl.cpp b/FMControl.cpp index 8a8f133..c07c8d4 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -89,7 +89,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) unsigned int pack = 0U; unsigned char* packPointer = (unsigned char*)&pack; - unsigned short out[168U]; + float out[168U]; unsigned int nOut = 0U; short unpackedSamples[2U]; @@ -102,28 +102,24 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) unpackedSamples[0U] = short(int(pack >> 12) - 2048); //process unpacked sample pair - for(unsigned char j = 0U; j < 2U; j++) { - //Convert to float (-1.0 to +1.0) + for (unsigned char j = 0U; j < 2U; j++) { + // Convert to float (-1.0 to +1.0) float sampleFloat = float(unpackedSamples[j]) / 2048.0F; - //De-emphasise and remove CTCSS + // De-emphasise and remove CTCSS sampleFloat = m_deemphasis->filter(sampleFloat); - sampleFloat = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(sampleFloat))); - - // Repack the float data to 16 bit unsigned - unsigned short sampleUShort = (unsigned short)((sampleFloat + 1.0F) * 32767.0F + 0.5F); - out[nOut++] = SWAP_BYTES_16(sampleUShort); + 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) { - fwrite(out, sizeof(unsigned short), nOut, audiofile); + fwrite(out, sizeof(float), nOut, audiofile); fclose(audiofile); } #endif - return m_network->writeData((unsigned char*)out, nOut * sizeof(unsigned short)); + return m_network->writeData(out, nOut); } return true; @@ -140,7 +136,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) if (space > 252U) space = 252U; - unsigned short netData[168U];//modem can handle up to 168 samples at a time + unsigned short netData[168U]; // Modem can handle up to 168 samples at a time unsigned int length = m_network->read((unsigned char*)netData, 168U * sizeof(unsigned short)); length /= sizeof(unsigned short); if (length == 0U) @@ -150,7 +146,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) unsigned char* packPointer = (unsigned char*)&pack; unsigned int nData = 0U; - for(unsigned int i = 0; i < length; i++) { + for (unsigned int i = 0; i < length; i++) { unsigned short netSample = SWAP_BYTES_16(netData[i]); // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) diff --git a/FMControl.h b/FMControl.h index 1647010..ac2142e 100644 --- a/FMControl.h +++ b/FMControl.h @@ -45,11 +45,11 @@ private: CFMNetwork* m_network; bool m_enabled; CRingBuffer m_incomingRFAudio; - CIIRDirectForm1Filter * m_preemphasis; - CIIRDirectForm1Filter * m_deemphasis; - CIIRDirectForm1Filter * m_filterStage1; - CIIRDirectForm1Filter * m_filterStage2; - CIIRDirectForm1Filter * m_filterStage3; + CIIRDirectForm1Filter* m_preemphasis; + CIIRDirectForm1Filter* m_deemphasis; + CIIRDirectForm1Filter* m_filterStage1; + CIIRDirectForm1Filter* m_filterStage2; + CIIRDirectForm1Filter* m_filterStage3; }; #endif diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 67d0f2e..afc2014 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -27,10 +27,11 @@ const unsigned int BUFFER_LENGTH = 500U; -CFMNetwork::CFMNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : +CFMNetwork::CFMNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug) : m_socket(localAddress, localPort), m_address(), m_port(gatewayPort), +m_sampleRate(sampleRate), m_debug(debug), m_enabled(false), m_buffer(2000U, "FM Network"), @@ -38,12 +39,22 @@ m_pollTimer(1000U, 5U) { assert(gatewayPort > 0U); assert(!gatewayAddress.empty()); + assert(sampleRate > 0U); m_address = CUDPSocket::lookup(gatewayAddress); + + int error; + m_incoming = ::src_new(SRC_SINC_FASTEST, 1, &error); + m_outgoing = ::src_new(SRC_SINC_FASTEST, 1, &error); + + assert(m_incoming != NULL); + assert(m_outgoing != NULL); } CFMNetwork::~CFMNetwork() { + ::src_delete(m_incoming); + ::src_delete(m_outgoing); } bool CFMNetwork::open() @@ -58,23 +69,53 @@ bool CFMNetwork::open() return m_socket.open(); } -bool CFMNetwork::writeData(const unsigned char* data, unsigned int length) +bool CFMNetwork::writeData(const float* data, unsigned int nSamples) { + assert(m_outgoing != NULL); assert(data != NULL); + assert(nSamples > 0U); - unsigned char buffer[500U]; - ::memset(buffer, 0x00U, 500U); + float out[1000U]; + SRC_DATA src; + + if (m_sampleRate != 8000U) { + src.data_in = data; + src.data_out = out; + src.input_frames = nSamples; + src.output_frames = 1000; + src.end_of_input = 0; + src.src_ratio = double(m_sampleRate) / 8000.0; + + int ret = ::src_process(m_outgoing, &src); + if (ret != 0) { + LogError("Error up/downsampling of the output audio has an error - %s", src_strerror(ret)); + return false; + } + } else { + src.data_out = data; + src.output_frames_gen = nSamples; + } + + unsigned int length = 3U; + + unsigned char buffer[1500U]; + ::memset(buffer, 0x00U, 1500U); buffer[0U] = 'F'; buffer[1U] = 'M'; buffer[2U] = 'D'; - ::memcpy(buffer + 3U, data, length); + for (long i = 0L; i < src.output_frames_gen; i++) { + unsigned short val = (unsigned short)((src.data_out[i] + 1.0F) * 32767.0F + 0.5F); + + buffer[length++] = (val >> 8) & 0xFFU; + buffer[length++] = (val >> 0) & 0xFFU; + } if (m_debug) - CUtils::dump(1U, "FM Network Data Sent", buffer, length + 3U); + CUtils::dump(1U, "FM Network Data Sent", buffer, length); - return m_socket.write(buffer, length + 3U, m_address, m_port); + return m_socket.write(buffer, length, m_address, m_port); } bool CFMNetwork::writeEOT() @@ -131,29 +172,67 @@ void CFMNetwork::clock(unsigned int ms) m_buffer.addData(buffer + 3U, length - 3U); } -unsigned int CFMNetwork::read(unsigned char* data, unsigned int space) +unsigned int CFMNetwork::read(float* data, unsigned int nSamples) { + assert(m_incoming != NULL); assert(data != NULL); + assert(nSamples > 0U); - - unsigned int bytes = m_buffer.dataSize(); + unsigned int bytes = m_buffer.dataSize() / sizeof(unsigned short); if (bytes == 0U) return 0U; - if (bytes < space) - space = bytes; + if (bytes < nSamples) + nSamples = bytes; - //we store usignedshorts, therefore ensure we always return and even number of data - if(space > 0 && space % 2 != 0) - space--;//round down to multiple of 2 + unsigned char buffer[1500U]; + m_buffer.getData(buffer, nSamples * sizeof(unsigned short)); - m_buffer.getData(data, space); + SRC_DATA src; - return space; + if (m_sampleRate != 8000U) { + float in[750U]; + + unsigned int j = 0U; + for (unsigned int i = 0U; i < nSamples; i++) { + unsigned short val = ((buffer[j++] & 0xFFU) << 8) + ((buffer[j++] & 0xFFU) << 0); + in[i] = (float(val) - 32768.0F) / 32768.0F; + } + + src.data_in = in; + src.data_out = data; + src.input_frames = nSamples; + src.output_frames = 750; + src.end_of_input = 0; + src.src_ratio = 8000.0 / double(m_sampleRate); + + int ret = ::src_process(m_incoming, &src); + if (ret != 0) { + LogError("Error up/downsampling of the input audio has an error - %s", src_strerror(ret)); + return 0U; + } + + return src.output_frames_gen; + } else { + unsigned int j = 0U; + for (unsigned int i = 0U; i < nSamples; i++) { + unsigned short val = ((buffer[j++] & 0xFFU) << 8) + ((buffer[j++] & 0xFFU) << 0); + data[i] = (float(val) - 32768.0F) / 32768.0F; + } + + return nSamples; + } } void CFMNetwork::reset() { + assert(m_incoming != NULL); + assert(m_outgoing != NULL); + + m_buffer.clear(); + + ::src_reset(m_incoming); + ::src_reset(m_outgoing); } void CFMNetwork::close() @@ -168,7 +247,7 @@ void CFMNetwork::enable(bool enabled) if (enabled && !m_enabled) reset(); else if (!enabled && m_enabled) - m_buffer.clear(); + reset(); m_enabled = enabled; } diff --git a/FMNetwork.h b/FMNetwork.h index 453e776..6dcdaac 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -23,23 +23,25 @@ #include "UDPSocket.h" #include "Timer.h" +#include + #include #include class CFMNetwork { public: - CFMNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug); + CFMNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug); ~CFMNetwork(); bool open(); void enable(bool enabled); - bool writeData(const unsigned char* data, unsigned int length); + bool writeData(const float* data, unsigned int nSamples); bool writeEOT(); - unsigned int read(unsigned char* data, unsigned int space); + unsigned int read(float* data, unsigned int nSamples); void reset(); @@ -51,10 +53,13 @@ private: CUDPSocket m_socket; in_addr m_address; unsigned int m_port; + unsigned int m_sampleRate; bool m_debug; bool m_enabled; CRingBuffer m_buffer; CTimer m_pollTimer; + SRC_STATE* m_incoming; + SRC_STATE* m_outgoing; bool writePoll(); }; diff --git a/MMDVM.ini b/MMDVM.ini index 911cb29..6c35909 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -250,6 +250,7 @@ LocalAddress=127.0.0.1 LocalPort=3810 GatewayAddress=127.0.0.1 GatewayPort=4810 +SampleRate=8000 # ModeHang=3 Debug=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 2a04430..7066ad1 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1690,6 +1690,7 @@ bool CMMDVMHost::createFMNetwork() unsigned int gatewayPort = m_conf.getFMGatewayPort(); std::string localAddress = m_conf.getFMLocalAddress(); unsigned int localPort = m_conf.getFMLocalPort(); + unsigned int sampleRate = m_conf.getFMSampleRate(); m_fmNetModeHang = m_conf.getFMNetworkModeHang(); bool debug = m_conf.getFMNetworkDebug(); @@ -1698,9 +1699,10 @@ bool CMMDVMHost::createFMNetwork() LogInfo(" Gateway Port: %u", gatewayPort); LogInfo(" Local Address: %s", localAddress.c_str()); LogInfo(" Local Port: %u", localPort); + LogInfo(" Sample Rate: %u", sampleRate); LogInfo(" Mode Hang: %us", m_fmNetModeHang); - m_fmNetwork = new CFMNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug); + m_fmNetwork = new CFMNetwork(localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, debug); bool ret = m_fmNetwork->open(); if (!ret) { diff --git a/Version.h b/Version.h index 874077c..d5b3f85 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200713"; +const char* VERSION = "20200727"; #endif From 15c21de416f2597b27505f491d13ff89ae6ee524 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 27 Jul 2020 10:58:32 +0100 Subject: [PATCH 106/115] Fix complilation on Linux. --- FMControl.cpp | 14 ++++---------- FMNetwork.cpp | 10 +++++----- FMNetwork.h | 6 +++--- Makefile | 4 ++-- Makefile.Pi | 4 ++-- Makefile.Pi.Adafruit | 4 ++-- Makefile.Pi.HD44780 | 4 ++-- Makefile.Pi.OLED | 4 ++-- Makefile.Pi.PCF8574 | 4 ++-- 9 files changed, 24 insertions(+), 30 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index c07c8d4..9a2a78a 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -136,9 +136,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) if (space > 252U) space = 252U; - unsigned short netData[168U]; // Modem can handle up to 168 samples at a time - unsigned int length = m_network->read((unsigned char*)netData, 168U * sizeof(unsigned short)); - length /= sizeof(unsigned short); + float netData[168U]; // Modem can handle up to 168 samples at a time + unsigned int length = m_network->read(netData, 168U); if (length == 0U) return 0U; @@ -147,13 +146,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) unsigned int nData = 0U; for (unsigned int i = 0; i < length; i++) { - unsigned short netSample = SWAP_BYTES_16(netData[i]); - - // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) - float sampleFloat = (float(netSample) / 32768.0F) - 1.0F; - - //preemphasis - sampleFloat = m_preemphasis->filter(sampleFloat); + // Pre-emphasis + float sampleFloat = m_preemphasis->filter(netData[i]); // Convert float to 12-bit samples (0 to 4095) unsigned int sample12bit = (unsigned int)((sampleFloat + 1.0F) * 2048.0F + 0.5F); diff --git a/FMNetwork.cpp b/FMNetwork.cpp index afc2014..fd13df4 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -69,7 +69,7 @@ bool CFMNetwork::open() return m_socket.open(); } -bool CFMNetwork::writeData(const float* data, unsigned int nSamples) +bool CFMNetwork::writeData(float* data, unsigned int nSamples) { assert(m_outgoing != NULL); assert(data != NULL); @@ -193,9 +193,9 @@ unsigned int CFMNetwork::read(float* data, unsigned int nSamples) if (m_sampleRate != 8000U) { float in[750U]; - unsigned int j = 0U; for (unsigned int i = 0U; i < nSamples; i++) { - unsigned short val = ((buffer[j++] & 0xFFU) << 8) + ((buffer[j++] & 0xFFU) << 0); + unsigned short val = ((buffer[i * 2U + 0U] & 0xFFU) << 8) + + ((buffer[i * 2U + 1U] & 0xFFU) << 0); in[i] = (float(val) - 32768.0F) / 32768.0F; } @@ -214,9 +214,9 @@ unsigned int CFMNetwork::read(float* data, unsigned int nSamples) return src.output_frames_gen; } else { - unsigned int j = 0U; for (unsigned int i = 0U; i < nSamples; i++) { - unsigned short val = ((buffer[j++] & 0xFFU) << 8) + ((buffer[j++] & 0xFFU) << 0); + unsigned short val = ((buffer[i * 2U + 0U] & 0xFFU) << 8) + + ((buffer[i * 2U + 1U] & 0xFFU) << 0); data[i] = (float(val) - 32768.0F) / 32768.0F; } diff --git a/FMNetwork.h b/FMNetwork.h index 6dcdaac..f0d5d2a 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -37,11 +37,11 @@ public: void enable(bool enabled); - bool writeData(const float* data, unsigned int nSamples); + bool writeData(float* data, unsigned int nSamples); - bool writeEOT(); + bool writeEOT(); - unsigned int read(float* data, unsigned int nSamples); + unsigned int read(float* data, unsigned int nSamples); void reset(); diff --git a/Makefile b/Makefile index 91fcf2d..2181178 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,11 @@ CXX = c++ # Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -LIBS = -lpthread -lutil +LIBS = -lpthread -lutil -lsamplerate # Use the following CFLAGS and LIBS if you do want to use gpsd. #CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -#LIBS = -lpthread -lgps -lutil +#LIBS = -lpthread -lgps -lutil -lsamplerate LDFLAGS = -g diff --git a/Makefile.Pi b/Makefile.Pi index 62e27aa..7123530 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -4,11 +4,11 @@ CC = gcc CXX = g++ # Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DRASPBERRY_PI -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil +LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil -lsamplerate # Use the following CFLAGS and LIBS if you do want to use gpsd. #CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DRASPBERRY_PI -I/usr/local/include -#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil -lsamplerate LDFLAGS = -g -L/usr/local/lib diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 2915c69..4c5e9f5 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -5,11 +5,11 @@ CC = gcc CXX = g++ # Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil +LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil -lsamplerate # Use the following CFLAGS and LIBS if you do want to use gpsd. #CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include -#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil -lsamplerate LDFLAGS = -g -L/usr/local/lib diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index c00e58f..186b22f 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -5,11 +5,11 @@ CXX = g++ # Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil +LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil -lsamplerate # Use the following CFLAGS and LIBS if you do want to use gpsd. #CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -I/usr/local/include -#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil -lsamplerate LDFLAGS = -g -L/usr/local/lib diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 41e837e..34b2a9e 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -5,11 +5,11 @@ CXX = g++ # Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DOLED -I/usr/local/include -LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lutil +LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lutil -lsamplerate # Use the following CFLAGS and LIBS if you do want to use gpsd. #CFLAGS = -g -O3 -Wall -DUSE_GPS -std=c++0x -pthread -DOLED -I/usr/local/include -#LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lgps -lutil +#LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lgps -lutil -lsamplerate LDFLAGS = -g -L/usr/local/lib diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 37de0b1..bda859b 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -6,11 +6,11 @@ CXX = g++ # Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil +LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil -lsamplerate # Use the following CFLAGS and LIBS if you do want to use gpsd. #CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include -#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil -lsamplerate LDFLAGS = -g -L/usr/local/lib From 8f59691738c2e732925d425b09271b80d32c0550 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 18 Jul 2020 17:36:54 +0200 Subject: [PATCH 107/115] Moved existing scripts to pi-star folder --- linux/{ => pi-star}/init/README.md | 0 linux/{ => pi-star}/init/mmdvmhost | 0 linux/{ => pi-star}/systemd/README.md | 0 linux/{ => pi-star}/systemd/mmdvmhost.service | 0 linux/{ => pi-star}/systemd/mmdvmhost.timer | 0 linux/{ => pi-star}/systemd/mmdvmhost_service | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename linux/{ => pi-star}/init/README.md (100%) rename linux/{ => pi-star}/init/mmdvmhost (100%) rename linux/{ => pi-star}/systemd/README.md (100%) rename linux/{ => pi-star}/systemd/mmdvmhost.service (100%) rename linux/{ => pi-star}/systemd/mmdvmhost.timer (100%) rename linux/{ => pi-star}/systemd/mmdvmhost_service (100%) diff --git a/linux/init/README.md b/linux/pi-star/init/README.md similarity index 100% rename from linux/init/README.md rename to linux/pi-star/init/README.md diff --git a/linux/init/mmdvmhost b/linux/pi-star/init/mmdvmhost similarity index 100% rename from linux/init/mmdvmhost rename to linux/pi-star/init/mmdvmhost diff --git a/linux/systemd/README.md b/linux/pi-star/systemd/README.md similarity index 100% rename from linux/systemd/README.md rename to linux/pi-star/systemd/README.md diff --git a/linux/systemd/mmdvmhost.service b/linux/pi-star/systemd/mmdvmhost.service similarity index 100% rename from linux/systemd/mmdvmhost.service rename to linux/pi-star/systemd/mmdvmhost.service diff --git a/linux/systemd/mmdvmhost.timer b/linux/pi-star/systemd/mmdvmhost.timer similarity index 100% rename from linux/systemd/mmdvmhost.timer rename to linux/pi-star/systemd/mmdvmhost.timer diff --git a/linux/systemd/mmdvmhost_service b/linux/pi-star/systemd/mmdvmhost_service similarity index 100% rename from linux/systemd/mmdvmhost_service rename to linux/pi-star/systemd/mmdvmhost_service From 354e808ccb1a6ea1283a3719c86cc25bc5cb2803 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 18 Jul 2020 18:07:10 +0200 Subject: [PATCH 108/115] Add systemd unit --- linux/systemd/mmdvmhost.service | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 linux/systemd/mmdvmhost.service diff --git a/linux/systemd/mmdvmhost.service b/linux/systemd/mmdvmhost.service new file mode 100644 index 0000000..0587683 --- /dev/null +++ b/linux/systemd/mmdvmhost.service @@ -0,0 +1,12 @@ +[Unit] +Description=MMDVMHost Radio Servce +After=syslog.target network.target + +[Service] +User=mmdvm +Type=forking +ExecStart=/usr/bin/local/MMDVMHost +Restart=on-abnormal + +[Install] +WantedBy=multi-user.target From d4e6f2cb5ef3eebc9844d9fb96a61f4935d8e3b8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 18 Jul 2020 18:07:21 +0200 Subject: [PATCH 109/115] add install targets --- Makefile | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2181178..3f298dc 100644 --- a/Makefile +++ b/Makefile @@ -35,10 +35,31 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h From f64371b4c8e112850c2af0329c56e6742a859d99 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 20 Jul 2020 08:06:29 +0200 Subject: [PATCH 110/115] delete unit file on uninstall --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 3f298dc..df54350 100644 --- a/Makefile +++ b/Makefile @@ -55,10 +55,12 @@ install-service: install /etc/MMDVM.ini @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini @chown mmdvm:mmdvm /etc/MMDVM.ini +.PHONY uninstall-service: uninstall-service: @systemctl stop mmdvmhost.service || true @systemctl disable mmdvmhost.service || true @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h From 869edd33fd17f0421e3ef9cc9e2a2f6c32561fd9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 20 Jul 2020 08:13:27 +0200 Subject: [PATCH 111/115] fix typo in executable path --- linux/systemd/mmdvmhost.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/systemd/mmdvmhost.service b/linux/systemd/mmdvmhost.service index 0587683..7ab6aa1 100644 --- a/linux/systemd/mmdvmhost.service +++ b/linux/systemd/mmdvmhost.service @@ -5,7 +5,7 @@ After=syslog.target network.target [Service] User=mmdvm Type=forking -ExecStart=/usr/bin/local/MMDVMHost +ExecStart=/usr/local/bin/MMDVMHost Restart=on-abnormal [Install] From 7aec7eefcb08f98fbe6d7a71e621bcb06aa37641 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 20 Jul 2020 08:36:22 +0200 Subject: [PATCH 112/115] Add install service to othe rmakefiles --- Makefile.Pi | 25 ++++++++++++++++++++++++- Makefile.Pi.Adafruit | 25 ++++++++++++++++++++++++- Makefile.Pi.HD44780 | 25 ++++++++++++++++++++++++- Makefile.Pi.OLED | 25 ++++++++++++++++++++++++- Makefile.Pi.PCF8574 | 25 ++++++++++++++++++++++++- 5 files changed, 120 insertions(+), 5 deletions(-) diff --git a/Makefile.Pi b/Makefile.Pi index 7123530..3b14a13 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -34,10 +34,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 4c5e9f5..149d9ba 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -35,10 +35,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 186b22f..85044ef 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -35,10 +35,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 34b2a9e..0a3d7bb 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -35,10 +35,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index bda859b..deda9e3 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -36,10 +36,33 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -install: +.PHONY install: +install: all install -m 755 MMDVMHost /usr/local/bin/ install -m 755 RemoteCommand /usr/local/bin/ +.PHONY install-service: +install-service: install /etc/MMDVM.ini + @useradd --user-group -M --system mmdvm --shell /bin/false || true + @usermod --groups dialout --append mmdvm || true + @mkdir /var/log/mmdvm || true + @chown mmdvm:mmdvm /var/log/mmdvm + @cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/ + @systemctl enable mmdvmhost.service + +/etc/MMDVM.ini: + @cp -n MMDVM.ini /etc/MMDVM.ini + @sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini + @sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini + @chown mmdvm:mmdvm /etc/MMDVM.ini + +.PHONY uninstall-service: +uninstall-service: + @systemctl stop mmdvmhost.service || true + @systemctl disable mmdvmhost.service || true + @rm -f /usr/local/bin/MMDVMHost || true + @rm -f /lib/systemd/system/mmdvmhost.service || true + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h From c2c1266233cf4b8b5655b386c78ffe23a4037d01 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 20 Jul 2020 09:08:58 +0200 Subject: [PATCH 113/115] Correct typo --- linux/systemd/mmdvmhost.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/systemd/mmdvmhost.service b/linux/systemd/mmdvmhost.service index 7ab6aa1..27ca4ee 100644 --- a/linux/systemd/mmdvmhost.service +++ b/linux/systemd/mmdvmhost.service @@ -1,5 +1,5 @@ [Unit] -Description=MMDVMHost Radio Servce +Description=MMDVMHost Radio Service After=syslog.target network.target [Service] From 0579b4387a7bf77d92db09c3e26158fe5ed53cf5 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 28 Jul 2020 14:22:26 +0100 Subject: [PATCH 114/115] Add the noise squelch configuration items. --- Conf.cpp | 26 ++++++++++++++++++ Conf.h | 6 +++++ MMDVM.ini | 4 +++ MMDVMHost.cpp | 70 ++++++++++++++++++++++++++++--------------------- Modem.h | 2 +- NullModem.h | 2 +- SerialModem.cpp | 24 ++++++++++++----- SerialModem.h | 5 +++- Version.h | 2 +- 9 files changed, 101 insertions(+), 40 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 1ea5cc5..150b258 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -208,6 +208,9 @@ m_fmKerchunkTime(0U), m_fmHangTime(7U), m_fmAccessMode(1U), m_fmCOSInvert(false), +m_fmNoiseSquelch(false), +m_fmSquelchHighThreshold(30U), +m_fmSquelchLowThreshold(20U), m_fmRFAudioBoost(1U), m_fmMaxDevLevel(90.0F), m_fmExtAudioBoost(1U), @@ -808,6 +811,14 @@ bool CConf::read() m_fmAccessMode = ::atoi(value); else if (::strcmp(key, "COSInvert") == 0) m_fmCOSInvert = ::atoi(value) == 1; + else if (::strcmp(key, "NoiseSquelch") == 0) + m_fmNoiseSquelch = ::atoi(value) == 1; + else if (::strcmp(key, "SquelchThreshold") == 0) + m_fmSquelchHighThreshold = m_fmSquelchLowThreshold = (unsigned int)::atoi(value); + else if (::strcmp(key, "SquelchHighThreshold") == 0) + m_fmSquelchHighThreshold = (unsigned int)::atoi(value); + else if (::strcmp(key, "SquelchLowThreshold") == 0) + m_fmSquelchLowThreshold = (unsigned int)::atoi(value); else if (::strcmp(key, "RFAudioBoost") == 0) m_fmRFAudioBoost = (unsigned int)::atoi(value); else if (::strcmp(key, "MaxDevLevel") == 0) @@ -1757,6 +1768,21 @@ bool CConf::getFMCOSInvert() const return m_fmCOSInvert; } +bool CConf::getFMNoiseSquelch() const +{ + return m_fmNoiseSquelch; +} + +unsigned int CConf::getFMSquelchHighThreshold() const +{ + return m_fmSquelchHighThreshold; +} + +unsigned int CConf::getFMSquelchLowThreshold() const +{ + return m_fmSquelchLowThreshold; +} + unsigned int CConf::getFMRFAudioBoost() const { return m_fmRFAudioBoost; diff --git a/Conf.h b/Conf.h index 01ef9f5..f80ad87 100644 --- a/Conf.h +++ b/Conf.h @@ -211,6 +211,9 @@ public: unsigned int getFMHangTime() const; unsigned int getFMAccessMode() const; bool getFMCOSInvert() const; + bool getFMNoiseSquelch() const; + unsigned int getFMSquelchHighThreshold() const; + unsigned int getFMSquelchLowThreshold() const; unsigned int getFMRFAudioBoost() const; float getFMMaxDevLevel() const; unsigned int getFMExtAudioBoost() const; @@ -502,6 +505,9 @@ private: unsigned int m_fmHangTime; unsigned int m_fmAccessMode; bool m_fmCOSInvert; + bool m_fmNoiseSquelch; + unsigned int m_fmSquelchHighThreshold; + unsigned int m_fmSquelchLowThreshold; unsigned int m_fmRFAudioBoost; float m_fmMaxDevLevel; unsigned int m_fmExtAudioBoost; diff --git a/MMDVM.ini b/MMDVM.ini index 6c35909..2b5d8f1 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -174,6 +174,10 @@ KerchunkTime=0 HangTime=7 AccessMode=1 COSInvert=0 +NoiseSquelch=0 +SquelchThreshold=30 +# SquelchHighThreshold=30 +# SquelchLowThreshold=20 RFAudioBoost=1 MaxDevLevel=90 ExtAudioBoost=1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 7066ad1..2c712a6 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1356,35 +1356,38 @@ bool CMMDVMHost::createModem() m_modem->setAX25Params(rxTwist, ax25TXDelay, ax25SlotTime, ax25PPersist); if (m_fmEnabled) { - std::string callsign = m_conf.getFMCallsign(); - unsigned int callsignSpeed = m_conf.getFMCallsignSpeed(); - unsigned int callsignFrequency = m_conf.getFMCallsignFrequency(); - unsigned int callsignTime = m_conf.getFMCallsignTime(); - unsigned int callsignHoldoff = m_conf.getFMCallsignHoldoff(); - float callsignHighLevel = m_conf.getFMCallsignHighLevel(); - float callsignLowLevel = m_conf.getFMCallsignLowLevel(); - bool callsignAtStart = m_conf.getFMCallsignAtStart(); - bool callsignAtEnd = m_conf.getFMCallsignAtEnd(); - bool callsignAtLatch = m_conf.getFMCallsignAtLatch(); - std::string rfAck = m_conf.getFMRFAck(); - unsigned int ackSpeed = m_conf.getFMAckSpeed(); - unsigned int ackFrequency = m_conf.getFMAckFrequency(); - unsigned int ackMinTime = m_conf.getFMAckMinTime(); - unsigned int ackDelay = m_conf.getFMAckDelay(); - float ackLevel = m_conf.getFMAckLevel(); - unsigned int timeout = m_conf.getFMTimeout(); - float timeoutLevel = m_conf.getFMTimeoutLevel(); - float ctcssFrequency = m_conf.getFMCTCSSFrequency(); - unsigned int ctcssHighThreshold = m_conf.getFMCTCSSHighThreshold(); - unsigned int ctcssLowThreshold = m_conf.getFMCTCSSLowThreshold(); - float ctcssLevel = m_conf.getFMCTCSSLevel(); - unsigned int kerchunkTime = m_conf.getFMKerchunkTime(); - unsigned int hangTime = m_conf.getFMHangTime(); - unsigned int accessMode = m_conf.getFMAccessMode(); - bool cosInvert = m_conf.getFMCOSInvert(); - unsigned int rfAudioBoost = m_conf.getFMRFAudioBoost(); - float maxDevLevel = m_conf.getFMMaxDevLevel(); - unsigned int modeHangTime = m_conf.getFMModeHang(); + std::string callsign = m_conf.getFMCallsign(); + unsigned int callsignSpeed = m_conf.getFMCallsignSpeed(); + unsigned int callsignFrequency = m_conf.getFMCallsignFrequency(); + unsigned int callsignTime = m_conf.getFMCallsignTime(); + unsigned int callsignHoldoff = m_conf.getFMCallsignHoldoff(); + float callsignHighLevel = m_conf.getFMCallsignHighLevel(); + float callsignLowLevel = m_conf.getFMCallsignLowLevel(); + bool callsignAtStart = m_conf.getFMCallsignAtStart(); + bool callsignAtEnd = m_conf.getFMCallsignAtEnd(); + bool callsignAtLatch = m_conf.getFMCallsignAtLatch(); + std::string rfAck = m_conf.getFMRFAck(); + unsigned int ackSpeed = m_conf.getFMAckSpeed(); + unsigned int ackFrequency = m_conf.getFMAckFrequency(); + unsigned int ackMinTime = m_conf.getFMAckMinTime(); + unsigned int ackDelay = m_conf.getFMAckDelay(); + float ackLevel = m_conf.getFMAckLevel(); + unsigned int timeout = m_conf.getFMTimeout(); + float timeoutLevel = m_conf.getFMTimeoutLevel(); + float ctcssFrequency = m_conf.getFMCTCSSFrequency(); + unsigned int ctcssHighThreshold = m_conf.getFMCTCSSHighThreshold(); + unsigned int ctcssLowThreshold = m_conf.getFMCTCSSLowThreshold(); + float ctcssLevel = m_conf.getFMCTCSSLevel(); + unsigned int kerchunkTime = m_conf.getFMKerchunkTime(); + unsigned int hangTime = m_conf.getFMHangTime(); + unsigned int accessMode = m_conf.getFMAccessMode(); + bool cosInvert = m_conf.getFMCOSInvert(); + bool noiseSquelch = m_conf.getFMNoiseSquelch(); + unsigned int squelchHighThreshold = m_conf.getFMSquelchHighThreshold(); + unsigned int squelchLowThreshold = m_conf.getFMSquelchLowThreshold(); + unsigned int rfAudioBoost = m_conf.getFMRFAudioBoost(); + float maxDevLevel = m_conf.getFMMaxDevLevel(); + unsigned int modeHangTime = m_conf.getFMModeHang(); LogInfo("FM Parameters"); LogInfo(" Callsign: %s", callsign.c_str()); @@ -1413,13 +1416,20 @@ bool CMMDVMHost::createModem() LogInfo(" Hang Time: %us", hangTime); LogInfo(" Access Mode: %u", accessMode); LogInfo(" COS Invert: %s", cosInvert ? "yes" : "no"); + + LogInfo(" Noise Squelch: %s", noiseSquelch ? "yes" : "no"); + if (noiseSquelch) { + LogInfo(" Squelch High Threshold: %u", squelchHighThreshold); + LogInfo(" Squelch Low Threshold: %u", squelchLowThreshold); + } + LogInfo(" RF Audio Boost: x%u", rfAudioBoost); LogInfo(" Max. Deviation Level: %.1f%%", maxDevLevel); LogInfo(" Mode Hang: %us", modeHangTime); m_modem->setFMCallsignParams(callsign, callsignSpeed, callsignFrequency, callsignTime, callsignHoldoff, callsignHighLevel, callsignLowLevel, callsignAtStart, callsignAtEnd, callsignAtLatch); m_modem->setFMAckParams(rfAck, ackSpeed, ackFrequency, ackMinTime, ackDelay, ackLevel); - m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, accessMode, cosInvert, rfAudioBoost, maxDevLevel); + m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, accessMode, cosInvert, noiseSquelch, squelchHighThreshold, squelchLowThreshold, rfAudioBoost, maxDevLevel); if (m_conf.getFMNetworkEnabled()) { std::string extAck = m_conf.getFMExtAck(); diff --git a/Modem.h b/Modem.h index 45a5860..bbddc4d 100644 --- a/Modem.h +++ b/Modem.h @@ -40,7 +40,7 @@ public: virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) = 0; virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) = 0; - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) = 0; + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool cosInvert, bool noiseSquelch, unsigned int squelchHighThreshold, unsigned int squelchLowThreshold, unsigned int rfAudioBoost, float maxDevLevel) = 0; virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost) = 0; virtual bool open() = 0; diff --git a/NullModem.h b/NullModem.h index 41930c8..a99424a 100644 --- a/NullModem.h +++ b/NullModem.h @@ -42,7 +42,7 @@ public: virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) {}; virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) {}; - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) {}; + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool cosInvert, bool noiseSquelch, unsigned int squelchHighThreshold, unsigned int squelchLowThreshold, unsigned int rfAudioBoost, float maxDevLevel) {}; virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost) {}; virtual bool open(); diff --git a/SerialModem.cpp b/SerialModem.cpp index 0282850..cc0416d 100644 --- a/SerialModem.cpp +++ b/SerialModem.cpp @@ -224,6 +224,9 @@ m_fmKerchunkTime(0U), m_fmHangTime(5U), m_fmAccessMode(1U), m_fmCOSInvert(false), +m_fmNoiseSquelch(false), +m_fmSquelchHighThreshold(30U), +m_fmSquelchLowThreshold(20U), m_fmRFAudioBoost(1U), m_fmExtAudioBoost(1U), m_fmMaxDevLevel(90.0F), @@ -2186,7 +2189,7 @@ void CSerialModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpee m_fmAckLevel = ackLevel; } -void CSerialModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) +void CSerialModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool cosInvert, bool noiseSquelch, unsigned int squelchHighThreshold, unsigned int squelchLowThreshold, unsigned int rfAudioBoost, float maxDevLevel) { m_fmTimeout = timeout; m_fmTimeoutLevel = timeoutLevel; @@ -2203,6 +2206,10 @@ void CSerialModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, flo m_fmAccessMode = accessMode; m_fmCOSInvert = cosInvert; + m_fmNoiseSquelch = noiseSquelch; + m_fmSquelchHighThreshold = squelchHighThreshold; + m_fmSquelchLowThreshold = squelchLowThreshold; + m_fmRFAudioBoost = rfAudioBoost; m_fmMaxDevLevel = maxDevLevel; } @@ -2334,7 +2341,7 @@ bool CSerialModem::setFMMiscParams() unsigned char buffer[20U]; buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 15U; + buffer[1U] = 17U; buffer[2U] = MMDVM_FM_PARAMS3; buffer[3U] = m_fmTimeout / 5U; @@ -2348,7 +2355,9 @@ bool CSerialModem::setFMMiscParams() buffer[9U] = m_fmKerchunkTime; buffer[10U] = m_fmHangTime; - buffer[11U] = m_fmAccessMode; + buffer[11U] = m_fmAccessMode & 0x0FU; + if (m_fmNoiseSquelch) + buffer[11U] |= 0x40U; if (m_fmCOSInvert) buffer[11U] |= 0x80U; @@ -2358,10 +2367,13 @@ bool CSerialModem::setFMMiscParams() buffer[14U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); - // CUtils::dump(1U, "Written", buffer, 15U); + buffer[15U] = m_fmSquelchHighThreshold; + buffer[16U] = m_fmSquelchLowThreshold; - int ret = m_serial->write(buffer, 15U); - if (ret != 15) + // CUtils::dump(1U, "Written", buffer, 17U); + + int ret = m_serial->write(buffer, 17U); + if (ret != 17) return false; unsigned int count = 0U; diff --git a/SerialModem.h b/SerialModem.h index 365e311..223774b 100644 --- a/SerialModem.h +++ b/SerialModem.h @@ -60,7 +60,7 @@ public: virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool cosInvert, bool noiseSquelch, unsigned int squelchHighThreshold, unsigned int squelchLowThreshold, unsigned int rfAudioBoost, float maxDevLevel); virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost); virtual bool open(); @@ -247,6 +247,9 @@ private: unsigned int m_fmHangTime; unsigned int m_fmAccessMode; bool m_fmCOSInvert; + bool m_fmNoiseSquelch; + unsigned int m_fmSquelchHighThreshold; + unsigned int m_fmSquelchLowThreshold; unsigned int m_fmRFAudioBoost; unsigned int m_fmExtAudioBoost; float m_fmMaxDevLevel; diff --git a/Version.h b/Version.h index d5b3f85..342e069 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200727"; +const char* VERSION = "20200728"; #endif From 5a3c61644c9091b580dee6454c041a73155ee127 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 6 Sep 2020 14:49:52 +0100 Subject: [PATCH 115/115] Fix compilation. --- FMNetwork.cpp | 12 +++++++++--- Makefile | 6 +++--- Makefile.Pi | 2 +- Makefile.Pi.Adafruit | 2 +- Makefile.Pi.HD44780 | 2 +- Makefile.Pi.OLED | 2 +- Makefile.Pi.PCF8574 | 2 +- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 590a793..bc394c2 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -30,7 +30,7 @@ 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) : m_socket(localAddress, localPort), m_addr(), -m_addrLen(), +m_addrLen(0U), m_sampleRate(sampleRate), m_debug(debug), m_enabled(false), @@ -41,7 +41,8 @@ m_pollTimer(1000U, 5U) assert(!gatewayAddress.empty()); assert(sampleRate > 0U); - CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen); + if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) + m_addrLen = 0U; int error; m_incoming = ::src_new(SRC_SINC_FASTEST, 1, &error); @@ -59,11 +60,16 @@ CFMNetwork::~CFMNetwork() bool CFMNetwork::open() { + if (m_addrLen == 0U) { + LogError("Unable to resolve the address of the FM Gateway"); + return false; + } + LogMessage("Opening FM network connection"); m_pollTimer.start(); - return m_socket.open(); + return m_socket.open(m_addr); } bool CFMNetwork::writeData(float* data, unsigned int nSamples) diff --git a/Makefile b/Makefile index 6582ae6..adf0143 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ CC = cc CXX = c++ -CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -LIBS = -lpthread -LDFLAGS = -g +CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -I/usr/local/include +LIBS = -lpthread -lsamplerate -lutil +LDFLAGS = -g -L/usr/local/lib 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 DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ diff --git a/Makefile.Pi b/Makefile.Pi index 4a757ad..055d450 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -3,7 +3,7 @@ CC = cc CXX = c++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DRASPBERRY_PI -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread +LIBS = -lwiringPi -lwiringPiDev -lpthread -lsamplerate -lutil LDFLAGS = -g -L/usr/local/lib 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 \ diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 19ddbae..5301a2a 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -4,7 +4,7 @@ CC = cc CXX = c++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread +LIBS = -lwiringPi -lwiringPiDev -lpthread -lsamplerate -lutil LDFLAGS = -g -L/usr/local/lib 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 \ diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index f05b28d..906fc66 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -3,7 +3,7 @@ CC = cc CXX = c++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DHD44780 -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread +LIBS = -lwiringPi -lwiringPiDev -lpthread -lsamplerate -lutil LDFLAGS = -g -L/usr/local/lib 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 \ diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index a4a2e66..45b22ef 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -3,7 +3,7 @@ CC = cc CXX = c++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DOLED -I/usr/local/include -LIBS = -lArduiPi_OLED -lwiringPi -lpthread +LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lsamplerate -lutil LDFLAGS = -g -L/usr/local/lib 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 \ diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 7d8afa5..13291e4 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -4,7 +4,7 @@ CC = cc CXX = c++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread +LIBS = -lwiringPi -lwiringPiDev -lpthread -lsamplerate -lutil LDFLAGS = -g -L/usr/local/lib 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 \