mirror of
https://github.com/g4klx/MMDVMHost.git
synced 2026-01-06 08:30:05 +01:00
Merge remote-tracking branch 'g4klx/master'
This commit is contained in:
commit
2047204a86
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
|
||||
* 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<unsigned int> CConf::getDMRWhiteList() const
|
|||
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
|
||||
{
|
||||
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;
|
||||
|
|
|
|||
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
|
||||
* 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> getDMRBlackList() 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 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<unsigned int> m_dmrPrefixes;
|
||||
std::vector<unsigned int> m_dmrBlackList;
|
||||
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_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;
|
||||
|
|
|
|||
|
|
@ -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<unsigned int> CDMRAccessControl::m_whiteList;
|
|||
|
||||
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;
|
||||
|
||||
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_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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <vector>
|
||||
|
||||
#include "DMRLC.h"
|
||||
|
||||
class CDMRAccessControl {
|
||||
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:
|
||||
static std::vector<unsigned int> m_blackList;
|
||||
static std::vector<unsigned int> m_whiteList;
|
||||
|
||||
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 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
#include <cassert>
|
||||
#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_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;
|
||||
|
|
|
|||
|
|
@ -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<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();
|
||||
|
||||
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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -26,21 +26,26 @@
|
|||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
CDMREmbeddedLC::CDMREmbeddedLC() :
|
||||
m_rawLC(NULL),
|
||||
m_state(LCS_NONE)
|
||||
CDMREmbeddedLC::CDMREmbeddedLC(unsigned int slotNo) :
|
||||
m_slotNo(slotNo),
|
||||
m_raw(NULL),
|
||||
m_state(LCS_NONE),
|
||||
m_data(NULL),
|
||||
m_FLCO(FLCO_GROUP),
|
||||
m_valid(false)
|
||||
{
|
||||
// Allow for multi-block non embedded LC data
|
||||
m_rawLC = new bool[300U];
|
||||
m_raw = new bool[128U];
|
||||
m_data = new bool[72U];
|
||||
}
|
||||
|
||||
CDMREmbeddedLC::~CDMREmbeddedLC()
|
||||
{
|
||||
delete[] m_rawLC;
|
||||
delete[] m_raw;
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
// Add LC data (which may consist of 4 blocks) to the data store
|
||||
CDMRLC* CDMREmbeddedLC::addData(const unsigned char* data, unsigned char lcss)
|
||||
bool CDMREmbeddedLC::addData(const unsigned char* data, unsigned char lcss)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
|
|
@ -54,49 +59,48 @@ CDMRLC* CDMREmbeddedLC::addData(const unsigned char* data, unsigned char lcss)
|
|||
// Is this the first block of a 4 block embedded LC ?
|
||||
if (lcss == 1U) {
|
||||
for (unsigned int a = 0U; a < 32U; a++)
|
||||
m_rawLC[a] = rawData[a + 4U];
|
||||
m_raw[a] = rawData[a + 4U];
|
||||
|
||||
// Show we are ready for the next LC block
|
||||
m_state = LCS_FIRST;
|
||||
return NULL;
|
||||
m_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this the 2nd block of a 4 block embedded LC ?
|
||||
if (lcss == 3U && m_state == LCS_FIRST) {
|
||||
for (unsigned int a = 0U; a < 32U; a++)
|
||||
m_rawLC[a + 32U] = rawData[a + 4U];
|
||||
m_raw[a + 32U] = rawData[a + 4U];
|
||||
|
||||
// Show we are ready for the next LC block
|
||||
m_state = LCS_SECOND;
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this the 3rd block of a 4 block embedded LC ?
|
||||
if (lcss == 3U && m_state == LCS_SECOND) {
|
||||
for (unsigned int a = 0U; a < 32U; a++)
|
||||
m_rawLC[a + 64U] = rawData[a + 4U];
|
||||
m_raw[a + 64U] = rawData[a + 4U];
|
||||
|
||||
// Show we are ready for the final LC block
|
||||
m_state = LCS_THIRD;
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this the final block of a 4 block embedded LC ?
|
||||
if (lcss == 2U && m_state == LCS_THIRD) {
|
||||
for (unsigned int a = 0U; a < 32U; a++)
|
||||
m_rawLC[a + 96U] = rawData[a + 4U];
|
||||
m_raw[a + 96U] = rawData[a + 4U];
|
||||
|
||||
// Process the complete data block
|
||||
return processMultiBlockEmbeddedLC();
|
||||
return processEmbeddedData();
|
||||
}
|
||||
|
||||
// Is this a single block embedded LC
|
||||
if (lcss == 0U) {
|
||||
processSingleBlockEmbeddedLC(rawData + 4U);
|
||||
return NULL;
|
||||
}
|
||||
if (lcss == 0U)
|
||||
return false;
|
||||
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
void CDMREmbeddedLC::setData(const CDMRLC& lc)
|
||||
|
|
@ -143,7 +147,7 @@ void CDMREmbeddedLC::setData(const CDMRLC& lc)
|
|||
// The data is packed downwards in columns
|
||||
b = 0U;
|
||||
for (unsigned int a = 0U; a < 128U; a++) {
|
||||
m_rawLC[a] = data[b];
|
||||
m_raw[a] = data[b];
|
||||
b += 16U;
|
||||
if (b > 127U)
|
||||
b -= 127U;
|
||||
|
|
@ -159,7 +163,7 @@ unsigned char CDMREmbeddedLC::getData(unsigned char* data, unsigned char n) cons
|
|||
|
||||
bool bits[40U];
|
||||
::memset(bits, 0x00U, 40U * sizeof(bool));
|
||||
::memcpy(bits + 4U, m_rawLC + n * 32U, 32U * sizeof(bool));
|
||||
::memcpy(bits + 4U, m_raw + n * 32U, 32U * sizeof(bool));
|
||||
|
||||
unsigned char bytes[5U];
|
||||
CUtils::bitsToByteBE(bits + 0U, bytes[0U]);
|
||||
|
|
@ -194,7 +198,7 @@ unsigned char CDMREmbeddedLC::getData(unsigned char* data, unsigned char n) cons
|
|||
}
|
||||
|
||||
// Unpack and error check an embedded LC
|
||||
CDMRLC* CDMREmbeddedLC::processMultiBlockEmbeddedLC()
|
||||
bool CDMREmbeddedLC::processEmbeddedData()
|
||||
{
|
||||
// The data is unpacked downwards in columns
|
||||
bool data[128U];
|
||||
|
|
@ -202,7 +206,7 @@ CDMRLC* CDMREmbeddedLC::processMultiBlockEmbeddedLC()
|
|||
|
||||
unsigned int b = 0U;
|
||||
for (unsigned int a = 0U; a < 128U; a++) {
|
||||
data[b] = m_rawLC[a];
|
||||
data[b] = m_raw[a];
|
||||
b += 16U;
|
||||
if (b > 127U)
|
||||
b -= 127U;
|
||||
|
|
@ -211,33 +215,32 @@ CDMRLC* CDMREmbeddedLC::processMultiBlockEmbeddedLC()
|
|||
// Hamming (16,11,4) check each row except the last one
|
||||
for (unsigned int a = 0U; a < 112U; a += 16U) {
|
||||
if (!CHamming::decode16114(data + a))
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the parity bits
|
||||
for (unsigned int a = 0U; a < 16U; a++) {
|
||||
bool parity = data[a + 0U] ^ data[a + 16U] ^ data[a + 32U] ^ data[a + 48U] ^ data[a + 64U] ^ data[a + 80U] ^ data[a + 96U] ^ data[a + 112U];
|
||||
if (parity)
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have passed the Hamming check so extract the actual payload
|
||||
bool lcData[72U];
|
||||
b = 0U;
|
||||
for (unsigned int a = 0U; a < 11U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
m_data[b] = data[a];
|
||||
for (unsigned int a = 16U; a < 27U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
m_data[b] = data[a];
|
||||
for (unsigned int a = 32U; a < 42U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
m_data[b] = data[a];
|
||||
for (unsigned int a = 48U; a < 58U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
m_data[b] = data[a];
|
||||
for (unsigned int a = 64U; a < 74U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
m_data[b] = data[a];
|
||||
for (unsigned int a = 80U; a < 90U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
m_data[b] = data[a];
|
||||
for (unsigned int a = 96U; a < 106U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
m_data[b] = data[a];
|
||||
|
||||
// Extract the 5 bit CRC
|
||||
unsigned int crc = 0U;
|
||||
|
|
@ -248,45 +251,65 @@ CDMRLC* CDMREmbeddedLC::processMultiBlockEmbeddedLC()
|
|||
if (data[106]) crc += 1U;
|
||||
|
||||
// Now CRC check this
|
||||
if (!CCRC::checkFiveBit(lcData, crc))
|
||||
return NULL;
|
||||
if (!CCRC::checkFiveBit(m_data, crc))
|
||||
return false;
|
||||
|
||||
CDMRLC* lc = new CDMRLC(lcData);
|
||||
m_valid = true;
|
||||
|
||||
// Extract the FLCO
|
||||
unsigned char flco;
|
||||
CUtils::bitsToByteBE(m_data + 0U, flco);
|
||||
m_FLCO = FLCO(flco & 0x3FU);
|
||||
|
||||
char text[80U];
|
||||
|
||||
// Only generate the LC when it's the correct FLCO
|
||||
switch (lc->getFLCO()) {
|
||||
switch (m_FLCO) {
|
||||
case FLCO_GROUP:
|
||||
case FLCO_USER_USER:
|
||||
return lc;
|
||||
// ::sprintf(text, "DMR Slot %u, Embedded LC Data", m_slotNo);
|
||||
// CUtils::dump(1U, text, m_data, 72U);
|
||||
return true;
|
||||
case FLCO_GPS_INFO:
|
||||
CUtils::dump(1U, "DMR, Embedded GPS Info", lcData, 72U);
|
||||
delete lc;
|
||||
return NULL;
|
||||
::sprintf(text, "DMR Slot %u, Embedded GPS Info", m_slotNo);
|
||||
CUtils::dump(1U, text, m_data, 72U);
|
||||
return true;
|
||||
case FLCO_TALKER_ALIAS_HEADER:
|
||||
CUtils::dump(1U, "DMR, Embedded Talker Alias Header", lcData, 72U);
|
||||
delete lc;
|
||||
return NULL;
|
||||
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Header", m_slotNo);
|
||||
CUtils::dump(1U, text, m_data, 72U);
|
||||
return true;
|
||||
case FLCO_TALKER_ALIAS_BLOCK1:
|
||||
CUtils::dump(1U, "DMR, Embedded Talker Alias Block 1", lcData, 72U);
|
||||
delete lc;
|
||||
return NULL;
|
||||
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 1", m_slotNo);
|
||||
CUtils::dump(1U, text, m_data, 72U);
|
||||
return true;
|
||||
case FLCO_TALKER_ALIAS_BLOCK2:
|
||||
CUtils::dump(1U, "DMR, Embedded Talker Alias Block 2", lcData, 72U);
|
||||
delete lc;
|
||||
return NULL;
|
||||
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 2", m_slotNo);
|
||||
CUtils::dump(1U, text, m_data, 72U);
|
||||
return true;
|
||||
case FLCO_TALKER_ALIAS_BLOCK3:
|
||||
CUtils::dump(1U, "DMR, Embedded Talker Alias Block 3", lcData, 72U);
|
||||
delete lc;
|
||||
return NULL;
|
||||
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 3", m_slotNo);
|
||||
CUtils::dump(1U, text, m_data, 72U);
|
||||
return true;
|
||||
default:
|
||||
CUtils::dump(1U, "DMR, Unknown Embedded Data", lcData, 72U);
|
||||
delete lc;
|
||||
return NULL;
|
||||
::sprintf(text, "DMR Slot %u, Unknown Embedded Data", m_slotNo);
|
||||
CUtils::dump(1U, text, m_data, 72U);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with a single block embedded LC
|
||||
void CDMREmbeddedLC::processSingleBlockEmbeddedLC(const bool* data)
|
||||
CDMRLC* CDMREmbeddedLC::getLC() const
|
||||
{
|
||||
// Nothing interesting, or just NULL (I think)
|
||||
if (!m_valid)
|
||||
return NULL;
|
||||
|
||||
if (m_FLCO != FLCO_GROUP && m_FLCO != FLCO_USER_USER)
|
||||
return NULL;
|
||||
|
||||
return new CDMRLC(m_data);
|
||||
}
|
||||
|
||||
void CDMREmbeddedLC::reset()
|
||||
{
|
||||
m_state = LCS_NONE;
|
||||
m_valid = 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
#ifndef DMREmbeddedLC_H
|
||||
#define DMREmbeddedLC_H
|
||||
|
||||
#include "DMRDefines.h"
|
||||
#include "DMRLC.h"
|
||||
|
||||
enum LC_STATE {
|
||||
|
|
@ -31,20 +32,27 @@ enum LC_STATE {
|
|||
class CDMREmbeddedLC
|
||||
{
|
||||
public:
|
||||
CDMREmbeddedLC();
|
||||
CDMREmbeddedLC(unsigned int slotNo);
|
||||
~CDMREmbeddedLC();
|
||||
|
||||
CDMRLC* addData(const unsigned char* data, unsigned char lcss);
|
||||
bool addData(const unsigned char* data, unsigned char lcss);
|
||||
CDMRLC* getLC() const;
|
||||
|
||||
void setData(const CDMRLC& lc);
|
||||
|
||||
unsigned char getData(unsigned char* data, unsigned char n) const;
|
||||
|
||||
private:
|
||||
bool* m_rawLC;
|
||||
LC_STATE m_state;
|
||||
void reset();
|
||||
|
||||
CDMRLC* processMultiBlockEmbeddedLC();
|
||||
void processSingleBlockEmbeddedLC(const bool* data);
|
||||
private:
|
||||
unsigned int m_slotNo;
|
||||
bool* m_raw;
|
||||
LC_STATE m_state;
|
||||
bool* m_data;
|
||||
FLCO m_FLCO;
|
||||
bool m_valid;
|
||||
|
||||
bool processEmbeddedData();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
125
DMRSlot.cpp
125
DMRSlot.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
|
||||
|
|
@ -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 <cassert>
|
||||
#include <ctime>
|
||||
|
|
@ -58,7 +59,8 @@ m_slotNo(slotNo),
|
|||
m_queue(5000U, "DMR Slot"),
|
||||
m_rfState(RS_RF_LISTENING),
|
||||
m_netState(RS_NET_IDLE),
|
||||
m_rfEmbeddedLC(),
|
||||
m_rfEmbeddedLC(slotNo),
|
||||
m_netEmbeddedLC(slotNo),
|
||||
m_rfLC(NULL),
|
||||
m_netLC(NULL),
|
||||
m_rfDataHeader(),
|
||||
|
|
@ -83,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];
|
||||
|
|
@ -102,13 +107,16 @@ 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));
|
||||
if (m_rssi != 0U)
|
||||
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);
|
||||
else
|
||||
LogMessage("DMR Slot %u, RF voice transmission lost, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
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;
|
||||
}
|
||||
|
|
@ -130,6 +138,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;
|
||||
|
|
@ -154,13 +170,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
|
||||
|
|
@ -176,12 +199,18 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
data[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);
|
||||
|
|
@ -199,11 +228,12 @@ 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");
|
||||
m_display->writeDMRRSSI(m_slotNo, m_rssi);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -252,7 +282,10 @@ 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));
|
||||
if (m_rssi != 0U)
|
||||
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);
|
||||
else
|
||||
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));
|
||||
|
||||
writeEndRF();
|
||||
} else if (dataType == DT_DATA_HEADER) {
|
||||
|
|
@ -268,11 +301,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;
|
||||
|
|
@ -306,6 +344,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
if (m_netState == RS_NET_IDLE) {
|
||||
setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, false);
|
||||
m_display->writeDMR(m_slotNo, src, gi, dst, "R");
|
||||
m_display->writeDMRRSSI(m_slotNo, m_rssi);
|
||||
}
|
||||
|
||||
LogMessage("DMR Slot %u, received RF data header from %s to %s%s, %u blocks", m_slotNo, src.c_str(), gi ? "TG ": "", dst.c_str(), m_rfFrames);
|
||||
|
|
@ -327,10 +366,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
|
||||
|
|
@ -433,11 +477,16 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
m_rfEmbeddedLC.reset();
|
||||
|
||||
if (m_duplex)
|
||||
writeQueueRF(data);
|
||||
|
||||
writeNetworkRF(data, DT_VOICE_SYNC, errors);
|
||||
|
||||
m_display->writeDMRRSSI(m_slotNo, m_rssi);
|
||||
} else if (m_rfState == RS_RF_LISTENING) {
|
||||
m_rfEmbeddedLC.reset();
|
||||
m_rfState = RS_RF_LATE_ENTRY;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -458,6 +507,8 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
m_rfErrs += errors;
|
||||
}
|
||||
|
||||
m_rfEmbeddedLC.addData(data + 2U, emb.getLCSS());
|
||||
|
||||
m_rfBits += 141U;
|
||||
|
||||
m_rfFrames++;
|
||||
|
|
@ -478,17 +529,25 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
if (colorCode != m_colorCode)
|
||||
return;
|
||||
|
||||
CDMRLC* lc = m_rfEmbeddedLC.addData(data + 2U, emb.getLCSS());
|
||||
m_rfEmbeddedLC.addData(data + 2U, emb.getLCSS());
|
||||
CDMRLC* lc = m_rfEmbeddedLC.getLC();
|
||||
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
|
||||
|
|
@ -508,12 +567,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);
|
||||
|
|
@ -557,11 +622,12 @@ 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");
|
||||
m_display->writeDMRRSSI(m_slotNo, m_rssi);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -778,6 +844,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
m_lastFrameValid = false;
|
||||
|
||||
m_netTimeoutTimer.start();
|
||||
m_netEmbeddedLC.reset();
|
||||
|
||||
m_netFrames = 0U;
|
||||
m_netLost = 0U;
|
||||
|
|
@ -823,6 +890,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
m_lastFrameValid = false;
|
||||
|
||||
m_netTimeoutTimer.start();
|
||||
m_netEmbeddedLC.reset();
|
||||
|
||||
if (m_duplex) {
|
||||
m_queue.clear();
|
||||
|
|
@ -1071,6 +1139,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
|
||||
writeQueueNet(data);
|
||||
|
||||
m_netEmbeddedLC.reset();
|
||||
m_packetTimer.start();
|
||||
m_elapsed.start();
|
||||
|
||||
|
|
@ -1094,9 +1163,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, emb.getLCSS());
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
|
@ -1569,6 +1641,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) {
|
||||
|
|
@ -1581,11 +1657,8 @@ void CDMRSlot::insertSilence(unsigned int count)
|
|||
if (n == 0U) {
|
||||
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);
|
||||
m_netEmbeddedLC.getData(data + 2U, 0U);
|
||||
emb.getData(data + 2U);
|
||||
}
|
||||
|
||||
writeQueueNet(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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -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"
|
||||
|
|
@ -59,6 +58,7 @@ private:
|
|||
RPT_RF_STATE m_rfState;
|
||||
RPT_NET_STATE m_netState;
|
||||
CDMREmbeddedLC m_rfEmbeddedLC;
|
||||
CDMREmbeddedLC m_netEmbeddedLC;
|
||||
CDMRLC* m_rfLC;
|
||||
CDMRLC* m_netLC;
|
||||
CDMRDataHeader m_rfDataHeader;
|
||||
|
|
@ -83,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;
|
||||
|
|
|
|||
|
|
@ -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<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_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,10 @@ 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));
|
||||
if (m_rssi != 0U)
|
||||
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);
|
||||
else
|
||||
LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
writeEndRF();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -121,6 +131,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 +235,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);
|
||||
|
|
@ -203,8 +262,10 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len)
|
|||
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
|
||||
if (m_netState == RS_NET_IDLE)
|
||||
if (m_netState == RS_NET_IDLE) {
|
||||
m_display->writeDStar((char*)my1, (char*)my2, (char*)your, "R", " ");
|
||||
m_display->writeDStarRSSI(m_rssi);
|
||||
}
|
||||
|
||||
LogMessage("D-Star, received RF header from %8.8s/%4.4s to %8.8s", my1, my2, your);
|
||||
} else if (type == TAG_EOT) {
|
||||
|
|
@ -217,7 +278,10 @@ 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));
|
||||
if (m_rssi != 0U)
|
||||
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);
|
||||
else
|
||||
LogMessage("D-Star, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
|
||||
writeEndRF();
|
||||
}
|
||||
|
|
@ -248,9 +312,11 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len)
|
|||
if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0)
|
||||
m_rfN = 0U;
|
||||
|
||||
// Regenerate the sync
|
||||
if (m_rfN == 0U)
|
||||
// Regenerate the sync and send the RSSI data to the display
|
||||
if (m_rfN == 0U) {
|
||||
CSync::addDStarSync(data + 1U);
|
||||
m_display->writeDStarRSSI(m_rssi);
|
||||
}
|
||||
|
||||
LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_rfN, errors);
|
||||
|
||||
|
|
@ -328,6 +394,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;
|
||||
|
|
@ -377,8 +448,10 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len)
|
|||
|
||||
m_rfN = (m_rfN + 1U) % 21U;
|
||||
|
||||
if (m_netState == RS_NET_IDLE)
|
||||
if (m_netState == RS_NET_IDLE) {
|
||||
m_display->writeDStar((char*)my1, (char*)my2, (char*)your, "R", " ");
|
||||
m_display->writeDStarRSSI(m_rssi);
|
||||
}
|
||||
|
||||
LogMessage("D-Star, received RF late entry from %8.8s/%4.4s to %8.8s", my1, my2, your);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<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();
|
||||
|
||||
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();
|
||||
|
|
|
|||
42
Display.cpp
42
Display.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
|
||||
|
|
@ -84,6 +84,12 @@ void CDisplay::writeDStar(const char* my1, const char* my2, const char* your, co
|
|||
writeDStarInt(my1, my2, your, type, reflector);
|
||||
}
|
||||
|
||||
void CDisplay::writeDStarRSSI(unsigned char rssi)
|
||||
{
|
||||
if (rssi != 0U)
|
||||
writeDStarRSSIInt(rssi);
|
||||
}
|
||||
|
||||
void CDisplay::clearDStar()
|
||||
{
|
||||
if (m_timer1.hasExpired()) {
|
||||
|
|
@ -110,6 +116,12 @@ void CDisplay::writeDMR(unsigned int slotNo, const std::string& src, bool group,
|
|||
writeDMRInt(slotNo, src, group, dst, type);
|
||||
}
|
||||
|
||||
void CDisplay::writeDMRRSSI(unsigned int slotNo, unsigned char rssi)
|
||||
{
|
||||
if (rssi != 0U)
|
||||
writeDMRRSSIInt(slotNo, rssi);
|
||||
}
|
||||
|
||||
void CDisplay::clearDMR(unsigned int slotNo)
|
||||
{
|
||||
if (slotNo == 1U) {
|
||||
|
|
@ -144,6 +156,12 @@ void CDisplay::writeFusion(const char* source, const char* dest, const char* typ
|
|||
writeFusionInt(source, dest, type, origin);
|
||||
}
|
||||
|
||||
void CDisplay::writeFusionRSSI(unsigned char rssi)
|
||||
{
|
||||
if (rssi != 0U)
|
||||
writeFusionRSSIInt(rssi);
|
||||
}
|
||||
|
||||
void CDisplay::clearFusion()
|
||||
{
|
||||
if (m_timer1.hasExpired()) {
|
||||
|
|
@ -166,6 +184,12 @@ void CDisplay::writeP25(const char* source, bool group, unsigned int dest, const
|
|||
writeP25Int(source, group, dest, type);
|
||||
}
|
||||
|
||||
void CDisplay::writeP25RSSI(unsigned char rssi)
|
||||
{
|
||||
if (rssi != 0U)
|
||||
writeP25RSSIInt(rssi);
|
||||
}
|
||||
|
||||
void CDisplay::clearP25()
|
||||
{
|
||||
if (m_timer1.hasExpired()) {
|
||||
|
|
@ -236,3 +260,19 @@ void CDisplay::clock(unsigned int ms)
|
|||
void CDisplay::clockInt(unsigned int ms)
|
||||
{
|
||||
}
|
||||
|
||||
void CDisplay::writeDStarRSSIInt(unsigned char rssi)
|
||||
{
|
||||
}
|
||||
|
||||
void CDisplay::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
|
||||
{
|
||||
}
|
||||
|
||||
void CDisplay::writeFusionRSSIInt(unsigned char rssi)
|
||||
{
|
||||
}
|
||||
|
||||
void CDisplay::writeP25RSSIInt(unsigned char rssi)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
10
Display.h
10
Display.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
|
||||
|
|
@ -36,15 +36,19 @@ public:
|
|||
void setError(const char* text);
|
||||
|
||||
void writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
|
||||
void writeDStarRSSI(unsigned char rssi);
|
||||
void clearDStar();
|
||||
|
||||
void writeDMR(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
|
||||
void writeDMRRSSI(unsigned int slotNo, unsigned char rssi);
|
||||
void clearDMR(unsigned int slotNo);
|
||||
|
||||
void writeFusion(const char* source, const char* dest, const char* type, const char* origin);
|
||||
void writeFusionRSSI(unsigned char rssi);
|
||||
void clearFusion();
|
||||
|
||||
void writeP25(const char* source, bool group, unsigned int dest, const char* type);
|
||||
void writeP25RSSI(unsigned char rssi);
|
||||
void clearP25();
|
||||
|
||||
void writeCW();
|
||||
|
|
@ -60,15 +64,19 @@ protected:
|
|||
virtual void setErrorInt(const char* text) = 0;
|
||||
|
||||
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0;
|
||||
virtual void writeDStarRSSIInt(unsigned char rssi);
|
||||
virtual void clearDStarInt() = 0;
|
||||
|
||||
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) = 0;
|
||||
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
|
||||
virtual void clearDMRInt(unsigned int slotNo) = 0;
|
||||
|
||||
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin) = 0;
|
||||
virtual void writeFusionRSSIInt(unsigned char rssi);
|
||||
virtual void clearFusionInt() = 0;
|
||||
|
||||
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type) = 0;
|
||||
virtual void writeP25RSSIInt(unsigned char rssi);
|
||||
virtual void clearP25Int() = 0;
|
||||
|
||||
virtual void writeCWInt() = 0;
|
||||
|
|
|
|||
167
HD44780.cpp
167
HD44780.cpp
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2016, 2017 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
|
||||
*
|
||||
* 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,6 +36,11 @@ char m_buffer2[128U];
|
|||
char m_buffer3[128U];
|
||||
char m_buffer4[128U];
|
||||
|
||||
const unsigned int DSTAR_RSSI_COUNT = 3U; // 3 * 420ms = 1260ms
|
||||
const unsigned int DMR_RSSI_COUNT = 4U; // 4 * 360ms = 1440ms
|
||||
const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms
|
||||
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
|
||||
|
||||
CHD44780::CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector<unsigned int>& pins, unsigned int i2cAddress, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool displayClock, bool utc, bool duplex) :
|
||||
CDisplay(),
|
||||
m_rows(rows),
|
||||
|
|
@ -59,12 +64,9 @@ m_duplex(duplex),
|
|||
//m_duplex(true), // uncomment to force duplex display for testing!
|
||||
m_fd(-1),
|
||||
m_dmr(false),
|
||||
m_clockDisplayTimer(1000U, 0U, 250U) // Update the clock display every 250ms
|
||||
/*
|
||||
m_dmrScrollTimer1(1000U, 0U, 250U), // Scroll speed for slot 1 - every 250ms
|
||||
m_dmrScrollTimer2(1000U, 0U, 250U), // Scroll speed for slot 2 - every 250ms
|
||||
m_dstarScrollTimer(1000U, 0U, 250U) // Scroll speed for D-Star - every 250ms
|
||||
*/
|
||||
m_clockDisplayTimer(1000U, 0U, 250U), // Update the clock display every 250ms
|
||||
m_rssiCount1(0U),
|
||||
m_rssiCount2(0U)
|
||||
{
|
||||
assert(rows > 1U);
|
||||
assert(cols > 15U);
|
||||
|
|
@ -290,8 +292,6 @@ void CHD44780::pcf8574LCDSetup()
|
|||
|
||||
void CHD44780::setIdleInt()
|
||||
{
|
||||
//m_dmrScrollTimer1.stop(); // Stop the scroll timer on slot 1
|
||||
//m_dmrScrollTimer2.stop(); // Stop the scroll timer on slot 2
|
||||
m_clockDisplayTimer.start(); // Start the clock display in IDLE only
|
||||
::lcdClear(m_fd);
|
||||
|
||||
|
|
@ -330,8 +330,6 @@ void CHD44780::setErrorInt(const char* text)
|
|||
#endif
|
||||
|
||||
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||
//m_dmrScrollTimer1.stop(); // Stop the scroll timer on slot 1
|
||||
//m_dmrScrollTimer2.stop(); // Stop the scroll timer on slot 2
|
||||
::lcdClear(m_fd);
|
||||
|
||||
if (m_pwm) {
|
||||
|
|
@ -357,8 +355,6 @@ void CHD44780::setLockoutInt()
|
|||
#endif
|
||||
|
||||
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||
//m_dmrScrollTimer1.stop(); // Stop the scroll timer on slot 1
|
||||
//m_dmrScrollTimer2.stop(); // Stop the scroll timer on slot 2
|
||||
::lcdClear(m_fd);
|
||||
|
||||
if (m_pwm) {
|
||||
|
|
@ -439,14 +435,20 @@ void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your,
|
|||
::lcdPutchar(m_fd, 1);
|
||||
::lcdPrintf(m_fd, " %.*s", m_cols, m_buffer1);
|
||||
|
||||
// Start the D-Star scroll timer if text in m_buffer1 will not fit in the space available
|
||||
/*if (strlen(m_buffer1) > m_cols) {
|
||||
::sprintf(m_buffer3, "%.*s", m_cols, DEADSPACE);
|
||||
strcat(m_buffer1, m_buffer3);
|
||||
m_dstarScrollTimer.start();
|
||||
}*/
|
||||
|
||||
m_dmr = false;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CHD44780::writeDStarRSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U && m_rows > 2) {
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "-%3udBm", rssi);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= DSTAR_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CHD44780::clearDStarInt()
|
||||
|
|
@ -456,7 +458,6 @@ void CHD44780::clearDStarInt()
|
|||
#endif
|
||||
|
||||
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||
//m_dstarScrollTimer.stop();
|
||||
::lcdClear(m_fd);
|
||||
|
||||
::lcdPosition(m_fd, 0, (m_rows / 2) - 1);
|
||||
|
|
@ -538,13 +539,6 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
|
|||
::sprintf(m_buffer1, "%s>%s%s", src.c_str(), dst.c_str(), DEADSPACE);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols - 2U, m_buffer1);
|
||||
|
||||
// Start the DMR scroll timer on slot 1 if text in m_buffer1 will not fit in the space available
|
||||
/*if (strlen(m_buffer1) > m_cols - 5 ) {
|
||||
::sprintf(m_buffer3, "%.*s", m_cols, DEADSPACE);
|
||||
strcat(m_buffer1, m_buffer3);
|
||||
m_dmrScrollTimer1.start();
|
||||
}*/
|
||||
|
||||
::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2) - 1);
|
||||
::lcdPuts(m_fd, " ");
|
||||
|
||||
|
|
@ -568,13 +562,6 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
|
|||
::sprintf(m_buffer2, "%s>%s%s", src.c_str(), dst.c_str(), DEADSPACE);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols - 2U, m_buffer2);
|
||||
|
||||
// Start the DMR scroll timer on slot 2 if text in m_buffer2 will not fit in the space available
|
||||
/*if (strlen(m_buffer2) > m_cols - 5 ) {
|
||||
::sprintf(m_buffer4, "%.*s", m_cols, DEADSPACE);
|
||||
strcat(m_buffer2, m_buffer4);
|
||||
m_dmrScrollTimer2.start();
|
||||
}*/
|
||||
|
||||
::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2));
|
||||
::lcdPuts(m_fd, " ");
|
||||
|
||||
|
|
@ -622,6 +609,33 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
|
|||
}
|
||||
}
|
||||
m_dmr = true;
|
||||
m_rssiCount1 = 0U;
|
||||
m_rssiCount2 = 0U;
|
||||
}
|
||||
|
||||
void CHD44780::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
|
||||
{
|
||||
if (m_rows > 2) {
|
||||
if (slotNo == 1U) {
|
||||
if (m_rssiCount1 == 0U) {
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "-%3udBm", rssi);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= DMR_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
} else {
|
||||
if (m_rssiCount2 == 0U) {
|
||||
::lcdPosition(m_fd, (m_cols / 2), 3);
|
||||
::lcdPrintf(m_fd, "-%3udBm", rssi);
|
||||
}
|
||||
|
||||
m_rssiCount2++;
|
||||
if (m_rssiCount2 >= DMR_RSSI_COUNT)
|
||||
m_rssiCount2 = 0U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CHD44780::clearDMRInt(unsigned int slotNo)
|
||||
|
|
@ -634,16 +648,23 @@ void CHD44780::clearDMRInt(unsigned int slotNo)
|
|||
|
||||
if (m_duplex) {
|
||||
if (slotNo == 1U) {
|
||||
//m_dmrScrollTimer1.stop(); // Stop the scroll timer on slot 1
|
||||
::lcdPosition(m_fd, 0, (m_rows / 2) - 1);
|
||||
::lcdPrintf(m_fd, "1 %.*s", m_cols - 2U, LISTENING);
|
||||
|
||||
if (m_rows > 2) { // clear slot 1 RSSI
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols / 2, DEADSPACE);
|
||||
}
|
||||
} else {
|
||||
//m_dmrScrollTimer2.stop(); // Stop the scroll timer on slot 2
|
||||
::lcdPosition(m_fd, 0, (m_rows / 2));
|
||||
::lcdPrintf(m_fd, "2 %.*s", m_cols - 2U, LISTENING);
|
||||
|
||||
if (m_rows > 2) { // cleat slot 2 RSSI
|
||||
::lcdPosition(m_fd, m_cols / 2, 3);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols / 2, DEADSPACE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//m_dmrScrollTimer2.stop(); // Stop the scroll timer on slot 2
|
||||
|
||||
if (m_rows > 2U) {
|
||||
::lcdPosition(m_fd, 0, (m_rows / 2) - 2);
|
||||
|
|
@ -715,6 +736,19 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, const char*
|
|||
}
|
||||
|
||||
m_dmr = false;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CHD44780::writeFusionRSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U && m_rows > 2) {
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "-%3udBm", rssi);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= YSF_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CHD44780::clearFusionInt()
|
||||
|
|
@ -734,12 +768,18 @@ void CHD44780::clearFusionInt()
|
|||
|
||||
::lcdPosition(m_fd, 0, 2);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
|
||||
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
|
||||
} else if (m_rows == 4U && m_cols == 20U) {
|
||||
::lcdPosition(m_fd, 0, 1);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING);
|
||||
|
||||
::lcdPosition(m_fd, 0, 2);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
|
||||
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
|
||||
} else if (m_rows == 2 && m_cols == 40U) {
|
||||
::lcdPosition(m_fd, 0, 1);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING);
|
||||
|
|
@ -800,6 +840,19 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
|
|||
}
|
||||
|
||||
m_dmr = false;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CHD44780::writeP25RSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U && m_rows > 2) {
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "-%3udBm", rssi);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= P25_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CHD44780::clearP25Int()
|
||||
|
|
@ -819,12 +872,18 @@ void CHD44780::clearP25Int()
|
|||
|
||||
::lcdPosition(m_fd, 0, 2);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
|
||||
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
|
||||
} else if (m_rows == 4U && m_cols == 20U) {
|
||||
::lcdPosition(m_fd, 0, 1);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING);
|
||||
|
||||
::lcdPosition(m_fd, 0, 2);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
|
||||
|
||||
::lcdPosition(m_fd, 0, 3);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
|
||||
} else if (m_rows == 2 && m_cols == 40U) {
|
||||
::lcdPosition(m_fd, 0, 1);
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING);
|
||||
|
|
@ -846,9 +905,6 @@ void CHD44780::clearCWInt()
|
|||
void CHD44780::clockInt(unsigned int ms)
|
||||
{
|
||||
m_clockDisplayTimer.clock(ms);
|
||||
//m_dmrScrollTimer1.clock(ms);
|
||||
//m_dmrScrollTimer2.clock(ms);
|
||||
//m_dstarScrollTimer.clock(ms);
|
||||
|
||||
// Idle clock display
|
||||
if (m_displayClock && m_clockDisplayTimer.isRunning() && m_clockDisplayTimer.hasExpired()) {
|
||||
|
|
@ -878,35 +934,6 @@ void CHD44780::clockInt(unsigned int ms)
|
|||
|
||||
m_clockDisplayTimer.start();
|
||||
}
|
||||
|
||||
/* Scrolling disabled for now as it is slowing things down just enough to screw with the audio processing!
|
||||
|
||||
// DMR Slot 1 scrolling
|
||||
if (m_dmrScrollTimer1.isRunning() && m_dmrScrollTimer1.hasExpired()) {
|
||||
strncat(m_buffer1, m_buffer1, 1); // Move the first character to the end of the buffer
|
||||
memmove(m_buffer1, m_buffer1 + 1, strlen(m_buffer1)); // Strip the first character
|
||||
::lcdPosition(m_fd, 2, (m_rows / 2) - 1); // Position on the LCD
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols - 5U, m_buffer1); // Print it out
|
||||
m_dmrScrollTimer1.start(); // Restart the scroll timer
|
||||
}
|
||||
|
||||
// DMR Slot 2 scrolling
|
||||
if (m_dmrScrollTimer2.isRunning() && m_dmrScrollTimer2.hasExpired()) {
|
||||
strncat(m_buffer2, m_buffer2, 1);
|
||||
memmove(m_buffer2, m_buffer2 + 1, strlen(m_buffer2));
|
||||
::lcdPosition(m_fd, 2, (m_rows / 2));
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols - 5U, m_buffer2);
|
||||
m_dmrScrollTimer2.start();
|
||||
}
|
||||
|
||||
// D-Star scrolling
|
||||
if (m_dstarScrollTimer.isRunning() && m_dstarScrollTimer.hasExpired()) {
|
||||
strncat(m_buffer1, m_buffer1, 1);
|
||||
memmove(m_buffer1, m_buffer1 + 1, strlen(m_buffer1));
|
||||
::lcdPosition(m_fd, 0, (m_rows / 2));
|
||||
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
|
||||
m_dstarScrollTimer.start();
|
||||
}*/
|
||||
}
|
||||
|
||||
void CHD44780::close()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2016, 2017 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
|
||||
*
|
||||
* 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
|
||||
|
|
@ -102,15 +102,19 @@ protected:
|
|||
virtual void setLockoutInt();
|
||||
|
||||
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
|
||||
virtual void writeDStarRSSIInt(unsigned char rssi);
|
||||
virtual void clearDStarInt();
|
||||
|
||||
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
|
||||
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
|
||||
virtual void clearDMRInt(unsigned int slotNo);
|
||||
|
||||
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
|
||||
virtual void writeFusionRSSIInt(unsigned char rssi);
|
||||
virtual void clearFusionInt();
|
||||
|
||||
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
|
||||
virtual void writeP25RSSIInt(unsigned char rssi);
|
||||
virtual void clearP25Int();
|
||||
|
||||
virtual void writeCWInt();
|
||||
|
|
@ -140,6 +144,8 @@ private:
|
|||
int m_fd;
|
||||
bool m_dmr;
|
||||
CTimer m_clockDisplayTimer;
|
||||
unsigned int m_rssiCount1;
|
||||
unsigned int m_rssiCount2;
|
||||
/*
|
||||
CTimer m_dmrScrollTimer1;
|
||||
CTimer m_dmrScrollTimer2;
|
||||
|
|
|
|||
90
LCDproc.cpp
90
LCDproc.cpp
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2016, 2017 by Tony Corbett G0WFV
|
||||
*
|
||||
* 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
|
||||
|
|
@ -84,6 +84,11 @@ bool m_connected(false);
|
|||
char m_displayBuffer1[BUFFER_MAX_LEN];
|
||||
char m_displayBuffer2[BUFFER_MAX_LEN];
|
||||
|
||||
const unsigned int DSTAR_RSSI_COUNT = 3U; // 3 * 420ms = 1260ms
|
||||
const unsigned int DMR_RSSI_COUNT = 4U; // 4 * 360ms = 1440ms
|
||||
const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms
|
||||
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
|
||||
|
||||
CLCDproc::CLCDproc(std::string address, unsigned int port, unsigned int localPort, const std::string& callsign, unsigned int dmrid, bool displayClock, bool utc, bool duplex, bool dimOnIdle) :
|
||||
CDisplay(),
|
||||
m_address(address),
|
||||
|
|
@ -97,7 +102,9 @@ m_duplex(duplex),
|
|||
//m_duplex(true), // uncomment to force duplex display for testing!
|
||||
m_dimOnIdle(dimOnIdle),
|
||||
m_dmr(false),
|
||||
m_clockDisplayTimer(1000U, 0U, 250U) // Update the clock display every 250ms
|
||||
m_clockDisplayTimer(1000U, 0U, 250U), // Update the clock display every 250ms
|
||||
m_rssiCount1(0U),
|
||||
m_rssiCount2(0U)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -242,6 +249,18 @@ void CLCDproc::writeDStarInt(const char* my1, const char* my2, const char* your,
|
|||
}
|
||||
|
||||
m_dmr = false;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CLCDproc::writeDStarRSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U) {
|
||||
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= DSTAR_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CLCDproc::clearDStarInt()
|
||||
|
|
@ -301,6 +320,31 @@ void CLCDproc::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
|
|||
}
|
||||
socketPrintf(m_socketfd, "output 16"); // Set LED1 color red
|
||||
m_dmr = true;
|
||||
m_rssiCount1 = 0U;
|
||||
m_rssiCount2 = 0U;
|
||||
}
|
||||
|
||||
void CLCDproc::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
|
||||
{
|
||||
if (m_rows > 2) {
|
||||
if (slotNo == 1U) {
|
||||
if (m_rssiCount1 == 0U)
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot1RSSI %u %u -%3udBm", 1, 4, rssi);
|
||||
|
||||
m_rssiCount1++;
|
||||
|
||||
if (m_rssiCount1 >= DMR_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
} else {
|
||||
if (m_rssiCount2 == 0U)
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u -%3udBm", (m_cols / 2) + 1, 4, rssi);
|
||||
|
||||
m_rssiCount2++;
|
||||
|
||||
if (m_rssiCount2 >= DMR_RSSI_COUNT)
|
||||
m_rssiCount2 = 0U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CLCDproc::clearDMRInt(unsigned int slotNo)
|
||||
|
|
@ -308,13 +352,17 @@ void CLCDproc::clearDMRInt(unsigned int slotNo)
|
|||
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||
|
||||
if (m_duplex) {
|
||||
if (slotNo == 1U)
|
||||
if (slotNo == 1U) {
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot1 3 %u %u %u h 3 \"Listening\"", m_rows / 2, m_cols - 1, m_rows / 2);
|
||||
else
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot1RSSI %u %u %*.s", 1, 4, m_cols / 2, " ");
|
||||
} else {
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot2 3 %u %u %u h 3 \"Listening\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1);
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " ");
|
||||
}
|
||||
} else {
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 Listening");
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 15 3 h 3 \"\"");
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " ");
|
||||
}
|
||||
socketPrintf(m_socketfd, "output 1"); // Set LED1 color green
|
||||
}
|
||||
|
|
@ -342,6 +390,18 @@ void CLCDproc::writeFusionInt(const char* source, const char* dest, const char*
|
|||
}
|
||||
|
||||
m_dmr = false;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CLCDproc::writeFusionRSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U) {
|
||||
socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= YSF_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CLCDproc::clearFusionInt()
|
||||
|
|
@ -375,6 +435,18 @@ void CLCDproc::writeP25Int(const char* source, bool group, unsigned int dest, co
|
|||
}
|
||||
|
||||
m_dmr = false;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CLCDproc::writeP25RSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U) {
|
||||
socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= P25_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CLCDproc::clearP25Int()
|
||||
|
|
@ -599,9 +671,11 @@ void CLCDproc::defineScreens()
|
|||
socketPrintf(m_socketfd, "widget_add DStar Line3 scroller");
|
||||
socketPrintf(m_socketfd, "widget_add DStar Line4 scroller");
|
||||
|
||||
/* Do we need to pre-populate the values??
|
||||
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 Listening");
|
||||
socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\"");
|
||||
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\"");
|
||||
*/
|
||||
|
||||
// The DMR Screen
|
||||
|
||||
|
|
@ -613,11 +687,15 @@ void CLCDproc::defineScreens()
|
|||
socketPrintf(m_socketfd, "widget_add DMR Slot2_ string");
|
||||
socketPrintf(m_socketfd, "widget_add DMR Slot1 scroller");
|
||||
socketPrintf(m_socketfd, "widget_add DMR Slot2 scroller");
|
||||
socketPrintf(m_socketfd, "widget_add DMR Slot1RSSI string");
|
||||
socketPrintf(m_socketfd, "widget_add DMR Slot2RSSI string");
|
||||
|
||||
/* Do we need to pre-populate the values??
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u 1", m_rows / 2);
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u 2", m_rows / 2 + 1);
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 Listening");
|
||||
socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 Listening");
|
||||
*/
|
||||
|
||||
// The YSF Screen
|
||||
|
||||
|
|
@ -629,9 +707,11 @@ void CLCDproc::defineScreens()
|
|||
socketPrintf(m_socketfd, "widget_add YSF Line3 scroller");
|
||||
socketPrintf(m_socketfd, "widget_add YSF Line4 scroller");
|
||||
|
||||
/* Do we need to pre-populate the values??
|
||||
socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 Listening");
|
||||
socketPrintf(m_socketfd, "widget_set YSF Line3 3 1 15 1 h 3 \" \"");
|
||||
socketPrintf(m_socketfd, "widget_set YSF Line4 4 2 15 2 h 3 \" \"");
|
||||
*/
|
||||
|
||||
// The P25 Screen
|
||||
|
||||
|
|
@ -643,9 +723,11 @@ void CLCDproc::defineScreens()
|
|||
socketPrintf(m_socketfd, "widget_add P25 Line3 scroller");
|
||||
socketPrintf(m_socketfd, "widget_add P25 Line4 scroller");
|
||||
|
||||
/* Do we need to pre-populate the values??
|
||||
socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 Listening");
|
||||
socketPrintf(m_socketfd, "widget_set P25 Line3 3 1 15 1 h 3 \" \"");
|
||||
socketPrintf(m_socketfd, "widget_set P25 Line4 4 2 15 2 h 3 \" \"");
|
||||
*/
|
||||
|
||||
m_screensDefined = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2016, 2017 by Tony Corbett G0WFV
|
||||
*
|
||||
* 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
|
||||
|
|
@ -40,15 +40,19 @@ protected:
|
|||
virtual void setLockoutInt();
|
||||
|
||||
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
|
||||
virtual void writeDStarRSSIInt(unsigned char rssi);
|
||||
virtual void clearDStarInt();
|
||||
|
||||
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
|
||||
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
|
||||
virtual void clearDMRInt(unsigned int slotNo);
|
||||
|
||||
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
|
||||
virtual void writeFusionRSSIInt(unsigned char rssi);
|
||||
virtual void clearFusionInt();
|
||||
|
||||
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
|
||||
virtual void writeP25RSSIInt(unsigned char rssi);
|
||||
virtual void clearP25Int();
|
||||
|
||||
virtual void writeCWInt();
|
||||
|
|
@ -68,6 +72,8 @@ private:
|
|||
bool m_dimOnIdle;
|
||||
bool m_dmr;
|
||||
CTimer m_clockDisplayTimer;
|
||||
unsigned int m_rssiCount1;
|
||||
unsigned int m_rssiCount2;
|
||||
|
||||
int socketPrintf(int fd, const char *format, ...);
|
||||
void defineScreens();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<unsigned int> prefixes = m_conf.getDMRPrefixes();
|
||||
std::vector<unsigned int> blackList = m_conf.getDMRBlackList();
|
||||
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();
|
||||
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()) {
|
||||
|
|
|
|||
84
Nextion.cpp
84
Nextion.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
|
||||
|
|
@ -25,6 +25,11 @@
|
|||
#include <ctime>
|
||||
#include <clocale>
|
||||
|
||||
const unsigned int DSTAR_RSSI_COUNT = 3U; // 3 * 420ms = 1260ms
|
||||
const unsigned int DMR_RSSI_COUNT = 4U; // 4 * 360ms = 1440ms
|
||||
const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms
|
||||
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
|
||||
|
||||
CNextion::CNextion(const std::string& callsign, unsigned int dmrid, ISerialPort* serial, unsigned int brightness, bool displayClock, bool utc, unsigned int idleBrightness) :
|
||||
CDisplay(),
|
||||
m_callsign(callsign),
|
||||
|
|
@ -35,7 +40,9 @@ m_mode(MODE_IDLE),
|
|||
m_displayClock(displayClock),
|
||||
m_utc(utc),
|
||||
m_idleBrightness(idleBrightness),
|
||||
m_clockDisplayTimer(1000U, 0U, 400U)
|
||||
m_clockDisplayTimer(1000U, 0U, 400U),
|
||||
m_rssiCount1(0U),
|
||||
m_rssiCount2(0U)
|
||||
{
|
||||
assert(serial != NULL);
|
||||
assert(brightness >= 0U && brightness <= 100U);
|
||||
|
|
@ -143,6 +150,20 @@ void CNextion::writeDStarInt(const char* my1, const char* my2, const char* your,
|
|||
m_clockDisplayTimer.stop();
|
||||
|
||||
m_mode = MODE_DSTAR;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CNextion::writeDStarRSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U) {
|
||||
char text[20U];
|
||||
::sprintf(text, "t3.txt=\"-%udBm\"", rssi);
|
||||
sendCommand(text);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= DSTAR_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CNextion::clearDStarInt()
|
||||
|
|
@ -150,6 +171,7 @@ void CNextion::clearDStarInt()
|
|||
sendCommand("t0.txt=\"Listening\"");
|
||||
sendCommand("t1.txt=\"\"");
|
||||
sendCommand("t2.txt=\"\"");
|
||||
sendCommand("t3.txt=\"\"");
|
||||
}
|
||||
|
||||
void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
|
||||
|
|
@ -186,6 +208,33 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
|
|||
m_clockDisplayTimer.stop();
|
||||
|
||||
m_mode = MODE_DMR;
|
||||
m_rssiCount1 = 0U;
|
||||
m_rssiCount2 = 0U;
|
||||
}
|
||||
|
||||
void CNextion::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
|
||||
{
|
||||
if (slotNo == 1U) {
|
||||
if (m_rssiCount1 == 0U) {
|
||||
char text[20U];
|
||||
::sprintf(text, "t4.txt=\"-%udBm\"", rssi);
|
||||
sendCommand(text);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= DMR_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
} else {
|
||||
if (m_rssiCount2 == 0U) {
|
||||
char text[20U];
|
||||
::sprintf(text, "t5.txt=\"-%udBm\"", rssi);
|
||||
sendCommand(text);
|
||||
}
|
||||
|
||||
m_rssiCount2++;
|
||||
if (m_rssiCount2 >= DMR_RSSI_COUNT)
|
||||
m_rssiCount2 = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void CNextion::clearDMRInt(unsigned int slotNo)
|
||||
|
|
@ -193,9 +242,11 @@ void CNextion::clearDMRInt(unsigned int slotNo)
|
|||
if (slotNo == 1U) {
|
||||
sendCommand("t0.txt=\"1 Listening\"");
|
||||
sendCommand("t1.txt=\"\"");
|
||||
sendCommand("t4.txt=\"\"");
|
||||
} else {
|
||||
sendCommand("t2.txt=\"2 Listening\"");
|
||||
sendCommand("t3.txt=\"\"");
|
||||
sendCommand("t5.txt=\"\"");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,6 +277,20 @@ void CNextion::writeFusionInt(const char* source, const char* dest, const char*
|
|||
m_clockDisplayTimer.stop();
|
||||
|
||||
m_mode = MODE_YSF;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CNextion::writeFusionRSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U) {
|
||||
char text[20U];
|
||||
::sprintf(text, "t3.txt=\"-%udBm\"", rssi);
|
||||
sendCommand(text);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= YSF_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CNextion::clearFusionInt()
|
||||
|
|
@ -233,6 +298,7 @@ void CNextion::clearFusionInt()
|
|||
sendCommand("t0.txt=\"Listening\"");
|
||||
sendCommand("t1.txt=\"\"");
|
||||
sendCommand("t2.txt=\"\"");
|
||||
sendCommand("t3.txt=\"\"");
|
||||
}
|
||||
|
||||
void CNextion::writeP25Int(const char* source, bool group, unsigned int dest, const char* type)
|
||||
|
|
@ -256,6 +322,20 @@ void CNextion::writeP25Int(const char* source, bool group, unsigned int dest, co
|
|||
m_clockDisplayTimer.stop();
|
||||
|
||||
m_mode = MODE_P25;
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CNextion::writeP25RSSIInt(unsigned char rssi)
|
||||
{
|
||||
if (m_rssiCount1 == 0U) {
|
||||
char text[20U];
|
||||
::sprintf(text, "t2.txt=\"-%udBm\"", rssi);
|
||||
sendCommand(text);
|
||||
}
|
||||
|
||||
m_rssiCount1++;
|
||||
if (m_rssiCount1 >= P25_RSSI_COUNT)
|
||||
m_rssiCount1 = 0U;
|
||||
}
|
||||
|
||||
void CNextion::clearP25Int()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -42,15 +42,19 @@ protected:
|
|||
virtual void setLockoutInt();
|
||||
|
||||
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
|
||||
virtual void writeDStarRSSIInt(unsigned char rssi);
|
||||
virtual void clearDStarInt();
|
||||
|
||||
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
|
||||
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
|
||||
virtual void clearDMRInt(unsigned int slotNo);
|
||||
|
||||
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
|
||||
virtual void writeFusionRSSIInt(unsigned char rssi);
|
||||
virtual void clearFusionInt();
|
||||
|
||||
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
|
||||
virtual void writeP25RSSIInt(unsigned char rssi);
|
||||
virtual void clearP25Int();
|
||||
|
||||
virtual void writeCWInt();
|
||||
|
|
@ -68,6 +72,8 @@ private:
|
|||
bool m_utc;
|
||||
unsigned int m_idleBrightness;
|
||||
CTimer m_clockDisplayTimer;
|
||||
unsigned int m_rssiCount1;
|
||||
unsigned int m_rssiCount2;
|
||||
|
||||
void sendCommand(const char* command);
|
||||
};
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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,9 +108,14 @@ 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));
|
||||
if (m_rssi != 0U)
|
||||
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);
|
||||
else
|
||||
LogMessage("P25, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
|
||||
if (m_netState == RS_NET_IDLE)
|
||||
m_display->clearP25();
|
||||
|
||||
writeNetwork(m_rfLDU, m_lastDUID, true);
|
||||
writeNetwork(data + 2U, P25_DUID_TERM, true);
|
||||
m_rfState = RS_RF_LISTENING;
|
||||
|
|
@ -139,6 +151,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 +182,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 {
|
||||
|
|
@ -199,6 +238,8 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
|||
m_display->writeP25(source.c_str(), grp, dstId, "R");
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
}
|
||||
|
||||
m_display->writeP25RSSI(m_rssi);
|
||||
} else if (duid == P25_DUID_LDU2) {
|
||||
if (m_rfState == RS_RF_LISTENING)
|
||||
return false;
|
||||
|
|
@ -240,6 +281,8 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
|||
data[1U] = 0x00U;
|
||||
writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U);
|
||||
}
|
||||
|
||||
m_display->writeP25RSSI(m_rssi);
|
||||
} else if (duid == P25_DUID_TERM || duid == P25_DUID_TERM_LC) {
|
||||
if (m_rfState == RS_RF_LISTENING)
|
||||
return false;
|
||||
|
|
@ -262,7 +305,11 @@ 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));
|
||||
if (m_rssi != 0U)
|
||||
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);
|
||||
else
|
||||
LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
|
||||
m_display->clearP25();
|
||||
|
||||
#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
|
||||
* 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<unsigned char> 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);
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -1,6 +1,6 @@
|
|||
These are the source files for building the MMDVMHost, the program that interfaces to the MMDVM or DVMega on the one side, and a suitable network on the other. On the D-Star side the MMDVMHost interfaces with the ircDDB Gateway, on DMR it connects to Brand Meister, DMR+, and HB Link, on System Fusion it connects to the YSF Gateway. On P25 it connects to the P25NX network.
|
||||
These are the source files for building the MMDVMHost, the program that interfaces to the MMDVM or DVMega on the one side, and a suitable network on the other. It supports D-Star, DMR, P25 Phase 1, and System Fusion.
|
||||
|
||||
It supports D-Star, DMR, P25 Phase 1, and System Fusion.
|
||||
On the D-Star side the MMDVMHost interfaces with the ircDDB Gateway, on DMR it can connect to BrandMeister, DMR+, or HB Link, on System Fusion it connects to the YSF Gateway. On P25 it connects to the P25 Gateway.
|
||||
|
||||
It builds on 32-bit and 64-bit Linux as well as on Windows using VS2015 on x86 and x64. It can optionally control various Displays. Currently these are:
|
||||
|
||||
|
|
@ -9,11 +9,15 @@ It builds on 32-bit and 64-bit Linux as well as on Windows using VS2015 on x86 a
|
|||
- Adafruit 16x2 LCD+Keypad Kits (I2C)
|
||||
- Connection via PCF8574 GPIO Extender (I2C)
|
||||
- Nextion TFTs (sizes 2.4", 2.8", 3.2" and 3.5")
|
||||
- TFT displays sold by Hobbytronics in UK
|
||||
- TFT display sold by Hobbytronics in UK
|
||||
- OLED 128x64 (SSD1306)
|
||||
|
||||
The HD44780 displays are integrated with wiringPi for Raspberry Pi based platforms. The other displays can be directly connected to the UART on Raspberry Pis or with FT-232RL modules to any USB port.
|
||||
The Nextion displays can connect to the UART on the Raspberry Pi, or via a USB to TTL serial converter like the FT-232RL. It may also be connected to the UART output of the MMDVM modem (Arduino Due, STM32, Teensy), or to the UART output on the UMP.
|
||||
|
||||
The OLED display needs a extra lib see OLED.md
|
||||
The HD44780 displays are integrated with wiringPi for Raspberry Pi based platforms.
|
||||
|
||||
The Hobbytronics TFT Display, which is a Pi-Hat, connects to the UART on the Raspbery Pi.
|
||||
|
||||
The OLED display needs a extra library see OLED.md
|
||||
|
||||
This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden.
|
||||
|
|
|
|||
|
|
@ -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,10 @@ 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));
|
||||
if (m_rssi != 0U)
|
||||
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);
|
||||
else
|
||||
LogMessage("YSF, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
writeEndRF();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -102,6 +112,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 +148,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
|
||||
|
|
@ -185,6 +222,8 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len)
|
|||
}
|
||||
|
||||
m_rfFrames++;
|
||||
|
||||
m_display->writeFusionRSSI(m_rssi);
|
||||
} else if (valid && fi == YSF_FI_TERMINATOR) {
|
||||
CSync::addYSFSync(data + 2U);
|
||||
|
||||
|
|
@ -209,7 +248,11 @@ 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));
|
||||
if (m_rssi != 0U)
|
||||
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);
|
||||
else
|
||||
LogMessage("YSF, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
|
||||
writeEndRF();
|
||||
|
||||
return false;
|
||||
|
|
@ -314,6 +357,8 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len)
|
|||
#endif
|
||||
|
||||
m_rfFrames++;
|
||||
|
||||
m_display->writeFusionRSSI(m_rssi);
|
||||
} else {
|
||||
CSync::addYSFSync(data + 2U);
|
||||
|
||||
|
|
@ -329,6 +374,8 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len)
|
|||
writeFile(data + 2U);
|
||||
#endif
|
||||
m_rfFrames++;
|
||||
|
||||
m_display->writeFusionRSSI(m_rssi);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
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
|
||||
* 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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue