diff --git a/YSFGateway/DTMF.cpp b/YSFGateway/DTMF.cpp index 59b0571..eb8e14f 100644 --- a/YSFGateway/DTMF.cpp +++ b/YSFGateway/DTMF.cpp @@ -54,14 +54,14 @@ CDTMF::~CDTMF() { } -bool CDTMF::decode(const unsigned char* ambe, bool end) +WX_STATUS CDTMF::decodeVW(const unsigned char* ambe) { // DTMF begins with these byte values - if (!end && (ambe[0] & DTMF_MASK[0]) == DTMF_SIG[0] && (ambe[1] & DTMF_MASK[1]) == DTMF_SIG[1] && - (ambe[2] & DTMF_MASK[2]) == DTMF_SIG[2] && (ambe[3] & DTMF_MASK[3]) == DTMF_SIG[3] && - (ambe[4] & DTMF_MASK[4]) == DTMF_SIG[4] && (ambe[5] & DTMF_MASK[5]) == DTMF_SIG[5] && - (ambe[6] & DTMF_MASK[6]) == DTMF_SIG[6] && (ambe[7] & DTMF_MASK[7]) == DTMF_SIG[7] && - (ambe[8] & DTMF_MASK[8]) == DTMF_SIG[8]) { + if ((ambe[0] & DTMF_MASK[0]) == DTMF_SIG[0] && (ambe[1] & DTMF_MASK[1]) == DTMF_SIG[1] && + (ambe[2] & DTMF_MASK[2]) == DTMF_SIG[2] && (ambe[3] & DTMF_MASK[3]) == DTMF_SIG[3] && + (ambe[4] & DTMF_MASK[4]) == DTMF_SIG[4] && (ambe[5] & DTMF_MASK[5]) == DTMF_SIG[5] && + (ambe[6] & DTMF_MASK[6]) == DTMF_SIG[6] && (ambe[7] & DTMF_MASK[7]) == DTMF_SIG[7] && + (ambe[8] & DTMF_MASK[8]) == DTMF_SIG[8]) { unsigned char sym0 = ambe[4] & DTMF_SYM_MASK[0]; unsigned char sym1 = ambe[5] & DTMF_SYM_MASK[1]; unsigned char sym2 = ambe[7] & DTMF_SYM_MASK[2]; @@ -114,10 +114,10 @@ bool CDTMF::decode(const unsigned char* ambe, bool end) m_pressed = true; } - return c != ' '; + return validate(); } else { // If it is not a DTMF Code - if ((end || m_releaseCount >= 100U) && m_data.length() > 0U) { + if (m_releaseCount >= 100U && m_data.length() > 0U) { m_command = m_data; m_data.clear(); m_releaseCount = 0U; @@ -128,25 +128,192 @@ bool CDTMF::decode(const unsigned char* ambe, bool end) m_pressCount = 0U; m_lastChar = ' '; - return false; + return WXS_NONE; } } -bool CDTMF::hasCommand() const +WX_STATUS CDTMF::decodeDN1(const unsigned char* ambe) { - return !m_command.empty(); + // DTMF begins with these byte values + if ((ambe[0] & DTMF_MASK[0]) == DTMF_SIG[0] && (ambe[1] & DTMF_MASK[1]) == DTMF_SIG[1] && + (ambe[2] & DTMF_MASK[2]) == DTMF_SIG[2] && (ambe[3] & DTMF_MASK[3]) == DTMF_SIG[3] && + (ambe[4] & DTMF_MASK[4]) == DTMF_SIG[4] && (ambe[5] & DTMF_MASK[5]) == DTMF_SIG[5] && + (ambe[6] & DTMF_MASK[6]) == DTMF_SIG[6] && (ambe[7] & DTMF_MASK[7]) == DTMF_SIG[7] && + (ambe[8] & DTMF_MASK[8]) == DTMF_SIG[8]) { + unsigned char sym0 = ambe[4] & DTMF_SYM_MASK[0]; + unsigned char sym1 = ambe[5] & DTMF_SYM_MASK[1]; + unsigned char sym2 = ambe[7] & DTMF_SYM_MASK[2]; + unsigned char sym3 = ambe[8] & DTMF_SYM_MASK[3]; + + char c = ' '; + if (sym0 == DTMF_SYM0[0] && sym1 == DTMF_SYM0[1] && sym2 == DTMF_SYM0[2] && sym3 == DTMF_SYM0[3]) + c = '0'; + else if (sym0 == DTMF_SYM1[0] && sym1 == DTMF_SYM1[1] && sym2 == DTMF_SYM1[2] && sym3 == DTMF_SYM1[3]) + c = '1'; + else if (sym0 == DTMF_SYM2[0] && sym1 == DTMF_SYM2[1] && sym2 == DTMF_SYM2[2] && sym3 == DTMF_SYM2[3]) + c = '2'; + else if (sym0 == DTMF_SYM3[0] && sym1 == DTMF_SYM3[1] && sym2 == DTMF_SYM3[2] && sym3 == DTMF_SYM3[3]) + c = '3'; + else if (sym0 == DTMF_SYM4[0] && sym1 == DTMF_SYM4[1] && sym2 == DTMF_SYM4[2] && sym3 == DTMF_SYM4[3]) + c = '4'; + else if (sym0 == DTMF_SYM5[0] && sym1 == DTMF_SYM5[1] && sym2 == DTMF_SYM5[2] && sym3 == DTMF_SYM5[3]) + c = '5'; + else if (sym0 == DTMF_SYM6[0] && sym1 == DTMF_SYM6[1] && sym2 == DTMF_SYM6[2] && sym3 == DTMF_SYM6[3]) + c = '6'; + else if (sym0 == DTMF_SYM7[0] && sym1 == DTMF_SYM7[1] && sym2 == DTMF_SYM7[2] && sym3 == DTMF_SYM7[3]) + c = '7'; + else if (sym0 == DTMF_SYM8[0] && sym1 == DTMF_SYM8[1] && sym2 == DTMF_SYM8[2] && sym3 == DTMF_SYM8[3]) + c = '8'; + else if (sym0 == DTMF_SYM9[0] && sym1 == DTMF_SYM9[1] && sym2 == DTMF_SYM9[2] && sym3 == DTMF_SYM9[3]) + c = '9'; + else if (sym0 == DTMF_SYMA[0] && sym1 == DTMF_SYMA[1] && sym2 == DTMF_SYMA[2] && sym3 == DTMF_SYMA[3]) + c = 'A'; + else if (sym0 == DTMF_SYMB[0] && sym1 == DTMF_SYMB[1] && sym2 == DTMF_SYMB[2] && sym3 == DTMF_SYMB[3]) + c = 'B'; + else if (sym0 == DTMF_SYMC[0] && sym1 == DTMF_SYMC[1] && sym2 == DTMF_SYMC[2] && sym3 == DTMF_SYMC[3]) + c = 'C'; + else if (sym0 == DTMF_SYMD[0] && sym1 == DTMF_SYMD[1] && sym2 == DTMF_SYMD[2] && sym3 == DTMF_SYMD[3]) + c = 'D'; + else if (sym0 == DTMF_SYMS[0] && sym1 == DTMF_SYMS[1] && sym2 == DTMF_SYMS[2] && sym3 == DTMF_SYMS[3]) + c = '*'; + else if (sym0 == DTMF_SYMH[0] && sym1 == DTMF_SYMH[1] && sym2 == DTMF_SYMH[2] && sym3 == DTMF_SYMH[3]) + c = '#'; + + if (c == m_lastChar) { + m_pressCount++; + } else { + m_lastChar = c; + m_pressCount = 0U; + } + + if (c != ' ' && !m_pressed && m_pressCount >= 3U) { + m_data += c; + m_releaseCount = 0U; + m_pressed = true; + } + + return validate(); + } else { + // If it is not a DTMF Code + if (m_releaseCount >= 100U && m_data.length() > 0U) { + m_command = m_data; + m_data.clear(); + m_releaseCount = 0U; + } + + m_pressed = false; + m_releaseCount++; + m_pressCount = 0U; + m_lastChar = ' '; + + return WXS_NONE; + } } -// DTMF to YOUR call command -std::string CDTMF::translate() +WX_STATUS CDTMF::decodeDN2(const unsigned char* ambe) { - std::string command = m_command; - m_command.clear(); + // DTMF begins with these byte values + if ((ambe[0] & DTMF_MASK[0]) == DTMF_SIG[0] && (ambe[1] & DTMF_MASK[1]) == DTMF_SIG[1] && + (ambe[2] & DTMF_MASK[2]) == DTMF_SIG[2] && (ambe[3] & DTMF_MASK[3]) == DTMF_SIG[3] && + (ambe[4] & DTMF_MASK[4]) == DTMF_SIG[4] && (ambe[5] & DTMF_MASK[5]) == DTMF_SIG[5] && + (ambe[6] & DTMF_MASK[6]) == DTMF_SIG[6] && (ambe[7] & DTMF_MASK[7]) == DTMF_SIG[7] && + (ambe[8] & DTMF_MASK[8]) == DTMF_SIG[8]) { + unsigned char sym0 = ambe[4] & DTMF_SYM_MASK[0]; + unsigned char sym1 = ambe[5] & DTMF_SYM_MASK[1]; + unsigned char sym2 = ambe[7] & DTMF_SYM_MASK[2]; + unsigned char sym3 = ambe[8] & DTMF_SYM_MASK[3]; - if (command.at(0U) == '#') - return command; + char c = ' '; + if (sym0 == DTMF_SYM0[0] && sym1 == DTMF_SYM0[1] && sym2 == DTMF_SYM0[2] && sym3 == DTMF_SYM0[3]) + c = '0'; + else if (sym0 == DTMF_SYM1[0] && sym1 == DTMF_SYM1[1] && sym2 == DTMF_SYM1[2] && sym3 == DTMF_SYM1[3]) + c = '1'; + else if (sym0 == DTMF_SYM2[0] && sym1 == DTMF_SYM2[1] && sym2 == DTMF_SYM2[2] && sym3 == DTMF_SYM2[3]) + c = '2'; + else if (sym0 == DTMF_SYM3[0] && sym1 == DTMF_SYM3[1] && sym2 == DTMF_SYM3[2] && sym3 == DTMF_SYM3[3]) + c = '3'; + else if (sym0 == DTMF_SYM4[0] && sym1 == DTMF_SYM4[1] && sym2 == DTMF_SYM4[2] && sym3 == DTMF_SYM4[3]) + c = '4'; + else if (sym0 == DTMF_SYM5[0] && sym1 == DTMF_SYM5[1] && sym2 == DTMF_SYM5[2] && sym3 == DTMF_SYM5[3]) + c = '5'; + else if (sym0 == DTMF_SYM6[0] && sym1 == DTMF_SYM6[1] && sym2 == DTMF_SYM6[2] && sym3 == DTMF_SYM6[3]) + c = '6'; + else if (sym0 == DTMF_SYM7[0] && sym1 == DTMF_SYM7[1] && sym2 == DTMF_SYM7[2] && sym3 == DTMF_SYM7[3]) + c = '7'; + else if (sym0 == DTMF_SYM8[0] && sym1 == DTMF_SYM8[1] && sym2 == DTMF_SYM8[2] && sym3 == DTMF_SYM8[3]) + c = '8'; + else if (sym0 == DTMF_SYM9[0] && sym1 == DTMF_SYM9[1] && sym2 == DTMF_SYM9[2] && sym3 == DTMF_SYM9[3]) + c = '9'; + else if (sym0 == DTMF_SYMA[0] && sym1 == DTMF_SYMA[1] && sym2 == DTMF_SYMA[2] && sym3 == DTMF_SYMA[3]) + c = 'A'; + else if (sym0 == DTMF_SYMB[0] && sym1 == DTMF_SYMB[1] && sym2 == DTMF_SYMB[2] && sym3 == DTMF_SYMB[3]) + c = 'B'; + else if (sym0 == DTMF_SYMC[0] && sym1 == DTMF_SYMC[1] && sym2 == DTMF_SYMC[2] && sym3 == DTMF_SYMC[3]) + c = 'C'; + else if (sym0 == DTMF_SYMD[0] && sym1 == DTMF_SYMD[1] && sym2 == DTMF_SYMD[2] && sym3 == DTMF_SYMD[3]) + c = 'D'; + else if (sym0 == DTMF_SYMS[0] && sym1 == DTMF_SYMS[1] && sym2 == DTMF_SYMS[2] && sym3 == DTMF_SYMS[3]) + c = '*'; + else if (sym0 == DTMF_SYMH[0] && sym1 == DTMF_SYMH[1] && sym2 == DTMF_SYMH[2] && sym3 == DTMF_SYMH[3]) + c = '#'; + + if (c == m_lastChar) { + m_pressCount++; + } else { + m_lastChar = c; + m_pressCount = 0U; + } + + if (c != ' ' && !m_pressed && m_pressCount >= 3U) { + m_data += c; + m_releaseCount = 0U; + m_pressed = true; + } + + return validate(); + } else { + // If it is not a DTMF Code + if (m_releaseCount >= 100U && m_data.length() > 0U) { + m_command = m_data; + m_data.clear(); + m_releaseCount = 0U; + } + + m_pressed = false; + m_releaseCount++; + m_pressCount = 0U; + m_lastChar = ' '; + + return WXS_NONE; + } +} + +WX_STATUS CDTMF::validate() const +{ + if (m_command.length() != 6U) + return WXS_NONE; + + if (m_command.at(0U) != '#') + return WXS_NONE; + + for (unsigned int i = 1U; i <= 6U; i++) { + if (m_command.at(1U) < '0' || m_command.at(1U) > '9') + return WXS_NONE; + } + + if (m_command == "#99999") + return WXS_DISCONNECT; + + return WXS_CONNECT; +} + +unsigned int CDTMF::getReflector() +{ + std::string command = m_command; + reset(); - return ""; + // XXX FIXME + return 0U; } void CDTMF::reset() diff --git a/YSFGateway/DTMF.h b/YSFGateway/DTMF.h index c2c56bb..7e64403 100644 --- a/YSFGateway/DTMF.h +++ b/YSFGateway/DTMF.h @@ -19,6 +19,8 @@ #ifndef DTMF_H #define DTMF_H +#include "WiresX.h" + #include class CDTMF { @@ -26,11 +28,11 @@ public: CDTMF(); ~CDTMF(); - bool decode(const unsigned char* ambe, bool end); - - bool hasCommand() const; + WX_STATUS decodeVW(const unsigned char* ambe); + WX_STATUS decodeDN1(const unsigned char* ambe); + WX_STATUS decodeDN2(const unsigned char* ambe); - std::string translate(); + unsigned int getReflector(); void reset(); @@ -41,6 +43,8 @@ private: unsigned int m_releaseCount; unsigned int m_pressCount; char m_lastChar; + + WX_STATUS validate() const; }; #endif diff --git a/YSFGateway/YSFGateway.cpp b/YSFGateway/YSFGateway.cpp index 4f2fb28..cddeb22 100644 --- a/YSFGateway/YSFGateway.cpp +++ b/YSFGateway/YSFGateway.cpp @@ -80,6 +80,7 @@ m_suffix(), m_conf(configFile), m_gps(NULL), m_wiresX(NULL), +m_dtmf(NULL), m_netNetwork(NULL), m_linked(false), m_exclude(false) @@ -206,6 +207,7 @@ int CYSFGateway::run() unsigned int reloadTime = m_conf.getNetworkReloadTime(); m_wiresX = new CWiresX(m_callsign, m_suffix, &rptNetwork, fileName, reloadTime); + m_dtmf = new CDTMF; std::string name = m_conf.getName(); unsigned int txFrequency = m_conf.getTxFrequency(); @@ -304,6 +306,66 @@ int CYSFGateway::run() default: break; } + + status = WXS_NONE; + switch (dt) { + case YSF_DT_VOICE_FR_MODE: + status = m_dtmf->decodeVW(buffer + 35U); + break; + case YSF_DT_VD_MODE1: + status = m_dtmf->decodeDN1(buffer + 35U); + break; + case YSF_DT_VD_MODE2: + status = m_dtmf->decodeDN2(buffer + 35U); + break; + default: + break; + } + + // XXX call reset() on end of transmission. + + switch (status) { + case WXS_CONNECT: { + unsigned int refl = m_dtmf->getReflector(); + // XXX validate reflector + // XXX Inform Wires-X + m_netNetwork->writeUnlink(); + m_netNetwork->writeUnlink(); + m_netNetwork->writeUnlink(); + + CYSFReflector* reflector = m_wiresX->getReflector(); + LogMessage("Connect to %5.5s has been requested by %10.10s", reflector->m_id.c_str(), buffer + 14U); + + m_netNetwork->setDestination(reflector->m_address, reflector->m_port); + m_netNetwork->writePoll(); + m_netNetwork->writePoll(); + m_netNetwork->writePoll(); + + inactivityTimer.start(); + lostTimer.start(); + pollTimer.start(); + + m_linked = true; + } + break; + case WXS_DISCONNECT: + // XXX Inform Wires-X + LogMessage("Disconnect has been requested by %10.10s", buffer + 14U); + + m_netNetwork->writeUnlink(); + m_netNetwork->writeUnlink(); + m_netNetwork->writeUnlink(); + m_netNetwork->clearDestination(); + + inactivityTimer.stop(); + lostTimer.stop(); + pollTimer.stop(); + + m_linked = false; + break; + default: + break; + } } if (m_gps != NULL) @@ -423,6 +485,7 @@ int CYSFGateway::run() delete m_netNetwork; delete m_wiresX; + delete m_dtmf; ::LogFinalise(); diff --git a/YSFGateway/YSFGateway.h b/YSFGateway/YSFGateway.h index 9c3f413..ca7ee94 100644 --- a/YSFGateway/YSFGateway.h +++ b/YSFGateway/YSFGateway.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2017 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,6 +22,7 @@ #include "Network.h" #include "WiresX.h" #include "Conf.h" +#include "DTMF.h" #include "GPS.h" #include @@ -40,6 +41,7 @@ private: CConf m_conf; CGPS* m_gps; CWiresX* m_wiresX; + CDTMF* m_dtmf; CNetwork* m_netNetwork; bool m_linked; bool m_exclude;