diff --git a/docs/CONFIGURE.md b/docs/CONFIGURE.md index 95bb6c9cd..814b45701 100644 --- a/docs/CONFIGURE.md +++ b/docs/CONFIGURE.md @@ -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 :. 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 diff --git a/trunk-recorder/talkgroup.cc b/trunk-recorder/talkgroup.cc index afee663ec..3afb41cdc 100644 --- a/trunk-recorder/talkgroup.cc +++ b/trunk-recorder/talkgroup.cc @@ -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; @@ -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; diff --git a/trunk-recorder/talkgroup.h b/trunk-recorder/talkgroup.h index 82dec567c..4da8aa94b 100644 --- a/trunk-recorder/talkgroup.h +++ b/trunk-recorder/talkgroup.h @@ -9,6 +9,7 @@ class Talkgroup { public: long number; + unsigned long range; std::string mode; std::string alpha_tag; std::string description; @@ -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(); diff --git a/trunk-recorder/talkgroups.cc b/trunk-recorder/talkgroups.cc index 839124edd..3876a335d 100644 --- a/trunk-recorder/talkgroups.cc +++ b/trunk-recorder/talkgroups.cc @@ -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 @@ -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 range_sep("", ":", ""); + t_tokenizer tg_range(vec[0], range_sep); + std::vector 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++; @@ -198,6 +227,7 @@ 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::iterator it = talkgroups.begin(); it != talkgroups.end(); ++it) { Talkgroup *tg = (Talkgroup *)*it; @@ -205,6 +235,14 @@ Talkgroup *Talkgroups::find_talkgroup(int sys_num, long 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; }