mirror of
https://github.com/g4klx/MMDVMHost
synced 2025-12-22 16:25:45 +08:00
Add P25 to JSON/MQTT.
This commit is contained in:
@@ -43,6 +43,8 @@
|
|||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(_WIN64)
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|||||||
@@ -47,7 +47,6 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
class CMMDVMHost
|
class CMMDVMHost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1258,8 +1258,10 @@ void CNXDNControl::writeJSON(nlohmann::json& json, const char* source, const cha
|
|||||||
json["source"] = source;
|
json["source"] = source;
|
||||||
json["action"] = action;
|
json["action"] = action;
|
||||||
json["source_id"] = int(srcId);
|
json["source_id"] = int(srcId);
|
||||||
json["source_info"] = srcInfo;
|
|
||||||
json["destination_id"] = int(dstId);
|
json["destination_id"] = int(dstId);
|
||||||
json["destination_type"] = grp ? "group" : "individual";
|
json["destination_type"] = grp ? "group" : "individual";
|
||||||
|
|
||||||
|
if (!srcInfo.empty())
|
||||||
|
json["source_info"] = srcInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
class CNXDNControl {
|
class CNXDNControl {
|
||||||
public:
|
public:
|
||||||
CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper);
|
CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper);
|
||||||
|
|||||||
126
P25Control.cpp
126
P25Control.cpp
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016-2019,2021 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016-2019,2021,2023 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
|
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -124,12 +124,16 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
|||||||
if (data[0U] == TAG_LOST && m_rfState == RS_RF_AUDIO) {
|
if (data[0U] == TAG_LOST && m_rfState == RS_RF_AUDIO) {
|
||||||
bool grp = m_rfData.getLCF() == P25_LCF_GROUP;
|
bool grp = m_rfData.getLCF() == P25_LCF_GROUP;
|
||||||
unsigned int dstId = m_rfData.getDstId();
|
unsigned int dstId = m_rfData.getDstId();
|
||||||
std::string source = m_lookup->find(m_rfData.getSrcId());
|
unsigned int srcId = m_rfData.getSrcId();
|
||||||
|
std::string source = m_lookup->find(srcId);
|
||||||
|
|
||||||
if (m_rssi != 0U)
|
if (m_rssi != 0U) {
|
||||||
LogMessage("P25, transmission lost from %s to %s%u, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", source.c_str(), grp ? "TG " : "", dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
LogMessage("P25, transmission lost from %s to %s%u, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", source.c_str(), grp ? "TG " : "", dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
||||||
else
|
writeJSONRF("lost", srcId, source, grp, dstId, 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 from %s to %s%u, %.1f seconds, BER: %.1f%%", source.c_str(), grp ? "TG " : "", dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
|
LogMessage("P25, transmission lost from %s to %s%u, %.1f seconds, BER: %.1f%%", source.c_str(), grp ? "TG " : "", dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||||
|
writeJSONRF("lost", srcId, source, grp, dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||||
|
}
|
||||||
|
|
||||||
if (m_netState == RS_NET_IDLE)
|
if (m_netState == RS_NET_IDLE)
|
||||||
m_display->clearP25();
|
m_display->clearP25();
|
||||||
@@ -254,6 +258,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
|||||||
std::string source = m_lookup->find(srcId);
|
std::string source = m_lookup->find(srcId);
|
||||||
|
|
||||||
LogMessage("P25, received RF voice transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
|
LogMessage("P25, received RF voice transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
|
||||||
|
writeJSONRF("start", srcId, source, grp, dstId);
|
||||||
m_display->writeP25(source.c_str(), grp, dstId, "R");
|
m_display->writeP25(source.c_str(), grp, dstId, "R");
|
||||||
|
|
||||||
m_rfState = RS_RF_AUDIO;
|
m_rfState = RS_RF_AUDIO;
|
||||||
@@ -455,17 +460,21 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
|||||||
|
|
||||||
bool grp = m_rfData.getLCF() == P25_LCF_GROUP;
|
bool grp = m_rfData.getLCF() == P25_LCF_GROUP;
|
||||||
unsigned int dstId = m_rfData.getDstId();
|
unsigned int dstId = m_rfData.getDstId();
|
||||||
std::string source = m_lookup->find(m_rfData.getSrcId());
|
unsigned int srcId = m_rfData.getSrcId();
|
||||||
|
std::string source = m_lookup->find(srcId);
|
||||||
|
|
||||||
m_rfState = RS_RF_LISTENING;
|
m_rfState = RS_RF_LISTENING;
|
||||||
m_rfTimeout.stop();
|
m_rfTimeout.stop();
|
||||||
m_rfData.reset();
|
m_rfData.reset();
|
||||||
m_lastDUID = duid;
|
m_lastDUID = duid;
|
||||||
|
|
||||||
if (m_rssi != 0U)
|
if (m_rssi != 0U) {
|
||||||
LogMessage("P25, received RF end of voice transmission from %s to %s%u, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", source.c_str(), grp ? "TG " : "", dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
LogMessage("P25, received RF end of voice transmission from %s to %s%u, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", source.c_str(), grp ? "TG " : "", dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
||||||
else
|
writeJSONRF("end", srcId, source, grp, dstId, 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 voice transmission from %s to %s%u, %.1f seconds, BER: %.1f%%", source.c_str(), grp ? "TG " : "", dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
|
LogMessage("P25, received RF end of voice transmission from %s to %s%u, %.1f seconds, BER: %.1f%%", source.c_str(), grp ? "TG " : "", dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||||
|
writeJSONRF("end", srcId, source, grp, dstId, float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||||
|
}
|
||||||
|
|
||||||
m_display->clearP25();
|
m_display->clearP25();
|
||||||
|
|
||||||
@@ -725,8 +734,14 @@ void CP25Control::clock(unsigned int ms)
|
|||||||
m_networkWatchdog.clock(ms);
|
m_networkWatchdog.clock(ms);
|
||||||
|
|
||||||
if (m_networkWatchdog.hasExpired()) {
|
if (m_networkWatchdog.hasExpired()) {
|
||||||
|
unsigned int dstId = m_netData.getDstId();
|
||||||
|
unsigned int srcId = m_netData.getSrcId();
|
||||||
|
std::string source = m_lookup->find(srcId);
|
||||||
|
|
||||||
LogMessage("P25, network watchdog has expired, %.1f seconds, %u%% packet loss", float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames);
|
LogMessage("P25, network watchdog has expired, %.1f seconds, %u%% packet loss", float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames);
|
||||||
|
writeJSONNet("lost", srcId, source, m_netData.getLCF() == P25_LCF_GROUP, dstId, float(m_netFrames) / 50.0F, float(m_netLost * 100U) / float(m_netFrames));
|
||||||
m_display->clearP25();
|
m_display->clearP25();
|
||||||
|
|
||||||
m_networkWatchdog.stop();
|
m_networkWatchdog.stop();
|
||||||
m_netState = RS_NET_IDLE;
|
m_netState = RS_NET_IDLE;
|
||||||
m_netData.reset();
|
m_netData.reset();
|
||||||
@@ -971,7 +986,7 @@ void CP25Control::createNetHeader()
|
|||||||
std::string source = m_lookup->find(srcId);
|
std::string source = m_lookup->find(srcId);
|
||||||
|
|
||||||
LogMessage("P25, received network transmission from %s to %s%u", source.c_str(), lcf == P25_LCF_GROUP ? "TG " : "", dstId);
|
LogMessage("P25, received network transmission from %s to %s%u", source.c_str(), lcf == P25_LCF_GROUP ? "TG " : "", dstId);
|
||||||
|
writeJSONNet("start", srcId, source, lcf == P25_LCF_GROUP, dstId);
|
||||||
m_display->writeP25(source.c_str(), lcf == P25_LCF_GROUP, dstId, "N");
|
m_display->writeP25(source.c_str(), lcf == P25_LCF_GROUP, dstId, "N");
|
||||||
|
|
||||||
m_netState = RS_NET_AUDIO;
|
m_netState = RS_NET_AUDIO;
|
||||||
@@ -1121,9 +1136,12 @@ void CP25Control::createNetTerminator()
|
|||||||
|
|
||||||
writeQueueNet(buffer, P25_TERM_FRAME_LENGTH_BYTES + 2U);
|
writeQueueNet(buffer, P25_TERM_FRAME_LENGTH_BYTES + 2U);
|
||||||
|
|
||||||
std::string source = m_lookup->find(m_netData.getSrcId());
|
unsigned int dstId = m_netData.getDstId();
|
||||||
|
unsigned int srcId = m_netData.getSrcId();
|
||||||
|
std::string source = m_lookup->find(srcId);
|
||||||
|
|
||||||
LogMessage("P25, network end of transmission from %s to %s%u, %.1f seconds, %u%% packet loss", source.c_str(), m_netData.getLCF() == P25_LCF_GROUP ? "TG " : "", m_netData.getDstId(), float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames);
|
LogMessage("P25, network end of transmission from %s to %s%u, %.1f seconds, %u%% packet loss", source.c_str(), m_netData.getLCF() == P25_LCF_GROUP ? "TG " : "", dstId, float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames);
|
||||||
|
writeJSONNet("end", srcId, source, m_netData.getLCF() == P25_LCF_GROUP, dstId, float(m_netFrames) / 50.0F, float(m_netLost * 100U) / float(m_netFrames));
|
||||||
|
|
||||||
m_display->clearP25();
|
m_display->clearP25();
|
||||||
m_netTimeout.stop();
|
m_netTimeout.stop();
|
||||||
@@ -1198,3 +1216,91 @@ void CP25Control::enable(bool enabled)
|
|||||||
|
|
||||||
m_enabled = enabled;
|
m_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CP25Control::writeJSONRF(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId)
|
||||||
|
{
|
||||||
|
assert(action != NULL);
|
||||||
|
|
||||||
|
nlohmann::json json;
|
||||||
|
|
||||||
|
writeJSON(json, "rf", action, srcId, srcInfo, grp, dstId);
|
||||||
|
|
||||||
|
WriteJSON("P25", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Control::writeJSONRF(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId, float duration, float ber)
|
||||||
|
{
|
||||||
|
assert(action != NULL);
|
||||||
|
|
||||||
|
nlohmann::json json;
|
||||||
|
|
||||||
|
writeJSON(json, "rf", action, srcId, srcInfo, grp, dstId);
|
||||||
|
|
||||||
|
json["duration"] = duration;
|
||||||
|
json["ber"] = ber;
|
||||||
|
|
||||||
|
WriteJSON("P25", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Control::writeJSONRF(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId, float duration, float ber, unsigned char minRSSI, unsigned char maxRSSI, unsigned int aveRSSI)
|
||||||
|
{
|
||||||
|
assert(action != NULL);
|
||||||
|
|
||||||
|
nlohmann::json json;
|
||||||
|
|
||||||
|
writeJSON(json, "rf", action, srcId, srcInfo, grp, dstId);
|
||||||
|
|
||||||
|
json["duration"] = duration;
|
||||||
|
json["ber"] = ber;
|
||||||
|
|
||||||
|
nlohmann::json rssi;
|
||||||
|
rssi["min"] = -int(minRSSI);
|
||||||
|
rssi["max"] = -int(maxRSSI);
|
||||||
|
rssi["ave"] = -int(aveRSSI);
|
||||||
|
|
||||||
|
json["rssi"] = rssi;
|
||||||
|
|
||||||
|
WriteJSON("P25", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Control::writeJSONNet(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId)
|
||||||
|
{
|
||||||
|
assert(action != NULL);
|
||||||
|
|
||||||
|
nlohmann::json json;
|
||||||
|
|
||||||
|
writeJSON(json, "network", action, srcId, srcInfo, grp, dstId);
|
||||||
|
|
||||||
|
WriteJSON("P25", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Control::writeJSONNet(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId, float duration, float loss)
|
||||||
|
{
|
||||||
|
assert(action != NULL);
|
||||||
|
|
||||||
|
nlohmann::json json;
|
||||||
|
|
||||||
|
writeJSON(json, "network", action, srcId, srcInfo, grp, dstId);
|
||||||
|
|
||||||
|
json["duration"] = duration;
|
||||||
|
json["loss"] = loss;
|
||||||
|
|
||||||
|
WriteJSON("P25", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Control::writeJSON(nlohmann::json& json, const char* source, const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId)
|
||||||
|
{
|
||||||
|
assert(source != NULL);
|
||||||
|
assert(action != NULL);
|
||||||
|
|
||||||
|
json["timestamp"] = CUtils::createTimestamp();
|
||||||
|
json["source"] = source;
|
||||||
|
json["action"] = action;
|
||||||
|
json["source_id"] = int(srcId);
|
||||||
|
json["destination_id"] = int(dstId);
|
||||||
|
json["destination_type"] = grp ? "group" : "individual";
|
||||||
|
|
||||||
|
if (!srcInfo.empty())
|
||||||
|
json["source_info"] = srcInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
13
P25Control.h
13
P25Control.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016-2019 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016-2019,2023 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
|
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
class CP25Control {
|
class CP25Control {
|
||||||
public:
|
public:
|
||||||
CP25Control(unsigned int nac, unsigned int id, bool selfOly, bool uidOverride, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, bool remoteGateway, CRSSIInterpolator* rssiMapper);
|
CP25Control(unsigned int nac, unsigned int id, bool selfOly, bool uidOverride, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, bool remoteGateway, CRSSIInterpolator* rssiMapper);
|
||||||
@@ -118,6 +120,15 @@ private:
|
|||||||
bool openFile();
|
bool openFile();
|
||||||
bool writeFile(const unsigned char* data, unsigned char length);
|
bool writeFile(const unsigned char* data, unsigned char length);
|
||||||
void closeFile();
|
void closeFile();
|
||||||
|
|
||||||
|
void writeJSONRF(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId);
|
||||||
|
void writeJSONRF(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId, float duration, float ber);
|
||||||
|
void writeJSONRF(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId, float duration, float ber, unsigned char minRSSI, unsigned char maxRSSI, unsigned int aveRSSI);
|
||||||
|
|
||||||
|
void writeJSONNet(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId);
|
||||||
|
void writeJSONNet(const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId, float duration, float loss);
|
||||||
|
|
||||||
|
void writeJSON(nlohmann::json& json, const char* source, const char* action, unsigned int srcId, const std::string& srcInfo, bool grp, unsigned int dstId);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
struct POCSAGData {
|
struct POCSAGData {
|
||||||
unsigned int m_ric;
|
unsigned int m_ric;
|
||||||
std::string m_text;
|
std::string m_text;
|
||||||
|
|||||||
Reference in New Issue
Block a user