From af721f89e297d852d7c050a04fe82104247ccb11 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 5 Jan 2017 19:15:10 +0000 Subject: [PATCH] Add RSSI display for all modes. --- Conf.cpp | 38 +++++++++++++----- Conf.h | 8 ++-- DMRAccessControl.cpp | 39 ++++++++++++++---- DMRAccessControl.h | 15 ++++--- DMRControl.cpp | 8 ++-- DMRControl.h | 4 +- DMRNetwork.cpp | 10 ++--- DMRNetwork.h | 5 +-- DMRSlot.cpp | 95 +++++++++++++++++++++++++++++++++----------- DMRSlot.h | 6 ++- DStarControl.cpp | 69 ++++++++++++++++++++++++++++++-- DStarControl.h | 11 ++++- MMDVM.ini | 3 +- MMDVMHost.cpp | 39 ++++++++++-------- P25Control.cpp | 42 ++++++++++++++++++-- P25Control.h | 65 ++++++++++++++++-------------- YSFControl.cpp | 42 ++++++++++++++++++-- YSFControl.h | 11 ++++- 18 files changed, 381 insertions(+), 129 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 883519a..82158a7 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -107,6 +107,8 @@ m_dmrSelfOnly(false), m_dmrPrefixes(), m_dmrBlackList(), m_dmrWhiteList(), +m_dmrSlot1TGWhiteList(), +m_dmrSlot2TGWhiteList(), m_dmrCallHang(3U), m_dmrTXHang(4U), m_fusionEnabled(false), @@ -128,7 +130,6 @@ m_dmrNetworkDebug(false), m_dmrNetworkJitter(300U), m_dmrNetworkSlot1(true), m_dmrNetworkSlot2(true), -m_dmrNetworkRSSI(false), m_fusionNetworkEnabled(false), m_fusionNetworkMyAddress(), m_fusionNetworkMyPort(0U), @@ -393,6 +394,22 @@ bool CConf::read() m_dmrWhiteList.push_back(id); p = ::strtok(NULL, ",\r\n"); } + } else if (::strcmp(key, "Slot1TGWhiteList") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + unsigned int id = (unsigned int)::atoi(p); + if (id > 0U) + m_dmrSlot1TGWhiteList.push_back(id); + p = ::strtok(NULL, ",\r\n"); + } + } else if (::strcmp(key, "Slot2TGWhiteList") == 0) { + char* p = ::strtok(value, ",\r\n"); + while (p != NULL) { + unsigned int id = (unsigned int)::atoi(p); + if (id > 0U) + m_dmrSlot2TGWhiteList.push_back(id); + p = ::strtok(NULL, ",\r\n"); + } } else if (::strcmp(key, "TXHang") == 0) m_dmrTXHang = (unsigned int)::atoi(value); else if (::strcmp(key, "CallHang") == 0) @@ -439,8 +456,6 @@ bool CConf::read() m_dmrNetworkSlot1 = ::atoi(value) == 1; else if (::strcmp(key, "Slot2") == 0) m_dmrNetworkSlot2 = ::atoi(value) == 1; - else if (::strcmp(key, "RSSI") == 0) - m_dmrNetworkRSSI = ::atoi(value) == 1; } else if (section == SECTION_FUSION_NETWORK) { if (::strcmp(key, "Enable") == 0) m_fusionNetworkEnabled = ::atoi(value) == 1; @@ -801,6 +816,16 @@ std::vector CConf::getDMRWhiteList() const return m_dmrWhiteList; } +std::vector CConf::getDMRSlot1TGWhiteList() const +{ + return m_dmrSlot1TGWhiteList; +} + +std::vector CConf::getDMRSlot2TGWhiteList() const +{ + return m_dmrSlot2TGWhiteList; +} + unsigned int CConf::getDMRCallHang() const { return m_dmrCallHang; @@ -906,11 +931,6 @@ bool CConf::getDMRNetworkSlot2() const return m_dmrNetworkSlot2; } -bool CConf::getDMRNetworkRSSI() const -{ - return m_dmrNetworkRSSI; -} - bool CConf::getFusionNetworkEnabled() const { return m_fusionNetworkEnabled; diff --git a/Conf.h b/Conf.h index a92ca1a..5c94f01 100644 --- a/Conf.h +++ b/Conf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -100,6 +100,8 @@ public: std::vector getDMRPrefixes() const; std::vector getDMRBlackList() const; std::vector getDMRWhiteList() const; + std::vector getDMRSlot1TGWhiteList() const; + std::vector getDMRSlot2TGWhiteList() const; unsigned int getDMRCallHang() const; unsigned int getDMRTXHang() const; @@ -129,7 +131,6 @@ public: unsigned int getDMRNetworkJitter() const; bool getDMRNetworkSlot1() const; bool getDMRNetworkSlot2() const; - bool getDMRNetworkRSSI() const; // The System Fusion Network section bool getFusionNetworkEnabled() const; @@ -245,6 +246,8 @@ private: std::vector m_dmrPrefixes; std::vector m_dmrBlackList; std::vector m_dmrWhiteList; + std::vector m_dmrSlot1TGWhiteList; + std::vector m_dmrSlot2TGWhiteList; unsigned int m_dmrCallHang; unsigned int m_dmrTXHang; @@ -270,7 +273,6 @@ private: unsigned int m_dmrNetworkJitter; bool m_dmrNetworkSlot1; bool m_dmrNetworkSlot2; - bool m_dmrNetworkRSSI; bool m_fusionNetworkEnabled; std::string m_fusionNetworkMyAddress; diff --git a/DMRAccessControl.cpp b/DMRAccessControl.cpp index ecda020..0415a62 100644 --- a/DMRAccessControl.cpp +++ b/DMRAccessControl.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2016 by Simon Rune G7RZU - * 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 @@ -28,20 +28,25 @@ std::vector CDMRAccessControl::m_whiteList; std::vector CDMRAccessControl::m_prefixes; +std::vector CDMRAccessControl::m_slot1TGWhiteList; +std::vector CDMRAccessControl::m_slot2TGWhiteList; + bool CDMRAccessControl::m_selfOnly = false; unsigned int CDMRAccessControl::m_id = 0U; -void CDMRAccessControl::init(const std::vector& blacklist, const std::vector& whitelist, bool selfOnly, const std::vector& prefixes, unsigned int id) +void CDMRAccessControl::init(const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, bool selfOnly, const std::vector& prefixes, unsigned int id) { - m_blackList = blacklist; - m_whiteList = whitelist; - m_selfOnly = selfOnly; - m_prefixes = prefixes; - m_id = id; + m_slot1TGWhiteList = slot1TGWhitelist; + m_slot2TGWhiteList = slot2TGWhitelist; + m_blackList = blacklist; + m_whiteList = whitelist; + m_selfOnly = selfOnly; + m_prefixes = prefixes; + m_id = id; } -bool CDMRAccessControl::validateId(unsigned int id) +bool CDMRAccessControl::validateSrcId(unsigned int id) { if (m_selfOnly) return id == m_id; @@ -64,3 +69,21 @@ bool CDMRAccessControl::validateId(unsigned int id) return true; } + +bool CDMRAccessControl::validateTGId(unsigned int slotNo, bool group, unsigned int id) +{ + if (!group) + return true; + + if (slotNo == 1U) { + if (m_slot1TGWhiteList.empty()) + return true; + + return std::find(m_slot1TGWhiteList.begin(), m_slot1TGWhiteList.end(), id) != m_slot1TGWhiteList.end(); + } else { + if (m_slot2TGWhiteList.empty()) + return true; + + return std::find(m_slot2TGWhiteList.begin(), m_slot2TGWhiteList.end(), id) != m_slot2TGWhiteList.end(); + } +} diff --git a/DMRAccessControl.h b/DMRAccessControl.h index ccb7c69..7d4aec1 100644 --- a/DMRAccessControl.h +++ b/DMRAccessControl.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2016 by Simon Rune G7RZU - * 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 @@ -20,20 +20,23 @@ #include -#include "DMRLC.h" - class CDMRAccessControl { public: - static bool validateId(unsigned int id); + static bool validateSrcId(unsigned int id); - static void init(const std::vector& blacklist, const std::vector& whitelist, bool selfOnly, const std::vector& prefixes, unsigned int id); + static bool validateTGId(unsigned int slotNo, bool group, unsigned int id); + + static void init(const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, bool selfOnly, const std::vector& prefixes, unsigned int id); private: static std::vector m_blackList; static std::vector m_whiteList; static std::vector m_prefixes; - + + static std::vector m_slot1TGWhiteList; + static std::vector m_slot2TGWhiteList; + static bool m_selfOnly; static unsigned int m_id; }; diff --git a/DMRControl.cpp b/DMRControl.cpp index 4f749b9..cdb12ff 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX + * Copyright (C) 2015,2016,2017 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,7 +21,7 @@ #include #include -CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter) : +CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, 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) : m_id(id), m_colorCode(colorCode), m_modem(modem), @@ -37,7 +37,7 @@ m_lookup(lookup) assert(rssi != NULL); // Load black and white lists to DMRAccessControl - CDMRAccessControl::init(blacklist, whitelist, selfOnly, prefixes, id); + CDMRAccessControl::init(blacklist, whitelist, slot1TGWhitelist, slot2TGWhitelist, selfOnly, prefixes, id); CDMRSlot::init(colorCode, callHang, modem, network, display, duplex, m_lookup, rssi, jitter); } @@ -68,7 +68,7 @@ bool CDMRControl::processWakeup(const unsigned char* data) std::string src = m_lookup->find(srcId); - bool ret = CDMRAccessControl::validateId(srcId); + bool ret = CDMRAccessControl::validateSrcId(srcId); if (!ret) { LogMessage("Invalid CSBK BS_Dwn_Act received from %s", src.c_str()); return false; diff --git a/DMRControl.h b/DMRControl.h index d631047..466ca2c 100644 --- a/DMRControl.h +++ b/DMRControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -31,7 +31,7 @@ class CDMRControl { public: - CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter); + CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, 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); ~CDMRControl(); bool processWakeup(const unsigned char* data); diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index 6bb182f..5101fb1 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -31,7 +31,7 @@ const unsigned int BUFFER_LENGTH = 500U; const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; -CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, bool rssi, HW_TYPE hwType) : +CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType) : m_address(), m_port(port), m_id(NULL), @@ -43,7 +43,6 @@ m_socket(local), m_enabled(false), m_slot1(slot1), m_slot2(slot2), -m_rssi(rssi), m_hwType(hwType), m_status(WAITING_CONNECT), m_retryTimer(1000U, 10U), @@ -268,10 +267,7 @@ bool CDMRNetwork::write(const CDMRData& data) buffer[53U] = data.getBER(); - if (m_rssi) - buffer[54U] = data.getRSSI(); - else - buffer[54U] = 0x00U; + buffer[54U] = data.getRSSI(); if (m_debug) CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH); diff --git a/DMRNetwork.h b/DMRNetwork.h index 1739410..325b2ea 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -31,7 +31,7 @@ class CDMRNetwork { public: - CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, bool rssi, HW_TYPE hwType); + CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType); ~CDMRNetwork(); void setOptions(const std::string& options); @@ -64,7 +64,6 @@ private: bool m_enabled; bool m_slot1; bool m_slot2; - bool m_rssi; HW_TYPE m_hwType; enum STATUS { diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 8d2291c..18a1883 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include "DMRAccessControl.h" #include "DMRSlotType.h" #include "DMRShortLC.h" #include "DMRTrellis.h" @@ -18,11 +19,11 @@ #include "BPTC19696.h" #include "DMRSlot.h" #include "DMRCSBK.h" +#include "DMREMB.h" #include "Utils.h" #include "Sync.h" #include "CRC.h" #include "Log.h" -#include "DMRAccessControl.h" #include #include @@ -84,8 +85,11 @@ m_rfErrs(0U), m_netErrs(0U), m_lastFrame(NULL), m_lastFrameValid(false), -m_lastEMB(), m_rssi(0U), +m_maxRSSI(0U), +m_minRSSI(0U), +m_aveRSSI(0U), +m_rssiCount(0U), m_fp(NULL) { m_lastFrame = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -103,13 +107,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) assert(data != NULL); if (data[0U] == TAG_LOST && m_rfState == RS_RF_AUDIO) { - LogMessage("DMR Slot %u, RF transmission lost, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits)); + LogMessage("DMR Slot %u, RF voice transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); writeEndRF(true); return; } if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) { - LogMessage("DMR Slot %u, RF transmission lost", m_slotNo); + LogMessage("DMR Slot %u, RF data transmission lost", m_slotNo); writeEndRF(); return; } @@ -131,6 +135,14 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) // RSSI is always reported as positive m_rssi = (rssi >= 0) ? rssi : -rssi; + + if (m_rssi > m_minRSSI) + m_minRSSI = m_rssi; + if (m_rssi < m_maxRSSI) + m_maxRSSI = m_rssi; + + m_aveRSSI += m_rssi; + m_rssiCount++; } bool dataSync = (data[1U] & DMR_SYNC_DATA) == DMR_SYNC_DATA; @@ -155,13 +167,20 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) unsigned int srcId = lc->getSrcId(); unsigned int dstId = lc->getDstId(); + FLCO flco = lc->getFLCO(); - if (!CDMRAccessControl::validateId(srcId)) { + if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); delete lc; return; } + if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) { + LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); + delete lc; + return; + } + m_rfLC = lc; // Regenerate the LC data @@ -184,6 +203,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) m_rfBits = 1U; m_rfErrs = 0U; + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; + if (m_duplex) { m_queue.clear(); m_modem->writeDMRAbort(m_slotNo); @@ -201,11 +225,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) std::string dst = m_lookup->find(dstId); if (m_netState == RS_NET_IDLE) { - setShortLC(m_slotNo, dstId, m_rfLC->getFLCO(), true); - m_display->writeDMR(m_slotNo, src, m_rfLC->getFLCO() == FLCO_GROUP, dst, "R"); + setShortLC(m_slotNo, dstId, flco, true); + m_display->writeDMR(m_slotNo, src, flco == FLCO_GROUP, dst, "R"); } - LogMessage("DMR Slot %u, received RF voice header from %s to %s%s", m_slotNo, src.c_str(), m_rfLC->getFLCO() == FLCO_GROUP ? "TG " : "", dst.c_str()); + LogMessage("DMR Slot %u, received RF voice header from %s to %s%s", m_slotNo, src.c_str(), flco == FLCO_GROUP ? "TG " : "", dst.c_str()); } else if (dataType == DT_VOICE_PI_HEADER) { if (m_rfState != RS_RF_AUDIO) return; @@ -254,7 +278,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) writeQueueRF(data); } - LogMessage("DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits)); + LogMessage("DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); writeEndRF(); } else if (dataType == DT_DATA_HEADER) { @@ -270,11 +294,16 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) unsigned int srcId = dataHeader.getSrcId(); unsigned int dstId = dataHeader.getDstId(); - if (!CDMRAccessControl::validateId(srcId)) { + if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); return; } + if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) { + LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); + return; + } + m_rfFrames = dataHeader.getBlocks(); m_rfDataHeader = dataHeader; @@ -329,10 +358,15 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) unsigned int dstId = csbk.getDstId(); if (srcId != 0U || dstId != 0U) { - if (!CDMRAccessControl::validateId(srcId)) { + if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); return; } + + if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) { + LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); + return; + } } // Regenerate the CSBK data @@ -490,13 +524,20 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) if (lc != NULL) { unsigned int srcId = lc->getSrcId(); unsigned int dstId = lc->getDstId(); + FLCO flco = lc->getFLCO(); - if (!CDMRAccessControl::validateId(srcId)) { + if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); delete lc; return; } + if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) { + LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); + delete lc; + return; + } + m_rfLC = lc; // Create a dummy start frame to replace the received frame @@ -516,12 +557,18 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) start[1U] = 0x00U; m_rfTimeoutTimer.start(); + m_rfEmbeddedLC.reset(); m_rfFrames = 0U; m_rfSeqNo = 0U; m_rfBits = 1U; m_rfErrs = 0U; + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; + if (m_duplex) { m_queue.clear(); m_modem->writeDMRAbort(m_slotNo); @@ -565,11 +612,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) std::string dst = m_lookup->find(dstId); if (m_netState == RS_NET_IDLE) { - setShortLC(m_slotNo, dstId, m_rfLC->getFLCO(), true); - m_display->writeDMR(m_slotNo, src, m_rfLC->getFLCO() == FLCO_GROUP, dst, "R"); + setShortLC(m_slotNo, dstId, flco, true); + m_display->writeDMR(m_slotNo, src, flco == FLCO_GROUP, dst, "R"); } - LogMessage("DMR Slot %u, received RF late entry from %s to %s%s", m_slotNo, src.c_str(), m_rfLC->getFLCO() == FLCO_GROUP ? "TG " : "", dst.c_str()); + LogMessage("DMR Slot %u, received RF late entry from %s to %s%s", m_slotNo, src.c_str(), flco == FLCO_GROUP ? "TG " : "", dst.c_str()); } } } @@ -1105,11 +1152,12 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netBits += 141U; // Change the color code in the EMB - m_lastEMB.putData(data + 2U); - m_lastEMB.setColorCode(m_colorCode); - m_lastEMB.getData(data + 2U); + CDMREMB emb; + emb.putData(data + 2U); + emb.setColorCode(m_colorCode); + emb.getData(data + 2U); - m_netEmbeddedLC.addData(data + 2U, m_lastEMB.getLCSS()); + m_netEmbeddedLC.addData(data + 2U, emb.getLCSS()); data[0U] = TAG_DATA; data[1U] = 0x00U; @@ -1582,6 +1630,10 @@ void CDMRSlot::insertSilence(unsigned int count) unsigned char fid = m_netLC->getFID(); + CDMREMB emb; + emb.setColorCode(m_colorCode); + emb.setLCSS(0U); + for (unsigned int i = 0U; i < count; i++) { // Only use our silence frame if its AMBE audio data if (fid == FID_ETSI || fid == FID_DMRA) { @@ -1595,10 +1647,7 @@ void CDMRSlot::insertSilence(unsigned int count) CSync::addDMRAudioSync(data + 2U, m_duplex); } else { ::memset(data + 2U + 13U, 0x00U, 7U); - - m_lastEMB.setColorCode(m_colorCode); - m_lastEMB.setLCSS(0U); - m_lastEMB.getData(data + 2U); + emb.getData(data + 2U); } writeQueueNet(data); diff --git a/DMRSlot.h b/DMRSlot.h index 8c54bd6..e27532c 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -31,7 +31,6 @@ #include "DMRData.h" #include "Display.h" #include "Defines.h" -#include "DMREMB.h" #include "Timer.h" #include "Modem.h" #include "DMRLC.h" @@ -84,8 +83,11 @@ private: unsigned int m_netErrs; unsigned char* m_lastFrame; bool m_lastFrameValid; - CDMREMB m_lastEMB; unsigned char m_rssi; + unsigned char m_maxRSSI; + unsigned char m_minRSSI; + unsigned int m_aveRSSI; + unsigned int m_rssiCount; FILE* m_fp; static unsigned int m_colorCode; diff --git a/DStarControl.cpp b/DStarControl.cpp index bc967a0..b25f0c1 100644 --- a/DStarControl.cpp +++ b/DStarControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX + * Copyright (C) 2015,2016,2017 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 @@ -36,7 +36,7 @@ bool CallsignCompare(const std::string& arg, const unsigned char* my) // #define DUMP_DSTAR -CDStarControl::CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex) : +CDStarControl::CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) : m_callsign(NULL), m_gateway(NULL), m_selfOnly(selfOnly), @@ -70,9 +70,16 @@ m_rfErrs(0U), m_netErrs(0U), m_lastFrame(NULL), m_lastFrameValid(false), +m_rssiMapper(rssiMapper), +m_rssi(0U), +m_maxRSSI(0U), +m_minRSSI(0U), +m_aveRSSI(0U), +m_rssiCount(0U), m_fp(NULL) { assert(display != NULL); + assert(rssiMapper != NULL); m_callsign = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH]; m_gateway = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH]; @@ -111,7 +118,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) unsigned char type = data[0U]; if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) { - LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits)); + LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); writeEndRF(); return false; } @@ -121,6 +128,50 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) return false; } + // Have we got RSSI bytes on the end of a D-Star header? + if (len == (DSTAR_HEADER_LENGTH_BYTES + 3U)) { + uint16_t raw = 0U; + raw |= (data[42U] << 8) & 0xFF00U; + raw |= (data[43U] << 0) & 0x00FFU; + + // Convert the raw RSSI to dBm + int rssi = m_rssiMapper->interpolate(raw); + LogDebug("D-Star, raw RSSI: %u, reported RSSI: %d dBm", raw, rssi); + + // RSSI is always reported as positive + m_rssi = (rssi >= 0) ? rssi : -rssi; + + if (m_rssi > m_minRSSI) + m_minRSSI = m_rssi; + if (m_rssi < m_maxRSSI) + m_maxRSSI = m_rssi; + + m_aveRSSI += m_rssi; + m_rssiCount++; + } + + // Have we got RSSI bytes on the end of D-Star data? + if (len == (DSTAR_FRAME_LENGTH_BYTES + 3U)) { + uint16_t raw = 0U; + raw |= (data[13U] << 8) & 0xFF00U; + raw |= (data[14U] << 0) & 0x00FFU; + + // Convert the raw RSSI to dBm + int rssi = m_rssiMapper->interpolate(raw); + LogDebug("D-Star, raw RSSI: %u, reported RSSI: %d dBm", raw, rssi); + + // RSSI is always reported as positive + m_rssi = (rssi >= 0) ? rssi : -rssi; + + if (m_rssi > m_minRSSI) + m_minRSSI = m_rssi; + if (m_rssi < m_maxRSSI) + m_maxRSSI = m_rssi; + + m_aveRSSI += m_rssi; + m_rssiCount++; + } + if (type == TAG_HEADER) { CDStarHeader header(data + 1U); @@ -181,6 +232,11 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) m_rfFrames = 1U; m_rfN = 0U; + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; + if (m_duplex) { // Modify the header header.setRepeater(false); @@ -217,7 +273,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) if (m_duplex) writeQueueEOTRF(); - LogMessage("D-Star, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits)); + LogMessage("D-Star, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); writeEndRF(); } @@ -328,6 +384,11 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) m_rfN = 0U; m_rfFrames = 1U; + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; + if (m_duplex) { unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U]; start[0U] = TAG_HEADER; diff --git a/DStarControl.h b/DStarControl.h index 0654ce9..9eab5e3 100644 --- a/DStarControl.h +++ b/DStarControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -19,6 +19,7 @@ #if !defined(DStarControl_H) #define DStarControl_H +#include "RSSIInterpolator.h" #include "DStarNetwork.h" #include "DStarSlowData.h" #include "DStarDefines.h" @@ -36,7 +37,7 @@ class CDStarControl { public: - CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex); + CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper); ~CDStarControl(); bool writeModem(unsigned char* data, unsigned int len); @@ -79,6 +80,12 @@ private: unsigned int m_netErrs; unsigned char* m_lastFrame; bool m_lastFrameValid; + CRSSIInterpolator* m_rssiMapper; + unsigned char m_rssi; + unsigned char m_maxRSSI; + unsigned char m_minRSSI; + unsigned int m_aveRSSI; + unsigned int m_rssiCount; FILE* m_fp; void writeNetwork(); diff --git a/MMDVM.ini b/MMDVM.ini index acb3f57..d94707f 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -70,6 +70,8 @@ Id=123456 ColorCode=1 SelfOnly=0 # Prefixes=234,235 +# Slot1TGWhiteList= +# Slot2TGWhiteList= CallHang=3 TXHang=4 @@ -96,7 +98,6 @@ Jitter=300 # Local=3350 Password=PASSWORD # Options= -RSSI=0 Slot1=1 Slot2=1 Debug=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index ad976af..b063c59 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -297,6 +297,16 @@ int CMMDVMHost::run() CTimer dmrBeaconTimer(1000U, 4U); bool dmrBeaconsEnabled = m_dmrEnabled && m_conf.getDMRBeacons(); + // For all modes we handle RSSI + std::string rssiMappingFile = m_conf.getModemRSSIMappingFile(); + + CRSSIInterpolator* rssi = new CRSSIInterpolator; + if (!rssiMappingFile.empty()) { + LogInfo("RSSI"); + LogInfo(" Mapping File: %s", rssiMappingFile.c_str()); + rssi->load(rssiMappingFile); + } + // For DMR and P25 we try to map IDs to callsigns if (m_dmrEnabled || m_p25Enabled) { std::string lookupFile = m_conf.getDMRIdLookupFile(); @@ -327,7 +337,7 @@ int CMMDVMHost::run() if (blackList.size() > 0U) LogInfo(" Black List: %u", blackList.size()); - dstar = new CDStarControl(m_callsign, module, selfOnly, blackList, m_dstarNetwork, m_display, m_timeout, m_duplex); + dstar = new CDStarControl(m_callsign, module, selfOnly, blackList, m_dstarNetwork, m_display, m_timeout, m_duplex, rssi); } CDMRControl* dmr = NULL; @@ -338,9 +348,10 @@ int CMMDVMHost::run() std::vector prefixes = m_conf.getDMRPrefixes(); std::vector blackList = m_conf.getDMRBlackList(); std::vector whiteList = m_conf.getDMRWhiteList(); - unsigned int callHang = m_conf.getDMRCallHang(); + std::vector slot1TGWhiteList = m_conf.getDMRSlot1TGWhiteList(); + std::vector slot2TGWhiteList = m_conf.getDMRSlot2TGWhiteList(); + unsigned int callHang = m_conf.getDMRCallHang(); unsigned int txHang = m_conf.getDMRTXHang(); - std::string rssiMappingFile = m_conf.getModemRSSIMappingFile(); unsigned int jitter = m_conf.getDMRNetworkJitter(); if (txHang > m_rfModeHang) @@ -361,17 +372,15 @@ int CMMDVMHost::run() LogInfo(" Source ID Black List: %u", blackList.size()); if (whiteList.size() > 0U) LogInfo(" Source ID White List: %u", whiteList.size()); + if (slot1TGWhiteList.size() > 0U) + LogInfo(" Slot 1 TG White List: %u", slot1TGWhiteList.size()); + if (slot2TGWhiteList.size() > 0U) + LogInfo(" Slot 2 TG White List: %u", slot2TGWhiteList.size()); LogInfo(" Call Hang: %us", callHang); LogInfo(" TX Hang: %us", txHang); - CRSSIInterpolator* rssi = new CRSSIInterpolator; - if (!rssiMappingFile.empty()) { - LogInfo(" RSSI Mapping File: %s", rssiMappingFile.c_str()); - rssi->load(rssiMappingFile); - } - - dmr = new CDMRControl(id, colorCode, callHang, selfOnly, prefixes, blackList, whiteList, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, m_lookup, rssi, jitter); + dmr = new CDMRControl(id, colorCode, callHang, selfOnly, prefixes, blackList, whiteList, slot1TGWhiteList, slot2TGWhiteList, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, m_lookup, rssi, jitter); m_dmrTXTimer.setTimeout(txHang); } @@ -383,7 +392,7 @@ int CMMDVMHost::run() LogInfo("YSF Parameters"); LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no"); - ysf = new CYSFControl(m_callsign, m_ysfNetwork, m_display, m_timeout, m_duplex, remoteGateway); + ysf = new CYSFControl(m_callsign, m_ysfNetwork, m_display, m_timeout, m_duplex, remoteGateway, rssi); } CP25Control* p25 = NULL; @@ -393,7 +402,7 @@ int CMMDVMHost::run() LogInfo("P25 Parameters"); LogInfo(" NAC: $%03X", nac); - p25 = new CP25Control(nac, m_p25Network, m_display, m_timeout, m_duplex, m_lookup); + p25 = new CP25Control(nac, m_p25Network, m_display, m_timeout, m_duplex, m_lookup, rssi); } setMode(MODE_IDLE); @@ -854,7 +863,6 @@ bool CMMDVMHost::createDMRNetwork() unsigned int jitter = m_conf.getDMRNetworkJitter(); bool slot1 = m_conf.getDMRNetworkSlot1(); bool slot2 = m_conf.getDMRNetworkSlot2(); - bool rssi = m_conf.getDMRNetworkRSSI(); HW_TYPE hwType = m_modem->getHWType(); LogInfo("DMR Network Parameters"); @@ -867,9 +875,8 @@ bool CMMDVMHost::createDMRNetwork() LogInfo(" Jitter: %ums", jitter); LogInfo(" Slot 1: %s", slot1 ? "enabled" : "disabled"); LogInfo(" Slot 2: %s", slot2 ? "enabled" : "disabled"); - LogInfo(" RSSI: %s", rssi ? "enabled" : "disabled"); - m_dmrNetwork = new CDMRNetwork(address, port, local, id, password, m_duplex, VERSION, debug, slot1, slot2, rssi, hwType); + m_dmrNetwork = new CDMRNetwork(address, port, local, id, password, m_duplex, VERSION, debug, slot1, slot2, hwType); std::string options = m_conf.getDMRNetworkOptions(); if (!options.empty()) { diff --git a/P25Control.cpp b/P25Control.cpp index 26560f7..acaa087 100644 --- a/P25Control.cpp +++ b/P25Control.cpp @@ -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 @@ -35,7 +35,7 @@ const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U #define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) #define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) -CP25Control::CP25Control(unsigned int nac, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup) : +CP25Control::CP25Control(unsigned int nac, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper) : m_nac(nac), m_network(network), m_display(display), @@ -63,10 +63,17 @@ m_netLDU1(NULL), m_netLDU2(NULL), m_lastIMBE(NULL), m_rfLDU(NULL), +m_rssiMapper(rssiMapper), +m_rssi(0U), +m_maxRSSI(0U), +m_minRSSI(0U), +m_aveRSSI(0U), +m_rssiCount(0U), m_fp(NULL) { assert(display != NULL); assert(lookup != NULL); + assert(rssiMapper != NULL); m_netLDU1 = new unsigned char[9U * 25U]; m_netLDU2 = new unsigned char[9U * 25U]; @@ -101,7 +108,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) return false; if (data[0U] == TAG_LOST) { - LogMessage("P25, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits)); + LogMessage("P25, transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); if (m_netState == RS_NET_IDLE) m_display->clearP25(); writeNetwork(m_rfLDU, m_lastDUID, true); @@ -139,6 +146,28 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) } } + // Have we got RSSI bytes on the end of a P25 LDU? + if (len == (P25_LDU_FRAME_LENGTH_BYTES + 4U)) { + uint16_t raw = 0U; + raw |= (data[218U] << 8) & 0xFF00U; + raw |= (data[219U] << 0) & 0x00FFU; + + // Convert the raw RSSI to dBm + int rssi = m_rssiMapper->interpolate(raw); + LogDebug("P25, raw RSSI: %u, reported RSSI: %d dBm", raw, rssi); + + // RSSI is always reported as positive + m_rssi = (rssi >= 0) ? rssi : -rssi; + + if (m_rssi > m_minRSSI) + m_minRSSI = m_rssi; + if (m_rssi < m_maxRSSI) + m_maxRSSI = m_rssi; + + m_aveRSSI += m_rssi; + m_rssiCount++; + } + if (duid == P25_DUID_LDU1) { if (m_rfState == RS_RF_LISTENING) { m_rfData.reset(); @@ -148,6 +177,11 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) return false; } + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; + createRFHeader(); writeNetwork(data + 2U, P25_DUID_HEADER, false); } else { @@ -262,7 +296,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) m_rfData.reset(); m_lastDUID = duid; - LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits)); + LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); m_display->clearP25(); #if defined(DUMP_P25) diff --git a/P25Control.h b/P25Control.h index edd726a..3a2e1a2 100644 --- a/P25Control.h +++ b/P25Control.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 @@ -19,6 +19,7 @@ #if !defined(P25Control_H) #define P25Control_H +#include "RSSIInterpolator.h" #include "P25LowSpeedData.h" #include "RingBuffer.h" #include "P25Network.h" @@ -35,7 +36,7 @@ class CP25Control { public: - CP25Control(unsigned int nac, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup); + CP25Control(unsigned int nac, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper); ~CP25Control(); bool writeModem(unsigned char* data, unsigned int len); @@ -45,34 +46,40 @@ public: void clock(unsigned int ms); private: - unsigned int m_nac; - CP25Network* m_network; - CDisplay* m_display; - bool m_duplex; - CDMRLookup* m_lookup; + unsigned int m_nac; + CP25Network* m_network; + CDisplay* m_display; + bool m_duplex; + CDMRLookup* m_lookup; CRingBuffer m_queue; - RPT_RF_STATE m_rfState; - RPT_NET_STATE m_netState; - CTimer m_rfTimeout; - CTimer m_netTimeout; - CTimer m_networkWatchdog; - unsigned int m_rfFrames; - unsigned int m_rfBits; - unsigned int m_rfErrs; - unsigned int m_netFrames; - unsigned int m_netLost; - CP25NID m_nid; - unsigned char m_lastDUID; - CP25Audio m_audio; - CP25Data m_rfData; - CP25Data m_netData; - CP25LowSpeedData m_rfLSD; - CP25LowSpeedData m_netLSD; - unsigned char* m_netLDU1; - unsigned char* m_netLDU2; - unsigned char* m_lastIMBE; - unsigned char* m_rfLDU; - FILE* m_fp; + RPT_RF_STATE m_rfState; + RPT_NET_STATE m_netState; + CTimer m_rfTimeout; + CTimer m_netTimeout; + CTimer m_networkWatchdog; + unsigned int m_rfFrames; + unsigned int m_rfBits; + unsigned int m_rfErrs; + unsigned int m_netFrames; + unsigned int m_netLost; + CP25NID m_nid; + unsigned char m_lastDUID; + CP25Audio m_audio; + CP25Data m_rfData; + CP25Data m_netData; + CP25LowSpeedData m_rfLSD; + CP25LowSpeedData m_netLSD; + unsigned char* m_netLDU1; + unsigned char* m_netLDU2; + unsigned char* m_lastIMBE; + unsigned char* m_rfLDU; + CRSSIInterpolator* m_rssiMapper; + unsigned char m_rssi; + unsigned char m_maxRSSI; + unsigned char m_minRSSI; + unsigned int m_aveRSSI; + unsigned int m_rssiCount; + FILE* m_fp; void writeQueueRF(const unsigned char* data, unsigned int length); void writeQueueNet(const unsigned char* data, unsigned int length); diff --git a/YSFControl.cpp b/YSFControl.cpp index c0a3ea7..a884e93 100644 --- a/YSFControl.cpp +++ b/YSFControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX + * Copyright (C) 2015,2016,2017 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,7 +24,7 @@ // #define DUMP_YSF -CYSFControl::CYSFControl(const std::string& callsign, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway) : +CYSFControl::CYSFControl(const std::string& callsign, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper) : m_callsign(NULL), m_network(network), m_display(display), @@ -56,9 +56,16 @@ m_lastMR(YSF_MR_NOT_BUSY), m_netN(0U), m_rfPayload(), m_netPayload(), +m_rssiMapper(rssiMapper), +m_rssi(0U), +m_maxRSSI(0U), +m_minRSSI(0U), +m_aveRSSI(0U), +m_rssiCount(0U), m_fp(NULL) { assert(display != NULL); + assert(rssiMapper != NULL); m_rfPayload.setUplink(callsign); m_rfPayload.setDownlink(callsign); @@ -94,7 +101,7 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len) unsigned char type = data[0U]; if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) { - LogMessage("YSF, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits)); + LogMessage("YSF, transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); writeEndRF(); return false; } @@ -102,6 +109,28 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len) if (type == TAG_LOST) return false; + // Have we got RSSI bytes on the end? + if (len == (YSF_FRAME_LENGTH_BYTES + 4U)) { + uint16_t raw = 0U; + raw |= (data[122U] << 8) & 0xFF00U; + raw |= (data[123U] << 0) & 0x00FFU; + + // Convert the raw RSSI to dBm + int rssi = m_rssiMapper->interpolate(raw); + LogDebug("YSF, raw RSSI: %u, reported RSSI: %d dBm", raw, rssi); + + // RSSI is always reported as positive + m_rssi = (rssi >= 0) ? rssi : -rssi; + + if (m_rssi > m_minRSSI) + m_minRSSI = m_rssi; + if (m_rssi < m_maxRSSI) + m_maxRSSI = m_rssi; + + m_aveRSSI += m_rssi; + m_rssiCount++; + } + CYSFFICH fich; bool valid = fich.decode(data + 2U); @@ -116,6 +145,11 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len) m_rfTimeoutTimer.start(); m_rfPayload.reset(); m_rfState = RS_RF_AUDIO; + + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; #if defined(DUMP_YSF) openFile(); #endif @@ -209,7 +243,7 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len) m_rfFrames++; - LogMessage("YSF, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits)); + LogMessage("YSF, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); writeEndRF(); return false; diff --git a/YSFControl.h b/YSFControl.h index 62020ef..bc98146 100644 --- a/YSFControl.h +++ b/YSFControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -19,6 +19,7 @@ #if !defined(YSFControl_H) #define YSFControl_H +#include "RSSIInterpolator.h" #include "YSFNetwork.h" #include "YSFDefines.h" #include "YSFPayload.h" @@ -33,7 +34,7 @@ class CYSFControl { public: - CYSFControl(const std::string& callsign, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway); + CYSFControl(const std::string& callsign, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper); ~CYSFControl(); bool writeModem(unsigned char* data, unsigned int len); @@ -74,6 +75,12 @@ private: unsigned char m_netN; CYSFPayload m_rfPayload; CYSFPayload m_netPayload; + CRSSIInterpolator* m_rssiMapper; + unsigned char m_rssi; + unsigned char m_maxRSSI; + unsigned char m_minRSSI; + unsigned int m_aveRSSI; + unsigned int m_rssiCount; FILE* m_fp; void writeQueueRF(const unsigned char* data);