Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow talkgroups to match a range of values #852

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
20 changes: 13 additions & 7 deletions docs/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,22 +411,28 @@ The matching simplestream config to send audio from talkgroup 58918 to TCP port

This file provides info on the different talkgroups in a trunking system. A lot of this info can be found on the [Radio Reference](http://www.radioreference.com/) website. You need to be a Radio Reference member to download the table for your system preformatted as a CSV file. You can also try clicking on the "List All in one table" link, selecting everything in the table and copying it into a spreadsheet program, and then exporting or saving as a CSV file.

**Note:** You can use the direct CSV from Radio Reference for talk groups, but setting priority is not supported with this file format. If you need to use the Priority field, you'll need to reorder the CSV to match the format described below.

You may add an additional column that adds a priority for each talkgroup. The priority field specifies the number of recorders the system must have available to record a new call for the talkgroup. For example, a priority of 1, the highest means as long as at least a single recorder is available, the system will record the new call. If the priority is 2, the system would at least 2 free recorders to record the new call, and so on. If there is no priority set for a talkgroup entry, a prioity of 1 is assumed.

Talkgroups matching a range of decimal numbers may also be defined. In this case the channel numbers should take the form <min>:<max>. The hex
value is not used. Note that this formatting will not be detected if the radio reference style. This is useful when receiving a system with a range of talkgroups in use by a agency using encryption, for which no further details are available. This is doubly problematic for P25 phase 2 talkgroups, where the trunking system does not flag calls as encrypted before Trunk Recorder attempts to record them. Rather than enter every unknown talkgroup as it is discovered, the entire range can be set to a priority of -1 and ignored.

When Trunk Recorder looks up a talkgroup, it does so by its decimal number. The first talkgroup in the list with a single matching number will be used. If there is no match, then the first talkgroup specified by a range that includes the supplied talkgroup number will be returned, if one exists.

Talkgroups assigned a priority of -1 will never be recorded, regardless of the number of available recorders.

Trunk Recorder really only uses the priority information and the decimal talkgroup ID. The Website uses the same file though to help display information about each talkgroup.

**Note:** You can use the direct CSV from Radio Reference for talk groups, but talkgroup priority and talkgroup ranges are not supported with this file format. If you need to use either or these features, you'll need to reorder the CSV to match the format described below.

Here are the column headers and some sample data: NOTE: If you are adding the Priority to a RR csv, as well as changing order you must use a heading for the first column other than "Decimal" eg DEC for TR to detect you are supplying this layout.

| DEC | HEX | Mode | Alpha Tag | Description | Tag | Group | Priority | PreferredNAC (optional) |
|-----|-----|------|--------------|----------------|----------------|----------|----------|-------------------------|
|101 | 065 | D | DCFD 01 Disp | 01 Dispatch | Fire Dispatch | Fire | 1 | 1000 |
|2227 | 8b3 | D | DC StcarYard | Streetcar Yard | Transportation | Services | 3 | 1001 |
| DEC | HEX | Mode | Alpha Tag | Description | Tag | Group | Priority | PreferredNAC (optional) |
|------|-----|------|--------------|----------------|----------------|----------|----------|-------------------------|
|101 | 065 | D | DCFD 01 Disp | 01 Dispatch | Fire Dispatch | Fire | 1 | 1000 |
|2227 | 8b3 | D | DC StcarYard | Streetcar Yard | Transportation | Services | 3 | 1001 |
|1:100 | 0 | D | Police | Encrypted | Encrypted | Law | -1 | |

In Multi-Site mode, the preferred NAC for a specific talk group is used to specify the site you prefer the talk group to be recorded from.
In Multi-Site mode, the preferred NAC for a specific talk group is used to specify the site you prefer the talk group to be recorded from.

## channelFile

Expand Down
4 changes: 3 additions & 1 deletion trunk-recorder/talkgroup.cc
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#include "talkgroup.h"

Talkgroup::Talkgroup(int sys_num, long num, std::string mode, std::string alpha_tag, std::string description, std::string tag, std::string group, int priority, unsigned long preferredNAC) {
Talkgroup::Talkgroup(int sys_num, long num, unsigned long range, std::string mode, std::string alpha_tag, std::string description, std::string tag, std::string group, int priority, unsigned long preferredNAC) {
this->sys_num = sys_num;
this->number = num;
this->range = range;
this->mode = mode;
this->alpha_tag = alpha_tag;
this->description = description;
Expand All @@ -18,6 +19,7 @@ Talkgroup::Talkgroup(int sys_num, long num, std::string mode, std::string alpha_
Talkgroup::Talkgroup(int sys_num, long num, double freq, double tone, std::string alpha_tag, std::string description, std::string tag, std::string group) {
this->sys_num = sys_num;
this->number = num;
this->range = 1;
this->mode = "Z";
this->alpha_tag = alpha_tag;
this->description = description;
Expand Down
3 changes: 2 additions & 1 deletion trunk-recorder/talkgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
class Talkgroup {
public:
long number;
unsigned long range;
std::string mode;
std::string alpha_tag;
std::string description;
Expand All @@ -22,7 +23,7 @@ class Talkgroup {
double freq;
double tone;

Talkgroup(int sys_num, long num, std::string mode, std::string alpha_tag, std::string description, std::string tag, std::string group, int priority, unsigned long preferredNAC);
Talkgroup(int sys_num, long num, unsigned long range, std::string mode, std::string alpha_tag, std::string description, std::string tag, std::string group, int priority, unsigned long preferredNAC);
Talkgroup(int sys_num, long num, double freq, double tone, std::string alpha_tag, std::string description, std::string tag, std::string group);

bool is_active();
Expand Down
46 changes: 42 additions & 4 deletions trunk-recorder/talkgroups.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,12 @@ void Talkgroups::load_talkgroups(int sys_num, std::string filename) {
BOOST_LOG_TRIVIAL(error) << "Malformed radioreference talkgroup entry at line " << lines_read << ".";
continue;
}

tg = new Talkgroup(sys_num, atoi(vec[0].c_str()), vec[3].c_str(), vec[2].c_str(), vec[4].c_str(), vec[5].c_str(), vec[6].c_str(), 1, 0);
tg = new Talkgroup(sys_num, atoi(vec[0].c_str()), 1, vec[3].c_str(), vec[2].c_str(), vec[4].c_str(), vec[5].c_str(), vec[6].c_str(), 1, 0);

} else {
// Talkgroup configuration columns:
//
// [0] - talkgroup number
// [0] - talkgroup number, or talkgroup range min:max
// [1] - unused
// [2] - mode
// [3] - alpha_tag
Expand All @@ -97,8 +96,38 @@ void Talkgroups::load_talkgroups(int sys_num, std::string filename) {
priority = (vec.size() == 8) ? atoi(vec[7].c_str()) : 1;
unsigned long preferredNAC = (vec.size() == 9) ? atoi(vec[8].c_str()) : 0;

tg = new Talkgroup(sys_num, atoi(vec[0].c_str()), vec[2].c_str(), vec[3].c_str(), vec[4].c_str(), vec[5].c_str(), vec[6].c_str(), priority, preferredNAC);
// parse talkgroup range as tokens
boost::escaped_list_separator<char> range_sep("", ":", "");
t_tokenizer tg_range(vec[0], range_sep);
std::vector<std::string> tgvec;
tgvec.assign(tg_range.begin(), tg_range.end());

// Assert single talkgroup or range min:max
if ((tgvec.size() < 1) || (tgvec.size() > 2)) {
BOOST_LOG_TRIVIAL(error) << "Malformed talkgroup range entry at line " << lines_read << ".";
continue;
}

long tgnum = atoi(tgvec[0].c_str());

if (tgnum < 0) {
BOOST_LOG_TRIVIAL(error) << "Talkgroup " << tgnum << " invalid: Cannot be negative";
continue;
}
unsigned long tgnum_range = 1;

// handle talkgroup range
if ((tgvec.size() == 2)) {

long tg_max = atoi(tgvec[1].c_str());

if (tg_max > tgnum) {
tgnum_range = tg_max - tgnum;
BOOST_LOG_TRIVIAL(info) << "Talkgroup range: " << tgnum << ":" << tg_max << " [" << tgnum_range << "]";
}
else BOOST_LOG_TRIVIAL(error) << "Talkgroup range " << tgnum << ":" << tg_max << " invalid";
}
tg = new Talkgroup(sys_num, tgnum, tgnum_range, vec[2].c_str(), vec[3].c_str(), vec[4].c_str(), vec[5].c_str(), vec[6].c_str(), priority, preferredNAC);
}
talkgroups.push_back(tg);
lines_pushed++;
Expand Down Expand Up @@ -198,13 +227,22 @@ void Talkgroups::load_channels(int sys_num, std::string filename) {
Talkgroup *Talkgroups::find_talkgroup(int sys_num, long tg_number) {
Talkgroup *tg_match = NULL;

// Return first matching talkgroup by number or within range of talkgroups. Prioritise individual talkgroups.
for (std::vector<Talkgroup *>::iterator it = talkgroups.begin(); it != talkgroups.end(); ++it) {
Talkgroup *tg = (Talkgroup *)*it;

if ((tg->sys_num == sys_num) && (tg->number == tg_number)) {
tg_match = tg;
break;
}

else if (tg->range > 1) {
long tg_range = (long)tg->range; // talkgroups must be >=0, so will be within bounds
if ((tg->sys_num == sys_num) && (tg->number >= tg_number) && (tg_number <= (tg->number + tg_range - 1))) {
tg_match = tg;
BOOST_LOG_TRIVIAL(debug) << "Range Match " << tg_number << " in " << tg->number << ":" << tg->number + tg_range;
}
}
}
return tg_match;
}
Expand Down