Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ During the status display, each source will report the running average as well a
| bandplanSpacing | | | number | *SmartNet, 400_custom only* The channel spacing, specified in Hz. Typically this is *25000*. |
| bandplanOffset | | | number | *SmartNet, 400_custom only* The offset used to calculate frequencies. |
| customFrequencyTableFile | | | string | *P25 only* The filename for a CSV file that provides information about the P25 custom frequency tables. The format for the file is described below. |
| knownSitesFile | | | string | *P25 only* Optional CSV of known sites. Advertised neighboring RFSS/site IDs are matched to this file and printed with the site's name. CSV columns: `RFSS,SITEID,NAME`. |
| decodeMDC | | false | **true** / **false** | *Conventional systems only* enable the MDC-1200 signaling decoder. |
| decodeFSync | | false | **true** / **false** | *Conventional systems only* enable the Fleet Sync signaling decoder. |
| decodeStar | | false | **true** / **false** | *Conventional systems only* enable the Star signaling decoder. |
Expand Down Expand Up @@ -918,3 +919,11 @@ A **Header Row** is required for the file and the headers must match the column
| 2 | FDMA | 762.00625 | 6.25 | +30 |
| 3 | TDMA | 851.01250 | 12.5 | -45 |
| 4 | TDMA | 762.00625 | 12.5 | +30 |

## knownSitesFile

For P25 trunked systems, `knownSitesFile` may point to a CSV used to label adjacent sites in the periodic control-channel information output. Neighbor frequency and RFSS/site IDs are learned from P25 adjacent-status broadcasts; the CSV supplies the site name. Neighbors that do not match an entry are highlighted in yellow when console colors are enabled. Neighbor information is still printed when no file is configured.

