From bc791577e79b27ea57ff775133233b4d7e3ebf5e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 16:08:58 +0100 Subject: [PATCH 01/54] 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 02/54] 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 03/54] 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 04/54] 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 05/54] 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 06/54] 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 07/54] 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 08/54] 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 09/54] 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 10/54] 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 11/54] 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 12/54] 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 13/54] 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 14/54] 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 15/54] 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 16/54] 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 17/54] 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 18/54] 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 19/54] 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 20/54] 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 21/54] 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 22/54] 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 23/54] 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 24/54] 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 25/54] 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 26/54] 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 27/54] 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 28/54] 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 29/54] 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 30/54] 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 31/54] 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 32/54] 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 33/54] 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 34/54] 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 35/54] 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 36/54] 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 37/54] 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 38/54] 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 39/54] 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 40/54] 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 41/54] 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 42/54] 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 43/54] 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 44/54] 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 45/54] 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 46/54] 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 47/54] 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 48/54] 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 49/54] 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 50/54] 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 51/54] 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 52/54] 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 53/54] 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 f936a6c5b640514954ca06cd12ec93f3e80c78ca Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 20 Jun 2020 20:44:02 +0100 Subject: [PATCH 54/54] 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