Add RSSI display for all modes.
This commit is contained in:
parent
8debea45e4
commit
af721f89e2
38
Conf.cpp
38
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -107,6 +107,8 @@ m_dmrSelfOnly(false),
|
||||||
m_dmrPrefixes(),
|
m_dmrPrefixes(),
|
||||||
m_dmrBlackList(),
|
m_dmrBlackList(),
|
||||||
m_dmrWhiteList(),
|
m_dmrWhiteList(),
|
||||||
|
m_dmrSlot1TGWhiteList(),
|
||||||
|
m_dmrSlot2TGWhiteList(),
|
||||||
m_dmrCallHang(3U),
|
m_dmrCallHang(3U),
|
||||||
m_dmrTXHang(4U),
|
m_dmrTXHang(4U),
|
||||||
m_fusionEnabled(false),
|
m_fusionEnabled(false),
|
||||||
|
@ -128,7 +130,6 @@ m_dmrNetworkDebug(false),
|
||||||
m_dmrNetworkJitter(300U),
|
m_dmrNetworkJitter(300U),
|
||||||
m_dmrNetworkSlot1(true),
|
m_dmrNetworkSlot1(true),
|
||||||
m_dmrNetworkSlot2(true),
|
m_dmrNetworkSlot2(true),
|
||||||
m_dmrNetworkRSSI(false),
|
|
||||||
m_fusionNetworkEnabled(false),
|
m_fusionNetworkEnabled(false),
|
||||||
m_fusionNetworkMyAddress(),
|
m_fusionNetworkMyAddress(),
|
||||||
m_fusionNetworkMyPort(0U),
|
m_fusionNetworkMyPort(0U),
|
||||||
|
@ -393,6 +394,22 @@ bool CConf::read()
|
||||||
m_dmrWhiteList.push_back(id);
|
m_dmrWhiteList.push_back(id);
|
||||||
p = ::strtok(NULL, ",\r\n");
|
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)
|
} else if (::strcmp(key, "TXHang") == 0)
|
||||||
m_dmrTXHang = (unsigned int)::atoi(value);
|
m_dmrTXHang = (unsigned int)::atoi(value);
|
||||||
else if (::strcmp(key, "CallHang") == 0)
|
else if (::strcmp(key, "CallHang") == 0)
|
||||||
|
@ -439,8 +456,6 @@ bool CConf::read()
|
||||||
m_dmrNetworkSlot1 = ::atoi(value) == 1;
|
m_dmrNetworkSlot1 = ::atoi(value) == 1;
|
||||||
else if (::strcmp(key, "Slot2") == 0)
|
else if (::strcmp(key, "Slot2") == 0)
|
||||||
m_dmrNetworkSlot2 = ::atoi(value) == 1;
|
m_dmrNetworkSlot2 = ::atoi(value) == 1;
|
||||||
else if (::strcmp(key, "RSSI") == 0)
|
|
||||||
m_dmrNetworkRSSI = ::atoi(value) == 1;
|
|
||||||
} else if (section == SECTION_FUSION_NETWORK) {
|
} else if (section == SECTION_FUSION_NETWORK) {
|
||||||
if (::strcmp(key, "Enable") == 0)
|
if (::strcmp(key, "Enable") == 0)
|
||||||
m_fusionNetworkEnabled = ::atoi(value) == 1;
|
m_fusionNetworkEnabled = ::atoi(value) == 1;
|
||||||
|
@ -801,6 +816,16 @@ std::vector<unsigned int> CConf::getDMRWhiteList() const
|
||||||
return m_dmrWhiteList;
|
return m_dmrWhiteList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> CConf::getDMRSlot1TGWhiteList() const
|
||||||
|
{
|
||||||
|
return m_dmrSlot1TGWhiteList;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> CConf::getDMRSlot2TGWhiteList() const
|
||||||
|
{
|
||||||
|
return m_dmrSlot2TGWhiteList;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int CConf::getDMRCallHang() const
|
unsigned int CConf::getDMRCallHang() const
|
||||||
{
|
{
|
||||||
return m_dmrCallHang;
|
return m_dmrCallHang;
|
||||||
|
@ -906,11 +931,6 @@ bool CConf::getDMRNetworkSlot2() const
|
||||||
return m_dmrNetworkSlot2;
|
return m_dmrNetworkSlot2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CConf::getDMRNetworkRSSI() const
|
|
||||||
{
|
|
||||||
return m_dmrNetworkRSSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CConf::getFusionNetworkEnabled() const
|
bool CConf::getFusionNetworkEnabled() const
|
||||||
{
|
{
|
||||||
return m_fusionNetworkEnabled;
|
return m_fusionNetworkEnabled;
|
||||||
|
|
8
Conf.h
8
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -100,6 +100,8 @@ public:
|
||||||
std::vector<unsigned int> getDMRPrefixes() const;
|
std::vector<unsigned int> getDMRPrefixes() const;
|
||||||
std::vector<unsigned int> getDMRBlackList() const;
|
std::vector<unsigned int> getDMRBlackList() const;
|
||||||
std::vector<unsigned int> getDMRWhiteList() const;
|
std::vector<unsigned int> getDMRWhiteList() const;
|
||||||
|
std::vector<unsigned int> getDMRSlot1TGWhiteList() const;
|
||||||
|
std::vector<unsigned int> getDMRSlot2TGWhiteList() const;
|
||||||
unsigned int getDMRCallHang() const;
|
unsigned int getDMRCallHang() const;
|
||||||
unsigned int getDMRTXHang() const;
|
unsigned int getDMRTXHang() const;
|
||||||
|
|
||||||
|
@ -129,7 +131,6 @@ public:
|
||||||
unsigned int getDMRNetworkJitter() const;
|
unsigned int getDMRNetworkJitter() const;
|
||||||
bool getDMRNetworkSlot1() const;
|
bool getDMRNetworkSlot1() const;
|
||||||
bool getDMRNetworkSlot2() const;
|
bool getDMRNetworkSlot2() const;
|
||||||
bool getDMRNetworkRSSI() const;
|
|
||||||
|
|
||||||
// The System Fusion Network section
|
// The System Fusion Network section
|
||||||
bool getFusionNetworkEnabled() const;
|
bool getFusionNetworkEnabled() const;
|
||||||
|
@ -245,6 +246,8 @@ private:
|
||||||
std::vector<unsigned int> m_dmrPrefixes;
|
std::vector<unsigned int> m_dmrPrefixes;
|
||||||
std::vector<unsigned int> m_dmrBlackList;
|
std::vector<unsigned int> m_dmrBlackList;
|
||||||
std::vector<unsigned int> m_dmrWhiteList;
|
std::vector<unsigned int> m_dmrWhiteList;
|
||||||
|
std::vector<unsigned int> m_dmrSlot1TGWhiteList;
|
||||||
|
std::vector<unsigned int> m_dmrSlot2TGWhiteList;
|
||||||
unsigned int m_dmrCallHang;
|
unsigned int m_dmrCallHang;
|
||||||
unsigned int m_dmrTXHang;
|
unsigned int m_dmrTXHang;
|
||||||
|
|
||||||
|
@ -270,7 +273,6 @@ private:
|
||||||
unsigned int m_dmrNetworkJitter;
|
unsigned int m_dmrNetworkJitter;
|
||||||
bool m_dmrNetworkSlot1;
|
bool m_dmrNetworkSlot1;
|
||||||
bool m_dmrNetworkSlot2;
|
bool m_dmrNetworkSlot2;
|
||||||
bool m_dmrNetworkRSSI;
|
|
||||||
|
|
||||||
bool m_fusionNetworkEnabled;
|
bool m_fusionNetworkEnabled;
|
||||||
std::string m_fusionNetworkMyAddress;
|
std::string m_fusionNetworkMyAddress;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 by Simon Rune G7RZU
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -28,20 +28,25 @@ std::vector<unsigned int> CDMRAccessControl::m_whiteList;
|
||||||
|
|
||||||
std::vector<unsigned int> CDMRAccessControl::m_prefixes;
|
std::vector<unsigned int> CDMRAccessControl::m_prefixes;
|
||||||
|
|
||||||
|
std::vector<unsigned int> CDMRAccessControl::m_slot1TGWhiteList;
|
||||||
|
std::vector<unsigned int> CDMRAccessControl::m_slot2TGWhiteList;
|
||||||
|
|
||||||
bool CDMRAccessControl::m_selfOnly = false;
|
bool CDMRAccessControl::m_selfOnly = false;
|
||||||
|
|
||||||
unsigned int CDMRAccessControl::m_id = 0U;
|
unsigned int CDMRAccessControl::m_id = 0U;
|
||||||
|
|
||||||
void CDMRAccessControl::init(const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, bool selfOnly, const std::vector<unsigned int>& prefixes, unsigned int id)
|
void CDMRAccessControl::init(const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, bool selfOnly, const std::vector<unsigned int>& prefixes, unsigned int id)
|
||||||
{
|
{
|
||||||
m_blackList = blacklist;
|
m_slot1TGWhiteList = slot1TGWhitelist;
|
||||||
m_whiteList = whitelist;
|
m_slot2TGWhiteList = slot2TGWhitelist;
|
||||||
m_selfOnly = selfOnly;
|
m_blackList = blacklist;
|
||||||
m_prefixes = prefixes;
|
m_whiteList = whitelist;
|
||||||
m_id = id;
|
m_selfOnly = selfOnly;
|
||||||
|
m_prefixes = prefixes;
|
||||||
|
m_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDMRAccessControl::validateId(unsigned int id)
|
bool CDMRAccessControl::validateSrcId(unsigned int id)
|
||||||
{
|
{
|
||||||
if (m_selfOnly)
|
if (m_selfOnly)
|
||||||
return id == m_id;
|
return id == m_id;
|
||||||
|
@ -64,3 +69,21 @@ bool CDMRAccessControl::validateId(unsigned int id)
|
||||||
|
|
||||||
return true;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 by Simon Rune G7RZU
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,20 +20,23 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "DMRLC.h"
|
|
||||||
|
|
||||||
class CDMRAccessControl {
|
class CDMRAccessControl {
|
||||||
public:
|
public:
|
||||||
static bool validateId(unsigned int id);
|
static bool validateSrcId(unsigned int id);
|
||||||
|
|
||||||
static void init(const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, bool selfOnly, const std::vector<unsigned int>& prefixes, unsigned int id);
|
static bool validateTGId(unsigned int slotNo, bool group, unsigned int id);
|
||||||
|
|
||||||
|
static void init(const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, bool selfOnly, const std::vector<unsigned int>& prefixes, unsigned int id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::vector<unsigned int> m_blackList;
|
static std::vector<unsigned int> m_blackList;
|
||||||
static std::vector<unsigned int> m_whiteList;
|
static std::vector<unsigned int> m_whiteList;
|
||||||
|
|
||||||
static std::vector<unsigned int> m_prefixes;
|
static std::vector<unsigned int> m_prefixes;
|
||||||
|
|
||||||
|
static std::vector<unsigned int> m_slot1TGWhiteList;
|
||||||
|
static std::vector<unsigned int> m_slot2TGWhiteList;
|
||||||
|
|
||||||
static bool m_selfOnly;
|
static bool m_selfOnly;
|
||||||
static unsigned int m_id;
|
static unsigned int m_id;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& 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<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter) :
|
||||||
m_id(id),
|
m_id(id),
|
||||||
m_colorCode(colorCode),
|
m_colorCode(colorCode),
|
||||||
m_modem(modem),
|
m_modem(modem),
|
||||||
|
@ -37,7 +37,7 @@ m_lookup(lookup)
|
||||||
assert(rssi != NULL);
|
assert(rssi != NULL);
|
||||||
|
|
||||||
// Load black and white lists to DMRAccessControl
|
// 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);
|
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);
|
std::string src = m_lookup->find(srcId);
|
||||||
|
|
||||||
bool ret = CDMRAccessControl::validateId(srcId);
|
bool ret = CDMRAccessControl::validateSrcId(srcId);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
LogMessage("Invalid CSBK BS_Dwn_Act received from %s", src.c_str());
|
LogMessage("Invalid CSBK BS_Dwn_Act received from %s", src.c_str());
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
class CDMRControl {
|
class CDMRControl {
|
||||||
public:
|
public:
|
||||||
CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& 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<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter);
|
||||||
~CDMRControl();
|
~CDMRControl();
|
||||||
|
|
||||||
bool processWakeup(const unsigned char* data);
|
bool processWakeup(const unsigned char* data);
|
||||||
|
|
|
@ -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
|
* 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
|
* 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;
|
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_address(),
|
||||||
m_port(port),
|
m_port(port),
|
||||||
m_id(NULL),
|
m_id(NULL),
|
||||||
|
@ -43,7 +43,6 @@ m_socket(local),
|
||||||
m_enabled(false),
|
m_enabled(false),
|
||||||
m_slot1(slot1),
|
m_slot1(slot1),
|
||||||
m_slot2(slot2),
|
m_slot2(slot2),
|
||||||
m_rssi(rssi),
|
|
||||||
m_hwType(hwType),
|
m_hwType(hwType),
|
||||||
m_status(WAITING_CONNECT),
|
m_status(WAITING_CONNECT),
|
||||||
m_retryTimer(1000U, 10U),
|
m_retryTimer(1000U, 10U),
|
||||||
|
@ -268,10 +267,7 @@ bool CDMRNetwork::write(const CDMRData& data)
|
||||||
|
|
||||||
buffer[53U] = data.getBER();
|
buffer[53U] = data.getBER();
|
||||||
|
|
||||||
if (m_rssi)
|
buffer[54U] = data.getRSSI();
|
||||||
buffer[54U] = data.getRSSI();
|
|
||||||
else
|
|
||||||
buffer[54U] = 0x00U;
|
|
||||||
|
|
||||||
if (m_debug)
|
if (m_debug)
|
||||||
CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
class CDMRNetwork
|
class CDMRNetwork
|
||||||
{
|
{
|
||||||
public:
|
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();
|
~CDMRNetwork();
|
||||||
|
|
||||||
void setOptions(const std::string& options);
|
void setOptions(const std::string& options);
|
||||||
|
@ -64,7 +64,6 @@ private:
|
||||||
bool m_enabled;
|
bool m_enabled;
|
||||||
bool m_slot1;
|
bool m_slot1;
|
||||||
bool m_slot2;
|
bool m_slot2;
|
||||||
bool m_rssi;
|
|
||||||
HW_TYPE m_hwType;
|
HW_TYPE m_hwType;
|
||||||
|
|
||||||
enum STATUS {
|
enum STATUS {
|
||||||
|
|
95
DMRSlot.cpp
95
DMRSlot.cpp
|
@ -11,6 +11,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "DMRAccessControl.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
#include "DMRShortLC.h"
|
#include "DMRShortLC.h"
|
||||||
#include "DMRTrellis.h"
|
#include "DMRTrellis.h"
|
||||||
|
@ -18,11 +19,11 @@
|
||||||
#include "BPTC19696.h"
|
#include "BPTC19696.h"
|
||||||
#include "DMRSlot.h"
|
#include "DMRSlot.h"
|
||||||
#include "DMRCSBK.h"
|
#include "DMRCSBK.h"
|
||||||
|
#include "DMREMB.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "Sync.h"
|
#include "Sync.h"
|
||||||
#include "CRC.h"
|
#include "CRC.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "DMRAccessControl.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
@ -84,8 +85,11 @@ m_rfErrs(0U),
|
||||||
m_netErrs(0U),
|
m_netErrs(0U),
|
||||||
m_lastFrame(NULL),
|
m_lastFrame(NULL),
|
||||||
m_lastFrameValid(false),
|
m_lastFrameValid(false),
|
||||||
m_lastEMB(),
|
|
||||||
m_rssi(0U),
|
m_rssi(0U),
|
||||||
|
m_maxRSSI(0U),
|
||||||
|
m_minRSSI(0U),
|
||||||
|
m_aveRSSI(0U),
|
||||||
|
m_rssiCount(0U),
|
||||||
m_fp(NULL)
|
m_fp(NULL)
|
||||||
{
|
{
|
||||||
m_lastFrame = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U];
|
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);
|
assert(data != NULL);
|
||||||
|
|
||||||
if (data[0U] == TAG_LOST && m_rfState == RS_RF_AUDIO) {
|
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);
|
writeEndRF(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) {
|
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();
|
writeEndRF();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +135,14 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
||||||
|
|
||||||
// RSSI is always reported as positive
|
// RSSI is always reported as positive
|
||||||
m_rssi = (rssi >= 0) ? rssi : -rssi;
|
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;
|
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 srcId = lc->getSrcId();
|
||||||
unsigned int dstId = lc->getDstId();
|
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);
|
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||||
delete lc;
|
delete lc;
|
||||||
return;
|
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;
|
m_rfLC = lc;
|
||||||
|
|
||||||
// Regenerate the LC data
|
// Regenerate the LC data
|
||||||
|
@ -184,6 +203,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
||||||
m_rfBits = 1U;
|
m_rfBits = 1U;
|
||||||
m_rfErrs = 0U;
|
m_rfErrs = 0U;
|
||||||
|
|
||||||
|
m_minRSSI = m_rssi;
|
||||||
|
m_maxRSSI = m_rssi;
|
||||||
|
m_aveRSSI = m_rssi;
|
||||||
|
m_rssiCount = 1U;
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
m_queue.clear();
|
m_queue.clear();
|
||||||
m_modem->writeDMRAbort(m_slotNo);
|
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);
|
std::string dst = m_lookup->find(dstId);
|
||||||
|
|
||||||
if (m_netState == RS_NET_IDLE) {
|
if (m_netState == RS_NET_IDLE) {
|
||||||
setShortLC(m_slotNo, dstId, m_rfLC->getFLCO(), true);
|
setShortLC(m_slotNo, dstId, flco, true);
|
||||||
m_display->writeDMR(m_slotNo, src, m_rfLC->getFLCO() == FLCO_GROUP, dst, "R");
|
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) {
|
} else if (dataType == DT_VOICE_PI_HEADER) {
|
||||||
if (m_rfState != RS_RF_AUDIO)
|
if (m_rfState != RS_RF_AUDIO)
|
||||||
return;
|
return;
|
||||||
|
@ -254,7 +278,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
||||||
writeQueueRF(data);
|
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();
|
writeEndRF();
|
||||||
} else if (dataType == DT_DATA_HEADER) {
|
} 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 srcId = dataHeader.getSrcId();
|
||||||
unsigned int dstId = dataHeader.getDstId();
|
unsigned int dstId = dataHeader.getDstId();
|
||||||
|
|
||||||
if (!CDMRAccessControl::validateId(srcId)) {
|
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||||
return;
|
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_rfFrames = dataHeader.getBlocks();
|
||||||
|
|
||||||
m_rfDataHeader = dataHeader;
|
m_rfDataHeader = dataHeader;
|
||||||
|
@ -329,10 +358,15 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
||||||
unsigned int dstId = csbk.getDstId();
|
unsigned int dstId = csbk.getDstId();
|
||||||
|
|
||||||
if (srcId != 0U || dstId != 0U) {
|
if (srcId != 0U || dstId != 0U) {
|
||||||
if (!CDMRAccessControl::validateId(srcId)) {
|
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||||
return;
|
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
|
// Regenerate the CSBK data
|
||||||
|
@ -490,13 +524,20 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
||||||
if (lc != NULL) {
|
if (lc != NULL) {
|
||||||
unsigned int srcId = lc->getSrcId();
|
unsigned int srcId = lc->getSrcId();
|
||||||
unsigned int dstId = lc->getDstId();
|
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);
|
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||||
delete lc;
|
delete lc;
|
||||||
return;
|
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;
|
m_rfLC = lc;
|
||||||
|
|
||||||
// Create a dummy start frame to replace the received frame
|
// 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;
|
start[1U] = 0x00U;
|
||||||
|
|
||||||
m_rfTimeoutTimer.start();
|
m_rfTimeoutTimer.start();
|
||||||
|
m_rfEmbeddedLC.reset();
|
||||||
|
|
||||||
m_rfFrames = 0U;
|
m_rfFrames = 0U;
|
||||||
m_rfSeqNo = 0U;
|
m_rfSeqNo = 0U;
|
||||||
m_rfBits = 1U;
|
m_rfBits = 1U;
|
||||||
m_rfErrs = 0U;
|
m_rfErrs = 0U;
|
||||||
|
|
||||||
|
m_minRSSI = m_rssi;
|
||||||
|
m_maxRSSI = m_rssi;
|
||||||
|
m_aveRSSI = m_rssi;
|
||||||
|
m_rssiCount = 1U;
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
m_queue.clear();
|
m_queue.clear();
|
||||||
m_modem->writeDMRAbort(m_slotNo);
|
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);
|
std::string dst = m_lookup->find(dstId);
|
||||||
|
|
||||||
if (m_netState == RS_NET_IDLE) {
|
if (m_netState == RS_NET_IDLE) {
|
||||||
setShortLC(m_slotNo, dstId, m_rfLC->getFLCO(), true);
|
setShortLC(m_slotNo, dstId, flco, true);
|
||||||
m_display->writeDMR(m_slotNo, src, m_rfLC->getFLCO() == FLCO_GROUP, dst, "R");
|
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;
|
m_netBits += 141U;
|
||||||
|
|
||||||
// Change the color code in the EMB
|
// Change the color code in the EMB
|
||||||
m_lastEMB.putData(data + 2U);
|
CDMREMB emb;
|
||||||
m_lastEMB.setColorCode(m_colorCode);
|
emb.putData(data + 2U);
|
||||||
m_lastEMB.getData(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[0U] = TAG_DATA;
|
||||||
data[1U] = 0x00U;
|
data[1U] = 0x00U;
|
||||||
|
@ -1582,6 +1630,10 @@ void CDMRSlot::insertSilence(unsigned int count)
|
||||||
|
|
||||||
unsigned char fid = m_netLC->getFID();
|
unsigned char fid = m_netLC->getFID();
|
||||||
|
|
||||||
|
CDMREMB emb;
|
||||||
|
emb.setColorCode(m_colorCode);
|
||||||
|
emb.setLCSS(0U);
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < count; i++) {
|
for (unsigned int i = 0U; i < count; i++) {
|
||||||
// Only use our silence frame if its AMBE audio data
|
// Only use our silence frame if its AMBE audio data
|
||||||
if (fid == FID_ETSI || fid == FID_DMRA) {
|
if (fid == FID_ETSI || fid == FID_DMRA) {
|
||||||
|
@ -1595,10 +1647,7 @@ void CDMRSlot::insertSilence(unsigned int count)
|
||||||
CSync::addDMRAudioSync(data + 2U, m_duplex);
|
CSync::addDMRAudioSync(data + 2U, m_duplex);
|
||||||
} else {
|
} else {
|
||||||
::memset(data + 2U + 13U, 0x00U, 7U);
|
::memset(data + 2U + 13U, 0x00U, 7U);
|
||||||
|
emb.getData(data + 2U);
|
||||||
m_lastEMB.setColorCode(m_colorCode);
|
|
||||||
m_lastEMB.setLCSS(0U);
|
|
||||||
m_lastEMB.getData(data + 2U);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writeQueueNet(data);
|
writeQueueNet(data);
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#include "DMRData.h"
|
#include "DMRData.h"
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
#include "Defines.h"
|
#include "Defines.h"
|
||||||
#include "DMREMB.h"
|
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "Modem.h"
|
#include "Modem.h"
|
||||||
#include "DMRLC.h"
|
#include "DMRLC.h"
|
||||||
|
@ -84,8 +83,11 @@ private:
|
||||||
unsigned int m_netErrs;
|
unsigned int m_netErrs;
|
||||||
unsigned char* m_lastFrame;
|
unsigned char* m_lastFrame;
|
||||||
bool m_lastFrameValid;
|
bool m_lastFrameValid;
|
||||||
CDMREMB m_lastEMB;
|
|
||||||
unsigned char m_rssi;
|
unsigned char m_rssi;
|
||||||
|
unsigned char m_maxRSSI;
|
||||||
|
unsigned char m_minRSSI;
|
||||||
|
unsigned int m_aveRSSI;
|
||||||
|
unsigned int m_rssiCount;
|
||||||
FILE* m_fp;
|
FILE* m_fp;
|
||||||
|
|
||||||
static unsigned int m_colorCode;
|
static unsigned int m_colorCode;
|
||||||
|
|
|
@ -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
|
* 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
|
* 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
|
// #define DUMP_DSTAR
|
||||||
|
|
||||||
CDStarControl::CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector<std::string>& 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<std::string>& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) :
|
||||||
m_callsign(NULL),
|
m_callsign(NULL),
|
||||||
m_gateway(NULL),
|
m_gateway(NULL),
|
||||||
m_selfOnly(selfOnly),
|
m_selfOnly(selfOnly),
|
||||||
|
@ -70,9 +70,16 @@ m_rfErrs(0U),
|
||||||
m_netErrs(0U),
|
m_netErrs(0U),
|
||||||
m_lastFrame(NULL),
|
m_lastFrame(NULL),
|
||||||
m_lastFrameValid(false),
|
m_lastFrameValid(false),
|
||||||
|
m_rssiMapper(rssiMapper),
|
||||||
|
m_rssi(0U),
|
||||||
|
m_maxRSSI(0U),
|
||||||
|
m_minRSSI(0U),
|
||||||
|
m_aveRSSI(0U),
|
||||||
|
m_rssiCount(0U),
|
||||||
m_fp(NULL)
|
m_fp(NULL)
|
||||||
{
|
{
|
||||||
assert(display != NULL);
|
assert(display != NULL);
|
||||||
|
assert(rssiMapper != NULL);
|
||||||
|
|
||||||
m_callsign = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
|
m_callsign = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
|
||||||
m_gateway = 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];
|
unsigned char type = data[0U];
|
||||||
|
|
||||||
if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) {
|
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();
|
writeEndRF();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -121,6 +128,50 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len)
|
||||||
return false;
|
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) {
|
if (type == TAG_HEADER) {
|
||||||
CDStarHeader header(data + 1U);
|
CDStarHeader header(data + 1U);
|
||||||
|
|
||||||
|
@ -181,6 +232,11 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len)
|
||||||
m_rfFrames = 1U;
|
m_rfFrames = 1U;
|
||||||
m_rfN = 0U;
|
m_rfN = 0U;
|
||||||
|
|
||||||
|
m_minRSSI = m_rssi;
|
||||||
|
m_maxRSSI = m_rssi;
|
||||||
|
m_aveRSSI = m_rssi;
|
||||||
|
m_rssiCount = 1U;
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
// Modify the header
|
// Modify the header
|
||||||
header.setRepeater(false);
|
header.setRepeater(false);
|
||||||
|
@ -217,7 +273,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len)
|
||||||
if (m_duplex)
|
if (m_duplex)
|
||||||
writeQueueEOTRF();
|
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();
|
writeEndRF();
|
||||||
}
|
}
|
||||||
|
@ -328,6 +384,11 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len)
|
||||||
m_rfN = 0U;
|
m_rfN = 0U;
|
||||||
m_rfFrames = 1U;
|
m_rfFrames = 1U;
|
||||||
|
|
||||||
|
m_minRSSI = m_rssi;
|
||||||
|
m_maxRSSI = m_rssi;
|
||||||
|
m_aveRSSI = m_rssi;
|
||||||
|
m_rssiCount = 1U;
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U];
|
unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U];
|
||||||
start[0U] = TAG_HEADER;
|
start[0U] = TAG_HEADER;
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
#if !defined(DStarControl_H)
|
#if !defined(DStarControl_H)
|
||||||
#define DStarControl_H
|
#define DStarControl_H
|
||||||
|
|
||||||
|
#include "RSSIInterpolator.h"
|
||||||
#include "DStarNetwork.h"
|
#include "DStarNetwork.h"
|
||||||
#include "DStarSlowData.h"
|
#include "DStarSlowData.h"
|
||||||
#include "DStarDefines.h"
|
#include "DStarDefines.h"
|
||||||
|
@ -36,7 +37,7 @@
|
||||||
|
|
||||||
class CDStarControl {
|
class CDStarControl {
|
||||||
public:
|
public:
|
||||||
CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector<std::string>& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex);
|
CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector<std::string>& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper);
|
||||||
~CDStarControl();
|
~CDStarControl();
|
||||||
|
|
||||||
bool writeModem(unsigned char* data, unsigned int len);
|
bool writeModem(unsigned char* data, unsigned int len);
|
||||||
|
@ -79,6 +80,12 @@ private:
|
||||||
unsigned int m_netErrs;
|
unsigned int m_netErrs;
|
||||||
unsigned char* m_lastFrame;
|
unsigned char* m_lastFrame;
|
||||||
bool m_lastFrameValid;
|
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;
|
FILE* m_fp;
|
||||||
|
|
||||||
void writeNetwork();
|
void writeNetwork();
|
||||||
|
|
|
@ -70,6 +70,8 @@ Id=123456
|
||||||
ColorCode=1
|
ColorCode=1
|
||||||
SelfOnly=0
|
SelfOnly=0
|
||||||
# Prefixes=234,235
|
# Prefixes=234,235
|
||||||
|
# Slot1TGWhiteList=
|
||||||
|
# Slot2TGWhiteList=
|
||||||
CallHang=3
|
CallHang=3
|
||||||
TXHang=4
|
TXHang=4
|
||||||
|
|
||||||
|
@ -96,7 +98,6 @@ Jitter=300
|
||||||
# Local=3350
|
# Local=3350
|
||||||
Password=PASSWORD
|
Password=PASSWORD
|
||||||
# Options=
|
# Options=
|
||||||
RSSI=0
|
|
||||||
Slot1=1
|
Slot1=1
|
||||||
Slot2=1
|
Slot2=1
|
||||||
Debug=0
|
Debug=0
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -297,6 +297,16 @@ int CMMDVMHost::run()
|
||||||
CTimer dmrBeaconTimer(1000U, 4U);
|
CTimer dmrBeaconTimer(1000U, 4U);
|
||||||
bool dmrBeaconsEnabled = m_dmrEnabled && m_conf.getDMRBeacons();
|
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
|
// For DMR and P25 we try to map IDs to callsigns
|
||||||
if (m_dmrEnabled || m_p25Enabled) {
|
if (m_dmrEnabled || m_p25Enabled) {
|
||||||
std::string lookupFile = m_conf.getDMRIdLookupFile();
|
std::string lookupFile = m_conf.getDMRIdLookupFile();
|
||||||
|
@ -327,7 +337,7 @@ int CMMDVMHost::run()
|
||||||
if (blackList.size() > 0U)
|
if (blackList.size() > 0U)
|
||||||
LogInfo(" Black List: %u", blackList.size());
|
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;
|
CDMRControl* dmr = NULL;
|
||||||
|
@ -338,9 +348,10 @@ int CMMDVMHost::run()
|
||||||
std::vector<unsigned int> prefixes = m_conf.getDMRPrefixes();
|
std::vector<unsigned int> prefixes = m_conf.getDMRPrefixes();
|
||||||
std::vector<unsigned int> blackList = m_conf.getDMRBlackList();
|
std::vector<unsigned int> blackList = m_conf.getDMRBlackList();
|
||||||
std::vector<unsigned int> whiteList = m_conf.getDMRWhiteList();
|
std::vector<unsigned int> whiteList = m_conf.getDMRWhiteList();
|
||||||
unsigned int callHang = m_conf.getDMRCallHang();
|
std::vector<unsigned int> slot1TGWhiteList = m_conf.getDMRSlot1TGWhiteList();
|
||||||
|
std::vector<unsigned int> slot2TGWhiteList = m_conf.getDMRSlot2TGWhiteList();
|
||||||
|
unsigned int callHang = m_conf.getDMRCallHang();
|
||||||
unsigned int txHang = m_conf.getDMRTXHang();
|
unsigned int txHang = m_conf.getDMRTXHang();
|
||||||
std::string rssiMappingFile = m_conf.getModemRSSIMappingFile();
|
|
||||||
unsigned int jitter = m_conf.getDMRNetworkJitter();
|
unsigned int jitter = m_conf.getDMRNetworkJitter();
|
||||||
|
|
||||||
if (txHang > m_rfModeHang)
|
if (txHang > m_rfModeHang)
|
||||||
|
@ -361,17 +372,15 @@ int CMMDVMHost::run()
|
||||||
LogInfo(" Source ID Black List: %u", blackList.size());
|
LogInfo(" Source ID Black List: %u", blackList.size());
|
||||||
if (whiteList.size() > 0U)
|
if (whiteList.size() > 0U)
|
||||||
LogInfo(" Source ID White List: %u", whiteList.size());
|
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(" Call Hang: %us", callHang);
|
||||||
LogInfo(" TX Hang: %us", txHang);
|
LogInfo(" TX Hang: %us", txHang);
|
||||||
|
|
||||||
CRSSIInterpolator* rssi = new CRSSIInterpolator;
|
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);
|
||||||
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);
|
|
||||||
|
|
||||||
m_dmrTXTimer.setTimeout(txHang);
|
m_dmrTXTimer.setTimeout(txHang);
|
||||||
}
|
}
|
||||||
|
@ -383,7 +392,7 @@ int CMMDVMHost::run()
|
||||||
LogInfo("YSF Parameters");
|
LogInfo("YSF Parameters");
|
||||||
LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no");
|
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;
|
CP25Control* p25 = NULL;
|
||||||
|
@ -393,7 +402,7 @@ int CMMDVMHost::run()
|
||||||
LogInfo("P25 Parameters");
|
LogInfo("P25 Parameters");
|
||||||
LogInfo(" NAC: $%03X", nac);
|
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);
|
setMode(MODE_IDLE);
|
||||||
|
@ -854,7 +863,6 @@ bool CMMDVMHost::createDMRNetwork()
|
||||||
unsigned int jitter = m_conf.getDMRNetworkJitter();
|
unsigned int jitter = m_conf.getDMRNetworkJitter();
|
||||||
bool slot1 = m_conf.getDMRNetworkSlot1();
|
bool slot1 = m_conf.getDMRNetworkSlot1();
|
||||||
bool slot2 = m_conf.getDMRNetworkSlot2();
|
bool slot2 = m_conf.getDMRNetworkSlot2();
|
||||||
bool rssi = m_conf.getDMRNetworkRSSI();
|
|
||||||
HW_TYPE hwType = m_modem->getHWType();
|
HW_TYPE hwType = m_modem->getHWType();
|
||||||
|
|
||||||
LogInfo("DMR Network Parameters");
|
LogInfo("DMR Network Parameters");
|
||||||
|
@ -867,9 +875,8 @@ bool CMMDVMHost::createDMRNetwork()
|
||||||
LogInfo(" Jitter: %ums", jitter);
|
LogInfo(" Jitter: %ums", jitter);
|
||||||
LogInfo(" Slot 1: %s", slot1 ? "enabled" : "disabled");
|
LogInfo(" Slot 1: %s", slot1 ? "enabled" : "disabled");
|
||||||
LogInfo(" Slot 2: %s", slot2 ? "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();
|
std::string options = m_conf.getDMRNetworkOptions();
|
||||||
if (!options.empty()) {
|
if (!options.empty()) {
|
||||||
|
|
|
@ -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
|
* 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
|
* 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 WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||||
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
#define 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_nac(nac),
|
||||||
m_network(network),
|
m_network(network),
|
||||||
m_display(display),
|
m_display(display),
|
||||||
|
@ -63,10 +63,17 @@ m_netLDU1(NULL),
|
||||||
m_netLDU2(NULL),
|
m_netLDU2(NULL),
|
||||||
m_lastIMBE(NULL),
|
m_lastIMBE(NULL),
|
||||||
m_rfLDU(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)
|
m_fp(NULL)
|
||||||
{
|
{
|
||||||
assert(display != NULL);
|
assert(display != NULL);
|
||||||
assert(lookup != NULL);
|
assert(lookup != NULL);
|
||||||
|
assert(rssiMapper != NULL);
|
||||||
|
|
||||||
m_netLDU1 = new unsigned char[9U * 25U];
|
m_netLDU1 = new unsigned char[9U * 25U];
|
||||||
m_netLDU2 = 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;
|
return false;
|
||||||
|
|
||||||
if (data[0U] == TAG_LOST) {
|
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)
|
if (m_netState == RS_NET_IDLE)
|
||||||
m_display->clearP25();
|
m_display->clearP25();
|
||||||
writeNetwork(m_rfLDU, m_lastDUID, true);
|
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 (duid == P25_DUID_LDU1) {
|
||||||
if (m_rfState == RS_RF_LISTENING) {
|
if (m_rfState == RS_RF_LISTENING) {
|
||||||
m_rfData.reset();
|
m_rfData.reset();
|
||||||
|
@ -148,6 +177,11 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_minRSSI = m_rssi;
|
||||||
|
m_maxRSSI = m_rssi;
|
||||||
|
m_aveRSSI = m_rssi;
|
||||||
|
m_rssiCount = 1U;
|
||||||
|
|
||||||
createRFHeader();
|
createRFHeader();
|
||||||
writeNetwork(data + 2U, P25_DUID_HEADER, false);
|
writeNetwork(data + 2U, P25_DUID_HEADER, false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -262,7 +296,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
m_rfData.reset();
|
m_rfData.reset();
|
||||||
m_lastDUID = duid;
|
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();
|
m_display->clearP25();
|
||||||
|
|
||||||
#if defined(DUMP_P25)
|
#if defined(DUMP_P25)
|
||||||
|
|
65
P25Control.h
65
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
#if !defined(P25Control_H)
|
#if !defined(P25Control_H)
|
||||||
#define P25Control_H
|
#define P25Control_H
|
||||||
|
|
||||||
|
#include "RSSIInterpolator.h"
|
||||||
#include "P25LowSpeedData.h"
|
#include "P25LowSpeedData.h"
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
#include "P25Network.h"
|
#include "P25Network.h"
|
||||||
|
@ -35,7 +36,7 @@
|
||||||
|
|
||||||
class CP25Control {
|
class CP25Control {
|
||||||
public:
|
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();
|
~CP25Control();
|
||||||
|
|
||||||
bool writeModem(unsigned char* data, unsigned int len);
|
bool writeModem(unsigned char* data, unsigned int len);
|
||||||
|
@ -45,34 +46,40 @@ public:
|
||||||
void clock(unsigned int ms);
|
void clock(unsigned int ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int m_nac;
|
unsigned int m_nac;
|
||||||
CP25Network* m_network;
|
CP25Network* m_network;
|
||||||
CDisplay* m_display;
|
CDisplay* m_display;
|
||||||
bool m_duplex;
|
bool m_duplex;
|
||||||
CDMRLookup* m_lookup;
|
CDMRLookup* m_lookup;
|
||||||
CRingBuffer<unsigned char> m_queue;
|
CRingBuffer<unsigned char> m_queue;
|
||||||
RPT_RF_STATE m_rfState;
|
RPT_RF_STATE m_rfState;
|
||||||
RPT_NET_STATE m_netState;
|
RPT_NET_STATE m_netState;
|
||||||
CTimer m_rfTimeout;
|
CTimer m_rfTimeout;
|
||||||
CTimer m_netTimeout;
|
CTimer m_netTimeout;
|
||||||
CTimer m_networkWatchdog;
|
CTimer m_networkWatchdog;
|
||||||
unsigned int m_rfFrames;
|
unsigned int m_rfFrames;
|
||||||
unsigned int m_rfBits;
|
unsigned int m_rfBits;
|
||||||
unsigned int m_rfErrs;
|
unsigned int m_rfErrs;
|
||||||
unsigned int m_netFrames;
|
unsigned int m_netFrames;
|
||||||
unsigned int m_netLost;
|
unsigned int m_netLost;
|
||||||
CP25NID m_nid;
|
CP25NID m_nid;
|
||||||
unsigned char m_lastDUID;
|
unsigned char m_lastDUID;
|
||||||
CP25Audio m_audio;
|
CP25Audio m_audio;
|
||||||
CP25Data m_rfData;
|
CP25Data m_rfData;
|
||||||
CP25Data m_netData;
|
CP25Data m_netData;
|
||||||
CP25LowSpeedData m_rfLSD;
|
CP25LowSpeedData m_rfLSD;
|
||||||
CP25LowSpeedData m_netLSD;
|
CP25LowSpeedData m_netLSD;
|
||||||
unsigned char* m_netLDU1;
|
unsigned char* m_netLDU1;
|
||||||
unsigned char* m_netLDU2;
|
unsigned char* m_netLDU2;
|
||||||
unsigned char* m_lastIMBE;
|
unsigned char* m_lastIMBE;
|
||||||
unsigned char* m_rfLDU;
|
unsigned char* m_rfLDU;
|
||||||
FILE* m_fp;
|
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 writeQueueRF(const unsigned char* data, unsigned int length);
|
||||||
void writeQueueNet(const unsigned char* data, unsigned int length);
|
void writeQueueNet(const unsigned char* data, unsigned int length);
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
// #define DUMP_YSF
|
// #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_callsign(NULL),
|
||||||
m_network(network),
|
m_network(network),
|
||||||
m_display(display),
|
m_display(display),
|
||||||
|
@ -56,9 +56,16 @@ m_lastMR(YSF_MR_NOT_BUSY),
|
||||||
m_netN(0U),
|
m_netN(0U),
|
||||||
m_rfPayload(),
|
m_rfPayload(),
|
||||||
m_netPayload(),
|
m_netPayload(),
|
||||||
|
m_rssiMapper(rssiMapper),
|
||||||
|
m_rssi(0U),
|
||||||
|
m_maxRSSI(0U),
|
||||||
|
m_minRSSI(0U),
|
||||||
|
m_aveRSSI(0U),
|
||||||
|
m_rssiCount(0U),
|
||||||
m_fp(NULL)
|
m_fp(NULL)
|
||||||
{
|
{
|
||||||
assert(display != NULL);
|
assert(display != NULL);
|
||||||
|
assert(rssiMapper != NULL);
|
||||||
|
|
||||||
m_rfPayload.setUplink(callsign);
|
m_rfPayload.setUplink(callsign);
|
||||||
m_rfPayload.setDownlink(callsign);
|
m_rfPayload.setDownlink(callsign);
|
||||||
|
@ -94,7 +101,7 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len)
|
||||||
unsigned char type = data[0U];
|
unsigned char type = data[0U];
|
||||||
|
|
||||||
if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) {
|
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();
|
writeEndRF();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -102,6 +109,28 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len)
|
||||||
if (type == TAG_LOST)
|
if (type == TAG_LOST)
|
||||||
return false;
|
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;
|
CYSFFICH fich;
|
||||||
bool valid = fich.decode(data + 2U);
|
bool valid = fich.decode(data + 2U);
|
||||||
|
|
||||||
|
@ -116,6 +145,11 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len)
|
||||||
m_rfTimeoutTimer.start();
|
m_rfTimeoutTimer.start();
|
||||||
m_rfPayload.reset();
|
m_rfPayload.reset();
|
||||||
m_rfState = RS_RF_AUDIO;
|
m_rfState = RS_RF_AUDIO;
|
||||||
|
|
||||||
|
m_minRSSI = m_rssi;
|
||||||
|
m_maxRSSI = m_rssi;
|
||||||
|
m_aveRSSI = m_rssi;
|
||||||
|
m_rssiCount = 1U;
|
||||||
#if defined(DUMP_YSF)
|
#if defined(DUMP_YSF)
|
||||||
openFile();
|
openFile();
|
||||||
#endif
|
#endif
|
||||||
|
@ -209,7 +243,7 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len)
|
||||||
|
|
||||||
m_rfFrames++;
|
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();
|
writeEndRF();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
11
YSFControl.h
11
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
#if !defined(YSFControl_H)
|
#if !defined(YSFControl_H)
|
||||||
#define YSFControl_H
|
#define YSFControl_H
|
||||||
|
|
||||||
|
#include "RSSIInterpolator.h"
|
||||||
#include "YSFNetwork.h"
|
#include "YSFNetwork.h"
|
||||||
#include "YSFDefines.h"
|
#include "YSFDefines.h"
|
||||||
#include "YSFPayload.h"
|
#include "YSFPayload.h"
|
||||||
|
@ -33,7 +34,7 @@
|
||||||
|
|
||||||
class CYSFControl {
|
class CYSFControl {
|
||||||
public:
|
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();
|
~CYSFControl();
|
||||||
|
|
||||||
bool writeModem(unsigned char* data, unsigned int len);
|
bool writeModem(unsigned char* data, unsigned int len);
|
||||||
|
@ -74,6 +75,12 @@ private:
|
||||||
unsigned char m_netN;
|
unsigned char m_netN;
|
||||||
CYSFPayload m_rfPayload;
|
CYSFPayload m_rfPayload;
|
||||||
CYSFPayload m_netPayload;
|
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;
|
FILE* m_fp;
|
||||||
|
|
||||||
void writeQueueRF(const unsigned char* data);
|
void writeQueueRF(const unsigned char* data);
|
||||||
|
|
Loading…
Reference in New Issue