| RFSS | SITEID | NAME |
|------|--------|------|
| 1 | 7 | North Ridge |
7 changes: 7 additions & 0 deletions trunk-recorder/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,13 @@ bool load_config(string config_file, Config &config, gr::top_block_sptr &tb, std

system->set_system_type(element["type"]);
BOOST_LOG_TRIVIAL(info) << "System Type: " << system->get_system_type();
if (system->get_system_type() == "p25") {
std::string known_sites_file = element.value("knownSitesFile", "");
if (!known_sites_file.empty()) {
system->set_known_sites_file(known_sites_file);
BOOST_LOG_TRIVIAL(info) << "Known Sites File: " << known_sites_file;
}
}

// If it is a conventional System
if ((system->get_system_type() == "conventional") || (system->get_system_type() == "conventionalP25") || (system->get_system_type() == "conventionalDMR") || (system->get_system_type() == "conventionalSIGMF")) {
Expand Down
7 changes: 7 additions & 0 deletions trunk-recorder/monitor_systems.cc
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ void print_status(std::vector<Source *> &sources, std::vector<System *> &systems

if ((sys->get_system_type() != "conventional") && (sys->get_system_type() != "conventionalP25") && (sys->get_system_type() != "conventionalDMR") && (sys->get_system_type() != "conventionalSIGMF")) {
BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t" << format_freq(sys->get_current_control_channel()) << "\t" << sys->get_decode_rate() << " msg/sec";
if (sys->get_system_type() == "p25") {
for (const auto &site : sys->get_adjacent_sites()) BOOST_LOG_TRIVIAL(info) << site;
}

// SmartNet's offset comes from the decoded FSK levels, so only trust it
// while the control channel is actually decoding.
Expand Down Expand Up @@ -653,6 +656,10 @@ void handle_message(std::vector<TrunkMessage> messages, System *sys, Config &con
current_system_sysid(message, sys);
break;

case ADJACENT_SITE:
if (sys->get_system_type() == "p25") sys->update_adjacent_site(message);
break;

case STATUS:
current_system_status(message, sys);
break;
Expand Down
11 changes: 10 additions & 1 deletion trunk-recorder/systems/p25_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,11 @@ std::vector<TrunkMessage> P25Parser::decode_mbt_data(unsigned long opcode, boost
unsigned long stid = bitset_shift_mask(header, 16, 0xff);
unsigned long ch1 = bitset_shift_mask(mbt_data, 80, 0xffff);
unsigned long ch2 = bitset_shift_mask(mbt_data, 64, 0xffff);
unsigned long f1 = channel_id_to_frequency(ch1, sys_num);
message.message_type = ADJACENT_SITE;
message.neighbor_rfss = rfid;
message.neighbor_site_id = stid;
message.freq = f1;
BOOST_LOG_TRIVIAL(debug) << "mbt3c adjacent status "
<< "syid " << syid << " rfid " << rfid << " stid " << stid << " ch1 " << ch1 << " ch2 " << ch2;
} else if (opcode == 0x04) { // Unit to Unit Voice Service Channel Grant -Extended (UU_V_CH_GRANT)
Expand Down Expand Up @@ -984,6 +989,10 @@ std::vector<TrunkMessage> P25Parser::decode_tsbk(boost::dynamic_bitset<> &tsbk,
unsigned long stid = bitset_shift_mask(tsbk, 40, 0xff);
unsigned long ch1 = bitset_shift_mask(tsbk, 24, 0xffff);
unsigned long f1 = channel_id_to_frequency(ch1, sys_num);
message.message_type = ADJACENT_SITE;
message.neighbor_rfss = rfid;
message.neighbor_site_id = stid;
message.freq = f1;
BOOST_LOG_TRIVIAL(debug) << "tsbk3c\tAdjacent Status\t rfid " << std::dec << rfid << " stid " << stid << " ch1 " << channel_to_string(ch1, sys_num) << "(" << channel_id_to_freq_string(ch1, sys_num) << ") ";

if (f1) {
Expand Down Expand Up @@ -1194,4 +1203,4 @@ std::vector<TrunkMessage> P25Parser::parse_message(gr::message::sptr msg, System
}
messages.push_back(message);
return messages;
}
}
3 changes: 3 additions & 0 deletions trunk-recorder/systems/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum MessageType {
INVALID_CC_MESSAGE = 16,
TDULC = 17,
CALL_ALERT = 18,
ADJACENT_SITE = 19,
UNKNOWN = 99
};

Expand Down Expand Up @@ -54,6 +55,8 @@ struct TrunkMessage {
unsigned long wacn;
PatchData patch_data;
unsigned long opcode;
unsigned long neighbor_rfss = 0;
unsigned long neighbor_site_id = 0;

};

Expand Down
5 changes: 4 additions & 1 deletion trunk-recorder/systems/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ class System {
virtual const char *get_xor_mask() = 0;
virtual bool update_status(TrunkMessage message) = 0;
virtual bool update_sysid(TrunkMessage message) = 0;
virtual void update_adjacent_site(TrunkMessage message) = 0;
virtual void set_known_sites_file(std::string file) = 0;
virtual std::vector<std::string> get_adjacent_sites() = 0;
virtual int get_sys_num() = 0;
virtual void set_system_type(std::string) = 0;
virtual std::string get_talkgroups_file() = 0;
Expand Down Expand Up @@ -270,4 +273,4 @@ class System {
virtual void set_dmr_variant(const std::string &v) = 0;
virtual std::string get_dmr_variant() = 0;
};
#endif
#endif
49 changes: 48 additions & 1 deletion trunk-recorder/systems/system_impl.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include "system_impl.h"
#include "system.h"
#include "../formatter.h"
#include <fstream>
#include <sstream>

System *System::make(int sys_num) {
return (System *)new System_impl(sys_num);
Expand Down Expand Up @@ -277,6 +280,50 @@ bool System_impl::update_sysid(TrunkMessage message) {
return false;
}

void System_impl::set_known_sites_file(std::string file) {
known_sites_file = file;
if (file.empty()) return;
std::ifstream input(file);
if (!input) {
BOOST_LOG_TRIVIAL(error) << "Unable to open known sites file: " << file;
return;
}
std::string line;
std::getline(input, line); // RFSS,SITEID,NAME
while (std::getline(input, line)) {
std::stringstream row(line);
std::string rfss, site, name;
if (!std::getline(row, rfss, ',') || !std::getline(row, site, ',') || !std::getline(row, name)) continue;
if (name.size() >= 2 && name.front() == '"' && name.back() == '"') {
name = name.substr(1, name.size() - 2);
size_t quote = 0;
while ((quote = name.find("\"\"", quote)) != std::string::npos) name.replace(quote, 2, "\"");
}
try { known_sites[{std::stoi(rfss), std::stoi(site)}] = name; }
catch (...) { BOOST_LOG_TRIVIAL(warning) << "Ignoring malformed known site row: " << line; }
}
BOOST_LOG_TRIVIAL(info) << "Loaded " << known_sites.size() << " known P25 sites from " << file;
}

void System_impl::update_adjacent_site(TrunkMessage message) {
adjacent_sites[{static_cast<int>(message.neighbor_rfss), static_cast<int>(message.neighbor_site_id)}] = message.freq;
}

std::vector<std::string> System_impl::get_adjacent_sites() {
std::vector<std::string> result;
for (const auto &site : adjacent_sites) {
std::ostringstream line;
auto known = known_sites.find(site.first);
if (known == known_sites.end()) line << Color::YEL;
line << "[" << short_name << "]\tNeighbour RFSS " << site.first.first << " Site " << site.first.second;
if (known != known_sites.end()) line << " (" << known->second << ")";
if (site.second > 0) line << " Control Channel " << format_freq(site.second);
if (known == known_sites.end()) line << Color::RST;
result.push_back(line.str());
}
return result;
}

gr::msg_queue::sptr System_impl::get_msg_queue() {
return msg_queue;
}
Expand Down Expand Up @@ -981,4 +1028,4 @@ void System_impl::set_dmr_variant(const std::string &v) {

std::string System_impl::get_dmr_variant() {
return dmr_variant;
}
}
6 changes: 6 additions & 0 deletions trunk-recorder/systems/system_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class System_impl : public System {
unsigned long nac;
int sys_rfss;
int sys_site_id;
std::string known_sites_file;
std::map<std::pair<int, int>, std::string> known_sites;
std::map<std::pair<int, int>, double> adjacent_sites;

public:
Talkgroups *talkgroups;
Expand Down Expand Up @@ -242,6 +245,9 @@ class System_impl : public System {
const char *get_xor_mask() override;
bool update_status(TrunkMessage message) override;
bool update_sysid(TrunkMessage message) override;
void update_adjacent_site(TrunkMessage message) override;
void set_known_sites_file(std::string file) override;
std::vector<std::string> get_adjacent_sites() override;
int get_sys_num() override;
void set_system_type(std::string) override;
std::string get_talkgroups_file() override;
Expand Down
Loading