From a52d831ba5901717cc28ca8cdc454220101409cc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 21 Feb 2018 21:53:58 +0000 Subject: [PATCH] Add the FCS protocol and the beginnings of the control for it. --- YSFGateway/Conf.cpp | 18 ++++++- YSFGateway/Conf.h | 4 ++ YSFGateway/DTMF.cpp | 11 +++- YSFGateway/FCSNetwork.cpp | 102 +++++++++++++++++++------------------- YSFGateway/FCSNetwork.h | 13 +++-- YSFGateway/YSFGateway.cpp | 79 +++++++++++++++++++++-------- YSFGateway/YSFGateway.ini | 2 + 7 files changed, 148 insertions(+), 81 deletions(-) diff --git a/YSFGateway/Conf.cpp b/YSFGateway/Conf.cpp index 99eda25..01e9f8a 100644 --- a/YSFGateway/Conf.cpp +++ b/YSFGateway/Conf.cpp @@ -40,6 +40,7 @@ CConf::CConf(const std::string& file) : m_file(file), m_callsign(), m_suffix(), +m_id(0U), m_rptAddress(), m_rptPort(0U), m_myAddress(), @@ -50,6 +51,7 @@ m_txFrequency(0U), m_power(0U), m_latitude(0.0F), m_longitude(0.0F), +m_locator(), m_height(0), m_name(), m_description(), @@ -134,7 +136,9 @@ bool CConf::read() for (unsigned int i = 0U; value[i] != 0; i++) value[i] = ::toupper(value[i]); m_suffix = value; - } else if (::strcmp(key, "RptAddress") == 0) + } else if (::strcmp(key, "Id") == 0) + m_id = (unsigned int)::atoi(value); + else if (::strcmp(key, "RptAddress") == 0) m_rptAddress = value; else if (::strcmp(key, "RptPort") == 0) m_rptPort = (unsigned int)::atoi(value); @@ -155,6 +159,8 @@ bool CConf::read() m_latitude = float(::atof(value)); else if (::strcmp(key, "Longitude") == 0) m_longitude = float(::atof(value)); + else if (::strcmp(key, "Locator") == 0) + m_locator = value; else if (::strcmp(key, "Height") == 0) m_height = ::atoi(value); else if (::strcmp(key, "Name") == 0) @@ -231,6 +237,11 @@ std::string CConf::getSuffix() const return m_suffix; } +unsigned int CConf::getId() const +{ + return m_id; +} + std::string CConf::getRptAddress() const { return m_rptAddress; @@ -281,6 +292,11 @@ float CConf::getLongitude() const return m_longitude; } +std::string CConf::getLocator() const +{ + return m_locator; +} + int CConf::getHeight() const { return m_height; diff --git a/YSFGateway/Conf.h b/YSFGateway/Conf.h index 716c6dd..1c05cb8 100644 --- a/YSFGateway/Conf.h +++ b/YSFGateway/Conf.h @@ -33,6 +33,7 @@ public: // The General section std::string getCallsign() const; std::string getSuffix() const; + unsigned int getId() const; std::string getRptAddress() const; unsigned int getRptPort() const; std::string getMyAddress() const; @@ -45,6 +46,7 @@ public: unsigned int getPower() const; float getLatitude() const; float getLongitude() const; + std::string getLocator() const; int getHeight() const; std::string getName() const; std::string getDescription() const; @@ -85,6 +87,7 @@ private: std::string m_file; std::string m_callsign; std::string m_suffix; + unsigned int m_id; std::string m_rptAddress; unsigned int m_rptPort; std::string m_myAddress; @@ -96,6 +99,7 @@ private: unsigned int m_power; float m_latitude; float m_longitude; + std::string m_locator; int m_height; std::string m_name; std::string m_description; diff --git a/YSFGateway/DTMF.cpp b/YSFGateway/DTMF.cpp index c475f41..de30b72 100644 --- a/YSFGateway/DTMF.cpp +++ b/YSFGateway/DTMF.cpp @@ -161,14 +161,21 @@ WX_STATUS CDTMF::decodeVDMode2Slice(const unsigned char* ambe, bool end) WX_STATUS CDTMF::validate() const { size_t length = m_command.length(); - if (length != 4U && length != 6U) + if (length != 3U && length != 4U && length != 6U) return WXS_NONE; char first = m_command.at(0U); if (first != '#' && first != 'A') return WXS_NONE; - if (length == 4U) { + if (length == 3U) { + for (unsigned int i = 1U; i <= 3U; i++) { + if (m_command.at(1U) < '0' || m_command.at(1U) > '9') + return WXS_NONE; + } + + return WXS_CONNECT_FCS; + } else if (length == 4U) { for (unsigned int i = 1U; i <= 4U; i++) { if (m_command.at(1U) < '0' || m_command.at(1U) > '9') return WXS_NONE; diff --git a/YSFGateway/FCSNetwork.cpp b/YSFGateway/FCSNetwork.cpp index 7851de0..ec90975 100644 --- a/YSFGateway/FCSNetwork.cpp +++ b/YSFGateway/FCSNetwork.cpp @@ -25,59 +25,31 @@ #include #include -const unsigned int BUFFER_LENGTH = 200U; - -CFCSNetwork::CFCSNetwork(const std::string& address, unsigned int port, const std::string& callsign, bool debug) : -m_socket(address, port), -m_debug(debug), -m_address(), -m_port(0U), -m_poll(NULL), -m_unlink(NULL), -m_buffer(1000U, "FCS Network Buffer") -{ - m_poll = new unsigned char[14U]; - ::memcpy(m_poll + 0U, "YSFP", 4U); +const char* FCS_VERSION = "MMDVM v.01"; - m_unlink = new unsigned char[14U]; - ::memcpy(m_unlink + 0U, "YSFU", 4U); - - std::string node = callsign; - node.resize(YSF_CALLSIGN_LENGTH, ' '); - - for (unsigned int i = 0U; i < YSF_CALLSIGN_LENGTH; i++) { - m_poll[i + 4U] = node.at(i); - m_unlink[i + 4U] = node.at(i); - } -} +const unsigned int BUFFER_LENGTH = 200U; -CFCSNetwork::CFCSNetwork(unsigned int port, const std::string& callsign, bool debug) : +CFCSNetwork::CFCSNetwork(unsigned int port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool debug) : m_socket(port), m_debug(debug), m_address(), m_port(0U), -m_poll(NULL), -m_unlink(NULL), +m_info(NULL), +m_callsign(callsign), +m_reflector(), m_buffer(1000U, "FCS Network Buffer") { - m_poll = new unsigned char[14U]; - ::memcpy(m_poll + 0U, "YSFP", 4U); - - m_unlink = new unsigned char[14U]; - ::memcpy(m_unlink + 0U, "YSFU", 4U); + m_info = new unsigned char[100U]; + ::memset(m_info, ' ', 100U); - std::string node = callsign; - node.resize(YSF_CALLSIGN_LENGTH, ' '); + m_callsign.resize(6U, ' '); - for (unsigned int i = 0U; i < YSF_CALLSIGN_LENGTH; i++) { - m_poll[i + 4U] = node.at(i); - m_unlink[i + 4U] = node.at(i); - } + ::sprintf((char*)m_info, "%9u%9u%-6.6s%-12.12s%7u", rxFrequency, txFrequency, locator.c_str(), FCS_VERSION, id); } CFCSNetwork::~CFCSNetwork() { - delete[] m_poll; + delete[] m_info; } bool CFCSNetwork::open() @@ -106,18 +78,35 @@ bool CFCSNetwork::write(const unsigned char* data) if (m_port == 0U) return true; + unsigned char buffer[130U]; + ::memset(buffer + 0U, ' ', 130U); + ::memcpy(buffer + 0U, data + 35U, 120U); + ::memcpy(buffer + 121U, m_reflector.c_str(), 8U); + if (m_debug) - CUtils::dump(1U, "FCS Network Data Sent", data, 155U); + CUtils::dump(1U, "FCS Network Data Sent", buffer, 130U); - return m_socket.write(data, 155U, m_address, m_port); + return m_socket.write(buffer, 130U, m_address, m_port); } -bool CFCSNetwork::writePoll() +bool CFCSNetwork::writeLink(const std::string& reflector) { if (m_port == 0U) return true; - return m_socket.write(m_poll, 14U, m_address, m_port); + m_reflector = reflector; + m_reflector.resize(8U, ' '); + + unsigned char buffer[25U]; + ::memset(buffer + 0U, ' ', 25U); + ::memcpy(buffer + 0U, "PING", 4U); + ::memcpy(buffer + 4U, m_callsign.c_str(), 6U); + ::memcpy(buffer + 10U, m_reflector.c_str(), 6U); + + if (m_debug) + CUtils::dump(1U, "FCS Network Data Sent", buffer, 25U); + + return m_socket.write(buffer, 25U, m_address, m_port); } bool CFCSNetwork::writeUnlink() @@ -125,7 +114,7 @@ bool CFCSNetwork::writeUnlink() if (m_port == 0U) return true; - return m_socket.write(m_unlink, 14U, m_address, m_port); + return m_socket.write((unsigned char*)"CLOSE ", 11U, m_address, m_port); } void CFCSNetwork::clock(unsigned int ms) @@ -147,10 +136,11 @@ void CFCSNetwork::clock(unsigned int ms) if (m_debug) CUtils::dump(1U, "FCS Network Data Received", buffer, length); - unsigned char len = length; - m_buffer.addData(&len, 1U); + if (length == 7 || length == 10) + writeInfo(); - m_buffer.addData(buffer, length); + if (length == 130) + m_buffer.addData(buffer, 130U); } unsigned int CFCSNetwork::read(unsigned char* data) @@ -160,12 +150,9 @@ unsigned int CFCSNetwork::read(unsigned char* data) if (m_buffer.isEmpty()) return 0U; - unsigned char len = 0U; - m_buffer.getData(&len, 1U); + m_buffer.getData(data, 130U); - m_buffer.getData(data, len); - - return len; + return 155U; } void CFCSNetwork::close() @@ -174,3 +161,14 @@ void CFCSNetwork::close() LogMessage("Closing FCS network connection"); } + +void CFCSNetwork::writeInfo() +{ + if (m_port == 0U) + return; + + if (m_debug) + CUtils::dump(1U, "FCS Network Data Sent", m_info, 100U); + + m_socket.write(m_info, 100U, m_address, m_port); +} diff --git a/YSFGateway/FCSNetwork.h b/YSFGateway/FCSNetwork.h index aad0f99..3d89d20 100644 --- a/YSFGateway/FCSNetwork.h +++ b/YSFGateway/FCSNetwork.h @@ -28,8 +28,7 @@ class CFCSNetwork { public: - CFCSNetwork(const std::string& address, unsigned int port, const std::string& callsign, bool debug); - CFCSNetwork(unsigned int port, const std::string& callsign, bool debug); + CFCSNetwork(unsigned int port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool debug); ~CFCSNetwork(); bool open(); @@ -39,7 +38,8 @@ public: bool write(const unsigned char* data); - bool writePoll(); + bool writeLink(const std::string& reflector); + bool writeUnlink(); unsigned int read(unsigned char* data); @@ -53,9 +53,12 @@ private: bool m_debug; in_addr m_address; unsigned int m_port; - unsigned char* m_poll; - unsigned char* m_unlink; + unsigned char* m_info; + std::string m_callsign; + std::string m_reflector; CRingBuffer m_buffer; + + void writeInfo(); }; #endif diff --git a/YSFGateway/YSFGateway.cpp b/YSFGateway/YSFGateway.cpp index 168572f..01c942d 100644 --- a/YSFGateway/YSFGateway.cpp +++ b/YSFGateway/YSFGateway.cpp @@ -198,9 +198,14 @@ int CYSFGateway::run() return 1; } + unsigned int txFrequency = m_conf.getTxFrequency(); + unsigned int rxFrequency = m_conf.getRxFrequency(); + std::string locator = m_conf.getLocator(); + unsigned int id = m_conf.getId(); + unsigned int fcsPort = m_conf.getFCSNetworkPort(); - m_fcsNetwork = new CFCSNetwork(fcsPort, m_callsign, debug); + m_fcsNetwork = new CFCSNetwork(fcsPort, m_callsign, rxFrequency, txFrequency, locator, id, debug); ret = m_fcsNetwork->open(); if (!ret) { ::LogError("Cannot open the FCS reflector network port"); @@ -222,8 +227,6 @@ int CYSFGateway::run() m_wiresX = new CWiresX(m_callsign, m_suffix, &rptNetwork, fileName, reloadTime); std::string name = m_conf.getName(); - unsigned int txFrequency = m_conf.getTxFrequency(); - unsigned int rxFrequency = m_conf.getRxFrequency(); m_wiresX->setInfo(name, txFrequency, rxFrequency); @@ -300,9 +303,10 @@ int CYSFGateway::run() } if (fcsNetworkEnabled && m_linkType == LINK_FCS && !m_exclude) { - m_fcsNetwork->write(buffer); - if (::memcmp(buffer + 0U, "YSFD", 4U) == 0) + if (::memcmp(buffer + 0U, "YSFD", 4U) == 0) { + m_fcsNetwork->write(buffer); m_inactivityTimer.start(); + } } if ((buffer[34U] & 0x01U) == 0x01U) { @@ -325,10 +329,7 @@ int CYSFGateway::run() while (m_fcsNetwork->read(buffer) > 0U) { if (fcsNetworkEnabled && m_linkType == LINK_FCS) { - // Only pass through YSF data packets - if (::memcmp(buffer + 0U, "YSFD", 4U) == 0) - rptNetwork.write(buffer); - + rptNetwork.write(buffer); m_lostTimer.start(); } } @@ -468,9 +469,17 @@ void CYSFGateway::processWiresX(const unsigned char* buffer, unsigned char fi, u WX_STATUS status = m_wiresX->process(buffer + 35U, buffer + 14U, fi, dt, fn, ft); switch (status) { case WXS_CONNECT_YSF: { - m_ysfNetwork->writeUnlink(); - m_ysfNetwork->writeUnlink(); - m_ysfNetwork->writeUnlink(); + if (m_linkType == LINK_YSF) { + m_ysfNetwork->writeUnlink(); + m_ysfNetwork->writeUnlink(); + m_ysfNetwork->writeUnlink(); + } + if (m_linkType == LINK_FCS) { + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->clearDestination(); + } CYSFReflector* reflector = m_wiresX->getReflector(); LogMessage("Connect to %5.5s - \"%s\" has been requested by %10.10s", reflector->m_id.c_str(), reflector->m_name.c_str(), buffer + 14U); @@ -488,18 +497,33 @@ void CYSFGateway::processWiresX(const unsigned char* buffer, unsigned char fi, u } break; case WXS_DISCONNECT: - LogMessage("Disconnect has been requested by %10.10s", buffer + 14U); + if (m_linkType == LINK_YSF) { + LogMessage("Disconnect has been requested by %10.10s", buffer + 14U); + + m_ysfNetwork->writeUnlink(); + m_ysfNetwork->writeUnlink(); + m_ysfNetwork->writeUnlink(); + m_ysfNetwork->clearDestination(); + + m_inactivityTimer.stop(); + m_lostTimer.stop(); + m_ysfPollTimer.stop(); - m_ysfNetwork->writeUnlink(); - m_ysfNetwork->writeUnlink(); - m_ysfNetwork->writeUnlink(); - m_ysfNetwork->clearDestination(); + m_linkType = LINK_NONE; + } + if (m_linkType == LINK_FCS) { + LogMessage("Disconnect has been requested by %10.10s", buffer + 14U); + + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->clearDestination(); - m_inactivityTimer.stop(); - m_lostTimer.stop(); - m_ysfPollTimer.stop(); + m_inactivityTimer.stop(); + m_lostTimer.stop(); - m_linkType = LINK_NONE; + m_linkType = LINK_NONE; + } break; default: break; @@ -566,6 +590,19 @@ void CYSFGateway::processDTMF(const unsigned char* buffer, unsigned char dt) m_linkType = LINK_NONE; } + if (m_linkType == LINK_FCS) { + LogMessage("Disconnect via DTMF has been requested by %10.10s", buffer + 14U); + + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->writeUnlink(); + m_fcsNetwork->clearDestination(); + + m_inactivityTimer.stop(); + m_lostTimer.stop(); + + m_linkType = LINK_NONE; + } break; default: break; diff --git a/YSFGateway/YSFGateway.ini b/YSFGateway/YSFGateway.ini index c81d485..85d6d42 100644 --- a/YSFGateway/YSFGateway.ini +++ b/YSFGateway/YSFGateway.ini @@ -2,6 +2,7 @@ Callsign=G9BF Suffix=RPT # Suffix=ND +Id=1234567 RptAddress=127.0.0.1 RptPort=3200 LocalAddress=127.0.0.1 @@ -14,6 +15,7 @@ TXFrequency=439475000 Power=1 Latitude=0.0 Longitude=0.0 +Locator=IO90TT Height=0 Name=Nowhere Description=Multi-Mode Repeater