diff --git a/CASTInfo.cpp b/CASTInfo.cpp index cce34d8..4821251 100644 --- a/CASTInfo.cpp +++ b/CASTInfo.cpp @@ -21,7 +21,7 @@ static bool networkInfoInitialized = false; static unsigned char passCounter = 0; -CCASTInfo::CCASTInfo(CModem* modem) : +CCASTInfo::CCASTInfo(IModem* modem) : CDisplay(), m_modem(modem), m_ipaddress() diff --git a/CASTInfo.h b/CASTInfo.h index 9254995..4651cf0 100644 --- a/CASTInfo.h +++ b/CASTInfo.h @@ -28,7 +28,7 @@ class CCASTInfo : public CDisplay { public: - CCASTInfo(CModem* modem); + CCASTInfo(IModem* modem); virtual ~CCASTInfo(); virtual bool open(); @@ -64,7 +64,7 @@ protected: virtual void clearCWInt(); private: - CModem* m_modem; + IModem* m_modem; std::string m_ipaddress; }; diff --git a/Conf.cpp b/Conf.cpp index fae8b95..36c8ce3 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -60,7 +60,7 @@ enum SECTION { SECTION_OLED, SECTION_LCDPROC, SECTION_LOCK_FILE, - SECTION_MOBILE_GPS, + SECTION_GPSD, SECTION_REMOTE_CONTROL }; @@ -305,9 +305,9 @@ m_lcdprocUTC(false), m_lcdprocDimOnIdle(false), m_lockFileEnabled(false), m_lockFileName(), -m_mobileGPSEnabled(false), -m_mobileGPSAddress(), -m_mobileGPSPort(0U), +m_gpsdEnabled(false), +m_gpsdAddress(), +m_gpsdPort(), m_remoteControlEnabled(false), m_remoteControlPort(0U) { @@ -395,8 +395,8 @@ bool CConf::read() 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, "[GPSD]", 6U) == 0) + section = SECTION_GPSD; else if (::strncmp(buffer, "[Remote Control]", 16U) == 0) section = SECTION_REMOTE_CONTROL; else @@ -433,12 +433,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_nxdnNetworkModeHang = m_pocsagNetworkModeHang = m_fmNetworkModeHang = - m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_fmModeHang = (unsigned int)::atoi(value); + m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = + m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = (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); + m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = (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); + m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Display") == 0) m_display = value; else if (::strcmp(key, "Daemon") == 0) @@ -1017,13 +1017,13 @@ bool CConf::read() m_lockFileEnabled = ::atoi(value) == 1; else if (::strcmp(key, "File") == 0) m_lockFileName = value; - } else if (section == SECTION_MOBILE_GPS) { + } else if (section == SECTION_GPSD) { if (::strcmp(key, "Enable") == 0) - m_mobileGPSEnabled = ::atoi(value) == 1; + m_gpsdEnabled = ::atoi(value) == 1; else if (::strcmp(key, "Address") == 0) - m_mobileGPSAddress = value; + m_gpsdAddress = value; else if (::strcmp(key, "Port") == 0) - m_mobileGPSPort = (unsigned int)::atoi(value); + m_gpsdPort = value; } else if (section == SECTION_REMOTE_CONTROL) { if (::strcmp(key, "Enable") == 0) m_remoteControlEnabled = ::atoi(value) == 1; @@ -2232,19 +2232,19 @@ std::string CConf::getLockFileName() const return m_lockFileName; } -bool CConf::getMobileGPSEnabled() const +bool CConf::getGPSDEnabled() const { - return m_mobileGPSEnabled; + return m_gpsdEnabled; } -std::string CConf::getMobileGPSAddress() const +std::string CConf::getGPSDAddress() const { - return m_mobileGPSAddress; + return m_gpsdAddress; } -unsigned int CConf::getMobileGPSPort() const +std::string CConf::getGPSDPort() const { - return m_mobileGPSPort; + return m_gpsdPort; } bool CConf::getRemoteControlEnabled() const diff --git a/Conf.h b/Conf.h index c87c730..cbae96c 100644 --- a/Conf.h +++ b/Conf.h @@ -331,10 +331,10 @@ public: bool getLockFileEnabled() const; std::string getLockFileName() const; - // The Mobile GPS section - bool getMobileGPSEnabled() const; - std::string getMobileGPSAddress() const; - unsigned int getMobileGPSPort() const; + // The GPSD section + bool getGPSDEnabled() const; + std::string getGPSDAddress() const; + std::string getGPSDPort() const; // The Remote Control section bool getRemoteControlEnabled() const; @@ -612,9 +612,9 @@ private: bool m_lockFileEnabled; std::string m_lockFileName; - bool m_mobileGPSEnabled; - std::string m_mobileGPSAddress; - unsigned int m_mobileGPSPort; + bool m_gpsdEnabled; + std::string m_gpsdAddress; + std::string m_gpsdPort; bool m_remoteControlEnabled; unsigned int m_remoteControlPort; diff --git a/DMRControl.cpp b/DMRControl.cpp index bd07082..4ec1a4c 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -21,7 +21,7 @@ #include #include -CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) : +CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, IModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) : m_colorCode(colorCode), m_modem(modem), m_network(network), diff --git a/DMRControl.h b/DMRControl.h index 4d2597e..5a8d7de 100644 --- a/DMRControl.h +++ b/DMRControl.h @@ -31,7 +31,7 @@ class CDMRControl { public: - CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm); + CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, IModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm); ~CDMRControl(); bool processWakeup(const unsigned char* data); @@ -50,7 +50,7 @@ public: private: unsigned int m_colorCode; - CModem* m_modem; + IModem* m_modem; CDMRNetwork* m_network; CDMRSlot m_slot1; CDMRSlot m_slot2; diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 1cfecab..5554328 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -37,7 +37,7 @@ unsigned int CDMRSlot::m_colorCode = 0U; bool CDMRSlot::m_embeddedLCOnly = false; bool CDMRSlot::m_dumpTAData = true; -CModem* CDMRSlot::m_modem = NULL; +IModem* CDMRSlot::m_modem = NULL; CDMRNetwork* CDMRSlot::m_network = NULL; CDisplay* CDMRSlot::m_display = NULL; bool CDMRSlot::m_duplex = true; @@ -1896,7 +1896,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data) m_queue.addData(data, len); } -void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm) +void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, IModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm) { assert(modem != NULL); assert(display != NULL); diff --git a/DMRSlot.h b/DMRSlot.h index 1e95dc2..f50596b 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,7 +62,7 @@ public: void enable(bool enabled); - static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm); + static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, IModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm); private: unsigned int m_slotNo; @@ -117,7 +117,7 @@ private: static bool m_embeddedLCOnly; static bool m_dumpTAData; - static CModem* m_modem; + static IModem* m_modem; static CDMRNetwork* m_network; static CDisplay* m_display; static bool m_duplex; diff --git a/Display.cpp b/Display.cpp index 22bc953..ce19ce5 100644 --- a/Display.cpp +++ b/Display.cpp @@ -490,7 +490,7 @@ int CDisplay::writeNXDNIntEx(const class CUserDBentry& source, bool group, unsig /* Factory method extracted from MMDVMHost.cpp - BG5HHP */ -CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) +CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, IModem* modem) { CDisplay *display = NULL; @@ -509,7 +509,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) ISerialPort* serial = NULL; if (port == "modem") - serial = new CModemSerialPort(modem); + serial = new IModemSerialPort(modem); else serial = new CSerialController(port, (type == "TFT Serial") ? 9600U : 115200U); @@ -555,7 +555,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) } if (port == "modem") { - ISerialPort* serial = new CModemSerialPort(modem); + ISerialPort* serial = new IModemSerialPort(modem); display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation()); } else if (port == "ump") { if (ump != NULL) { diff --git a/Display.h b/Display.h index 17caa41..c4937d2 100644 --- a/Display.h +++ b/Display.h @@ -21,13 +21,14 @@ #include "Timer.h" #include "UserDBentry.h" +#include "Modem.h" #include #include class CConf; -class CModem; +class IModem; class CUMP; class CDisplay @@ -81,7 +82,7 @@ public: void clock(unsigned int ms); - static CDisplay* createDisplay(const CConf& conf, CUMP* ump, CModem* modem); + static CDisplay* createDisplay(const CConf& conf, CUMP* ump, IModem* modem); protected: virtual void setIdleInt() = 0; diff --git a/GPSD.cpp b/GPSD.cpp new file mode 100644 index 0000000..c06321a --- /dev/null +++ b/GPSD.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018,2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "GPSD.h" + +#if defined(USE_GPSD) + +#include +#include +#include +#include + +CGPSD::CGPSD(const std::string& address, const std::string& port, CDMRNetwork* network) : +m_gpsdAddress(address), +m_gpsdPort(port), +m_network(network), +m_gpsdData(), +m_idTimer(1000U, 60U) +{ + assert(!address.empty()); + assert(!port.empty()); + assert(network != NULL); +} + +CGPSD::~CGPSD() +{ +} + +bool CGPSD::open() +{ + int ret = ::gps_open(m_gpsdAddress.c_str(), m_gpsdPort.c_str(), &m_gpsdData); + if (ret != 0) { + LogError("Error when opening access to gpsd - %d - %s", errno, ::gps_errstr(errno)); + return false; + } + + ::gps_stream(&m_gpsdData, WATCH_ENABLE | WATCH_JSON, NULL); + + LogMessage("Connected to GPSD"); + + m_idTimer.start(); + + return true; +} + +void CGPSD::clock(unsigned int ms) +{ + m_idTimer.clock(ms); + + if (m_idTimer.hasExpired()) { + sendReport(); + m_idTimer.start(); + } +} + +void CGPSD::close() +{ + ::gps_stream(&m_gpsdData, WATCH_DISABLE, NULL); + ::gps_close(&m_gpsdData); +} + +void CGPSD::sendReport() +{ + if (!::gps_waiting(&m_gpsdData, 0)) + return; + +#if GPSD_API_MAJOR_VERSION >= 7 + if (::gps_read(&m_gpsdData, NULL, 0) <= 0) + return; +#else + if (::gps_read(&m_gpsdData) <= 0) + return; +#endif + + if (m_gpsdData.status != STATUS_FIX) + return; + + bool latlonSet = (m_gpsdData.set & LATLON_SET) == LATLON_SET; + if (!latlonSet) + return; + + float latitude = float(m_gpsdData.fix.latitude); + float longitude = float(m_gpsdData.fix.longitude); + + m_network->writeHomePosition(latitude, longitude); +} + +#endif diff --git a/MobileGPS.h b/GPSD.h similarity index 60% rename from MobileGPS.h rename to GPSD.h index 8d69572..cef93b5 100644 --- a/MobileGPS.h +++ b/GPSD.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 by Jonathan Naylor G4KLX + * Copyright (C) 2018,2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,32 +16,22 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef MobileGPS_H -#define MobileGPS_H +#ifndef GPSD_H +#define GPSD_H + +#if defined(USE_GPSD) #include "DMRNetwork.h" -#include "UDPSocket.h" #include "Timer.h" #include -#if !defined(_WIN32) && !defined(_WIN64) -#include -#include -#include -#include -#include -#include -#include -#include -#else -#include -#endif +#include -class CMobileGPS { +class CGPSD { public: - CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network); - ~CMobileGPS(); + CGPSD(const std::string& address, const std::string& port, CDMRNetwork* network); + ~CGPSD(); bool open(); @@ -50,14 +40,15 @@ public: void close(); private: - CTimer m_idTimer; - in_addr m_address; - unsigned int m_port; - CUDPSocket m_socket; - CDMRNetwork* m_network; + std::string m_gpsdAddress; + std::string m_gpsdPort; + CDMRNetwork* m_network; + struct gps_data_t m_gpsdData; + CTimer m_idTimer; - bool pollGPS(); void sendReport(); }; #endif + +#endif diff --git a/MMDVM.ini b/MMDVM.ini index 6cb0a9c..474bcbb 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -313,10 +313,10 @@ UTC=0 Enable=0 File=/tmp/MMDVM_Active.lck -[Mobile GPS] +[GPSD] Enable=0 Address=127.0.0.1 -Port=7834 +Port=2947 [Remote Control] Enable=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index b8d94a2..93ee9f7 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -21,6 +21,8 @@ #include "NXDNIcomNetwork.h" #include "RSSIInterpolator.h" #include "SerialController.h" +#include "SerialModem.h" +#include "NullModem.h" #include "Version.h" #include "StopWatch.h" #include "Defines.h" @@ -168,7 +170,9 @@ m_id(0U), m_cwCallsign(), m_lockFileEnabled(false), m_lockFileName(), -m_mobileGPS(NULL), +#if defined(USE_GPSD) +m_gpsd(NULL), +#endif m_remoteControl(NULL), m_fixedMode(false) { @@ -512,7 +516,6 @@ int CMMDVMHost::run() else if (ovcm == DMR_OVCM_ON) LogInfo(" OVCM: on"); - switch (dmrBeacons) { case DMR_BEACONS_NETWORK: { unsigned int dmrBeaconDuration = m_conf.getDMRBeaconDuration(); @@ -1100,8 +1103,10 @@ int CMMDVMHost::run() if (m_fmNetwork != NULL) m_fmNetwork->clock(ms); - if (m_mobileGPS != NULL) - m_mobileGPS->clock(ms); +#if defined(USE_GPSD) + if (m_gpsd != NULL) + m_gpsd->clock(ms); +#endif m_cwIdTimer.clock(ms); if (m_cwIdTimer.isRunning() && m_cwIdTimer.hasExpired()) { @@ -1178,10 +1183,12 @@ int CMMDVMHost::run() m_display->close(); delete m_display; - if (m_mobileGPS != NULL) { - m_mobileGPS->close(); - delete m_mobileGPS; +#if defined(USE_GPSD) + if (m_gpsd != NULL) { + m_gpsd->close(); + delete m_gpsd; } +#endif if (m_ump != NULL) { m_ump->close(); @@ -1326,7 +1333,10 @@ bool CMMDVMHost::createModem() LogInfo(" AX.25 TX Level: %.1f%%", ax25TXLevel); LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset); - m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); + if (port == "NullModem") + m_modem = new CNullModem; + else + m_modem = new CSerialModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); m_modem->setSerialParams(protocol, address, speed); m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled, m_ax25Enabled); m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel); @@ -1520,23 +1530,25 @@ bool CMMDVMHost::createDMRNetwork() return false; } - bool mobileGPSEnabled = m_conf.getMobileGPSEnabled(); - if (mobileGPSEnabled) { - std::string mobileGPSAddress = m_conf.getMobileGPSAddress(); - unsigned int mobileGPSPort = m_conf.getMobileGPSPort(); +#if defined(USE_GPSD) + bool gpsdEnabled = m_conf.getGPSDEnabled(); + if (gpsdEnabled) { + std::string gpsdAddress = m_conf.getGPSDAddress(); + std::string gpsdPort = m_conf.getGPSDPort(); - LogInfo("Mobile GPS Parameters"); - LogInfo(" Address: %s", mobileGPSAddress.c_str()); - LogInfo(" Port: %u", mobileGPSPort); + LogInfo("GPSD Parameters"); + LogInfo(" Address: %s", gpsdAddress.c_str()); + LogInfo(" Port: %s", gpsdPort.c_str()); - m_mobileGPS = new CMobileGPS(address, port, m_dmrNetwork); + m_gpsd = new CGPSD(gpsdAddress, gpsdPort, m_dmrNetwork); - ret = m_mobileGPS->open(); + ret = m_gpsd->open(); if (!ret) { - delete m_mobileGPS; - m_mobileGPS = NULL; + delete m_gpsd; + m_gpsd = NULL; } } +#endif m_dmrNetwork->enable(true); diff --git a/MMDVMHost.h b/MMDVMHost.h index c44ed5f..9cb28cb 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -37,12 +37,12 @@ #include "DMRNetwork.h" #include "FMNetwork.h" #include "DMRLookup.h" -#include "MobileGPS.h" #include "FMControl.h" #include "Display.h" #include "Timer.h" #include "Modem.h" #include "Conf.h" +#include "GPSD.h" #include "UMP.h" #include @@ -59,7 +59,7 @@ public: private: CConf m_conf; - CModem* m_modem; + IModem* m_modem; CDStarControl* m_dstar; CDMRControl* m_dmr; CYSFControl* m_ysf; @@ -113,7 +113,9 @@ private: std::string m_cwCallsign; bool m_lockFileEnabled; std::string m_lockFileName; - CMobileGPS* m_mobileGPS; +#if defined(USE_GPSD) + CGPSD* m_gpsd; +#endif CRemoteControl* m_remoteControl; bool m_fixedMode; diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 7f64db6..96f4c96 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -188,13 +188,13 @@ + - @@ -236,6 +236,7 @@ + @@ -291,12 +292,12 @@ + - @@ -334,6 +335,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 00ed473..0757e74 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -275,9 +275,6 @@ Header Files - - Header Files - Header Files @@ -323,6 +320,12 @@ Header Files + + Header Files + + + Header Files + @@ -562,9 +565,6 @@ Source Files - - Source Files - Source Files @@ -607,5 +607,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index bd07c05..91fcf2d 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,27 @@ CC = cc CXX = c++ + +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lpthread -lutil + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread +#LIBS = -lpthread -lgps -lutil + LDFLAGS = -g -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ - NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o \ - P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o \ + DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o \ + Golay2087.o Golay24128.o GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o \ + NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ + NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi b/Makefile.Pi index 2e7fb1c..62e27aa 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -2,19 +2,26 @@ CC = gcc CXX = g++ +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DRASPBERRY_PI -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread +LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DRASPBERRY_PI -I/usr/local/include +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil + LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ - NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o \ - P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o \ + DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o \ + Golay2087.o Golay24128.o GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o \ + NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ + NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 1f274ef..2915c69 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -3,19 +3,26 @@ CC = gcc CXX = g++ +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread +LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil + LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ - NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o \ + DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o \ + Golay2087.o Golay24128.o GPSD.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o \ + NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ + NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 3adaeab..c00e58f 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -2,19 +2,27 @@ CC = gcc CXX = g++ + +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread +LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -I/usr/local/include +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil + LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ - NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o \ + DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o \ + Golay2087.o Golay24128.o GPSD.o Hamming.o HD44780.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o \ + NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ + NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 79d1f6e..41e837e 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -2,19 +2,27 @@ CC = gcc CXX = g++ + +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DOLED -I/usr/local/include -LIBS = -lArduiPi_OLED -lwiringPi -lpthread +LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lutil + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPS -std=c++0x -pthread -DOLED -I/usr/local/include +#LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lgps -lutil + LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \ - NXDNLayer3.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \ - P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o \ + DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o \ + Golay2087.o Golay24128.o GPSD.o Hamming.o I2CController.o IIRDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o \ + NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ + NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 81871cc..37de0b1 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -3,19 +3,27 @@ CC = gcc CXX = g++ + +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include -LIBS = -lwiringPi -lwiringPiDev -lpthread +LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps -lutil + LDFLAGS = -g -L/usr/local/lib -OBJECTS = AX25Control.o AX25Network.o \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \ - ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ - NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o +OBJECTS = AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o \ + DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o \ + Golay2087.o Golay24128.o GPSD.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o Modem.o \ + ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o \ + NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ + NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialModem.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ + UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/MobileGPS.cpp b/MobileGPS.cpp deleted file mode 100644 index 27721bd..0000000 --- a/MobileGPS.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2018 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 "MobileGPS.h" - -#include -#include -#include -#include - -CMobileGPS::CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network) : -m_idTimer(1000U, 60U), -m_address(), -m_port(port), -m_socket(), -m_network(network) -{ - assert(!address.empty()); - assert(port > 0U); - assert(network != NULL); - - m_address = CUDPSocket::lookup(address); -} - -CMobileGPS::~CMobileGPS() -{ -} - -bool CMobileGPS::open() -{ - bool ret = m_socket.open(); - if (!ret) - return false; - - m_idTimer.start(); - - return true; -} - -void CMobileGPS::clock(unsigned int ms) -{ - m_idTimer.clock(ms); - - if (m_idTimer.hasExpired()) { - pollGPS(); - m_idTimer.start(); - } - - sendReport(); -} - -void CMobileGPS::close() -{ - m_socket.close(); -} - -bool CMobileGPS::pollGPS() -{ - return m_socket.write((unsigned char*)"MMDVMHost", 9U, m_address, m_port); -} - -void CMobileGPS::sendReport() -{ - // Grab GPS data if it's available - unsigned char buffer[200U]; - in_addr address; - unsigned int port; - int ret = m_socket.read(buffer, 200U, address, port); - if (ret <= 0) - return; - - buffer[ret] = '\0'; - - // Parse the GPS data - char* pLatitude = ::strtok((char*)buffer, ",\n"); // Latitude - char* pLongitude = ::strtok(NULL, ",\n"); // Longitude - - if (pLatitude == NULL || pLongitude == NULL) - return; - - float latitude = float(::atof(pLatitude)); - float longitude = float(::atof(pLongitude)); - - m_network->writeHomePosition(latitude, longitude); -} - diff --git a/Modem.cpp b/Modem.cpp index 9591b0f..75c65dc 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,2457 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "SerialController.h" -#if defined(__linux__) -#include "I2CController.h" -#endif -#include "DStarDefines.h" -#include "DMRDefines.h" -#include "YSFDefines.h" -#include "P25Defines.h" -#include "NXDNDefines.h" -#include "AX25Defines.h" -#include "POCSAGDefines.h" -#include "Thread.h" #include "Modem.h" -#include "NullModem.h" -#include "Utils.h" -#include "Log.h" -#include -#include -#include -#include -#include - -#if defined(_WIN32) || defined(_WIN64) -#include -#else -#include -#endif - -const unsigned char MMDVM_FRAME_START = 0xE0U; - -const unsigned char MMDVM_GET_VERSION = 0x00U; -const unsigned char MMDVM_GET_STATUS = 0x01U; -const unsigned char MMDVM_SET_CONFIG = 0x02U; -const unsigned char MMDVM_SET_MODE = 0x03U; -const unsigned char MMDVM_SET_FREQ = 0x04U; - -const unsigned char MMDVM_SEND_CWID = 0x0AU; - -const unsigned char MMDVM_DSTAR_HEADER = 0x10U; -const unsigned char MMDVM_DSTAR_DATA = 0x11U; -const unsigned char MMDVM_DSTAR_LOST = 0x12U; -const unsigned char MMDVM_DSTAR_EOT = 0x13U; - -const unsigned char MMDVM_DMR_DATA1 = 0x18U; -const unsigned char MMDVM_DMR_LOST1 = 0x19U; -const unsigned char MMDVM_DMR_DATA2 = 0x1AU; -const unsigned char MMDVM_DMR_LOST2 = 0x1BU; -const unsigned char MMDVM_DMR_SHORTLC = 0x1CU; -const unsigned char MMDVM_DMR_START = 0x1DU; -const unsigned char MMDVM_DMR_ABORT = 0x1EU; - -const unsigned char MMDVM_YSF_DATA = 0x20U; -const unsigned char MMDVM_YSF_LOST = 0x21U; - -const unsigned char MMDVM_P25_HDR = 0x30U; -const unsigned char MMDVM_P25_LDU = 0x31U; -const unsigned char MMDVM_P25_LOST = 0x32U; - -const unsigned char MMDVM_NXDN_DATA = 0x40U; -const unsigned char MMDVM_NXDN_LOST = 0x41U; - -const unsigned char MMDVM_POCSAG_DATA = 0x50U; - -const unsigned char MMDVM_AX25_DATA = 0x55U; - -const unsigned char MMDVM_FM_PARAMS1 = 0x60U; -const unsigned char MMDVM_FM_PARAMS2 = 0x61U; -const unsigned char MMDVM_FM_PARAMS3 = 0x62U; -const unsigned char MMDVM_FM_PARAMS4 = 0x63U; -const unsigned char MMDVM_FM_DATA = 0x65U; -const unsigned char MMDVM_FM_CONTROL = 0x66U; -const unsigned char MMDVM_FM_EOT = 0x67U; - -const unsigned char MMDVM_ACK = 0x70U; -const unsigned char MMDVM_NAK = 0x7FU; - -const unsigned char MMDVM_SERIAL = 0x80U; - -const unsigned char MMDVM_TRANSPARENT = 0x90U; -const unsigned char MMDVM_QSO_INFO = 0x91U; - -const unsigned char MMDVM_DEBUG1 = 0xF1U; -const unsigned char MMDVM_DEBUG2 = 0xF2U; -const unsigned char MMDVM_DEBUG3 = 0xF3U; -const unsigned char MMDVM_DEBUG4 = 0xF4U; -const unsigned char MMDVM_DEBUG5 = 0xF5U; - -const unsigned int MAX_RESPONSES = 30U; - -const unsigned int BUFFER_LENGTH = 2000U; - - -CModem::CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug) : -m_port(port), -m_dmrColorCode(0U), -m_ysfLoDev(false), -m_ysfTXHang(4U), -m_p25TXHang(5U), -m_nxdnTXHang(5U), -m_duplex(duplex), -m_rxInvert(rxInvert), -m_txInvert(txInvert), -m_pttInvert(pttInvert), -m_txDelay(txDelay), -m_dmrDelay(dmrDelay), -m_rxLevel(0.0F), -m_cwIdTXLevel(0.0F), -m_dstarTXLevel(0.0F), -m_dmrTXLevel(0.0F), -m_ysfTXLevel(0.0F), -m_p25TXLevel(0.0F), -m_nxdnTXLevel(0.0F), -m_pocsagTXLevel(0.0F), -m_fmTXLevel(0.0F), -m_ax25TXLevel(0.0F), -m_rfLevel(0.0F), -m_trace(trace), -m_debug(debug), -m_rxFrequency(0U), -m_txFrequency(0U), -m_pocsagFrequency(0U), -m_dstarEnabled(false), -m_dmrEnabled(false), -m_ysfEnabled(false), -m_p25Enabled(false), -m_nxdnEnabled(false), -m_pocsagEnabled(false), -m_fmEnabled(false), -m_ax25Enabled(false), -m_rxDCOffset(0), -m_txDCOffset(0), -m_serial(NULL), -m_buffer(NULL), -m_length(0U), -m_offset(0U), -m_state(SS_START), -m_type(0U), -m_rxDStarData(1000U, "Modem RX D-Star"), -m_txDStarData(1000U, "Modem TX D-Star"), -m_rxDMRData1(1000U, "Modem RX DMR1"), -m_rxDMRData2(1000U, "Modem RX DMR2"), -m_txDMRData1(1000U, "Modem TX DMR1"), -m_txDMRData2(1000U, "Modem TX DMR2"), -m_rxYSFData(1000U, "Modem RX YSF"), -m_txYSFData(1000U, "Modem TX YSF"), -m_rxP25Data(1000U, "Modem RX P25"), -m_txP25Data(1000U, "Modem TX P25"), -m_rxNXDNData(1000U, "Modem RX NXDN"), -m_txNXDNData(1000U, "Modem TX NXDN"), -m_txPOCSAGData(1000U, "Modem TX POCSAG"), -m_rxFMData(5000U, "Modem RX FM"), -m_txFMData(5000U, "Modem TX FM"), -m_rxAX25Data(1000U, "Modem RX AX.25"), -m_txAX25Data(1000U, "Modem TX AX.25"), -m_rxTransparentData(1000U, "Modem RX Transparent"), -m_txTransparentData(1000U, "Modem TX Transparent"), -m_sendTransparentDataFrameType(0U), -m_statusTimer(1000U, 0U, 250U), -m_inactivityTimer(1000U, 2U), -m_playoutTimer(1000U, 0U, 10U), -m_dstarSpace(0U), -m_dmrSpace1(0U), -m_dmrSpace2(0U), -m_ysfSpace(0U), -m_p25Space(0U), -m_nxdnSpace(0U), -m_pocsagSpace(0U), -m_fmSpace(0U), -m_ax25Space(0U), -m_tx(false), -m_cd(false), -m_lockout(false), -m_error(false), -m_mode(MODE_IDLE), -m_hwType(HWT_UNKNOWN), -m_ax25RXTwist(0), -m_ax25TXDelay(300U), -m_fmCallsign(), -m_fmCallsignSpeed(20U), -m_fmCallsignFrequency(1000U), -m_fmCallsignTime(600U), -m_fmCallsignHoldoff(0U), -m_fmCallsignHighLevel(35.0F), -m_fmCallsignLowLevel(15.0F), -m_fmCallsignAtStart(true), -m_fmCallsignAtEnd(true), -m_fmCallsignAtLatch(true), -m_fmRfAck("K"), -m_fmExtAck("N"), -m_fmAckSpeed(20U), -m_fmAckFrequency(1750U), -m_fmAckMinTime(4U), -m_fmAckDelay(1000U), -m_fmAckLevel(80.0F), -m_fmTimeout(120U), -m_fmTimeoutLevel(80.0F), -m_fmCtcssFrequency(88.4F), -m_fmCtcssHighThreshold(30U), -m_fmCtcssLowThreshold(20U), -m_fmCtcssLevel(10.0F), -m_fmKerchunkTime(0U), -m_fmKerchunkTX(true), -m_fmHangTime(5U), -m_fmUseCOS(true), -m_fmCOSInvert(false), -m_fmRFAudioBoost(1U), -m_fmExtAudioBoost(1U), -m_fmMaxDevLevel(90.0F), -m_fmExtEnable(false) -{ - m_buffer = new unsigned char[BUFFER_LENGTH]; - - assert(!port.empty()); -} - -CModem::~CModem() -{ - delete m_serial; - delete[] m_buffer; -} - -void CModem::setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) -{ - // Create the serial controller instance according the protocol specified in conf. -#if defined(__linux__) - if (protocol == "i2c") - m_serial = new CI2CController(m_port, address); - else -#endif - m_serial = new CSerialController(m_port, speed, true); -} - -void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) -{ - m_rxFrequency = rxFrequency + rxOffset; - m_txFrequency = txFrequency + txOffset; - m_txDCOffset = txDCOffset; - m_rxDCOffset = rxDCOffset; - m_rfLevel = rfLevel; - m_pocsagFrequency = pocsagFrequency + txOffset; -} - -void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) -{ - m_dstarEnabled = dstarEnabled; - m_dmrEnabled = dmrEnabled; - m_ysfEnabled = ysfEnabled; - m_p25Enabled = p25Enabled; - m_nxdnEnabled = nxdnEnabled; - m_pocsagEnabled = pocsagEnabled; - m_fmEnabled = fmEnabled; - m_ax25Enabled = ax25Enabled; -} - -void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel, float ax25TXLevel) -{ - m_rxLevel = rxLevel; - m_cwIdTXLevel = cwIdTXLevel; - m_dstarTXLevel = dstarTXLevel; - m_dmrTXLevel = dmrTXLevel; - m_ysfTXLevel = ysfTXLevel; - m_p25TXLevel = p25TXLevel; - m_nxdnTXLevel = nxdnTXLevel; - m_pocsagTXLevel = pocsagTXLevel; - m_fmTXLevel = fmTXLevel; - m_ax25TXLevel = ax25TXLevel; -} - -void CModem::setDMRParams(unsigned int colorCode) -{ - assert(colorCode < 16U); - - m_dmrColorCode = colorCode; -} - -void CModem::setYSFParams(bool loDev, unsigned int txHang) -{ - m_ysfLoDev = loDev; - m_ysfTXHang = txHang; -} - -void CModem::setP25Params(unsigned int txHang) -{ - m_p25TXHang = txHang; -} - -void CModem::setNXDNParams(unsigned int txHang) -{ - m_nxdnTXHang = txHang; -} - -void CModem::setAX25Params(int rxTwist, unsigned int txDelay) -{ - m_ax25RXTwist = rxTwist; - m_ax25TXDelay = txDelay; -} - -void CModem::setTransparentDataParams(unsigned int sendFrameType) -{ - m_sendTransparentDataFrameType = sendFrameType; -} - -bool CModem::open() -{ - ::LogMessage("Opening the MMDVM"); - - bool ret = m_serial->open(); - if (!ret) - return false; - - ret = readVersion(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } else { - /* Stopping the inactivity timer here when a firmware version has been - successfuly read prevents the death spiral of "no reply from modem..." */ - m_inactivityTimer.stop(); - } - - ret = setFrequency(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - ret = setConfig(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - if (m_fmEnabled && m_duplex) { - ret = setFMCallsignParams(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - ret = setFMAckParams(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - ret = setFMMiscParams(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - - if (m_fmExtEnable) { - ret = setFMExtParams(); - if (!ret) { - m_serial->close(); - delete m_serial; - m_serial = NULL; - return false; - } - } - } - - m_statusTimer.start(); - - m_error = false; - m_offset = 0U; - - return true; -} - -void CModem::clock(unsigned int ms) -{ - assert(m_serial != NULL); - - // Poll the modem status every 250ms - m_statusTimer.clock(ms); - if (m_statusTimer.hasExpired()) { - readStatus(); - m_statusTimer.start(); - } - - m_inactivityTimer.clock(ms); - if (m_inactivityTimer.hasExpired()) { - LogError("No reply from the modem for some time, resetting it"); - m_error = true; - close(); - - CThread::sleep(2000U); // 2s - while (!open()) - CThread::sleep(5000U); // 5s - } - - RESP_TYPE_MMDVM type = getResponse(); - - if (type == RTM_TIMEOUT) { - // Nothing to do - } else if (type == RTM_ERROR) { - // Nothing to do - } else { - // type == RTM_OK - switch (m_type) { - case MMDVM_DSTAR_HEADER: { - if (m_trace) - CUtils::dump(1U, "RX D-Star Header", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxDStarData.addData(&data, 1U); - - data = TAG_HEADER; - m_rxDStarData.addData(&data, 1U); - - m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_DSTAR_DATA: { - if (m_trace) - CUtils::dump(1U, "RX D-Star Data", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxDStarData.addData(&data, 1U); - - data = TAG_DATA; - m_rxDStarData.addData(&data, 1U); - - m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_DSTAR_LOST: { - if (m_trace) - CUtils::dump(1U, "RX D-Star Lost", m_buffer, m_length); - - unsigned char data = 1U; - m_rxDStarData.addData(&data, 1U); - - data = TAG_LOST; - m_rxDStarData.addData(&data, 1U); - } - break; - - case MMDVM_DSTAR_EOT: { - if (m_trace) - CUtils::dump(1U, "RX D-Star EOT", m_buffer, m_length); - - unsigned char data = 1U; - m_rxDStarData.addData(&data, 1U); - - data = TAG_EOT; - m_rxDStarData.addData(&data, 1U); - } - break; - - case MMDVM_DMR_DATA1: { - if (m_trace) - CUtils::dump(1U, "RX DMR Data 1", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxDMRData1.addData(&data, 1U); - - if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) - data = TAG_EOT; - else - data = TAG_DATA; - m_rxDMRData1.addData(&data, 1U); - - m_rxDMRData1.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_DMR_DATA2: { - if (m_trace) - CUtils::dump(1U, "RX DMR Data 2", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxDMRData2.addData(&data, 1U); - - if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) - data = TAG_EOT; - else - data = TAG_DATA; - m_rxDMRData2.addData(&data, 1U); - - m_rxDMRData2.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_DMR_LOST1: { - if (m_trace) - CUtils::dump(1U, "RX DMR Lost 1", m_buffer, m_length); - - unsigned char data = 1U; - m_rxDMRData1.addData(&data, 1U); - - data = TAG_LOST; - m_rxDMRData1.addData(&data, 1U); - } - break; - - case MMDVM_DMR_LOST2: { - if (m_trace) - CUtils::dump(1U, "RX DMR Lost 2", m_buffer, m_length); - - unsigned char data = 1U; - m_rxDMRData2.addData(&data, 1U); - - data = TAG_LOST; - m_rxDMRData2.addData(&data, 1U); - } - break; - - case MMDVM_YSF_DATA: { - if (m_trace) - CUtils::dump(1U, "RX YSF Data", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxYSFData.addData(&data, 1U); - - data = TAG_DATA; - m_rxYSFData.addData(&data, 1U); - - m_rxYSFData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_YSF_LOST: { - if (m_trace) - CUtils::dump(1U, "RX YSF Lost", m_buffer, m_length); - - unsigned char data = 1U; - m_rxYSFData.addData(&data, 1U); - - data = TAG_LOST; - m_rxYSFData.addData(&data, 1U); - } - break; - - case MMDVM_P25_HDR: { - if (m_trace) - CUtils::dump(1U, "RX P25 Header", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxP25Data.addData(&data, 1U); - - data = TAG_HEADER; - m_rxP25Data.addData(&data, 1U); - - m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_P25_LDU: { - if (m_trace) - CUtils::dump(1U, "RX P25 LDU", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxP25Data.addData(&data, 1U); - - data = TAG_DATA; - m_rxP25Data.addData(&data, 1U); - - m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_P25_LOST: { - if (m_trace) - CUtils::dump(1U, "RX P25 Lost", m_buffer, m_length); - - unsigned char data = 1U; - m_rxP25Data.addData(&data, 1U); - - data = TAG_LOST; - m_rxP25Data.addData(&data, 1U); - } - break; - - case MMDVM_NXDN_DATA: { - if (m_trace) - CUtils::dump(1U, "RX NXDN Data", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxNXDNData.addData(&data, 1U); - - data = TAG_DATA; - m_rxNXDNData.addData(&data, 1U); - - m_rxNXDNData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_NXDN_LOST: { - if (m_trace) - CUtils::dump(1U, "RX NXDN Lost", m_buffer, m_length); - - unsigned char data = 1U; - m_rxNXDNData.addData(&data, 1U); - - data = TAG_LOST; - m_rxNXDNData.addData(&data, 1U); - } - break; - - case MMDVM_FM_DATA: { - if (m_trace) - CUtils::dump(1U, "RX FM Data", m_buffer, m_length); - - unsigned int data1 = m_length - m_offset + 1U; - m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); - - unsigned char data2 = TAG_DATA; - m_rxFMData.addData(&data2, 1U); - - m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_FM_CONTROL: { - if (m_trace) - CUtils::dump(1U, "RX FM Control", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxFMData.addData(&data, 1U); - - data = TAG_HEADER; - m_rxFMData.addData(&data, 1U); - - m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_FM_EOT: { - if(m_trace) - CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); - - unsigned char data = m_length - m_offset + 1U; - m_rxFMData.addData(&data, 1U); - - data = TAG_EOT; - m_rxFMData.addData(&data, 1U); - - m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_AX25_DATA: { - if (m_trace) - CUtils::dump(1U, "RX AX.25 Data", m_buffer, m_length); - - unsigned int data = m_length - m_offset; - m_rxAX25Data.addData((unsigned char*)&data, sizeof(unsigned int)); - - m_rxAX25Data.addData(m_buffer + m_offset, m_length - m_offset); - } - break; - - case MMDVM_GET_STATUS: { - // if (m_trace) - // CUtils::dump(1U, "GET_STATUS", m_buffer, m_length); - - m_p25Space = 0U; - m_nxdnSpace = 0U; - m_pocsagSpace = 0U; - m_fmSpace = 0U; - m_ax25Space = 0U; - - m_mode = m_buffer[m_offset + 1U]; - - m_tx = (m_buffer[m_offset + 2U] & 0x01U) == 0x01U; - - bool adcOverflow = (m_buffer[m_offset + 2U] & 0x02U) == 0x02U; - if (adcOverflow) - LogError("MMDVM ADC levels have overflowed"); - - bool rxOverflow = (m_buffer[m_offset + 2U] & 0x04U) == 0x04U; - if (rxOverflow) - LogError("MMDVM RX buffer has overflowed"); - - bool txOverflow = (m_buffer[m_offset + 2U] & 0x08U) == 0x08U; - if (txOverflow) - LogError("MMDVM TX buffer has overflowed"); - - m_lockout = (m_buffer[m_offset + 2U] & 0x10U) == 0x10U; - - bool dacOverflow = (m_buffer[m_offset + 2U] & 0x20U) == 0x20U; - if (dacOverflow) - LogError("MMDVM DAC levels have overflowed"); - - m_cd = (m_buffer[m_offset + 2U] & 0x40U) == 0x40U; - - m_dstarSpace = m_buffer[m_offset + 3U]; - m_dmrSpace1 = m_buffer[m_offset + 4U]; - m_dmrSpace2 = m_buffer[m_offset + 5U]; - m_ysfSpace = m_buffer[m_offset + 6U]; - - if (m_length > (m_offset + 7U)) - m_p25Space = m_buffer[m_offset + 7U]; - if (m_length > (m_offset + 8U)) - m_nxdnSpace = m_buffer[m_offset + 8U]; - if (m_length > (m_offset + 9U)) - m_pocsagSpace = m_buffer[m_offset + 9U]; - if (m_length > (m_offset + 10U)) - m_fmSpace = m_buffer[m_offset + 10U]; - if (m_length > (m_offset + 11U)) - m_ax25Space = m_buffer[m_offset + 11U]; - - m_inactivityTimer.start(); - // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, m_fmSpace, m_ax25Space, int(m_lockout), int(m_cd)); - } - break; - - case MMDVM_TRANSPARENT: { - if (m_trace) - CUtils::dump(1U, "RX Transparent Data", m_buffer, m_length); - - unsigned char offset = m_sendTransparentDataFrameType; - if (offset > 1U) offset = 1U; - unsigned char data = m_length - m_offset + offset; - m_rxTransparentData.addData(&data, 1U); - - m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); - } - break; - - // These should not be received, but don't complain if we do - case MMDVM_GET_VERSION: - case MMDVM_ACK: - break; - - case MMDVM_NAK: - LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[m_offset], m_buffer[m_offset + 1U]); - break; - - case MMDVM_DEBUG1: - case MMDVM_DEBUG2: - case MMDVM_DEBUG3: - case MMDVM_DEBUG4: - case MMDVM_DEBUG5: - printDebug(); - break; - - case MMDVM_SERIAL: - //MMDVMHost does not process serial data from the display, - // so we send it to the transparent port if sendFrameType==1 - if (m_sendTransparentDataFrameType > 0U) { - if (m_trace) - CUtils::dump(1U, "RX Serial Data", m_buffer, m_length); - - unsigned char offset = m_sendTransparentDataFrameType; - if (offset > 1U) offset = 1U; - unsigned char data = m_length - m_offset + offset; - m_rxTransparentData.addData(&data, 1U); - - m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); - break; //only break when sendFrameType>0, else message is unknown - } - default: - LogMessage("Unknown message, type: %02X", m_type); - CUtils::dump("Buffer dump", m_buffer, m_length); - break; - } - } - - // Only feed data to the modem if the playout timer has expired - m_playoutTimer.clock(ms); - if (!m_playoutTimer.hasExpired()) - return; - - if (m_dstarSpace > 1U && !m_txDStarData.isEmpty()) { - unsigned char buffer[4U]; - m_txDStarData.peek(buffer, 4U); - - if ((buffer[3U] == MMDVM_DSTAR_HEADER && m_dstarSpace > 4U) || - (buffer[3U] == MMDVM_DSTAR_DATA && m_dstarSpace > 1U) || - (buffer[3U] == MMDVM_DSTAR_EOT && m_dstarSpace > 1U)) { - unsigned char len = 0U; - m_txDStarData.getData(&len, 1U); - m_txDStarData.getData(m_buffer, len); - - switch (buffer[3U]) { - case MMDVM_DSTAR_HEADER: - if (m_trace) - CUtils::dump(1U, "TX D-Star Header", m_buffer, len); - m_dstarSpace -= 4U; - break; - case MMDVM_DSTAR_DATA: - if (m_trace) - CUtils::dump(1U, "TX D-Star Data", m_buffer, len); - m_dstarSpace -= 1U; - break; - default: - if (m_trace) - CUtils::dump(1U, "TX D-Star EOT", m_buffer, len); - m_dstarSpace -= 1U; - break; - } - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing D-Star data to the MMDVM"); - - m_playoutTimer.start(); - } - } - - if (m_dmrSpace1 > 1U && !m_txDMRData1.isEmpty()) { - unsigned char len = 0U; - m_txDMRData1.getData(&len, 1U); - m_txDMRData1.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX DMR Data 1", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing DMR data to the MMDVM"); - - m_playoutTimer.start(); - - m_dmrSpace1--; - } - - if (m_dmrSpace2 > 1U && !m_txDMRData2.isEmpty()) { - unsigned char len = 0U; - m_txDMRData2.getData(&len, 1U); - m_txDMRData2.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX DMR Data 2", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing DMR data to the MMDVM"); - - m_playoutTimer.start(); - - m_dmrSpace2--; - } - - if (m_ysfSpace > 1U && !m_txYSFData.isEmpty()) { - unsigned char len = 0U; - m_txYSFData.getData(&len, 1U); - m_txYSFData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX YSF Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing YSF data to the MMDVM"); - - m_playoutTimer.start(); - - m_ysfSpace--; - } - - if (m_p25Space > 1U && !m_txP25Data.isEmpty()) { - unsigned char len = 0U; - m_txP25Data.getData(&len, 1U); - m_txP25Data.getData(m_buffer, len); - - if (m_trace) { - if (m_buffer[2U] == MMDVM_P25_HDR) - CUtils::dump(1U, "TX P25 HDR", m_buffer, len); - else - CUtils::dump(1U, "TX P25 LDU", m_buffer, len); - } - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing P25 data to the MMDVM"); - - m_playoutTimer.start(); - - m_p25Space--; - } - - if (m_nxdnSpace > 1U && !m_txNXDNData.isEmpty()) { - unsigned char len = 0U; - m_txNXDNData.getData(&len, 1U); - m_txNXDNData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX NXDN Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing NXDN data to the MMDVM"); - - m_playoutTimer.start(); - - m_nxdnSpace--; - } - - if (m_pocsagSpace > 1U && !m_txPOCSAGData.isEmpty()) { - unsigned char len = 0U; - m_txPOCSAGData.getData(&len, 1U); - m_txPOCSAGData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX POCSAG Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing POCSAG data to the MMDVM"); - - m_playoutTimer.start(); - - m_pocsagSpace--; - } - - if (m_fmSpace > 1U && !m_txFMData.isEmpty()) { - unsigned char len = 0U; - m_txFMData.getData(&len, 1U); - m_txFMData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX FM Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing FM data to the MMDVM"); - - m_playoutTimer.start(); - - m_fmSpace--; - } - - if (m_ax25Space > 0U && !m_txAX25Data.isEmpty()) { - unsigned char len = 0U; - m_txAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); - m_txAX25Data.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX AX.25 Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing AX.25 data to the MMDVM"); - - m_playoutTimer.start(); - - m_ax25Space = 0U; - } - - if (!m_txTransparentData.isEmpty()) { - unsigned char len = 0U; - m_txTransparentData.getData(&len, 1U); - m_txTransparentData.getData(m_buffer, len); - - if (m_trace) - CUtils::dump(1U, "TX Transparent Data", m_buffer, len); - - int ret = m_serial->write(m_buffer, len); - if (ret != int(len)) - LogWarning("Error when writing Transparent data to the MMDVM"); - } -} - -void CModem::close() -{ - assert(m_serial != NULL); - - ::LogMessage("Closing the MMDVM"); - - m_serial->close(); -} - -unsigned int CModem::readDStarData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxDStarData.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxDStarData.getData(&len, 1U); - m_rxDStarData.getData(data, len); - - return len; -} - -unsigned int CModem::readDMRData1(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxDMRData1.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxDMRData1.getData(&len, 1U); - m_rxDMRData1.getData(data, len); - - return len; -} - -unsigned int CModem::readDMRData2(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxDMRData2.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxDMRData2.getData(&len, 1U); - m_rxDMRData2.getData(data, len); - - return len; -} - -unsigned int CModem::readYSFData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxYSFData.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxYSFData.getData(&len, 1U); - m_rxYSFData.getData(data, len); - - return len; -} - -unsigned int CModem::readP25Data(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxP25Data.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxP25Data.getData(&len, 1U); - m_rxP25Data.getData(data, len); - - return len; -} - -unsigned int CModem::readNXDNData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxNXDNData.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxNXDNData.getData(&len, 1U); - m_rxNXDNData.getData(data, len); - - return len; -} - -unsigned int CModem::readFMData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxFMData.isEmpty()) - return 0U; - - unsigned int len = 0U; - m_rxFMData.getData((unsigned char*)&len, sizeof(unsigned int)); - m_rxFMData.getData(data, len); - - return len; -} - -unsigned int CModem::readAX25Data(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxAX25Data.isEmpty()) - return 0U; - - unsigned int len = 0U; - m_rxAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); - m_rxAX25Data.getData(data, len); - - return len; -} - -unsigned int CModem::readTransparentData(unsigned char* data) -{ - assert(data != NULL); - - if (m_rxTransparentData.isEmpty()) - return 0U; - - unsigned char len = 0U; - m_rxTransparentData.getData(&len, 1U); - m_rxTransparentData.getData(data, len); - - return len; -} - -// To be implemented later if needed -unsigned int CModem::readSerial(unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - return 0U; -} - -bool CModem::hasDStarSpace() const -{ - unsigned int space = m_txDStarData.freeSpace() / (DSTAR_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::writeDStarData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[50U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - - switch (data[0U]) { - case TAG_HEADER: - buffer[2U] = MMDVM_DSTAR_HEADER; - break; - case TAG_DATA: - buffer[2U] = MMDVM_DSTAR_DATA; - break; - case TAG_EOT: - buffer[2U] = MMDVM_DSTAR_EOT; - break; - default: - CUtils::dump(2U, "Unknown D-Star packet type", data, length); - return false; - } - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txDStarData.addData(&len, 1U); - m_txDStarData.addData(buffer, len); - - return true; -} - -bool CModem::hasDMRSpace1() const -{ - unsigned int space = m_txDMRData1.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::hasDMRSpace2() const -{ - unsigned int space = m_txDMRData2.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::writeDMRData1(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) - return false; - - unsigned char buffer[40U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = MMDVM_DMR_DATA1; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txDMRData1.addData(&len, 1U); - m_txDMRData1.addData(buffer, len); - - return true; -} - -bool CModem::writeDMRData2(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) - return false; - - unsigned char buffer[40U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = MMDVM_DMR_DATA2; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txDMRData2.addData(&len, 1U); - m_txDMRData2.addData(buffer, len); - - return true; -} - -bool CModem::hasYSFSpace() const -{ - unsigned int space = m_txYSFData.freeSpace() / (YSF_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::writeYSFData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) - return false; - - unsigned char buffer[130U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = MMDVM_YSF_DATA; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txYSFData.addData(&len, 1U); - m_txYSFData.addData(buffer, len); - - return true; -} - -bool CModem::hasP25Space() const -{ - unsigned int space = m_txP25Data.freeSpace() / (P25_LDU_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::writeP25Data(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - if (data[0U] != TAG_HEADER && data[0U] != TAG_DATA && data[0U] != TAG_EOT) - return false; - - unsigned char buffer[250U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = (data[0U] == TAG_HEADER) ? MMDVM_P25_HDR : MMDVM_P25_LDU; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txP25Data.addData(&len, 1U); - m_txP25Data.addData(buffer, len); - - return true; -} - -bool CModem::hasNXDNSpace() const -{ - unsigned int space = m_txNXDNData.freeSpace() / (NXDN_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::writeNXDNData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) - return false; - - unsigned char buffer[130U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 2U; - buffer[2U] = MMDVM_NXDN_DATA; - - ::memcpy(buffer + 3U, data + 1U, length - 1U); - - unsigned char len = length + 2U; - m_txNXDNData.addData(&len, 1U); - m_txNXDNData.addData(buffer, len); - - return true; -} - -bool CModem::hasPOCSAGSpace() const -{ - unsigned int space = m_txPOCSAGData.freeSpace() / (POCSAG_FRAME_LENGTH_BYTES + 4U); - - return space > 1U; -} - -bool CModem::writePOCSAGData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[130U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_POCSAG_DATA; - - ::memcpy(buffer + 3U, data, length); - - unsigned char len = length + 3U; - m_txPOCSAGData.addData(&len, 1U); - m_txPOCSAGData.addData(buffer, len); - - return true; -} - -unsigned int CModem::getFMSpace() const -{ - return m_txFMData.freeSpace(); -} - -bool CModem::writeFMData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[500U]; - - unsigned int len; - if (length > 252U) { - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 0U; - buffer[2U] = (length + 4U) - 255U; - buffer[3U] = MMDVM_FM_DATA; - ::memcpy(buffer + 4U, data, length); - len = length + 4U; - } else { - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_FM_DATA; - ::memcpy(buffer + 3U, data, length); - len = length + 3U; - } - - m_txFMData.addData((unsigned char*)&len, sizeof(unsigned int)); - m_txFMData.addData(buffer, len); - - return true; -} - -bool CModem::hasAX25Space() const -{ - unsigned int space = m_txAX25Data.freeSpace() / (AX25_MAX_FRAME_LENGTH_BYTES + 5U); - - return space > 1U; -} - -bool CModem::writeAX25Data(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[500U]; - - unsigned int len; - if (length > 252U) { - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 0U; - buffer[2U] = (length + 4U) - 255U; - buffer[3U] = MMDVM_AX25_DATA; - ::memcpy(buffer + 4U, data, length); - len = length + 4U; - } else { - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_AX25_DATA; - ::memcpy(buffer + 3U, data, length); - len = length + 3U; - } - - m_txAX25Data.addData((unsigned char*)&len, sizeof(unsigned int)); - m_txAX25Data.addData(buffer, len); - - return true; -} - -bool CModem::writeTransparentData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[250U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_TRANSPARENT; - - if (m_sendTransparentDataFrameType > 0U) { - ::memcpy(buffer + 2U, data, length); - length--; - buffer[1U]--; - - //when sendFrameType==1 , only 0x80 and 0x90 (MMDVM_SERIAL and MMDVM_TRANSPARENT) are allowed - // and reverted to default (MMDVM_TRANSPARENT) for any other value - //when >1, frame type is not checked - if (m_sendTransparentDataFrameType == 1U) { - if ((buffer[2U] & 0xE0) != 0x80) - buffer[2U] = MMDVM_TRANSPARENT; - } - } else { - ::memcpy(buffer + 3U, data, length); - } - - unsigned char len = length + 3U; - m_txTransparentData.addData(&len, 1U); - m_txTransparentData.addData(buffer, len); - - return true; -} - -bool CModem::writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) -{ - assert(m_serial != NULL); - assert(my1 != NULL); - assert(my2 != NULL); - assert(your != NULL); - assert(type != NULL); - assert(reflector != NULL); - - unsigned char buffer[50U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 33U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_DSTAR; - - ::memcpy(buffer + 4U, my1, DSTAR_LONG_CALLSIGN_LENGTH); - ::memcpy(buffer + 12U, my2, DSTAR_SHORT_CALLSIGN_LENGTH); - - ::memcpy(buffer + 16U, your, DSTAR_LONG_CALLSIGN_LENGTH); - - ::memcpy(buffer + 24U, type, 1U); - - ::memcpy(buffer + 25U, reflector, DSTAR_LONG_CALLSIGN_LENGTH); - - return m_serial->write(buffer, 33U) != 33; -} - -bool CModem::writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dest, const char* type) -{ - assert(m_serial != NULL); - assert(type != NULL); - - unsigned char buffer[50U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 47U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_DMR; - - buffer[4U] = slotNo; - - ::sprintf((char*)(buffer + 5U), "%20.20s", src.c_str()); - - buffer[25U] = group ? 'G' : 'I'; - - ::sprintf((char*)(buffer + 26U), "%20.20s", dest.c_str()); - - ::memcpy(buffer + 46U, type, 1U); - - return m_serial->write(buffer, 47U) != 47; -} - -bool CModem::writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin) -{ - assert(m_serial != NULL); - assert(source != NULL); - assert(dest != NULL); - assert(type != NULL); - assert(origin != NULL); - - unsigned char buffer[50U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 35U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_YSF; - - ::memcpy(buffer + 4U, source, YSF_CALLSIGN_LENGTH); - ::memcpy(buffer + 14U, dest, YSF_CALLSIGN_LENGTH); - - ::memcpy(buffer + 24U, type, 1U); - - ::memcpy(buffer + 25U, origin, YSF_CALLSIGN_LENGTH); - - return m_serial->write(buffer, 35U) != 35; -} - -bool CModem::writeP25Info(const char* source, bool group, unsigned int dest, const char* type) -{ - assert(m_serial != NULL); - assert(source != NULL); - assert(type != NULL); - - unsigned char buffer[40U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 31U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_DMR; - - ::sprintf((char*)(buffer + 4U), "%20.20s", source); - - buffer[24U] = group ? 'G' : 'I'; - - ::sprintf((char*)(buffer + 25U), "%05u", dest); // 16-bits - - ::memcpy(buffer + 30U, type, 1U); - - return m_serial->write(buffer, 31U) != 31; -} - -bool CModem::writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type) -{ - assert(m_serial != NULL); - assert(source != NULL); - assert(type != NULL); - - unsigned char buffer[40U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 31U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_NXDN; - - ::sprintf((char*)(buffer + 4U), "%20.20s", source); - - buffer[24U] = group ? 'G' : 'I'; - - ::sprintf((char*)(buffer + 25U), "%05u", dest); // 16-bits - - ::memcpy(buffer + 30U, type, 1U); - - return m_serial->write(buffer, 31U) != 31; -} - -bool CModem::writePOCSAGInfo(unsigned int ric, const std::string& message) -{ - assert(m_serial != NULL); - - size_t length = message.size(); - - unsigned char buffer[250U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 11U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = MODE_POCSAG; - - ::sprintf((char*)(buffer + 4U), "%07u", ric); // 21-bits - - ::memcpy(buffer + 11U, message.c_str(), length); - - int ret = m_serial->write(buffer, length + 11U); - - return ret != int(length + 11U); -} - -bool CModem::writeIPInfo(const std::string& address) -{ - assert(m_serial != NULL); - - size_t length = address.size(); - - unsigned char buffer[25U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 4U; - buffer[2U] = MMDVM_QSO_INFO; - - buffer[3U] = 250U; - - ::memcpy(buffer + 4U, address.c_str(), length); - - int ret = m_serial->write(buffer, length + 4U); - - return ret != int(length + 4U); -} - -bool CModem::writeSerial(const unsigned char* data, unsigned int length) -{ - assert(m_serial != NULL); - assert(data != NULL); - assert(length > 0U); - - unsigned char buffer[250U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_SERIAL; - - ::memcpy(buffer + 3U, data, length); - - int ret = m_serial->write(buffer, length + 3U); - - return ret != int(length + 3U); -} - -bool CModem::hasTX() const -{ - return m_tx; -} - -bool CModem::hasCD() const -{ - return m_cd; -} - -bool CModem::hasLockout() const -{ - return m_lockout; -} - -bool CModem::hasError() const -{ - return m_error; -} - -bool CModem::readVersion() -{ - assert(m_serial != NULL); - - CThread::sleep(2000U); // 2s - - for (unsigned int i = 0U; i < 6U; i++) { - unsigned char buffer[3U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 3U; - buffer[2U] = MMDVM_GET_VERSION; - - // CUtils::dump(1U, "Written", buffer, 3U); - - int ret = m_serial->write(buffer, 3U); - if (ret != 3) - return false; - -#if defined(__APPLE__) - m_serial->setNonblock(true); -#endif - - for (unsigned int count = 0U; count < MAX_RESPONSES; count++) { - CThread::sleep(10U); - RESP_TYPE_MMDVM resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] == MMDVM_GET_VERSION) { - if (::memcmp(m_buffer + 4U, "MMDVM ", 6U) == 0) - m_hwType = HWT_MMDVM; - else if (::memcmp(m_buffer + 4U, "DVMEGA", 6U) == 0) - m_hwType = HWT_DVMEGA; - else if (::memcmp(m_buffer + 4U, "ZUMspot", 7U) == 0) - m_hwType = HWT_MMDVM_ZUMSPOT; - else if (::memcmp(m_buffer + 4U, "MMDVM_HS_Hat", 12U) == 0) - m_hwType = HWT_MMDVM_HS_HAT; - else if (::memcmp(m_buffer + 4U, "MMDVM_HS_Dual_Hat", 17U) == 0) - m_hwType = HWT_MMDVM_HS_DUAL_HAT; - else if (::memcmp(m_buffer + 4U, "Nano_hotSPOT", 12U) == 0) - m_hwType = HWT_NANO_HOTSPOT; - else if (::memcmp(m_buffer + 4U, "Nano_DV", 7U) == 0) - m_hwType = HWT_NANO_DV; - else if (::memcmp(m_buffer + 4U, "D2RG_MMDVM_HS", 13U) == 0) - m_hwType = HWT_D2RG_MMDVM_HS; - else if (::memcmp(m_buffer + 4U, "MMDVM_HS-", 9U) == 0) - m_hwType = HWT_MMDVM_HS; - else if (::memcmp(m_buffer + 4U, "OpenGD77_HS", 11U) == 0) - m_hwType = HWT_OPENGD77_HS; - - LogInfo("MMDVM protocol version: %u, description: %.*s", m_buffer[3U], m_length - 4U, m_buffer + 4U); - return true; - } - } - - CThread::sleep(1500U); - } - - LogError("Unable to read the firmware version after six attempts"); - - return false; -} - -bool CModem::readStatus() -{ - assert(m_serial != NULL); - - unsigned char buffer[3U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 3U; - buffer[2U] = MMDVM_GET_STATUS; - - // CUtils::dump(1U, "Written", buffer, 3U); - - return m_serial->write(buffer, 3U) == 3; -} - -bool CModem::writeConfig() -{ - return setConfig(); -} - -bool CModem::setConfig() -{ - assert(m_serial != NULL); - - unsigned char buffer[30U]; - - buffer[0U] = MMDVM_FRAME_START; - - buffer[1U] = 27U; - - buffer[2U] = MMDVM_SET_CONFIG; - - buffer[3U] = 0x00U; - if (m_rxInvert) - buffer[3U] |= 0x01U; - if (m_txInvert) - buffer[3U] |= 0x02U; - if (m_pttInvert) - buffer[3U] |= 0x04U; - if (m_ysfLoDev) - buffer[3U] |= 0x08U; - if (m_debug) - buffer[3U] |= 0x10U; - if (!m_duplex) - buffer[3U] |= 0x80U; - - buffer[4U] = 0x00U; - if (m_dstarEnabled) - buffer[4U] |= 0x01U; - if (m_dmrEnabled) - buffer[4U] |= 0x02U; - if (m_ysfEnabled) - buffer[4U] |= 0x04U; - if (m_p25Enabled) - buffer[4U] |= 0x08U; - if (m_nxdnEnabled) - buffer[4U] |= 0x10U; - if (m_pocsagEnabled) - buffer[4U] |= 0x20U; - if (m_fmEnabled && m_duplex) - buffer[4U] |= 0x40U; - if (m_ax25Enabled) - buffer[4U] |= 0x80U; - - buffer[5U] = m_txDelay / 10U; // In 10ms units - - buffer[6U] = MODE_IDLE; - - buffer[7U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); - - buffer[8U] = (unsigned char)(m_cwIdTXLevel * 2.55F + 0.5F); - - buffer[9U] = m_dmrColorCode; - - buffer[10U] = m_dmrDelay; - - buffer[11U] = 128U; // Was OscOffset - - buffer[12U] = (unsigned char)(m_dstarTXLevel * 2.55F + 0.5F); - buffer[13U] = (unsigned char)(m_dmrTXLevel * 2.55F + 0.5F); - buffer[14U] = (unsigned char)(m_ysfTXLevel * 2.55F + 0.5F); - buffer[15U] = (unsigned char)(m_p25TXLevel * 2.55F + 0.5F); - - buffer[16U] = (unsigned char)(m_txDCOffset + 128); - buffer[17U] = (unsigned char)(m_rxDCOffset + 128); - - buffer[18U] = (unsigned char)(m_nxdnTXLevel * 2.55F + 0.5F); - - buffer[19U] = (unsigned char)m_ysfTXHang; - - buffer[20U] = (unsigned char)(m_pocsagTXLevel * 2.55F + 0.5F); - - buffer[21U] = (unsigned char)(m_fmTXLevel * 2.55F + 0.5F); - - buffer[22U] = (unsigned char)m_p25TXHang; - - buffer[23U] = (unsigned char)m_nxdnTXHang; - - buffer[24U] = (unsigned char)(m_ax25TXLevel * 2.55F + 0.5F); - - buffer[25U] = (unsigned char)(m_ax25RXTwist + 128); - - buffer[26U] = m_ax25TXDelay / 10U; // In 10ms units - - // CUtils::dump(1U, "Written", buffer, 27U); - - int ret = m_serial->write(buffer, 27U); - if (ret != 27) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_CONFIG command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_CONFIG command from the modem"); - return false; - } - - m_playoutTimer.start(); - - return true; -} - -bool CModem::setFrequency() -{ - assert(m_serial != NULL); - - unsigned char buffer[20U]; - unsigned char len; - unsigned int pocsagFrequency = 433000000U; - - if (m_pocsagEnabled) - pocsagFrequency = m_pocsagFrequency; - - if (m_hwType == HWT_DVMEGA) - len = 12U; - else { - buffer[12U] = (unsigned char)(m_rfLevel * 2.55F + 0.5F); - - buffer[13U] = (pocsagFrequency >> 0) & 0xFFU; - buffer[14U] = (pocsagFrequency >> 8) & 0xFFU; - buffer[15U] = (pocsagFrequency >> 16) & 0xFFU; - buffer[16U] = (pocsagFrequency >> 24) & 0xFFU; - - len = 17U; - } - - buffer[0U] = MMDVM_FRAME_START; - - buffer[1U] = len; - - buffer[2U] = MMDVM_SET_FREQ; - - buffer[3U] = 0x00U; - - buffer[4U] = (m_rxFrequency >> 0) & 0xFFU; - buffer[5U] = (m_rxFrequency >> 8) & 0xFFU; - buffer[6U] = (m_rxFrequency >> 16) & 0xFFU; - buffer[7U] = (m_rxFrequency >> 24) & 0xFFU; - - buffer[8U] = (m_txFrequency >> 0) & 0xFFU; - buffer[9U] = (m_txFrequency >> 8) & 0xFFU; - buffer[10U] = (m_txFrequency >> 16) & 0xFFU; - buffer[11U] = (m_txFrequency >> 24) & 0xFFU; - - // CUtils::dump(1U, "Written", buffer, len); - - int ret = m_serial->write(buffer, len); - if (ret != len) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FREQ command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FREQ command from the modem"); - return false; - } - - return true; -} - -RESP_TYPE_MMDVM CModem::getResponse() -{ - assert(m_serial != NULL); - - if (m_state == SS_START) { - // Get the start of the frame or nothing at all - int ret = m_serial->read(m_buffer + 0U, 1U); - if (ret < 0) { - LogError("Error when reading from the modem"); - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - if (m_buffer[0U] != MMDVM_FRAME_START) - return RTM_TIMEOUT; - - m_state = SS_LENGTH1; - m_length = 1U; - } - - if (m_state == SS_LENGTH1) { - // Get the length of the frame, 1/2 - int ret = m_serial->read(m_buffer + 1U, 1U); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_state = SS_START; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - m_length = m_buffer[1U]; - m_offset = 2U; - - if (m_length == 0U) - m_state = SS_LENGTH2; - else - m_state = SS_TYPE; - } - - if (m_state == SS_LENGTH2) { - // Get the length of the frane, 2/2 - int ret = m_serial->read(m_buffer + 2U, 1U); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_state = SS_START; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - m_length = m_buffer[2U] + 255U; - m_offset = 3U; - m_state = SS_TYPE; - } - - if (m_state == SS_TYPE) { - // Get the frame type - int ret = m_serial->read(&m_type, 1U); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_state = SS_START; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - m_buffer[m_offset++] = m_type; - - m_state = SS_DATA; - } - - if (m_state == SS_DATA) { - while (m_offset < m_length) { - int ret = m_serial->read(m_buffer + m_offset, m_length - m_offset); - if (ret < 0) { - LogError("Error when reading from the modem"); - m_state = SS_START; - return RTM_ERROR; - } - - if (ret == 0) - return RTM_TIMEOUT; - - if (ret > 0) - m_offset += ret; - } - } - - // CUtils::dump(1U, "Received", m_buffer, m_length); - - m_offset = m_length > 255U ? 4U : 3U; - m_state = SS_START; - - return RTM_OK; -} - -HW_TYPE CModem::getHWType() const -{ - return m_hwType; -} - -unsigned char CModem::getMode() const -{ - return m_mode; -} - -bool CModem::setMode(unsigned char mode) -{ - assert(m_serial != NULL); - - unsigned char buffer[4U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 4U; - buffer[2U] = MMDVM_SET_MODE; - buffer[3U] = mode; - - // CUtils::dump(1U, "Written", buffer, 4U); - - return m_serial->write(buffer, 4U) == 4; -} - -bool CModem::sendCWId(const std::string& callsign) -{ - assert(m_serial != NULL); - - unsigned int length = callsign.length(); - if (length > 200U) - length = 200U; - - unsigned char buffer[205U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = length + 3U; - buffer[2U] = MMDVM_SEND_CWID; - - for (unsigned int i = 0U; i < length; i++) - buffer[i + 3U] = callsign.at(i); - - // CUtils::dump(1U, "Written", buffer, length + 3U); - - return m_serial->write(buffer, length + 3U) == int(length + 3U); -} - -bool CModem::writeDMRStart(bool tx) -{ - assert(m_serial != NULL); - - if (tx && m_tx) - return true; - if (!tx && !m_tx) - return true; - - unsigned char buffer[4U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 4U; - buffer[2U] = MMDVM_DMR_START; - buffer[3U] = tx ? 0x01U : 0x00U; - - // CUtils::dump(1U, "Written", buffer, 4U); - - return m_serial->write(buffer, 4U) == 4; -} - -bool CModem::writeDMRAbort(unsigned int slotNo) -{ - assert(m_serial != NULL); - - if (slotNo == 1U) - m_txDMRData1.clear(); - else - m_txDMRData2.clear(); - - unsigned char buffer[4U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 4U; - buffer[2U] = MMDVM_DMR_ABORT; - buffer[3U] = slotNo; - - // CUtils::dump(1U, "Written", buffer, 4U); - - return m_serial->write(buffer, 4U) == 4; -} - -bool CModem::writeDMRShortLC(const unsigned char* lc) -{ - assert(m_serial != NULL); - assert(lc != NULL); - - unsigned char buffer[12U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 12U; - buffer[2U] = MMDVM_DMR_SHORTLC; - buffer[3U] = lc[0U]; - buffer[4U] = lc[1U]; - buffer[5U] = lc[2U]; - buffer[6U] = lc[3U]; - buffer[7U] = lc[4U]; - buffer[8U] = lc[5U]; - buffer[9U] = lc[6U]; - buffer[10U] = lc[7U]; - buffer[11U] = lc[8U]; - - // CUtils::dump(1U, "Written", buffer, 12U); - - return m_serial->write(buffer, 12U) == 12; -} - -void CModem::setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) -{ - m_fmCallsign = callsign; - m_fmCallsignSpeed = callsignSpeed; - m_fmCallsignFrequency = callsignFrequency; - m_fmCallsignTime = callsignTime; - m_fmCallsignHoldoff = callsignHoldoff; - m_fmCallsignHighLevel = callsignHighLevel; - m_fmCallsignLowLevel = callsignLowLevel; - m_fmCallsignAtStart = callsignAtStart; - m_fmCallsignAtEnd = callsignAtEnd; - m_fmCallsignAtLatch = callsignAtLatch; -} - -void CModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) -{ - m_fmRfAck = rfAck; - m_fmAckSpeed = ackSpeed; - m_fmAckFrequency = ackFrequency; - m_fmAckMinTime = ackMinTime; - m_fmAckDelay = ackDelay; - m_fmAckLevel = ackLevel; -} - -void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) -{ - m_fmTimeout = timeout; - m_fmTimeoutLevel = timeoutLevel; - - m_fmCtcssFrequency = ctcssFrequency; - m_fmCtcssHighThreshold = ctcssHighThreshold; - m_fmCtcssLowThreshold = ctcssLowThreshold; - m_fmCtcssLevel = ctcssLevel; - - m_fmKerchunkTime = kerchunkTime; - m_fmKerchunkTX = kerchunkTX; - - m_fmHangTime = hangTime; - - m_fmUseCOS = useCOS; - m_fmCOSInvert = cosInvert; - - m_fmRFAudioBoost = rfAudioBoost; - m_fmMaxDevLevel = maxDevLevel; -} - -void CModem::setFMExtParams(const std::string& ack, unsigned int audioBoost) -{ - m_fmExtAck = ack; - m_fmExtAudioBoost = audioBoost; - m_fmExtEnable = true; -} - -bool CModem::setFMCallsignParams() -{ - assert(m_serial != NULL); - - unsigned char buffer[80U]; - unsigned char len = 10U + m_fmCallsign.size(); - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = len; - buffer[2U] = MMDVM_FM_PARAMS1; - - buffer[3U] = m_fmCallsignSpeed; - buffer[4U] = m_fmCallsignFrequency / 10U; - buffer[5U] = m_fmCallsignTime; - buffer[6U] = m_fmCallsignHoldoff; - - buffer[7U] = (unsigned char)(m_fmCallsignHighLevel * 2.55F + 0.5F); - buffer[8U] = (unsigned char)(m_fmCallsignLowLevel * 2.55F + 0.5F); - - buffer[9U] = 0x00U; - if (m_fmCallsignAtStart) - buffer[9U] |= 0x01U; - if (m_fmCallsignAtEnd) - buffer[9U] |= 0x02U; - if (m_fmCallsignAtLatch) - buffer[9U] |= 0x04U; - - for (unsigned int i = 0U; i < m_fmCallsign.size(); i++) - buffer[10U + i] = m_fmCallsign.at(i); - - // CUtils::dump(1U, "Written", buffer, len); - - int ret = m_serial->write(buffer, len); - if (ret != len) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FM_PARAMS1 command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FM_PARAMS1 command from the modem"); - return false; - } - - return true; -} - -bool CModem::setFMAckParams() -{ - assert(m_serial != NULL); - - unsigned char buffer[80U]; - unsigned char len = 8U + m_fmRfAck.size(); - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = len; - buffer[2U] = MMDVM_FM_PARAMS2; - - buffer[3U] = m_fmAckSpeed; - buffer[4U] = m_fmAckFrequency / 10U; - buffer[5U] = m_fmAckMinTime; - buffer[6U] = m_fmAckDelay / 10U; - - buffer[7U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); - - for (unsigned int i = 0U; i < m_fmRfAck.size(); i++) - buffer[8U + i] = m_fmRfAck.at(i); - - // CUtils::dump(1U, "Written", buffer, len); - - int ret = m_serial->write(buffer, len); - if (ret != len) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FM_PARAMS2 command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FM_PARAMS2 command from the modem"); - return false; - } - - return true; -} - -bool CModem::setFMMiscParams() -{ - assert(m_serial != NULL); - - unsigned char buffer[20U]; - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 15U; - buffer[2U] = MMDVM_FM_PARAMS3; - - buffer[3U] = m_fmTimeout / 5U; - buffer[4U] = (unsigned char)(m_fmTimeoutLevel * 2.55F + 0.5F); - - buffer[5U] = (unsigned char)m_fmCtcssFrequency; - buffer[6U] = m_fmCtcssHighThreshold; - buffer[7U] = m_fmCtcssLowThreshold; - buffer[8U] = (unsigned char)(m_fmCtcssLevel * 2.55F + 0.5F); - - buffer[9U] = m_fmKerchunkTime; - buffer[10U] = m_fmHangTime; - - buffer[11U] = 0x00U; - if (m_fmUseCOS) - buffer[11U] |= 0x01U; - if (m_fmCOSInvert) - buffer[11U] |= 0x02U; - if (m_fmKerchunkTX) - buffer[11U] |= 0x04U; - - buffer[12U] = m_fmRFAudioBoost; - - buffer[13U] = (unsigned char)(m_fmMaxDevLevel * 2.55F + 0.5F); - - buffer[14U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); - - // CUtils::dump(1U, "Written", buffer, 15U); - - int ret = m_serial->write(buffer, 15U); - if (ret != 15) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FM_PARAMS3 command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FM_PARAMS3 command from the modem"); - return false; - } - - return true; -} - -bool CModem::setFMExtParams() -{ - assert(m_serial != NULL); - - unsigned char buffer[80U]; - unsigned char len = 7U + m_fmExtAck.size(); - - buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = len; - buffer[2U] = MMDVM_FM_PARAMS4; - - buffer[3U] = m_fmExtAudioBoost; - buffer[4U] = m_fmAckSpeed; - buffer[5U] = m_fmAckFrequency / 10U; - - buffer[6U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); - - for (unsigned int i = 0U; i < m_fmExtAck.size(); i++) - buffer[7U + i] = m_fmExtAck.at(i); - - // CUtils::dump(1U, "Written", buffer, len); - - int ret = m_serial->write(buffer, len); - if (ret != len) - return false; - - unsigned int count = 0U; - RESP_TYPE_MMDVM resp; - do { - CThread::sleep(10U); - - resp = getResponse(); - if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { - count++; - if (count >= MAX_RESPONSES) { - LogError("The MMDVM is not responding to the SET_FM_PARAMS4 command"); - return false; - } - } - } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); - - // CUtils::dump(1U, "Response", m_buffer, m_length); - - if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { - LogError("Received a NAK to the SET_FM_PARAMS4 command from the modem"); - return false; - } - - return true; -} - -void CModem::printDebug() +IModem::~IModem() { - if (m_buffer[2U] == MMDVM_DEBUG1) { - LogMessage("Debug: %.*s", m_length - m_offset - 0U, m_buffer + m_offset); - } else if (m_buffer[2U] == MMDVM_DEBUG2) { - short val1 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d", m_length - m_offset - 2U, m_buffer + m_offset, val1); - } else if (m_buffer[2U] == MMDVM_DEBUG3) { - short val1 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; - short val2 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d", m_length - m_offset - 4U, m_buffer + m_offset, val1, val2); - } else if (m_buffer[2U] == MMDVM_DEBUG4) { - short val1 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; - short val2 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; - short val3 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d %d", m_length - m_offset - 6U, m_buffer + m_offset, val1, val2, val3); - } else if (m_buffer[2U] == MMDVM_DEBUG5) { - short val1 = (m_buffer[m_length - 8U] << 8) | m_buffer[m_length - 7U]; - short val2 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; - short val3 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; - short val4 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; - LogMessage("Debug: %.*s %d %d %d %d", m_length - m_offset - 8U, m_buffer + m_offset, val1, val2, val3, val4); - } -} - -CModem* CModem::createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug){ - if (port == "NullModem") - return new CNullModem(port, duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); - else - return new CModem(port, duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); } diff --git a/Modem.h b/Modem.h index 822d50f..c408f01 100644 --- a/Modem.h +++ b/Modem.h @@ -19,249 +19,99 @@ #ifndef MODEM_H #define MODEM_H -#include "SerialPort.h" -#include "RingBuffer.h" #include "Defines.h" -#include "Timer.h" #include -enum RESP_TYPE_MMDVM { - RTM_OK, - RTM_TIMEOUT, - RTM_ERROR -}; - -enum SERIAL_STATE { - SS_START, - SS_LENGTH1, - SS_LENGTH2, - SS_TYPE, - SS_DATA -}; - -class CModem { +class IModem { public: - CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); - virtual ~CModem(); + virtual ~IModem() = 0; - virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed); - virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); - virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled); - virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel); - virtual void setDMRParams(unsigned int colorCode); - virtual void setYSFParams(bool loDev, unsigned int txHang); - virtual void setP25Params(unsigned int txHang); - virtual void setNXDNParams(unsigned int txHang); - virtual void setAX25Params(int rxTwist, unsigned int txDelay); - virtual void setTransparentDataParams(unsigned int sendFrameType); + virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) = 0; + virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) = 0; + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) = 0; + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel) = 0; + virtual void setDMRParams(unsigned int colorCode) = 0; + virtual void setYSFParams(bool loDev, unsigned int txHang) = 0; + virtual void setP25Params(unsigned int txHang) = 0; + virtual void setNXDNParams(unsigned int txHang) = 0; + virtual void setAX25Params(int rxTwist, unsigned int txDelay) = 0; + virtual void setTransparentDataParams(unsigned int sendFrameType) = 0; - virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); - virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); - virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); - virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost); + virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) = 0; + virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) = 0; + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) = 0; + virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost) = 0; - virtual bool open(); + virtual bool open() = 0; - virtual unsigned int readDStarData(unsigned char* data); - virtual unsigned int readDMRData1(unsigned char* data); - virtual unsigned int readDMRData2(unsigned char* data); - virtual unsigned int readYSFData(unsigned char* data); - virtual unsigned int readP25Data(unsigned char* data); - virtual unsigned int readNXDNData(unsigned char* data); - virtual unsigned int readFMData(unsigned char* data); - virtual unsigned int readAX25Data(unsigned char* data); - virtual unsigned int readTransparentData(unsigned char* data); + virtual unsigned int readDStarData(unsigned char* data) = 0; + virtual unsigned int readDMRData1(unsigned char* data) = 0; + virtual unsigned int readDMRData2(unsigned char* data) = 0; + virtual unsigned int readYSFData(unsigned char* data) = 0; + virtual unsigned int readP25Data(unsigned char* data) = 0; + virtual unsigned int readNXDNData(unsigned char* data) = 0; + virtual unsigned int readFMData(unsigned char* data) = 0; + virtual unsigned int readAX25Data(unsigned char* data) = 0; + virtual unsigned int readTransparentData(unsigned char* data) = 0; - virtual unsigned int readSerial(unsigned char* data, unsigned int length); + virtual unsigned int readSerial(unsigned char* data, unsigned int length) = 0; - virtual bool hasDStarSpace() const; - virtual bool hasDMRSpace1() const; - virtual bool hasDMRSpace2() const; - virtual bool hasYSFSpace() const; - virtual bool hasP25Space() const; - virtual bool hasNXDNSpace() const; - virtual bool hasPOCSAGSpace() const; - virtual unsigned int getFMSpace() const; - virtual bool hasAX25Space() const; + virtual bool hasDStarSpace() const = 0; + virtual bool hasDMRSpace1() const = 0; + virtual bool hasDMRSpace2() const = 0; + virtual bool hasYSFSpace() const = 0; + virtual bool hasP25Space() const = 0; + virtual bool hasNXDNSpace() const = 0; + virtual bool hasPOCSAGSpace() const = 0; + virtual unsigned int getFMSpace() const = 0; + virtual bool hasAX25Space() const = 0; - virtual bool hasTX() const; - virtual bool hasCD() const; + virtual bool hasTX() const = 0; + virtual bool hasCD() const = 0; - virtual bool hasLockout() const; - virtual bool hasError() const; + virtual bool hasLockout() const = 0; + virtual bool hasError() const = 0; - virtual bool writeConfig(); - virtual bool writeDStarData(const unsigned char* data, unsigned int length); - virtual bool writeDMRData1(const unsigned char* data, unsigned int length); - virtual bool writeDMRData2(const unsigned char* data, unsigned int length); - virtual bool writeYSFData(const unsigned char* data, unsigned int length); - virtual bool writeP25Data(const unsigned char* data, unsigned int length); - virtual bool writeNXDNData(const unsigned char* data, unsigned int length); - virtual bool writePOCSAGData(const unsigned char* data, unsigned int length); - virtual bool writeFMData(const unsigned char* data, unsigned int length); - virtual bool writeAX25Data(const unsigned char* data, unsigned int length); + virtual bool writeConfig() = 0; + virtual bool writeDStarData(const unsigned char* data, unsigned int length) = 0; + virtual bool writeDMRData1(const unsigned char* data, unsigned int length) = 0; + virtual bool writeDMRData2(const unsigned char* data, unsigned int length) = 0; + virtual bool writeYSFData(const unsigned char* data, unsigned int length) = 0; + virtual bool writeP25Data(const unsigned char* data, unsigned int length) = 0; + virtual bool writeNXDNData(const unsigned char* data, unsigned int length) = 0; + virtual bool writePOCSAGData(const unsigned char* data, unsigned int length) = 0; + virtual bool writeFMData(const unsigned char* data, unsigned int length) = 0; + virtual bool writeAX25Data(const unsigned char* data, unsigned int length) = 0; - virtual bool writeTransparentData(const unsigned char* data, unsigned int length); + virtual bool writeTransparentData(const unsigned char* data, unsigned int length) = 0; - virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); - virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type); - virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin); - virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type); - virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type); - virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message); - virtual bool writeIPInfo(const std::string& address); + virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0; + virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) = 0; + virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin) = 0; + virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type) = 0; + virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type) = 0; + virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message) = 0; + virtual bool writeIPInfo(const std::string& address) = 0; - virtual bool writeDMRStart(bool tx); - virtual bool writeDMRShortLC(const unsigned char* lc); - virtual bool writeDMRAbort(unsigned int slotNo); + virtual bool writeDMRStart(bool tx) = 0; + virtual bool writeDMRShortLC(const unsigned char* lc) = 0; + virtual bool writeDMRAbort(unsigned int slotNo) = 0; - virtual bool writeSerial(const unsigned char* data, unsigned int length); + virtual bool writeSerial(const unsigned char* data, unsigned int length) = 0; - virtual unsigned char getMode() const; - virtual bool setMode(unsigned char mode); + virtual unsigned char getMode() const = 0; + virtual bool setMode(unsigned char mode) = 0; - virtual bool sendCWId(const std::string& callsign); + virtual bool sendCWId(const std::string& callsign) = 0; - virtual HW_TYPE getHWType() const; + virtual HW_TYPE getHWType() const = 0; - virtual void clock(unsigned int ms); + virtual void clock(unsigned int ms) = 0; - virtual void close(); - - static CModem* createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); + virtual void close() = 0; private: - std::string m_port; - unsigned int m_dmrColorCode; - bool m_ysfLoDev; - unsigned int m_ysfTXHang; - unsigned int m_p25TXHang; - unsigned int m_nxdnTXHang; - bool m_duplex; - bool m_rxInvert; - bool m_txInvert; - bool m_pttInvert; - unsigned int m_txDelay; - unsigned int m_dmrDelay; - float m_rxLevel; - float m_cwIdTXLevel; - float m_dstarTXLevel; - float m_dmrTXLevel; - float m_ysfTXLevel; - float m_p25TXLevel; - float m_nxdnTXLevel; - float m_pocsagTXLevel; - float m_fmTXLevel; - float m_ax25TXLevel; - float m_rfLevel; - bool m_trace; - bool m_debug; - unsigned int m_rxFrequency; - unsigned int m_txFrequency; - unsigned int m_pocsagFrequency; - bool m_dstarEnabled; - bool m_dmrEnabled; - bool m_ysfEnabled; - bool m_p25Enabled; - bool m_nxdnEnabled; - bool m_pocsagEnabled; - bool m_fmEnabled; - bool m_ax25Enabled; - int m_rxDCOffset; - int m_txDCOffset; - ISerialPort* m_serial; - unsigned char* m_buffer; - unsigned int m_length; - unsigned int m_offset; - SERIAL_STATE m_state; - unsigned char m_type; - CRingBuffer m_rxDStarData; - CRingBuffer m_txDStarData; - CRingBuffer m_rxDMRData1; - CRingBuffer m_rxDMRData2; - CRingBuffer m_txDMRData1; - CRingBuffer m_txDMRData2; - CRingBuffer m_rxYSFData; - CRingBuffer m_txYSFData; - CRingBuffer m_rxP25Data; - CRingBuffer m_txP25Data; - CRingBuffer m_rxNXDNData; - CRingBuffer m_txNXDNData; - CRingBuffer m_txPOCSAGData; - CRingBuffer m_rxFMData; - CRingBuffer m_txFMData; - CRingBuffer m_rxAX25Data; - CRingBuffer m_txAX25Data; - CRingBuffer m_rxTransparentData; - CRingBuffer m_txTransparentData; - unsigned int m_sendTransparentDataFrameType; - CTimer m_statusTimer; - CTimer m_inactivityTimer; - CTimer m_playoutTimer; - unsigned int m_dstarSpace; - unsigned int m_dmrSpace1; - unsigned int m_dmrSpace2; - unsigned int m_ysfSpace; - unsigned int m_p25Space; - unsigned int m_nxdnSpace; - unsigned int m_pocsagSpace; - unsigned int m_fmSpace; - unsigned int m_ax25Space; - bool m_tx; - bool m_cd; - bool m_lockout; - bool m_error; - unsigned char m_mode; - HW_TYPE m_hwType; - int m_ax25RXTwist; - unsigned int m_ax25TXDelay; - - std::string m_fmCallsign; - unsigned int m_fmCallsignSpeed; - unsigned int m_fmCallsignFrequency; - unsigned int m_fmCallsignTime; - unsigned int m_fmCallsignHoldoff; - float m_fmCallsignHighLevel; - float m_fmCallsignLowLevel; - bool m_fmCallsignAtStart; - bool m_fmCallsignAtEnd; - bool m_fmCallsignAtLatch; - std::string m_fmRfAck; - std::string m_fmExtAck; - unsigned int m_fmAckSpeed; - unsigned int m_fmAckFrequency; - unsigned int m_fmAckMinTime; - unsigned int m_fmAckDelay; - float m_fmAckLevel; - unsigned int m_fmTimeout; - float m_fmTimeoutLevel; - float m_fmCtcssFrequency; - unsigned int m_fmCtcssHighThreshold; - unsigned int m_fmCtcssLowThreshold; - float m_fmCtcssLevel; - unsigned int m_fmKerchunkTime; - bool m_fmKerchunkTX; - unsigned int m_fmHangTime; - bool m_fmUseCOS; - bool m_fmCOSInvert; - unsigned int m_fmRFAudioBoost; - unsigned int m_fmExtAudioBoost; - float m_fmMaxDevLevel; - bool m_fmExtEnable; - - bool readVersion(); - bool readStatus(); - bool setConfig(); - bool setFrequency(); - bool setFMCallsignParams(); - bool setFMAckParams(); - bool setFMMiscParams(); - bool setFMExtParams(); - - void printDebug(); - - RESP_TYPE_MMDVM getResponse(); }; #endif diff --git a/ModemSerialPort.cpp b/ModemSerialPort.cpp index 51ba01d..c34cb3d 100644 --- a/ModemSerialPort.cpp +++ b/ModemSerialPort.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,22 +21,22 @@ #include #include -CModemSerialPort::CModemSerialPort(CModem* modem) : +IModemSerialPort::IModemSerialPort(IModem* modem) : m_modem(modem) { assert(modem != NULL); } -CModemSerialPort::~CModemSerialPort() +IModemSerialPort::~IModemSerialPort() { } -bool CModemSerialPort::open() +bool IModemSerialPort::open() { return true; } -int CModemSerialPort::write(const unsigned char* data, unsigned int length) +int IModemSerialPort::write(const unsigned char* data, unsigned int length) { assert(data != NULL); assert(length > 0U); @@ -46,7 +46,7 @@ int CModemSerialPort::write(const unsigned char* data, unsigned int length) return ret ? int(length) : -1; } -int CModemSerialPort::read(unsigned char* data, unsigned int length) +int IModemSerialPort::read(unsigned char* data, unsigned int length) { assert(data != NULL); assert(length > 0U); @@ -54,6 +54,6 @@ int CModemSerialPort::read(unsigned char* data, unsigned int length) return m_modem->readSerial(data, length); } -void CModemSerialPort::close() +void IModemSerialPort::close() { } diff --git a/ModemSerialPort.h b/ModemSerialPort.h index d6761ce..6de56a7 100644 --- a/ModemSerialPort.h +++ b/ModemSerialPort.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,10 +22,10 @@ #include "SerialPort.h" #include "Modem.h" -class CModemSerialPort : public ISerialPort { +class IModemSerialPort : public ISerialPort { public: - CModemSerialPort(CModem* modem); - virtual ~CModemSerialPort(); + IModemSerialPort(IModem* modem); + virtual ~IModemSerialPort(); virtual bool open(); @@ -36,7 +36,7 @@ public: virtual void close(); private: - CModem* m_modem; + IModem* m_modem; }; #endif diff --git a/NullModem.cpp b/NullModem.cpp index 8539f1b..40e3fdd 100644 --- a/NullModem.cpp +++ b/NullModem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 by Jonathan Naylor G4KLX + * Copyright (C) 2011-2018,2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,9 +19,7 @@ #include "NullModem.h" #include "Log.h" -CNullModem::CNullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug) : -CModem(port, duplex,rxInvert, txInvert,pttInvert,txDelay, dmrDelay, trace, debug), -m_hwType(HWT_MMDVM) +CNullModem::CNullModem() { } @@ -29,7 +27,9 @@ CNullModem::~CNullModem() { } -bool CNullModem::open(){ +bool CNullModem::open() +{ ::LogMessage("Opening the MMDVM Null Modem"); + return true; -} \ No newline at end of file +} diff --git a/NullModem.h b/NullModem.h index ec8757a..12ae460 100644 --- a/NullModem.h +++ b/NullModem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 by Jonathan Naylor G4KLX + * Copyright (C) 2011-2018,2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,83 +24,96 @@ #include - -class CNullModem : public CModem { +class CNullModem : public IModem { public: - CNullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); + CNullModem(); virtual ~CNullModem(); - virtual void setSerialParams(const std::string& protocol, unsigned int address){}; - virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency){}; - virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled){}; - virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel){}; - virtual void setDMRParams(unsigned int colorCode){}; - virtual void setYSFParams(bool loDev, unsigned int txHang){}; - virtual void setAX25Params(int rxTwist, unsigned int txDelay){}; - virtual void setTransparentDataParams(unsigned int sendFrameType){}; + virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) {}; + virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) {}; + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) {}; + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel) {}; + virtual void setDMRParams(unsigned int colorCode) {}; + virtual void setYSFParams(bool loDev, unsigned int txHang) {}; + virtual void setP25Params(unsigned int txHang) {}; + virtual void setNXDNParams(unsigned int txHang) {}; + virtual void setAX25Params(int rxTwist, unsigned int txDelay) {}; + virtual void setTransparentDataParams(unsigned int sendFrameType) {}; + + virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) {}; + virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) {}; + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) {}; + virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost) {}; virtual bool open(); - virtual unsigned int readDStarData(unsigned char* data){return 0;}; - virtual unsigned int readDMRData1(unsigned char* data){return 0;}; - virtual unsigned int readDMRData2(unsigned char* data){return 0;}; - virtual unsigned int readYSFData(unsigned char* data){return 0;}; - virtual unsigned int readP25Data(unsigned char* data){return 0;}; - virtual unsigned int readNXDNData(unsigned char* data){return 0;}; - virtual unsigned int readTransparentData(unsigned char* data){return 0;}; + virtual unsigned int readDStarData(unsigned char* data) { return 0U; }; + virtual unsigned int readDMRData1(unsigned char* data) { return 0U; }; + virtual unsigned int readDMRData2(unsigned char* data) { return 0U; }; + virtual unsigned int readYSFData(unsigned char* data) { return 0U; }; + virtual unsigned int readP25Data(unsigned char* data) { return 0U; }; + virtual unsigned int readNXDNData(unsigned char* data) { return 0U; }; + virtual unsigned int readFMData(unsigned char* data) { return 0U; }; + virtual unsigned int readAX25Data(unsigned char* data) { return 0U; }; + virtual unsigned int readTransparentData(unsigned char* data) { return 0U; }; - virtual unsigned int readSerial(unsigned char* data, unsigned int length){return 0;}; + virtual unsigned int readSerial(unsigned char* data, unsigned int length) { return 0; }; - virtual bool hasDStarSpace()const {return true;}; - virtual bool hasDMRSpace1() const {return true;}; - virtual bool hasDMRSpace2() const {return true;}; - virtual bool hasYSFSpace() const {return true;}; - virtual bool hasP25Space() const {return true;}; - virtual bool hasNXDNSpace() const {return true;}; - virtual bool hasPOCSAGSpace() const{return true;}; + virtual bool hasDStarSpace()const { return true; }; + virtual bool hasDMRSpace1() const { return true; }; + virtual bool hasDMRSpace2() const { return true; }; + virtual bool hasYSFSpace() const { return true; }; + virtual bool hasP25Space() const { return true; }; + virtual bool hasNXDNSpace() const { return true; }; + virtual bool hasPOCSAGSpace() const { return true; }; + virtual unsigned int getFMSpace() const { return true; }; + virtual bool hasAX25Space() const { return true; }; - virtual bool hasTX() const {return false;}; - virtual bool hasCD() const {return false;}; + virtual bool hasTX() const { return false; }; + virtual bool hasCD() const { return false; }; - virtual bool hasLockout() const {return false;}; - virtual bool hasError() const {return false;}; + virtual bool hasLockout() const { return false; }; + virtual bool hasError() const { return false; }; - virtual bool writeDStarData(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeDMRData1(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeDMRData2(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeYSFData(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeP25Data(const unsigned char* data, unsigned int length){return true;}; - virtual bool writeNXDNData(const unsigned char* data, unsigned int length){return true;}; - virtual bool writePOCSAGData(const unsigned char* data, unsigned int length){return true;}; + virtual bool writeDStarData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeDMRData1(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeDMRData2(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeYSFData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeP25Data(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeNXDNData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writePOCSAGData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeFMData(const unsigned char* data, unsigned int length) { return true; }; + virtual bool writeAX25Data(const unsigned char* data, unsigned int length) { return true; }; - virtual bool writeTransparentData(const unsigned char* data, unsigned int length){return true;}; + virtual bool writeTransparentData(const unsigned char* data, unsigned int length) { return true; }; - virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector){return true;}; - virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type){return true;}; - virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin){return true;}; - virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type){return true;}; - virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type){return true;}; - virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message){return true;}; - virtual bool writeIPInfo(const std::string& address){return true;}; + virtual bool writeConfig() { return true; }; + virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { return true; }; + virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) { return true; }; + virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin) { return true; }; + virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type) { return true; }; + virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type) { return true; }; + virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message) { return true; }; + virtual bool writeIPInfo(const std::string& address) { return true; }; - virtual bool writeDMRStart(bool tx){return true;}; - virtual bool writeDMRShortLC(const unsigned char* lc){return true;}; - virtual bool writeDMRAbort(unsigned int slotNo){return true;}; + virtual bool writeDMRStart(bool tx) { return true; }; + virtual bool writeDMRShortLC(const unsigned char* lc) { return true; }; + virtual bool writeDMRAbort(unsigned int slotNo) { return true; }; - virtual bool writeSerial(const unsigned char* data, unsigned int length){return true;}; + virtual bool writeSerial(const unsigned char* data, unsigned int length) { return true; }; - virtual bool setMode(unsigned char mode){return true;}; + virtual unsigned char getMode() const { return MODE_IDLE; }; + virtual bool setMode(unsigned char mode) { return true; }; - virtual bool sendCWId(const std::string& callsign){return true;}; + virtual bool sendCWId(const std::string& callsign) { return true; }; - virtual HW_TYPE getHWType() const {return m_hwType;}; + virtual HW_TYPE getHWType() const { return HWT_MMDVM; }; - virtual void clock(unsigned int ms){}; + virtual void clock(unsigned int ms) {}; - virtual void close(){}; + virtual void close() {}; private: - HW_TYPE m_hwType; }; #endif diff --git a/PseudoTTYController.cpp b/PseudoTTYController.cpp index 67df4a4..52a4ac9 100644 --- a/PseudoTTYController.cpp +++ b/PseudoTTYController.cpp @@ -37,7 +37,7 @@ CPseudoTTYController::CPseudoTTYController(const std::string& symlink, unsigned int speed, bool assertRTS) : -CSerialController("", speed, assertRTS), +CSerialController(speed, assertRTS), m_symlink(symlink) { } diff --git a/SerialController.cpp b/SerialController.cpp index f48cf70..6352743 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -48,6 +48,14 @@ m_handle(INVALID_HANDLE_VALUE) assert(!device.empty()); } +CSerialController::CSerialController(unsigned int speed, bool assertRTS) : +m_device(), +m_speed(speed), +m_assertRTS(assertRTS), +m_handle(INVALID_HANDLE_VALUE) +{ +} + CSerialController::~CSerialController() { } @@ -228,6 +236,14 @@ m_fd(-1) { } +CSerialController::CSerialController(unsigned int speed, bool assertRTS) : +m_device(), +m_speed(speed), +m_assertRTS(assertRTS), +m_fd(-1) +{ +} + CSerialController::~CSerialController() { } diff --git a/SerialController.h b/SerialController.h index d4cb519..e4adb7d 100644 --- a/SerialController.h +++ b/SerialController.h @@ -46,6 +46,8 @@ public: #endif protected: + CSerialController(unsigned int speed, bool assertRTS = false); + std::string m_device; unsigned int m_speed; bool m_assertRTS; diff --git a/SerialModem.cpp b/SerialModem.cpp new file mode 100644 index 0000000..10ddefa --- /dev/null +++ b/SerialModem.cpp @@ -0,0 +1,2465 @@ +/* + * Copyright (C) 2011-2018,2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "SerialController.h" +#if defined(__linux__) +#include "I2CController.h" +#endif +#include "DStarDefines.h" +#include "DMRDefines.h" +#include "YSFDefines.h" +#include "P25Defines.h" +#include "NXDNDefines.h" +#include "AX25Defines.h" +#include "POCSAGDefines.h" +#include "Thread.h" +#include "SerialModem.h" +#include "NullModem.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include +#include +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +const unsigned char MMDVM_FRAME_START = 0xE0U; + +const unsigned char MMDVM_GET_VERSION = 0x00U; +const unsigned char MMDVM_GET_STATUS = 0x01U; +const unsigned char MMDVM_SET_CONFIG = 0x02U; +const unsigned char MMDVM_SET_MODE = 0x03U; +const unsigned char MMDVM_SET_FREQ = 0x04U; + +const unsigned char MMDVM_SEND_CWID = 0x0AU; + +const unsigned char MMDVM_DSTAR_HEADER = 0x10U; +const unsigned char MMDVM_DSTAR_DATA = 0x11U; +const unsigned char MMDVM_DSTAR_LOST = 0x12U; +const unsigned char MMDVM_DSTAR_EOT = 0x13U; + +const unsigned char MMDVM_DMR_DATA1 = 0x18U; +const unsigned char MMDVM_DMR_LOST1 = 0x19U; +const unsigned char MMDVM_DMR_DATA2 = 0x1AU; +const unsigned char MMDVM_DMR_LOST2 = 0x1BU; +const unsigned char MMDVM_DMR_SHORTLC = 0x1CU; +const unsigned char MMDVM_DMR_START = 0x1DU; +const unsigned char MMDVM_DMR_ABORT = 0x1EU; + +const unsigned char MMDVM_YSF_DATA = 0x20U; +const unsigned char MMDVM_YSF_LOST = 0x21U; + +const unsigned char MMDVM_P25_HDR = 0x30U; +const unsigned char MMDVM_P25_LDU = 0x31U; +const unsigned char MMDVM_P25_LOST = 0x32U; + +const unsigned char MMDVM_NXDN_DATA = 0x40U; +const unsigned char MMDVM_NXDN_LOST = 0x41U; + +const unsigned char MMDVM_POCSAG_DATA = 0x50U; + +const unsigned char MMDVM_AX25_DATA = 0x55U; + +const unsigned char MMDVM_FM_PARAMS1 = 0x60U; +const unsigned char MMDVM_FM_PARAMS2 = 0x61U; +const unsigned char MMDVM_FM_PARAMS3 = 0x62U; +const unsigned char MMDVM_FM_PARAMS4 = 0x63U; +const unsigned char MMDVM_FM_DATA = 0x65U; +const unsigned char MMDVM_FM_CONTROL = 0x66U; +const unsigned char MMDVM_FM_EOT = 0x67U; + +const unsigned char MMDVM_ACK = 0x70U; +const unsigned char MMDVM_NAK = 0x7FU; + +const unsigned char MMDVM_SERIAL = 0x80U; + +const unsigned char MMDVM_TRANSPARENT = 0x90U; +const unsigned char MMDVM_QSO_INFO = 0x91U; + +const unsigned char MMDVM_DEBUG1 = 0xF1U; +const unsigned char MMDVM_DEBUG2 = 0xF2U; +const unsigned char MMDVM_DEBUG3 = 0xF3U; +const unsigned char MMDVM_DEBUG4 = 0xF4U; +const unsigned char MMDVM_DEBUG5 = 0xF5U; + +const unsigned int MAX_RESPONSES = 30U; + +const unsigned int BUFFER_LENGTH = 2000U; + + +CSerialModem::CSerialModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug) : +m_port(port), +m_dmrColorCode(0U), +m_ysfLoDev(false), +m_ysfTXHang(4U), +m_p25TXHang(5U), +m_nxdnTXHang(5U), +m_duplex(duplex), +m_rxInvert(rxInvert), +m_txInvert(txInvert), +m_pttInvert(pttInvert), +m_txDelay(txDelay), +m_dmrDelay(dmrDelay), +m_rxLevel(0.0F), +m_cwIdTXLevel(0.0F), +m_dstarTXLevel(0.0F), +m_dmrTXLevel(0.0F), +m_ysfTXLevel(0.0F), +m_p25TXLevel(0.0F), +m_nxdnTXLevel(0.0F), +m_pocsagTXLevel(0.0F), +m_fmTXLevel(0.0F), +m_ax25TXLevel(0.0F), +m_rfLevel(0.0F), +m_trace(trace), +m_debug(debug), +m_rxFrequency(0U), +m_txFrequency(0U), +m_pocsagFrequency(0U), +m_dstarEnabled(false), +m_dmrEnabled(false), +m_ysfEnabled(false), +m_p25Enabled(false), +m_nxdnEnabled(false), +m_pocsagEnabled(false), +m_fmEnabled(false), +m_ax25Enabled(false), +m_rxDCOffset(0), +m_txDCOffset(0), +m_serial(NULL), +m_buffer(NULL), +m_length(0U), +m_offset(0U), +m_state(SS_START), +m_type(0U), +m_rxDStarData(1000U, "Modem RX D-Star"), +m_txDStarData(1000U, "Modem TX D-Star"), +m_rxDMRData1(1000U, "Modem RX DMR1"), +m_rxDMRData2(1000U, "Modem RX DMR2"), +m_txDMRData1(1000U, "Modem TX DMR1"), +m_txDMRData2(1000U, "Modem TX DMR2"), +m_rxYSFData(1000U, "Modem RX YSF"), +m_txYSFData(1000U, "Modem TX YSF"), +m_rxP25Data(1000U, "Modem RX P25"), +m_txP25Data(1000U, "Modem TX P25"), +m_rxNXDNData(1000U, "Modem RX NXDN"), +m_txNXDNData(1000U, "Modem TX NXDN"), +m_txPOCSAGData(1000U, "Modem TX POCSAG"), +m_rxFMData(5000U, "Modem RX FM"), +m_txFMData(5000U, "Modem TX FM"), +m_rxAX25Data(1000U, "Modem RX AX.25"), +m_txAX25Data(1000U, "Modem TX AX.25"), +m_rxTransparentData(1000U, "Modem RX Transparent"), +m_txTransparentData(1000U, "Modem TX Transparent"), +m_sendTransparentDataFrameType(0U), +m_statusTimer(1000U, 0U, 250U), +m_inactivityTimer(1000U, 2U), +m_playoutTimer(1000U, 0U, 10U), +m_dstarSpace(0U), +m_dmrSpace1(0U), +m_dmrSpace2(0U), +m_ysfSpace(0U), +m_p25Space(0U), +m_nxdnSpace(0U), +m_pocsagSpace(0U), +m_fmSpace(0U), +m_ax25Space(0U), +m_tx(false), +m_cd(false), +m_lockout(false), +m_error(false), +m_mode(MODE_IDLE), +m_hwType(HWT_UNKNOWN), +m_ax25RXTwist(0), +m_ax25TXDelay(300U), +m_fmCallsign(), +m_fmCallsignSpeed(20U), +m_fmCallsignFrequency(1000U), +m_fmCallsignTime(600U), +m_fmCallsignHoldoff(0U), +m_fmCallsignHighLevel(35.0F), +m_fmCallsignLowLevel(15.0F), +m_fmCallsignAtStart(true), +m_fmCallsignAtEnd(true), +m_fmCallsignAtLatch(true), +m_fmRfAck("K"), +m_fmExtAck("N"), +m_fmAckSpeed(20U), +m_fmAckFrequency(1750U), +m_fmAckMinTime(4U), +m_fmAckDelay(1000U), +m_fmAckLevel(80.0F), +m_fmTimeout(120U), +m_fmTimeoutLevel(80.0F), +m_fmCtcssFrequency(88.4F), +m_fmCtcssHighThreshold(30U), +m_fmCtcssLowThreshold(20U), +m_fmCtcssLevel(10.0F), +m_fmKerchunkTime(0U), +m_fmKerchunkTX(true), +m_fmHangTime(5U), +m_fmUseCOS(true), +m_fmCOSInvert(false), +m_fmRFAudioBoost(1U), +m_fmExtAudioBoost(1U), +m_fmMaxDevLevel(90.0F), +m_fmExtEnable(false) +{ + m_buffer = new unsigned char[BUFFER_LENGTH]; + + assert(!port.empty()); +} + +CSerialModem::~CSerialModem() +{ + delete m_serial; + delete[] m_buffer; +} + +void CSerialModem::setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed) +{ + // Create the serial controller instance according the protocol specified in conf. +#if defined(__linux__) + if (protocol == "i2c") + m_serial = new CI2CController(m_port, address); + else +#endif + m_serial = new CSerialController(m_port, speed, true); +} + +void CSerialModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) +{ + m_rxFrequency = rxFrequency + rxOffset; + m_txFrequency = txFrequency + txOffset; + m_txDCOffset = txDCOffset; + m_rxDCOffset = rxDCOffset; + m_rfLevel = rfLevel; + m_pocsagFrequency = pocsagFrequency + txOffset; +} + +void CSerialModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled) +{ + m_dstarEnabled = dstarEnabled; + m_dmrEnabled = dmrEnabled; + m_ysfEnabled = ysfEnabled; + m_p25Enabled = p25Enabled; + m_nxdnEnabled = nxdnEnabled; + m_pocsagEnabled = pocsagEnabled; + m_fmEnabled = fmEnabled; + m_ax25Enabled = ax25Enabled; +} + +void CSerialModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel, float ax25TXLevel) +{ + m_rxLevel = rxLevel; + m_cwIdTXLevel = cwIdTXLevel; + m_dstarTXLevel = dstarTXLevel; + m_dmrTXLevel = dmrTXLevel; + m_ysfTXLevel = ysfTXLevel; + m_p25TXLevel = p25TXLevel; + m_nxdnTXLevel = nxdnTXLevel; + m_pocsagTXLevel = pocsagTXLevel; + m_fmTXLevel = fmTXLevel; + m_ax25TXLevel = ax25TXLevel; +} + +void CSerialModem::setDMRParams(unsigned int colorCode) +{ + assert(colorCode < 16U); + + m_dmrColorCode = colorCode; +} + +void CSerialModem::setYSFParams(bool loDev, unsigned int txHang) +{ + m_ysfLoDev = loDev; + m_ysfTXHang = txHang; +} + +void CSerialModem::setP25Params(unsigned int txHang) +{ + m_p25TXHang = txHang; +} + +void CSerialModem::setNXDNParams(unsigned int txHang) +{ + m_nxdnTXHang = txHang; +} + +void CSerialModem::setAX25Params(int rxTwist, unsigned int txDelay) +{ + m_ax25RXTwist = rxTwist; + m_ax25TXDelay = txDelay; +} + +void CSerialModem::setTransparentDataParams(unsigned int sendFrameType) +{ + m_sendTransparentDataFrameType = sendFrameType; +} + +bool CSerialModem::open() +{ + ::LogMessage("Opening the MMDVM"); + + bool ret = m_serial->open(); + if (!ret) + return false; + + ret = readVersion(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } else { + /* Stopping the inactivity timer here when a firmware version has been + successfuly read prevents the death spiral of "no reply from modem..." */ + m_inactivityTimer.stop(); + } + + ret = setFrequency(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + ret = setConfig(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + if (m_fmEnabled && m_duplex) { + ret = setFMCallsignParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + ret = setFMAckParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + ret = setFMMiscParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + if (m_fmExtEnable) { + ret = setFMExtParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + } + } + + m_statusTimer.start(); + + m_error = false; + m_offset = 0U; + + return true; +} + +void CSerialModem::clock(unsigned int ms) +{ + assert(m_serial != NULL); + + // Poll the modem status every 250ms + m_statusTimer.clock(ms); + if (m_statusTimer.hasExpired()) { + readStatus(); + m_statusTimer.start(); + } + + m_inactivityTimer.clock(ms); + if (m_inactivityTimer.hasExpired()) { + LogError("No reply from the modem for some time, resetting it"); + m_error = true; + close(); + + CThread::sleep(2000U); // 2s + while (!open()) + CThread::sleep(5000U); // 5s + } + + RESP_TYPE_MMDVM type = getResponse(); + + if (type == RTM_TIMEOUT) { + // Nothing to do + } else if (type == RTM_ERROR) { + // Nothing to do + } else { + // type == RTM_OK + switch (m_type) { + case MMDVM_DSTAR_HEADER: { + if (m_trace) + CUtils::dump(1U, "RX D-Star Header", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxDStarData.addData(&data, 1U); + + data = TAG_HEADER; + m_rxDStarData.addData(&data, 1U); + + m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_DSTAR_DATA: { + if (m_trace) + CUtils::dump(1U, "RX D-Star Data", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxDStarData.addData(&data, 1U); + + data = TAG_DATA; + m_rxDStarData.addData(&data, 1U); + + m_rxDStarData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_DSTAR_LOST: { + if (m_trace) + CUtils::dump(1U, "RX D-Star Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxDStarData.addData(&data, 1U); + + data = TAG_LOST; + m_rxDStarData.addData(&data, 1U); + } + break; + + case MMDVM_DSTAR_EOT: { + if (m_trace) + CUtils::dump(1U, "RX D-Star EOT", m_buffer, m_length); + + unsigned char data = 1U; + m_rxDStarData.addData(&data, 1U); + + data = TAG_EOT; + m_rxDStarData.addData(&data, 1U); + } + break; + + case MMDVM_DMR_DATA1: { + if (m_trace) + CUtils::dump(1U, "RX DMR Data 1", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxDMRData1.addData(&data, 1U); + + if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) + data = TAG_EOT; + else + data = TAG_DATA; + m_rxDMRData1.addData(&data, 1U); + + m_rxDMRData1.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_DMR_DATA2: { + if (m_trace) + CUtils::dump(1U, "RX DMR Data 2", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxDMRData2.addData(&data, 1U); + + if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC)) + data = TAG_EOT; + else + data = TAG_DATA; + m_rxDMRData2.addData(&data, 1U); + + m_rxDMRData2.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_DMR_LOST1: { + if (m_trace) + CUtils::dump(1U, "RX DMR Lost 1", m_buffer, m_length); + + unsigned char data = 1U; + m_rxDMRData1.addData(&data, 1U); + + data = TAG_LOST; + m_rxDMRData1.addData(&data, 1U); + } + break; + + case MMDVM_DMR_LOST2: { + if (m_trace) + CUtils::dump(1U, "RX DMR Lost 2", m_buffer, m_length); + + unsigned char data = 1U; + m_rxDMRData2.addData(&data, 1U); + + data = TAG_LOST; + m_rxDMRData2.addData(&data, 1U); + } + break; + + case MMDVM_YSF_DATA: { + if (m_trace) + CUtils::dump(1U, "RX YSF Data", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxYSFData.addData(&data, 1U); + + data = TAG_DATA; + m_rxYSFData.addData(&data, 1U); + + m_rxYSFData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_YSF_LOST: { + if (m_trace) + CUtils::dump(1U, "RX YSF Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxYSFData.addData(&data, 1U); + + data = TAG_LOST; + m_rxYSFData.addData(&data, 1U); + } + break; + + case MMDVM_P25_HDR: { + if (m_trace) + CUtils::dump(1U, "RX P25 Header", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_HEADER; + m_rxP25Data.addData(&data, 1U); + + m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_P25_LDU: { + if (m_trace) + CUtils::dump(1U, "RX P25 LDU", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_DATA; + m_rxP25Data.addData(&data, 1U); + + m_rxP25Data.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_P25_LOST: { + if (m_trace) + CUtils::dump(1U, "RX P25 Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_LOST; + m_rxP25Data.addData(&data, 1U); + } + break; + + case MMDVM_NXDN_DATA: { + if (m_trace) + CUtils::dump(1U, "RX NXDN Data", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxNXDNData.addData(&data, 1U); + + data = TAG_DATA; + m_rxNXDNData.addData(&data, 1U); + + m_rxNXDNData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_NXDN_LOST: { + if (m_trace) + CUtils::dump(1U, "RX NXDN Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxNXDNData.addData(&data, 1U); + + data = TAG_LOST; + m_rxNXDNData.addData(&data, 1U); + } + break; + + case MMDVM_FM_DATA: { + if (m_trace) + CUtils::dump(1U, "RX FM Data", m_buffer, m_length); + + unsigned int data1 = m_length - m_offset + 1U; + m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int)); + + unsigned char data2 = TAG_DATA; + m_rxFMData.addData(&data2, 1U); + + m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_FM_CONTROL: { + if (m_trace) + CUtils::dump(1U, "RX FM Control", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxFMData.addData(&data, 1U); + + data = TAG_HEADER; + m_rxFMData.addData(&data, 1U); + + m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_FM_EOT: { + if(m_trace) + CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length); + + unsigned char data = m_length - m_offset + 1U; + m_rxFMData.addData(&data, 1U); + + data = TAG_EOT; + m_rxFMData.addData(&data, 1U); + + m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_AX25_DATA: { + if (m_trace) + CUtils::dump(1U, "RX AX.25 Data", m_buffer, m_length); + + unsigned int data = m_length - m_offset; + m_rxAX25Data.addData((unsigned char*)&data, sizeof(unsigned int)); + + m_rxAX25Data.addData(m_buffer + m_offset, m_length - m_offset); + } + break; + + case MMDVM_GET_STATUS: { + // if (m_trace) + // CUtils::dump(1U, "GET_STATUS", m_buffer, m_length); + + m_p25Space = 0U; + m_nxdnSpace = 0U; + m_pocsagSpace = 0U; + m_fmSpace = 0U; + m_ax25Space = 0U; + + m_mode = m_buffer[m_offset + 1U]; + + m_tx = (m_buffer[m_offset + 2U] & 0x01U) == 0x01U; + + bool adcOverflow = (m_buffer[m_offset + 2U] & 0x02U) == 0x02U; + if (adcOverflow) + LogError("MMDVM ADC levels have overflowed"); + + bool rxOverflow = (m_buffer[m_offset + 2U] & 0x04U) == 0x04U; + if (rxOverflow) + LogError("MMDVM RX buffer has overflowed"); + + bool txOverflow = (m_buffer[m_offset + 2U] & 0x08U) == 0x08U; + if (txOverflow) + LogError("MMDVM TX buffer has overflowed"); + + m_lockout = (m_buffer[m_offset + 2U] & 0x10U) == 0x10U; + + bool dacOverflow = (m_buffer[m_offset + 2U] & 0x20U) == 0x20U; + if (dacOverflow) + LogError("MMDVM DAC levels have overflowed"); + + m_cd = (m_buffer[m_offset + 2U] & 0x40U) == 0x40U; + + m_dstarSpace = m_buffer[m_offset + 3U]; + m_dmrSpace1 = m_buffer[m_offset + 4U]; + m_dmrSpace2 = m_buffer[m_offset + 5U]; + m_ysfSpace = m_buffer[m_offset + 6U]; + + if (m_length > (m_offset + 7U)) + m_p25Space = m_buffer[m_offset + 7U]; + if (m_length > (m_offset + 8U)) + m_nxdnSpace = m_buffer[m_offset + 8U]; + if (m_length > (m_offset + 9U)) + m_pocsagSpace = m_buffer[m_offset + 9U]; + if (m_length > (m_offset + 10U)) + m_fmSpace = m_buffer[m_offset + 10U]; + if (m_length > (m_offset + 11U)) + m_ax25Space = m_buffer[m_offset + 11U]; + + m_inactivityTimer.start(); + // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, m_fmSpace, m_ax25Space, int(m_lockout), int(m_cd)); + } + break; + + case MMDVM_TRANSPARENT: { + if (m_trace) + CUtils::dump(1U, "RX Transparent Data", m_buffer, m_length); + + unsigned char offset = m_sendTransparentDataFrameType; + if (offset > 1U) offset = 1U; + unsigned char data = m_length - m_offset + offset; + m_rxTransparentData.addData(&data, 1U); + + m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); + } + break; + + // These should not be received, but don't complain if we do + case MMDVM_GET_VERSION: + case MMDVM_ACK: + break; + + case MMDVM_NAK: + LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[m_offset], m_buffer[m_offset + 1U]); + break; + + case MMDVM_DEBUG1: + case MMDVM_DEBUG2: + case MMDVM_DEBUG3: + case MMDVM_DEBUG4: + case MMDVM_DEBUG5: + printDebug(); + break; + + case MMDVM_SERIAL: + //MMDVMHost does not process serial data from the display, + // so we send it to the transparent port if sendFrameType==1 + if (m_sendTransparentDataFrameType > 0U) { + if (m_trace) + CUtils::dump(1U, "RX Serial Data", m_buffer, m_length); + + unsigned char offset = m_sendTransparentDataFrameType; + if (offset > 1U) offset = 1U; + unsigned char data = m_length - m_offset + offset; + m_rxTransparentData.addData(&data, 1U); + + m_rxTransparentData.addData(m_buffer + m_offset - offset, m_length - m_offset + offset); + break; //only break when sendFrameType>0, else message is unknown + } + default: + LogMessage("Unknown message, type: %02X", m_type); + CUtils::dump("Buffer dump", m_buffer, m_length); + break; + } + } + + // Only feed data to the modem if the playout timer has expired + m_playoutTimer.clock(ms); + if (!m_playoutTimer.hasExpired()) + return; + + if (m_dstarSpace > 1U && !m_txDStarData.isEmpty()) { + unsigned char buffer[4U]; + m_txDStarData.peek(buffer, 4U); + + if ((buffer[3U] == MMDVM_DSTAR_HEADER && m_dstarSpace > 4U) || + (buffer[3U] == MMDVM_DSTAR_DATA && m_dstarSpace > 1U) || + (buffer[3U] == MMDVM_DSTAR_EOT && m_dstarSpace > 1U)) { + unsigned char len = 0U; + m_txDStarData.getData(&len, 1U); + m_txDStarData.getData(m_buffer, len); + + switch (buffer[3U]) { + case MMDVM_DSTAR_HEADER: + if (m_trace) + CUtils::dump(1U, "TX D-Star Header", m_buffer, len); + m_dstarSpace -= 4U; + break; + case MMDVM_DSTAR_DATA: + if (m_trace) + CUtils::dump(1U, "TX D-Star Data", m_buffer, len); + m_dstarSpace -= 1U; + break; + default: + if (m_trace) + CUtils::dump(1U, "TX D-Star EOT", m_buffer, len); + m_dstarSpace -= 1U; + break; + } + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing D-Star data to the MMDVM"); + + m_playoutTimer.start(); + } + } + + if (m_dmrSpace1 > 1U && !m_txDMRData1.isEmpty()) { + unsigned char len = 0U; + m_txDMRData1.getData(&len, 1U); + m_txDMRData1.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX DMR Data 1", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing DMR data to the MMDVM"); + + m_playoutTimer.start(); + + m_dmrSpace1--; + } + + if (m_dmrSpace2 > 1U && !m_txDMRData2.isEmpty()) { + unsigned char len = 0U; + m_txDMRData2.getData(&len, 1U); + m_txDMRData2.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX DMR Data 2", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing DMR data to the MMDVM"); + + m_playoutTimer.start(); + + m_dmrSpace2--; + } + + if (m_ysfSpace > 1U && !m_txYSFData.isEmpty()) { + unsigned char len = 0U; + m_txYSFData.getData(&len, 1U); + m_txYSFData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX YSF Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing YSF data to the MMDVM"); + + m_playoutTimer.start(); + + m_ysfSpace--; + } + + if (m_p25Space > 1U && !m_txP25Data.isEmpty()) { + unsigned char len = 0U; + m_txP25Data.getData(&len, 1U); + m_txP25Data.getData(m_buffer, len); + + if (m_trace) { + if (m_buffer[2U] == MMDVM_P25_HDR) + CUtils::dump(1U, "TX P25 HDR", m_buffer, len); + else + CUtils::dump(1U, "TX P25 LDU", m_buffer, len); + } + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing P25 data to the MMDVM"); + + m_playoutTimer.start(); + + m_p25Space--; + } + + if (m_nxdnSpace > 1U && !m_txNXDNData.isEmpty()) { + unsigned char len = 0U; + m_txNXDNData.getData(&len, 1U); + m_txNXDNData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX NXDN Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing NXDN data to the MMDVM"); + + m_playoutTimer.start(); + + m_nxdnSpace--; + } + + if (m_pocsagSpace > 1U && !m_txPOCSAGData.isEmpty()) { + unsigned char len = 0U; + m_txPOCSAGData.getData(&len, 1U); + m_txPOCSAGData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX POCSAG Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing POCSAG data to the MMDVM"); + + m_playoutTimer.start(); + + m_pocsagSpace--; + } + + if (m_fmSpace > 1U && !m_txFMData.isEmpty()) { + unsigned char len = 0U; + m_txFMData.getData(&len, 1U); + m_txFMData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX FM Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing FM data to the MMDVM"); + + m_playoutTimer.start(); + + m_fmSpace--; + } + + if (m_ax25Space > 0U && !m_txAX25Data.isEmpty()) { + unsigned char len = 0U; + m_txAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); + m_txAX25Data.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX AX.25 Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing AX.25 data to the MMDVM"); + + m_playoutTimer.start(); + + m_ax25Space = 0U; + } + + if (!m_txTransparentData.isEmpty()) { + unsigned char len = 0U; + m_txTransparentData.getData(&len, 1U); + m_txTransparentData.getData(m_buffer, len); + + if (m_trace) + CUtils::dump(1U, "TX Transparent Data", m_buffer, len); + + int ret = m_serial->write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing Transparent data to the MMDVM"); + } +} + +void CSerialModem::close() +{ + assert(m_serial != NULL); + + ::LogMessage("Closing the MMDVM"); + + m_serial->close(); +} + +unsigned int CSerialModem::readDStarData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxDStarData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxDStarData.getData(&len, 1U); + m_rxDStarData.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readDMRData1(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxDMRData1.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxDMRData1.getData(&len, 1U); + m_rxDMRData1.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readDMRData2(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxDMRData2.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxDMRData2.getData(&len, 1U); + m_rxDMRData2.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readYSFData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxYSFData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxYSFData.getData(&len, 1U); + m_rxYSFData.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readP25Data(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxP25Data.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxP25Data.getData(&len, 1U); + m_rxP25Data.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readNXDNData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxNXDNData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxNXDNData.getData(&len, 1U); + m_rxNXDNData.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readFMData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxFMData.isEmpty()) + return 0U; + + unsigned int len = 0U; + m_rxFMData.getData((unsigned char*)&len, sizeof(unsigned int)); + m_rxFMData.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readAX25Data(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxAX25Data.isEmpty()) + return 0U; + + unsigned int len = 0U; + m_rxAX25Data.getData((unsigned char*)&len, sizeof(unsigned int)); + m_rxAX25Data.getData(data, len); + + return len; +} + +unsigned int CSerialModem::readTransparentData(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxTransparentData.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxTransparentData.getData(&len, 1U); + m_rxTransparentData.getData(data, len); + + return len; +} + +// To be implemented later if needed +unsigned int CSerialModem::readSerial(unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + return 0U; +} + +bool CSerialModem::hasDStarSpace() const +{ + unsigned int space = m_txDStarData.freeSpace() / (DSTAR_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeDStarData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[50U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + + switch (data[0U]) { + case TAG_HEADER: + buffer[2U] = MMDVM_DSTAR_HEADER; + break; + case TAG_DATA: + buffer[2U] = MMDVM_DSTAR_DATA; + break; + case TAG_EOT: + buffer[2U] = MMDVM_DSTAR_EOT; + break; + default: + CUtils::dump(2U, "Unknown D-Star packet type", data, length); + return false; + } + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txDStarData.addData(&len, 1U); + m_txDStarData.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasDMRSpace1() const +{ + unsigned int space = m_txDMRData1.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::hasDMRSpace2() const +{ + unsigned int space = m_txDMRData2.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeDMRData1(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[40U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = MMDVM_DMR_DATA1; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txDMRData1.addData(&len, 1U); + m_txDMRData1.addData(buffer, len); + + return true; +} + +bool CSerialModem::writeDMRData2(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[40U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = MMDVM_DMR_DATA2; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txDMRData2.addData(&len, 1U); + m_txDMRData2.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasYSFSpace() const +{ + unsigned int space = m_txYSFData.freeSpace() / (YSF_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeYSFData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[130U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = MMDVM_YSF_DATA; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txYSFData.addData(&len, 1U); + m_txYSFData.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasP25Space() const +{ + unsigned int space = m_txP25Data.freeSpace() / (P25_LDU_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeP25Data(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_HEADER && data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = (data[0U] == TAG_HEADER) ? MMDVM_P25_HDR : MMDVM_P25_LDU; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txP25Data.addData(&len, 1U); + m_txP25Data.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasNXDNSpace() const +{ + unsigned int space = m_txNXDNData.freeSpace() / (NXDN_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writeNXDNData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[130U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = MMDVM_NXDN_DATA; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txNXDNData.addData(&len, 1U); + m_txNXDNData.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasPOCSAGSpace() const +{ + unsigned int space = m_txPOCSAGData.freeSpace() / (POCSAG_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CSerialModem::writePOCSAGData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[130U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_POCSAG_DATA; + + ::memcpy(buffer + 3U, data, length); + + unsigned char len = length + 3U; + m_txPOCSAGData.addData(&len, 1U); + m_txPOCSAGData.addData(buffer, len); + + return true; +} + +unsigned int CSerialModem::getFMSpace() const +{ + return m_txFMData.freeSpace(); +} + +bool CSerialModem::writeFMData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[500U]; + + unsigned int len; + if (length > 252U) { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 0U; + buffer[2U] = (length + 4U) - 255U; + buffer[3U] = MMDVM_FM_DATA; + ::memcpy(buffer + 4U, data, length); + len = length + 4U; + } else { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_FM_DATA; + ::memcpy(buffer + 3U, data, length); + len = length + 3U; + } + + m_txFMData.addData((unsigned char*)&len, sizeof(unsigned int)); + m_txFMData.addData(buffer, len); + + return true; +} + +bool CSerialModem::hasAX25Space() const +{ + unsigned int space = m_txAX25Data.freeSpace() / (AX25_MAX_FRAME_LENGTH_BYTES + 5U); + + return space > 1U; +} + +bool CSerialModem::writeAX25Data(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[500U]; + + unsigned int len; + if (length > 252U) { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 0U; + buffer[2U] = (length + 4U) - 255U; + buffer[3U] = MMDVM_AX25_DATA; + ::memcpy(buffer + 4U, data, length); + len = length + 4U; + } else { + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_AX25_DATA; + ::memcpy(buffer + 3U, data, length); + len = length + 3U; + } + + m_txAX25Data.addData((unsigned char*)&len, sizeof(unsigned int)); + m_txAX25Data.addData(buffer, len); + + return true; +} + +bool CSerialModem::writeTransparentData(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_TRANSPARENT; + + if (m_sendTransparentDataFrameType > 0U) { + ::memcpy(buffer + 2U, data, length); + length--; + buffer[1U]--; + + //when sendFrameType==1 , only 0x80 and 0x90 (MMDVM_SERIAL and MMDVM_TRANSPARENT) are allowed + // and reverted to default (MMDVM_TRANSPARENT) for any other value + //when >1, frame type is not checked + if (m_sendTransparentDataFrameType == 1U) { + if ((buffer[2U] & 0xE0) != 0x80) + buffer[2U] = MMDVM_TRANSPARENT; + } + } else { + ::memcpy(buffer + 3U, data, length); + } + + unsigned char len = length + 3U; + m_txTransparentData.addData(&len, 1U); + m_txTransparentData.addData(buffer, len); + + return true; +} + +bool CSerialModem::writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) +{ + assert(m_serial != NULL); + assert(my1 != NULL); + assert(my2 != NULL); + assert(your != NULL); + assert(type != NULL); + assert(reflector != NULL); + + unsigned char buffer[50U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 33U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_DSTAR; + + ::memcpy(buffer + 4U, my1, DSTAR_LONG_CALLSIGN_LENGTH); + ::memcpy(buffer + 12U, my2, DSTAR_SHORT_CALLSIGN_LENGTH); + + ::memcpy(buffer + 16U, your, DSTAR_LONG_CALLSIGN_LENGTH); + + ::memcpy(buffer + 24U, type, 1U); + + ::memcpy(buffer + 25U, reflector, DSTAR_LONG_CALLSIGN_LENGTH); + + return m_serial->write(buffer, 33U) != 33; +} + +bool CSerialModem::writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dest, const char* type) +{ + assert(m_serial != NULL); + assert(type != NULL); + + unsigned char buffer[50U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 47U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_DMR; + + buffer[4U] = slotNo; + + ::sprintf((char*)(buffer + 5U), "%20.20s", src.c_str()); + + buffer[25U] = group ? 'G' : 'I'; + + ::sprintf((char*)(buffer + 26U), "%20.20s", dest.c_str()); + + ::memcpy(buffer + 46U, type, 1U); + + return m_serial->write(buffer, 47U) != 47; +} + +bool CSerialModem::writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin) +{ + assert(m_serial != NULL); + assert(source != NULL); + assert(dest != NULL); + assert(type != NULL); + assert(origin != NULL); + + unsigned char buffer[50U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 35U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_YSF; + + ::memcpy(buffer + 4U, source, YSF_CALLSIGN_LENGTH); + ::memcpy(buffer + 14U, dest, YSF_CALLSIGN_LENGTH); + + ::memcpy(buffer + 24U, type, 1U); + + ::memcpy(buffer + 25U, origin, YSF_CALLSIGN_LENGTH); + + return m_serial->write(buffer, 35U) != 35; +} + +bool CSerialModem::writeP25Info(const char* source, bool group, unsigned int dest, const char* type) +{ + assert(m_serial != NULL); + assert(source != NULL); + assert(type != NULL); + + unsigned char buffer[40U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 31U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_DMR; + + ::sprintf((char*)(buffer + 4U), "%20.20s", source); + + buffer[24U] = group ? 'G' : 'I'; + + ::sprintf((char*)(buffer + 25U), "%05u", dest); // 16-bits + + ::memcpy(buffer + 30U, type, 1U); + + return m_serial->write(buffer, 31U) != 31; +} + +bool CSerialModem::writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type) +{ + assert(m_serial != NULL); + assert(source != NULL); + assert(type != NULL); + + unsigned char buffer[40U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 31U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_NXDN; + + ::sprintf((char*)(buffer + 4U), "%20.20s", source); + + buffer[24U] = group ? 'G' : 'I'; + + ::sprintf((char*)(buffer + 25U), "%05u", dest); // 16-bits + + ::memcpy(buffer + 30U, type, 1U); + + return m_serial->write(buffer, 31U) != 31; +} + +bool CSerialModem::writePOCSAGInfo(unsigned int ric, const std::string& message) +{ + assert(m_serial != NULL); + + size_t length = message.size(); + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 11U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = MODE_POCSAG; + + ::sprintf((char*)(buffer + 4U), "%07u", ric); // 21-bits + + ::memcpy(buffer + 11U, message.c_str(), length); + + int ret = m_serial->write(buffer, length + 11U); + + return ret != int(length + 11U); +} + +bool CSerialModem::writeIPInfo(const std::string& address) +{ + assert(m_serial != NULL); + + size_t length = address.size(); + + unsigned char buffer[25U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 4U; + buffer[2U] = MMDVM_QSO_INFO; + + buffer[3U] = 250U; + + ::memcpy(buffer + 4U, address.c_str(), length); + + int ret = m_serial->write(buffer, length + 4U); + + return ret != int(length + 4U); +} + +bool CSerialModem::writeSerial(const unsigned char* data, unsigned int length) +{ + assert(m_serial != NULL); + assert(data != NULL); + assert(length > 0U); + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_SERIAL; + + ::memcpy(buffer + 3U, data, length); + + int ret = m_serial->write(buffer, length + 3U); + + return ret != int(length + 3U); +} + +bool CSerialModem::hasTX() const +{ + return m_tx; +} + +bool CSerialModem::hasCD() const +{ + return m_cd; +} + +bool CSerialModem::hasLockout() const +{ + return m_lockout; +} + +bool CSerialModem::hasError() const +{ + return m_error; +} + +bool CSerialModem::readVersion() +{ + assert(m_serial != NULL); + + CThread::sleep(2000U); // 2s + + for (unsigned int i = 0U; i < 6U; i++) { + unsigned char buffer[3U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 3U; + buffer[2U] = MMDVM_GET_VERSION; + + // CUtils::dump(1U, "Written", buffer, 3U); + + int ret = m_serial->write(buffer, 3U); + if (ret != 3) + return false; + +#if defined(__APPLE__) + m_serial->setNonblock(true); +#endif + + for (unsigned int count = 0U; count < MAX_RESPONSES; count++) { + CThread::sleep(10U); + RESP_TYPE_MMDVM resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] == MMDVM_GET_VERSION) { + if (::memcmp(m_buffer + 4U, "MMDVM ", 6U) == 0) + m_hwType = HWT_MMDVM; + else if (::memcmp(m_buffer + 4U, "DVMEGA", 6U) == 0) + m_hwType = HWT_DVMEGA; + else if (::memcmp(m_buffer + 4U, "ZUMspot", 7U) == 0) + m_hwType = HWT_MMDVM_ZUMSPOT; + else if (::memcmp(m_buffer + 4U, "MMDVM_HS_Hat", 12U) == 0) + m_hwType = HWT_MMDVM_HS_HAT; + else if (::memcmp(m_buffer + 4U, "MMDVM_HS_Dual_Hat", 17U) == 0) + m_hwType = HWT_MMDVM_HS_DUAL_HAT; + else if (::memcmp(m_buffer + 4U, "Nano_hotSPOT", 12U) == 0) + m_hwType = HWT_NANO_HOTSPOT; + else if (::memcmp(m_buffer + 4U, "Nano_DV", 7U) == 0) + m_hwType = HWT_NANO_DV; + else if (::memcmp(m_buffer + 4U, "D2RG_MMDVM_HS", 13U) == 0) + m_hwType = HWT_D2RG_MMDVM_HS; + else if (::memcmp(m_buffer + 4U, "MMDVM_HS-", 9U) == 0) + m_hwType = HWT_MMDVM_HS; + else if (::memcmp(m_buffer + 4U, "OpenGD77_HS", 11U) == 0) + m_hwType = HWT_OPENGD77_HS; + + LogInfo("MMDVM protocol version: %u, description: %.*s", m_buffer[3U], m_length - 4U, m_buffer + 4U); + return true; + } + } + + CThread::sleep(1500U); + } + + LogError("Unable to read the firmware version after six attempts"); + + return false; +} + +bool CSerialModem::readStatus() +{ + assert(m_serial != NULL); + + unsigned char buffer[3U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 3U; + buffer[2U] = MMDVM_GET_STATUS; + + // CUtils::dump(1U, "Written", buffer, 3U); + + return m_serial->write(buffer, 3U) == 3; +} + +bool CSerialModem::writeConfig() +{ + return setConfig(); +} + +bool CSerialModem::setConfig() +{ + assert(m_serial != NULL); + + unsigned char buffer[30U]; + + buffer[0U] = MMDVM_FRAME_START; + + buffer[1U] = 27U; + + buffer[2U] = MMDVM_SET_CONFIG; + + buffer[3U] = 0x00U; + if (m_rxInvert) + buffer[3U] |= 0x01U; + if (m_txInvert) + buffer[3U] |= 0x02U; + if (m_pttInvert) + buffer[3U] |= 0x04U; + if (m_ysfLoDev) + buffer[3U] |= 0x08U; + if (m_debug) + buffer[3U] |= 0x10U; + if (!m_duplex) + buffer[3U] |= 0x80U; + + buffer[4U] = 0x00U; + if (m_dstarEnabled) + buffer[4U] |= 0x01U; + if (m_dmrEnabled) + buffer[4U] |= 0x02U; + if (m_ysfEnabled) + buffer[4U] |= 0x04U; + if (m_p25Enabled) + buffer[4U] |= 0x08U; + if (m_nxdnEnabled) + buffer[4U] |= 0x10U; + if (m_pocsagEnabled) + buffer[4U] |= 0x20U; + if (m_fmEnabled && m_duplex) + buffer[4U] |= 0x40U; + if (m_ax25Enabled) + buffer[4U] |= 0x80U; + + buffer[5U] = m_txDelay / 10U; // In 10ms units + + buffer[6U] = MODE_IDLE; + + buffer[7U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); + + buffer[8U] = (unsigned char)(m_cwIdTXLevel * 2.55F + 0.5F); + + buffer[9U] = m_dmrColorCode; + + buffer[10U] = m_dmrDelay; + + buffer[11U] = 128U; // Was OscOffset + + buffer[12U] = (unsigned char)(m_dstarTXLevel * 2.55F + 0.5F); + buffer[13U] = (unsigned char)(m_dmrTXLevel * 2.55F + 0.5F); + buffer[14U] = (unsigned char)(m_ysfTXLevel * 2.55F + 0.5F); + buffer[15U] = (unsigned char)(m_p25TXLevel * 2.55F + 0.5F); + + buffer[16U] = (unsigned char)(m_txDCOffset + 128); + buffer[17U] = (unsigned char)(m_rxDCOffset + 128); + + buffer[18U] = (unsigned char)(m_nxdnTXLevel * 2.55F + 0.5F); + + buffer[19U] = (unsigned char)m_ysfTXHang; + + buffer[20U] = (unsigned char)(m_pocsagTXLevel * 2.55F + 0.5F); + + buffer[21U] = (unsigned char)(m_fmTXLevel * 2.55F + 0.5F); + + buffer[22U] = (unsigned char)m_p25TXHang; + + buffer[23U] = (unsigned char)m_nxdnTXHang; + + buffer[24U] = (unsigned char)(m_ax25TXLevel * 2.55F + 0.5F); + + buffer[25U] = (unsigned char)(m_ax25RXTwist + 128); + + buffer[26U] = m_ax25TXDelay / 10U; // In 10ms units + + // CUtils::dump(1U, "Written", buffer, 27U); + + int ret = m_serial->write(buffer, 27U); + if (ret != 27) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_CONFIG command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_CONFIG command from the modem"); + return false; + } + + m_playoutTimer.start(); + + return true; +} + +bool CSerialModem::setFrequency() +{ + assert(m_serial != NULL); + + unsigned char buffer[20U]; + unsigned char len; + unsigned int pocsagFrequency = 433000000U; + + if (m_pocsagEnabled) + pocsagFrequency = m_pocsagFrequency; + + if (m_hwType == HWT_DVMEGA) + len = 12U; + else { + buffer[12U] = (unsigned char)(m_rfLevel * 2.55F + 0.5F); + + buffer[13U] = (pocsagFrequency >> 0) & 0xFFU; + buffer[14U] = (pocsagFrequency >> 8) & 0xFFU; + buffer[15U] = (pocsagFrequency >> 16) & 0xFFU; + buffer[16U] = (pocsagFrequency >> 24) & 0xFFU; + + len = 17U; + } + + buffer[0U] = MMDVM_FRAME_START; + + buffer[1U] = len; + + buffer[2U] = MMDVM_SET_FREQ; + + buffer[3U] = 0x00U; + + buffer[4U] = (m_rxFrequency >> 0) & 0xFFU; + buffer[5U] = (m_rxFrequency >> 8) & 0xFFU; + buffer[6U] = (m_rxFrequency >> 16) & 0xFFU; + buffer[7U] = (m_rxFrequency >> 24) & 0xFFU; + + buffer[8U] = (m_txFrequency >> 0) & 0xFFU; + buffer[9U] = (m_txFrequency >> 8) & 0xFFU; + buffer[10U] = (m_txFrequency >> 16) & 0xFFU; + buffer[11U] = (m_txFrequency >> 24) & 0xFFU; + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FREQ command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FREQ command from the modem"); + return false; + } + + return true; +} + +RESP_TYPE_MMDVM CSerialModem::getResponse() +{ + assert(m_serial != NULL); + + if (m_state == SS_START) { + // Get the start of the frame or nothing at all + int ret = m_serial->read(m_buffer + 0U, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + if (m_buffer[0U] != MMDVM_FRAME_START) + return RTM_TIMEOUT; + + m_state = SS_LENGTH1; + m_length = 1U; + } + + if (m_state == SS_LENGTH1) { + // Get the length of the frame, 1/2 + int ret = m_serial->read(m_buffer + 1U, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + m_length = m_buffer[1U]; + m_offset = 2U; + + if (m_length == 0U) + m_state = SS_LENGTH2; + else + m_state = SS_TYPE; + } + + if (m_state == SS_LENGTH2) { + // Get the length of the frane, 2/2 + int ret = m_serial->read(m_buffer + 2U, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + m_length = m_buffer[2U] + 255U; + m_offset = 3U; + m_state = SS_TYPE; + } + + if (m_state == SS_TYPE) { + // Get the frame type + int ret = m_serial->read(&m_type, 1U); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + m_buffer[m_offset++] = m_type; + + m_state = SS_DATA; + } + + if (m_state == SS_DATA) { + while (m_offset < m_length) { + int ret = m_serial->read(m_buffer + m_offset, m_length - m_offset); + if (ret < 0) { + LogError("Error when reading from the modem"); + m_state = SS_START; + return RTM_ERROR; + } + + if (ret == 0) + return RTM_TIMEOUT; + + if (ret > 0) + m_offset += ret; + } + } + + // CUtils::dump(1U, "Received", m_buffer, m_length); + + m_offset = m_length > 255U ? 4U : 3U; + m_state = SS_START; + + return RTM_OK; +} + +HW_TYPE CSerialModem::getHWType() const +{ + return m_hwType; +} + +unsigned char CSerialModem::getMode() const +{ + return m_mode; +} + +bool CSerialModem::setMode(unsigned char mode) +{ + assert(m_serial != NULL); + + unsigned char buffer[4U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 4U; + buffer[2U] = MMDVM_SET_MODE; + buffer[3U] = mode; + + // CUtils::dump(1U, "Written", buffer, 4U); + + return m_serial->write(buffer, 4U) == 4; +} + +bool CSerialModem::sendCWId(const std::string& callsign) +{ + assert(m_serial != NULL); + + unsigned int length = callsign.length(); + if (length > 200U) + length = 200U; + + unsigned char buffer[205U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 3U; + buffer[2U] = MMDVM_SEND_CWID; + + for (unsigned int i = 0U; i < length; i++) + buffer[i + 3U] = callsign.at(i); + + // CUtils::dump(1U, "Written", buffer, length + 3U); + + return m_serial->write(buffer, length + 3U) == int(length + 3U); +} + +bool CSerialModem::writeDMRStart(bool tx) +{ + assert(m_serial != NULL); + + if (tx && m_tx) + return true; + if (!tx && !m_tx) + return true; + + unsigned char buffer[4U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 4U; + buffer[2U] = MMDVM_DMR_START; + buffer[3U] = tx ? 0x01U : 0x00U; + + // CUtils::dump(1U, "Written", buffer, 4U); + + return m_serial->write(buffer, 4U) == 4; +} + +bool CSerialModem::writeDMRAbort(unsigned int slotNo) +{ + assert(m_serial != NULL); + + if (slotNo == 1U) + m_txDMRData1.clear(); + else + m_txDMRData2.clear(); + + unsigned char buffer[4U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 4U; + buffer[2U] = MMDVM_DMR_ABORT; + buffer[3U] = slotNo; + + // CUtils::dump(1U, "Written", buffer, 4U); + + return m_serial->write(buffer, 4U) == 4; +} + +bool CSerialModem::writeDMRShortLC(const unsigned char* lc) +{ + assert(m_serial != NULL); + assert(lc != NULL); + + unsigned char buffer[12U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 12U; + buffer[2U] = MMDVM_DMR_SHORTLC; + buffer[3U] = lc[0U]; + buffer[4U] = lc[1U]; + buffer[5U] = lc[2U]; + buffer[6U] = lc[3U]; + buffer[7U] = lc[4U]; + buffer[8U] = lc[5U]; + buffer[9U] = lc[6U]; + buffer[10U] = lc[7U]; + buffer[11U] = lc[8U]; + + // CUtils::dump(1U, "Written", buffer, 12U); + + return m_serial->write(buffer, 12U) == 12; +} + +void CSerialModem::setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) +{ + m_fmCallsign = callsign; + m_fmCallsignSpeed = callsignSpeed; + m_fmCallsignFrequency = callsignFrequency; + m_fmCallsignTime = callsignTime; + m_fmCallsignHoldoff = callsignHoldoff; + m_fmCallsignHighLevel = callsignHighLevel; + m_fmCallsignLowLevel = callsignLowLevel; + m_fmCallsignAtStart = callsignAtStart; + m_fmCallsignAtEnd = callsignAtEnd; + m_fmCallsignAtLatch = callsignAtLatch; +} + +void CSerialModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) +{ + m_fmRfAck = rfAck; + m_fmAckSpeed = ackSpeed; + m_fmAckFrequency = ackFrequency; + m_fmAckMinTime = ackMinTime; + m_fmAckDelay = ackDelay; + m_fmAckLevel = ackLevel; +} + +void CSerialModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) +{ + m_fmTimeout = timeout; + m_fmTimeoutLevel = timeoutLevel; + + m_fmCtcssFrequency = ctcssFrequency; + m_fmCtcssHighThreshold = ctcssHighThreshold; + m_fmCtcssLowThreshold = ctcssLowThreshold; + m_fmCtcssLevel = ctcssLevel; + + m_fmKerchunkTime = kerchunkTime; + m_fmKerchunkTX = kerchunkTX; + + m_fmHangTime = hangTime; + + m_fmUseCOS = useCOS; + m_fmCOSInvert = cosInvert; + + m_fmRFAudioBoost = rfAudioBoost; + m_fmMaxDevLevel = maxDevLevel; +} + +void CSerialModem::setFMExtParams(const std::string& ack, unsigned int audioBoost) +{ + m_fmExtAck = ack; + m_fmExtAudioBoost = audioBoost; + m_fmExtEnable = true; +} + +bool CSerialModem::setFMCallsignParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 10U + m_fmCallsign.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS1; + + buffer[3U] = m_fmCallsignSpeed; + buffer[4U] = m_fmCallsignFrequency / 10U; + buffer[5U] = m_fmCallsignTime; + buffer[6U] = m_fmCallsignHoldoff; + + buffer[7U] = (unsigned char)(m_fmCallsignHighLevel * 2.55F + 0.5F); + buffer[8U] = (unsigned char)(m_fmCallsignLowLevel * 2.55F + 0.5F); + + buffer[9U] = 0x00U; + if (m_fmCallsignAtStart) + buffer[9U] |= 0x01U; + if (m_fmCallsignAtEnd) + buffer[9U] |= 0x02U; + if (m_fmCallsignAtLatch) + buffer[9U] |= 0x04U; + + for (unsigned int i = 0U; i < m_fmCallsign.size(); i++) + buffer[10U + i] = m_fmCallsign.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS1 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS1 command from the modem"); + return false; + } + + return true; +} + +bool CSerialModem::setFMAckParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 8U + m_fmRfAck.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS2; + + buffer[3U] = m_fmAckSpeed; + buffer[4U] = m_fmAckFrequency / 10U; + buffer[5U] = m_fmAckMinTime; + buffer[6U] = m_fmAckDelay / 10U; + + buffer[7U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); + + for (unsigned int i = 0U; i < m_fmRfAck.size(); i++) + buffer[8U + i] = m_fmRfAck.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS2 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS2 command from the modem"); + return false; + } + + return true; +} + +bool CSerialModem::setFMMiscParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[20U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 15U; + buffer[2U] = MMDVM_FM_PARAMS3; + + buffer[3U] = m_fmTimeout / 5U; + buffer[4U] = (unsigned char)(m_fmTimeoutLevel * 2.55F + 0.5F); + + buffer[5U] = (unsigned char)m_fmCtcssFrequency; + buffer[6U] = m_fmCtcssHighThreshold; + buffer[7U] = m_fmCtcssLowThreshold; + buffer[8U] = (unsigned char)(m_fmCtcssLevel * 2.55F + 0.5F); + + buffer[9U] = m_fmKerchunkTime; + buffer[10U] = m_fmHangTime; + + buffer[11U] = 0x00U; + if (m_fmUseCOS) + buffer[11U] |= 0x01U; + if (m_fmCOSInvert) + buffer[11U] |= 0x02U; + if (m_fmKerchunkTX) + buffer[11U] |= 0x04U; + + buffer[12U] = m_fmRFAudioBoost; + + buffer[13U] = (unsigned char)(m_fmMaxDevLevel * 2.55F + 0.5F); + + buffer[14U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); + + // CUtils::dump(1U, "Written", buffer, 15U); + + int ret = m_serial->write(buffer, 15U); + if (ret != 15) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS3 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS3 command from the modem"); + return false; + } + + return true; +} + +bool CSerialModem::setFMExtParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 7U + m_fmExtAck.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS4; + + buffer[3U] = m_fmExtAudioBoost; + buffer[4U] = m_fmAckSpeed; + buffer[5U] = m_fmAckFrequency / 10U; + + buffer[6U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); + + for (unsigned int i = 0U; i < m_fmExtAck.size(); i++) + buffer[7U + i] = m_fmExtAck.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS4 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS4 command from the modem"); + return false; + } + + return true; +} + +void CSerialModem::printDebug() +{ + if (m_buffer[2U] == MMDVM_DEBUG1) { + LogMessage("Debug: %.*s", m_length - m_offset - 0U, m_buffer + m_offset); + } else if (m_buffer[2U] == MMDVM_DEBUG2) { + short val1 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; + LogMessage("Debug: %.*s %d", m_length - m_offset - 2U, m_buffer + m_offset, val1); + } else if (m_buffer[2U] == MMDVM_DEBUG3) { + short val1 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; + short val2 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; + LogMessage("Debug: %.*s %d %d", m_length - m_offset - 4U, m_buffer + m_offset, val1, val2); + } else if (m_buffer[2U] == MMDVM_DEBUG4) { + short val1 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; + short val2 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; + short val3 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; + LogMessage("Debug: %.*s %d %d %d", m_length - m_offset - 6U, m_buffer + m_offset, val1, val2, val3); + } else if (m_buffer[2U] == MMDVM_DEBUG5) { + short val1 = (m_buffer[m_length - 8U] << 8) | m_buffer[m_length - 7U]; + short val2 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; + short val3 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; + short val4 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; + LogMessage("Debug: %.*s %d %d %d %d", m_length - m_offset - 8U, m_buffer + m_offset, val1, val2, val3, val4); + } +} diff --git a/SerialModem.h b/SerialModem.h new file mode 100644 index 0000000..e1ef578 --- /dev/null +++ b/SerialModem.h @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2011-2018,2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef SERIALMODEM_H +#define SERIALMODEM_H + +#include "Modem.h" + +#include "SerialPort.h" +#include "RingBuffer.h" +#include "Defines.h" +#include "Timer.h" + +#include + +enum RESP_TYPE_MMDVM { + RTM_OK, + RTM_TIMEOUT, + RTM_ERROR +}; + +enum SERIAL_STATE { + SS_START, + SS_LENGTH1, + SS_LENGTH2, + SS_TYPE, + SS_DATA +}; + +class CSerialModem : public IModem { +public: + CSerialModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug); + virtual ~CSerialModem(); + + virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed); + virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled); + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel); + virtual void setDMRParams(unsigned int colorCode); + virtual void setYSFParams(bool loDev, unsigned int txHang); + virtual void setP25Params(unsigned int txHang); + virtual void setNXDNParams(unsigned int txHang); + virtual void setAX25Params(int rxTwist, unsigned int txDelay); + virtual void setTransparentDataParams(unsigned int sendFrameType); + + virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); + virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); + virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost); + + virtual bool open(); + + virtual unsigned int readDStarData(unsigned char* data); + virtual unsigned int readDMRData1(unsigned char* data); + virtual unsigned int readDMRData2(unsigned char* data); + virtual unsigned int readYSFData(unsigned char* data); + virtual unsigned int readP25Data(unsigned char* data); + virtual unsigned int readNXDNData(unsigned char* data); + virtual unsigned int readFMData(unsigned char* data); + virtual unsigned int readAX25Data(unsigned char* data); + virtual unsigned int readTransparentData(unsigned char* data); + + virtual unsigned int readSerial(unsigned char* data, unsigned int length); + + virtual bool hasDStarSpace() const; + virtual bool hasDMRSpace1() const; + virtual bool hasDMRSpace2() const; + virtual bool hasYSFSpace() const; + virtual bool hasP25Space() const; + virtual bool hasNXDNSpace() const; + virtual bool hasPOCSAGSpace() const; + virtual unsigned int getFMSpace() const; + virtual bool hasAX25Space() const; + + virtual bool hasTX() const; + virtual bool hasCD() const; + + virtual bool hasLockout() const; + virtual bool hasError() const; + + virtual bool writeConfig(); + virtual bool writeDStarData(const unsigned char* data, unsigned int length); + virtual bool writeDMRData1(const unsigned char* data, unsigned int length); + virtual bool writeDMRData2(const unsigned char* data, unsigned int length); + virtual bool writeYSFData(const unsigned char* data, unsigned int length); + virtual bool writeP25Data(const unsigned char* data, unsigned int length); + virtual bool writeNXDNData(const unsigned char* data, unsigned int length); + virtual bool writePOCSAGData(const unsigned char* data, unsigned int length); + virtual bool writeFMData(const unsigned char* data, unsigned int length); + virtual bool writeAX25Data(const unsigned char* data, unsigned int length); + + virtual bool writeTransparentData(const unsigned char* data, unsigned int length); + + virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); + virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type); + virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin); + virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type); + virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type); + virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message); + virtual bool writeIPInfo(const std::string& address); + + virtual bool writeDMRStart(bool tx); + virtual bool writeDMRShortLC(const unsigned char* lc); + virtual bool writeDMRAbort(unsigned int slotNo); + + virtual bool writeSerial(const unsigned char* data, unsigned int length); + + virtual unsigned char getMode() const; + virtual bool setMode(unsigned char mode); + + virtual bool sendCWId(const std::string& callsign); + + virtual HW_TYPE getHWType() const; + + virtual void clock(unsigned int ms); + + virtual void close(); + +private: + std::string m_port; + unsigned int m_dmrColorCode; + bool m_ysfLoDev; + unsigned int m_ysfTXHang; + unsigned int m_p25TXHang; + unsigned int m_nxdnTXHang; + bool m_duplex; + bool m_rxInvert; + bool m_txInvert; + bool m_pttInvert; + unsigned int m_txDelay; + unsigned int m_dmrDelay; + float m_rxLevel; + float m_cwIdTXLevel; + float m_dstarTXLevel; + float m_dmrTXLevel; + float m_ysfTXLevel; + float m_p25TXLevel; + float m_nxdnTXLevel; + float m_pocsagTXLevel; + float m_fmTXLevel; + float m_ax25TXLevel; + float m_rfLevel; + bool m_trace; + bool m_debug; + unsigned int m_rxFrequency; + unsigned int m_txFrequency; + unsigned int m_pocsagFrequency; + bool m_dstarEnabled; + bool m_dmrEnabled; + bool m_ysfEnabled; + bool m_p25Enabled; + bool m_nxdnEnabled; + bool m_pocsagEnabled; + bool m_fmEnabled; + bool m_ax25Enabled; + int m_rxDCOffset; + int m_txDCOffset; + ISerialPort* m_serial; + unsigned char* m_buffer; + unsigned int m_length; + unsigned int m_offset; + SERIAL_STATE m_state; + unsigned char m_type; + CRingBuffer m_rxDStarData; + CRingBuffer m_txDStarData; + CRingBuffer m_rxDMRData1; + CRingBuffer m_rxDMRData2; + CRingBuffer m_txDMRData1; + CRingBuffer m_txDMRData2; + CRingBuffer m_rxYSFData; + CRingBuffer m_txYSFData; + CRingBuffer m_rxP25Data; + CRingBuffer m_txP25Data; + CRingBuffer m_rxNXDNData; + CRingBuffer m_txNXDNData; + CRingBuffer m_txPOCSAGData; + CRingBuffer m_rxFMData; + CRingBuffer m_txFMData; + CRingBuffer m_rxAX25Data; + CRingBuffer m_txAX25Data; + CRingBuffer m_rxTransparentData; + CRingBuffer m_txTransparentData; + unsigned int m_sendTransparentDataFrameType; + CTimer m_statusTimer; + CTimer m_inactivityTimer; + CTimer m_playoutTimer; + unsigned int m_dstarSpace; + unsigned int m_dmrSpace1; + unsigned int m_dmrSpace2; + unsigned int m_ysfSpace; + unsigned int m_p25Space; + unsigned int m_nxdnSpace; + unsigned int m_pocsagSpace; + unsigned int m_fmSpace; + unsigned int m_ax25Space; + bool m_tx; + bool m_cd; + bool m_lockout; + bool m_error; + unsigned char m_mode; + HW_TYPE m_hwType; + int m_ax25RXTwist; + unsigned int m_ax25TXDelay; + + std::string m_fmCallsign; + unsigned int m_fmCallsignSpeed; + unsigned int m_fmCallsignFrequency; + unsigned int m_fmCallsignTime; + unsigned int m_fmCallsignHoldoff; + float m_fmCallsignHighLevel; + float m_fmCallsignLowLevel; + bool m_fmCallsignAtStart; + bool m_fmCallsignAtEnd; + bool m_fmCallsignAtLatch; + std::string m_fmRfAck; + std::string m_fmExtAck; + unsigned int m_fmAckSpeed; + unsigned int m_fmAckFrequency; + unsigned int m_fmAckMinTime; + unsigned int m_fmAckDelay; + float m_fmAckLevel; + unsigned int m_fmTimeout; + float m_fmTimeoutLevel; + float m_fmCtcssFrequency; + unsigned int m_fmCtcssHighThreshold; + unsigned int m_fmCtcssLowThreshold; + float m_fmCtcssLevel; + unsigned int m_fmKerchunkTime; + bool m_fmKerchunkTX; + unsigned int m_fmHangTime; + bool m_fmUseCOS; + bool m_fmCOSInvert; + unsigned int m_fmRFAudioBoost; + unsigned int m_fmExtAudioBoost; + float m_fmMaxDevLevel; + bool m_fmExtEnable; + + bool readVersion(); + bool readStatus(); + bool setConfig(); + bool setFrequency(); + bool setFMCallsignParams(); + bool setFMAckParams(); + bool setFMMiscParams(); + bool setFMExtParams(); + + void printDebug(); + + RESP_TYPE_MMDVM getResponse(); +}; + +#endif diff --git a/Version.h b/Version.h index dc5e793..bb444d2 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200627"; +const char* VERSION = "20200630"; #endif