diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8786f7999..052befe6e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,11 @@
Trunk Recorder ChangeLog
========================
-### Version 4.3.0
+
+### Version 4.4.0
+* Add support for using a .csv file for adding for conventional channels
+* Removed alphaTags support from config.json, use the channel.csv instead
+
+### Version 4.3.0
* Add support for DMR / MotoTRBO
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac264449e..662a03e62 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,7 +37,7 @@ list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
# Set the version information here
set(VERSION_MAJOR 4)
-set(VERSION_API 3)
+set(VERSION_API 4)
set(VERSION_ABI 0)
set(VERSION_PATCH git)
diff --git a/README.md b/README.md
index dac3ff2c2..d15d67ac1 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-Trunk Recorder - v4.3.1
+Trunk Recorder - v4.3.2
=======================
## Sponsors
diff --git a/docs/CONFIGURE.md b/docs/CONFIGURE.md
index 6828d7f7e..3067b6f4e 100644
--- a/docs/CONFIGURE.md
+++ b/docs/CONFIGURE.md
@@ -163,6 +163,7 @@ Here is a map of the different sections of the *config.json* file:
| type | ✓ | | **"smartnet" "p25" "conventional, conventionalDMR"** or **"conventionalP25"** | The type of radio system. |
| control_channels | ✓ | | array of numbers;
[496537500, 496437500] | **For trunked systems** The control channel frequencies for the system, in Hz. The frequencies will automatically be cycled through if the system moves to an alternate channel. |
| channels | ✓ | | array of numbers;
[166725000, 166925000, 167075000, 166850000] | **For conventional systems** The channel frequencies, in Hz, used for the system. The channels get assigned a virtual talkgroup number based upon their position in the array. Squelch levels need to be specified for the Source(s) being used. |
+| channelFile | ✓ | | string | **For conventional systems** The filename for a CSV file that provides information about the conventional channels. The format for the file is described below. Squelch levels need to be specified for the Source(s) being used. *Use channels or channelFile, not both*. |
| modulation | | "qpsk" | **"qpsk"** or **"fsk4"** | The type of digital modulation that the system uses. You do not need to specify this with **conventionalDMR** systems. |
| squelch | | -160 | number | Squelch in DB, this needs to be set for all conventional systems. The squelch setting is also used for analog talkgroups in a SmartNet system. I generally use -60 for my rtl-sdr. The closer the squelch is to 0, the stronger the signal has to be to unmute it. |
| talkgroupsFile | | | string | The filename for a CSV file that provides information about the talkgroups. It determines whether a talkgroup is analog or digital, and what priority it should have. This file should be located in the same directory as the trunk-recorder executable. |
@@ -178,7 +179,6 @@ Here is a map of the different sections of the *config.json* file:
| analogLevels | | 8 | number (1-32) | The amount of amplification that will be applied to the analog audio. |
| maxDev | | 4000 | number | Allows you to set the maximum deviation for analog channels. If you analog recordings sound good or if you have a completely digital system, then there is no need to touch this. |
| digitalLevels | | 1 | number (1-16) | The amount of amplification that will be applied to the digital audio. |
-| alphatags | | | array of strings
e.g.: ["police", "fire", "ems"] | [*For conventional systems*] these tags will be displayed in the log files to show what each frequency is used for. They will be applied to the *channels* in the order the values appear in the array. |
| unitTagsFile | | | string | This is the filename of a CSV files that provides information about the unit tags. It allows a Unit ID to be assigned a name. This file should be located in the same directory as the trunk-recorder executable. The format is 2 columns, the first being the decimal number of the Unit ID, the second is the Unit Name, |
| recordUnknown | | true | **true** / **false** | Record talkgroups if they are not listed in the Talkgroups File. |
| hideEncrypted | | false | **true** / **false** | Hide encrypted talkgroups log entries |
@@ -355,3 +355,18 @@ Here are the column headers and some sample data:
|101 | 065 | D | DCFD 01 Disp | 01 Dispatch | Fire Dispatch | Fire | 1 |
|2227 | 8b3 | D | DC StcarYard | Streetcar Yard | Transportation | Services | 3 |
+
+
+## channelFile
+
+This file allows for you to specify additional information about conventional channels. A recorder is started for each line in the file and set the to frequency specified. The type of recorder is based on the type of System. A *Conventional* system would have Analog Recorders, while a *ConventionalP25* or *ConventionalDMR* would have digital recorders.
+
+*Tone based squelch is currently not supported.*
+
+The **Enable** Column is optional and defaults to *True*. It only needs to be added to rows that you do not want to have recorded. For those rows, set **Enable** to *False*.
+
+| TG Number | Frequency | Tone | Alpha Tag | Description | Tag | Group | Enable (*optional*) |
+| --------- | --------- | -------- | ------------- | ---------------------- | ------ | ------ | ------------------- |
+| 300 | 462275000 | 94.8 PL | Town A Police | Town A Police Dispatch | Police | Town A | |
+| 325 | 462275000 | 151.4 PL | Town B DPW | Town B Trash Dispatch | DPW | Town B | False |
+
diff --git a/examples/channel.csv b/examples/channel.csv
new file mode 100644
index 000000000..d3d6d3788
--- /dev/null
+++ b/examples/channel.csv
@@ -0,0 +1,22 @@
+1,462562500,0,FRS 01,Channel 1,FMN,Other
+2,462587500,0,FRS 02,Channel 2,FMN,Other
+3,462612500,0,FRS 03,Channel 3,FMN,Other
+4,462637500,0,FRS 04,Channel 4,FMN,Other
+5,462662500,0,FRS 05,Channel 5,FMN,Other
+6,462687500,0,FRS 06,Channel 6,FMN,Other
+7,462712500,0,FRS 07,Channel 7,FMN,Other, False
+8,467562500,0,FRS 08,Channel 8,FMN,Other
+9,467587500,0,FRS 09,Channel 9,FMN,Other
+10,467612500,0,FRS 10,Channel 10,FMN,Other
+11,467637500,0,FRS 11,Channel 11,FMN,Other
+12,467662500,0,FRS 12,Channel 12,FMN,Other
+13,467687500,0,FRS 13,Channel 13,FMN,Other
+14,467712500,0,FRS 14,Channel 14,FMN,Other
+15,462550000,0,FRS 15,Channel 15,FMN,Other
+16,462575000,0,FRS 16,Channel 16,FMN,Other
+17,462600000,0,FRS 17,Channel 17,FMN,Other
+18,462625000,0,FRS 18,Channel 18,FMN,Other
+19,462650000,0,FRS 19,Channel 19,FMN,Other
+20,462675000,0,FRS 20,Channel 20,FMN,Other
+21,462700000,0,FRS 21,Channel 21,FMN,Other
+22,462725000,0,FRS 22,Channel 22,FMN,Other
\ No newline at end of file
diff --git a/examples/config-frs-single.json b/examples/config-frs-single.json
new file mode 100644
index 000000000..c338c3eca
--- /dev/null
+++ b/examples/config-frs-single.json
@@ -0,0 +1,24 @@
+{
+ "ver": 2,
+ "sources": [
+ {
+ "center": 462500000,
+ "rate": 2048000,
+ "error": 0,
+ "gain": 36,
+ "debugRecorders": 0,
+ "digitalRecoders": 0,
+ "driver": "osmosdr"
+ }
+ ],
+ "systems": [
+ {
+ "type": "conventional",
+ "channels": [
+ 462562500
+ ],
+ "callLog": true,
+ "squelch": -20
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/config-frs.json b/examples/config-frs.json
new file mode 100644
index 000000000..6508ea63f
--- /dev/null
+++ b/examples/config-frs.json
@@ -0,0 +1,22 @@
+{
+ "ver": 2,
+ "sources": [
+ {
+ "center": 462500000,
+ "rate": 2048000,
+ "error": 0,
+ "gain": 36,
+ "debugRecorders": 0,
+ "digitalRecoders": 0,
+ "driver": "osmosdr"
+ }
+ ],
+ "systems": [
+ {
+ "type": "conventional",
+ "channelFile": "channel.csv",
+ "callLog": true,
+ "squelch": -20
+ }
+ ]
+}
\ No newline at end of file
diff --git a/lib/gr_blocks/nonstop_wavfile_sink_impl.cc b/lib/gr_blocks/nonstop_wavfile_sink_impl.cc
index fec116d1f..90f9cbc80 100644
--- a/lib/gr_blocks/nonstop_wavfile_sink_impl.cc
+++ b/lib/gr_blocks/nonstop_wavfile_sink_impl.cc
@@ -267,7 +267,7 @@ void nonstop_wavfile_sink_impl::stop_recording() {
}
if (state == RECORDING) {
- BOOST_LOG_TRIVIAL(error) << "stop_recording() - stopping wavfile sink but recorder state is: " << state << std::endl;
+ BOOST_LOG_TRIVIAL(trace) << "stop_recording() - stopping wavfile sink but recorder state is: " << state << std::endl;
}
d_current_call = NULL;
d_first_work = true;
diff --git a/trunk-recorder/main.cc b/trunk-recorder/main.cc
index 7b9418293..efc2af359 100755
--- a/trunk-recorder/main.cc
+++ b/trunk-recorder/main.cc
@@ -229,49 +229,34 @@ bool load_config(string config_file) {
system->set_system_type(node.second.get("type"));
BOOST_LOG_TRIVIAL(info) << "System Type: " << system->get_system_type();
- if (system->get_system_type() == "conventional") {
- BOOST_LOG_TRIVIAL(info) << "Conventional Channels: ";
- BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("channels")) {
- double channel = sub_node.second.get("", 0);
-
- BOOST_LOG_TRIVIAL(info) << " " << format_freq(channel);
- system->add_channel(channel);
- }
+ // If it is a conventional System
+ if ((system->get_system_type() == "conventional") || (system->get_system_type() == "conventionalP25") || (system->get_system_type() == "conventionalDMR")) {
+
+ boost::optional channel_file_exist = node.second.get_optional("channelFile");
+ boost::optional channels_exist = node.second.get_child_optional("channels");
- BOOST_LOG_TRIVIAL(info) << "Alpha Tags: ";
- if (node.second.count("alphatags") != 0) {
- int alphaIndex = 1;
- BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("alphatags")) {
- std::string alphaTag = sub_node.second.get("", "");
- BOOST_LOG_TRIVIAL(info) << " " << alphaTag;
- system->talkgroups->add(alphaIndex, alphaTag);
- alphaIndex++;
- }
+ if (channel_file_exist && channels_exist) {
+ BOOST_LOG_TRIVIAL(error) << "Both \"channels\" and \"channelFile\" cannot be defined for a system!";
+ return false;
}
- } else if ((system->get_system_type() == "conventionalP25") || (system->get_system_type() == "conventionalDMR") ) {
- BOOST_LOG_TRIVIAL(info) << "Conventional Channels: ";
- BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("channels")) {
- double channel = sub_node.second.get("", 0);
-
- BOOST_LOG_TRIVIAL(info) << " " << format_freq(channel);
- system->add_channel(channel);
- }
+ if (channels_exist) {
+ BOOST_LOG_TRIVIAL(info) << "Conventional Channels: ";
+ BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("channels")) {
+ double channel = sub_node.second.get("", 0);
- BOOST_LOG_TRIVIAL(info) << "Alpha Tags: ";
- if (node.second.count("alphatags") != 0) {
- int alphaIndex = 1;
- BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("alphatags")) {
- std::string alphaTag = sub_node.second.get("", "");
- BOOST_LOG_TRIVIAL(info) << " " << alphaTag;
- system->talkgroups->add(alphaIndex, alphaTag);
- alphaIndex++;
+ BOOST_LOG_TRIVIAL(info) << " " << format_freq(channel);
+ system->add_channel(channel);
}
+ } else if (channel_file_exist) {
+ std::string channel_file = node.second.get("channelFile");
+ BOOST_LOG_TRIVIAL(info) << "Channel File: " << channel_file;
+ system->set_channel_file(channel_file);
+ } else {
+ BOOST_LOG_TRIVIAL(error) << "Either \"channels\" or \"channelFile\" need to be defined for a conventional system!";
+ return false;
}
-
- system->set_delaycreateoutput(node.second.get("delayCreateOutput", false));
- BOOST_LOG_TRIVIAL(info) << "delayCreateOutput: " << system->get_delaycreateoutput();
-
+ // If it is a Trunked System
} else if ((system->get_system_type() == "smartnet") || (system->get_system_type() == "p25")) {
BOOST_LOG_TRIVIAL(info) << "Control Channels: ";
BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("control_channels")) {
@@ -279,10 +264,12 @@ bool load_config(string config_file) {
BOOST_LOG_TRIVIAL(info) << " " << format_freq(control_channel);
system->add_control_channel(control_channel);
+ system->set_talkgroups_file(node.second.get("talkgroupsFile", ""));
+ BOOST_LOG_TRIVIAL(info) << "Talkgroups File: " << system->get_talkgroups_file();
}
} else {
BOOST_LOG_TRIVIAL(error) << "System Type in config.json not recognized";
- exit(1);
+ return false;
}
bool qpsk_mod = true;
@@ -338,8 +325,6 @@ bool load_config(string config_file) {
BOOST_LOG_TRIVIAL(info) << "Audio Archive: " << system->get_audio_archive();
system->set_transmission_archive(node.second.get("transmissionArchive", false));
BOOST_LOG_TRIVIAL(info) << "Transmission Archive: " << system->get_transmission_archive();
- system->set_talkgroups_file(node.second.get("talkgroupsFile", ""));
- BOOST_LOG_TRIVIAL(info) << "Talkgroups File: " << system->get_talkgroups_file();
system->set_unit_tags_file(node.second.get("unitTagsFile", ""));
BOOST_LOG_TRIVIAL(info) << "Unit Tags File: " << system->get_unit_tags_file();
system->set_record_unknown(node.second.get("recordUnknown", true));
@@ -1248,49 +1233,37 @@ void monitor_messages() {
}
}
-bool setup_systems() {
-
- Source *source = NULL;
-
- for (vector::iterator sys_it = systems.begin(); sys_it != systems.end(); sys_it++) {
- System *system = *sys_it;
- //bool source_found = false;
- bool system_added = false;
- if ((system->get_system_type() == "conventional") || (system->get_system_type() == "conventionalP25") || (system->get_system_type() == "conventionalDMR")) {
- std::vector channels = system->get_channels();
- int tg_iterate_index = 0;
-
- for (vector::iterator chan_it = channels.begin(); chan_it != channels.end(); chan_it++) {
- double channel = *chan_it;
- ++tg_iterate_index;
- bool channel_added = false;
-
+bool setup_convetional_channel(System *system, double frequency, long channel_index) {
+ bool channel_added = false;
+ Source *source = NULL;
for (vector::iterator src_it = sources.begin(); src_it != sources.end(); src_it++) {
source = *src_it;
- if ((source->get_min_hz() <= channel) && (source->get_max_hz() >= channel)) {
+ if ((source->get_min_hz() <= frequency) && (source->get_max_hz() >= frequency)) {
channel_added = true;
if (system->get_squelch_db() == -160) {
BOOST_LOG_TRIVIAL(error) << "[" << system->get_short_name() << "]\tSquelch needs to be specified for the Source for Conventional Systems";
- system_added = false;
+ return false;
} else {
- system_added = true;
+ channel_added = true;
}
- // This source can be used for this channel (and a squelch is set)
- BOOST_LOG_TRIVIAL(info) << "[" << system->get_short_name() << "]\tMonitoring Conventional Channel: " << format_freq(channel) << " Talkgroup: " << tg_iterate_index;
- Call_conventional *call = new Call_conventional(tg_iterate_index, channel, system, config);
- Talkgroup *talkgroup = system->find_talkgroup(call->get_talkgroup());
-
- if (talkgroup) {
- call->set_talkgroup_tag(talkgroup->alpha_tag);
+
+
+ Call_conventional *call = NULL;
+ if (system->has_channel_file()) {
+ Talkgroup *tg = system->find_talkgroup_by_freq(frequency);
+ call = new Call_conventional(tg->number, tg->freq, system, config);
+ } else {
+ call = new Call_conventional(channel_index, frequency, system, config);
+ BOOST_LOG_TRIVIAL(info) << "[" << system->get_short_name() << "]\tMonitoring Conventional Channel: " << format_freq(frequency) << " Talkgroup: " << channel_index;
+
}
-
if (system->get_system_type() == "conventional") {
analog_recorder_sptr rec;
rec = source->create_conventional_recorder(tb);
rec->start(call);
- call->set_is_analog(true);
+ call->set_is_analog(true);
call->set_recorder((Recorder *)rec.get());
call->set_state(RECORDING);
system->add_conventional_recorder(rec);
@@ -1321,11 +1294,56 @@ bool setup_systems() {
break;
}
}
- if (!channel_added) {
- BOOST_LOG_TRIVIAL(error) << "[" << system->get_short_name() << "]\t Unable to find a source for this conventional channel! Channel not added: " << format_freq(channel) << " Talkgroup: " << tg_iterate_index;
- //return false;
- }
+ return channel_added;
+}
+
+
+bool setup_conventional_system(System *system) {
+ bool system_added = false;
+
+ if (system->has_channel_file()) {
+ std::vector talkgroups = system->get_talkgroups();
+ for (vector::iterator tg_it = talkgroups.begin(); tg_it != talkgroups.end(); tg_it++) {
+ Talkgroup *tg = *tg_it;
+
+ bool channel_added = setup_convetional_channel(system, tg->freq, tg->number);
+
+ if (!channel_added) {
+ BOOST_LOG_TRIVIAL(error) << "[" << system->get_short_name() << "]\t Unable to find a source for this conventional channel! Channel not added: " << format_freq(tg->freq) << " Talkgroup: " << tg->number;
+ //return false;
+ } else {
+ system_added = true;
+ }
+ }
+ } else {
+ std::vector channels = system->get_channels();
+ int channel_index = 0;
+ for (vector::iterator chan_it = channels.begin(); chan_it != channels.end(); chan_it++) {
+ double channel = *chan_it;
+ ++channel_index;
+ bool channel_added = setup_convetional_channel(system, channel, channel_index);
+
+ if (!channel_added) {
+ BOOST_LOG_TRIVIAL(error) << "[" << system->get_short_name() << "]\t Unable to find a source for this conventional channel! Channel not added: " << format_freq(channel) << " Talkgroup: " << channel_index;
+ //return false;
+ } else {
+ system_added = true;
}
+ }
+ }
+ return system_added;
+}
+
+bool setup_systems() {
+
+ Source *source = NULL;
+
+ for (vector::iterator sys_it = systems.begin(); sys_it != systems.end(); sys_it++) {
+ System *system = *sys_it;
+ //bool source_found = false;
+ bool system_added = false;
+ if ((system->get_system_type() == "conventional") || (system->get_system_type() == "conventionalP25") || (system->get_system_type() == "conventionalDMR")) {
+ system_added = setup_conventional_system(system);
} else {
// If it's not a conventional system, then it's a trunking system
double control_channel_freq = system->get_current_control_channel();
diff --git a/trunk-recorder/systems/system.cc b/trunk-recorder/systems/system.cc
index 8e444068d..f6ff67e95 100644
--- a/trunk-recorder/systems/system.cc
+++ b/trunk-recorder/systems/system.cc
@@ -77,7 +77,6 @@ System::System(int sys_num) {
// Setup the unit tags from the CSV file
unit_tags = new UnitTags();
talkgroup_patches = {};
- d_delaycreateoutput = false;
d_hideEncrypted = false;
d_hideUnknown = false;
d_mdc_enabled = false;
@@ -254,6 +253,20 @@ std::string System::get_unit_tags_file() {
return this->unit_tags_file;
}
+void System::set_channel_file(std::string channel_file) {
+ BOOST_LOG_TRIVIAL(info) << "Loading Talkgroups...";
+ this->channel_file = channel_file;
+ this->talkgroups->load_channels(channel_file);
+}
+
+bool System::has_channel_file() {
+ if (this->channel_file.length() > 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
void System::set_talkgroups_file(std::string talkgroups_file) {
BOOST_LOG_TRIVIAL(info) << "Loading Talkgroups...";
this->talkgroups_file = talkgroups_file;
@@ -278,6 +291,9 @@ Talkgroup *System::find_talkgroup(long tg_number) {
return talkgroups->find_talkgroup(tg_number);
}
+Talkgroup *System::find_talkgroup_by_freq(double freq) {
+ return talkgroups->find_talkgroup_by_freq(freq);
+}
UnitTag *System::find_unit_tag(long unitID) {
return unit_tags->find_unit_tag(unitID);
}
@@ -286,6 +302,9 @@ std::vector System::get_channels() {
return channels;
}
+std::vector System::get_talkgroups() {
+ return talkgroups->get_talkgroups();
+}
int System::channel_count() {
return channels.size();
}
@@ -418,14 +437,6 @@ System::TalkgroupDisplayFormat System::get_talkgroup_display_format() {
return talkgroup_display_format;
}
-bool System::get_delaycreateoutput() {
- return d_delaycreateoutput;
-}
-
-void System::set_delaycreateoutput(bool delaycreateoutput) {
- d_delaycreateoutput = delaycreateoutput;
-}
-
bool System::get_hideEncrypted() {
return d_hideEncrypted;
}
diff --git a/trunk-recorder/systems/system.h b/trunk-recorder/systems/system.h
index 7c698da9f..ae5e91739 100644
--- a/trunk-recorder/systems/system.h
+++ b/trunk-recorder/systems/system.h
@@ -55,6 +55,7 @@ class System {
p25p2_lfsr *lfsr;
Source *source;
std::string talkgroups_file;
+ std::string channel_file;
std::string unit_tags_file;
std::string short_name;
std::string api_key;
@@ -164,8 +165,11 @@ class System {
Source *get_source();
void set_source(Source *);
Talkgroup *find_talkgroup(long tg);
+ Talkgroup *find_talkgroup_by_freq(double freq);
UnitTag *find_unit_tag(long unitID);
void set_talkgroups_file(std::string);
+ void set_channel_file(std::string channel_file);
+ bool has_channel_file();
void set_unit_tags_file(std::string);
int control_channel_count();
void add_control_channel(double channel);
@@ -181,6 +185,7 @@ class System {
std::vector get_conventionalDMR_recorders();
std::vector get_channels();
std::vector get_control_channels();
+ std::vector get_talkgroups();
System(int sys_id);
void set_bandplan(std::string);
std::string get_bandplan();
@@ -197,9 +202,6 @@ class System {
void set_talkgroup_display_format(TalkgroupDisplayFormat format);
TalkgroupDisplayFormat get_talkgroup_display_format();
- bool get_delaycreateoutput();
- void set_delaycreateoutput(bool delaycreateoutput);
-
bool get_hideEncrypted();
void set_hideEncrypted(bool hideEncrypted);
@@ -216,7 +218,6 @@ class System {
private:
TalkgroupDisplayFormat talkgroup_display_format;
- bool d_delaycreateoutput;
bool d_hideEncrypted;
bool d_hideUnknown;
diff --git a/trunk-recorder/talkgroup.cc b/trunk-recorder/talkgroup.cc
index f8227d042..f9b5e0520 100644
--- a/trunk-recorder/talkgroup.cc
+++ b/trunk-recorder/talkgroup.cc
@@ -1,14 +1,29 @@
#include "talkgroup.h"
-Talkgroup::Talkgroup(long num, std::string m, std::string a, std::string d, std::string t, std::string g, int p) {
- number = num;
- mode = m;
- alpha_tag = a;
- description = d;
- tag = t;
- group = g;
- priority = p;
- active = false;
+Talkgroup::Talkgroup(long num, std::string mode, std::string alpha_tag, std::string description, std::string tag, std::string group, int priority) {
+ this->number = num;
+ this->mode = mode;
+ this->alpha_tag = alpha_tag;
+ this->description = description;
+ this->tag = tag;
+ this->group = group;
+ this->priority = priority;
+ this->active = false;
+ this->freq = 0;
+ this->tone = 0;
+}
+
+Talkgroup::Talkgroup(long num, double freq, double tone, std::string alpha_tag, std::string description, std::string tag, std::string group) {
+ this->number = num;
+ this->mode = "Z";
+ this->alpha_tag = alpha_tag;
+ this->description = description;
+ this->tag = tag;
+ this->group = group;
+ this->active = false;
+ this->freq = freq;
+ this->tone = tone;
+ this->priority = 0;
}
std::string Talkgroup::menu_string() {
diff --git a/trunk-recorder/talkgroup.h b/trunk-recorder/talkgroup.h
index 453c37041..058c15753 100644
--- a/trunk-recorder/talkgroup.h
+++ b/trunk-recorder/talkgroup.h
@@ -15,7 +15,15 @@ class Talkgroup {
std::string tag;
std::string group;
int priority;
- Talkgroup(long num, std::string m, std::string a, std::string d, std::string t, std::string g, int p);
+
+ // For Conventional
+ double freq;
+ double tone;
+
+
+ Talkgroup(long num, std::string mode, std::string alpha_tag, std::string description, std::string tag, std::string group, int priority);
+ Talkgroup(long num, double freq, double tone, std::string alpha_tag, std::string description, std::string tag, std::string group);
+
bool is_active();
int get_priority();
void set_priority(int new_priority);
diff --git a/trunk-recorder/talkgroups.cc b/trunk-recorder/talkgroups.cc
index 10bc989f1..3a83fd112 100644
--- a/trunk-recorder/talkgroups.cc
+++ b/trunk-recorder/talkgroups.cc
@@ -116,6 +116,90 @@ void Talkgroups::load_talkgroups(std::string filename) {
}
}
+void Talkgroups::load_channels(std::string filename) {
+ if (filename == "") {
+ return;
+ }
+
+ std::ifstream in(filename.c_str());
+
+ if (!in.is_open()) {
+ BOOST_LOG_TRIVIAL(error) << "Error Opening Channel File: " << filename << std::endl;
+ return;
+ }
+
+
+ boost::char_separator sep(",", "\t", boost::keep_empty_tokens);
+ typedef boost::tokenizer> t_tokenizer;
+
+ std::vector vec;
+ std::string line;
+
+ int lines_read = 0;
+ int lines_pushed = 0;
+ int priority = 1;
+
+ while (!safeGetline(in, line).eof()) // this works with \r, \n, or \r\n
+ {
+ if (line.size() && (line[line.size() - 1] == '\r')) {
+ line = line.substr(0, line.size() - 1);
+ }
+
+ lines_read++;
+
+ if (line == "")
+ continue;
+
+ t_tokenizer tok(line, sep);
+
+ vec.assign(tok.begin(), tok.end());
+
+ Talkgroup *tg = NULL;
+
+ // Channel File columns:
+ //
+ // [0] - talkgroup number
+ // [1] - channel freq
+ // [2] - tone
+ // [3] - alpha_tag
+ // [4] - description
+ // [5] - tag
+ // [6] - group
+ // [7] - enable (Optional, default is True)
+
+ if ((vec.size() != 7) && (vec.size() != 8)) {
+ BOOST_LOG_TRIVIAL(error) << "Malformed channel entry at line " << lines_read << ". Found: " << vec.size() << " Expected 7 or 8";
+ continue;
+ }
+ // TODO(nkw): more sanity checking here.
+ bool enable = true;
+ if (vec.size() == 8 ) {
+ boost::trim(vec[7]);
+ if (boost::iequals(vec[7], "false")) {
+ enable = false;
+ }
+ }
+
+//Talkgroup(long num, double freq, double tone, std::string mode, std::string alpha_tag, std::string description, std::string tag, std::string group) {
+ if (enable) {
+ tg = new Talkgroup(atoi(vec[0].c_str()), std::stod(vec[1]), std::stod(vec[2]), vec[3].c_str(), vec[4].c_str(), vec[5].c_str(), vec[6].c_str());
+
+ talkgroups.push_back(tg);
+ }
+ lines_pushed++;
+
+ }
+
+ if (lines_pushed != lines_read) {
+ // The parser above is pretty brittle. This will help with debugging it, for
+ // now.
+ BOOST_LOG_TRIVIAL(error) << "Warning: skipped " << lines_read - lines_pushed << " of " << lines_read << " channel entries! Invalid format?";
+ BOOST_LOG_TRIVIAL(error) << "The format is very particular. See https://github.com/robotastic/trunk-recorder for example input.";
+ } else {
+ BOOST_LOG_TRIVIAL(info) << "Read " << lines_pushed << " channels.";
+ }
+}
+
Talkgroup *Talkgroups::find_talkgroup(long tg_number) {
Talkgroup *tg_match = NULL;
@@ -130,7 +214,21 @@ Talkgroup *Talkgroups::find_talkgroup(long tg_number) {
return tg_match;
}
-void Talkgroups::add(long num, std::string alphaTag) {
- Talkgroup *tg = new Talkgroup(num, "X", alphaTag, "", "", "", 0);
- talkgroups.push_back(tg);
+Talkgroup *Talkgroups::find_talkgroup_by_freq(double freq) {
+ Talkgroup *tg_match = NULL;
+
+ for (std::vector::iterator it = talkgroups.begin(); it != talkgroups.end(); ++it) {
+ Talkgroup *tg = (Talkgroup *)*it;
+
+ if (tg->freq == freq) {
+ tg_match = tg;
+ break;
+ }
+ }
+ return tg_match;
+}
+
+std::vector Talkgroups::get_talkgroups() {
+ return talkgroups;
}
+
diff --git a/trunk-recorder/talkgroups.h b/trunk-recorder/talkgroups.h
index 8c69a34c0..4a8a21348 100644
--- a/trunk-recorder/talkgroups.h
+++ b/trunk-recorder/talkgroups.h
@@ -2,7 +2,7 @@
#define TALKGROUPS_H
#include "talkgroup.h"
-
+#include
#include
#include
@@ -12,7 +12,9 @@ class Talkgroups {
public:
Talkgroups();
void load_talkgroups(std::string filename);
+ void load_channels(std::string filename);
Talkgroup *find_talkgroup(long tg);
- void add(long num, std::string alphaTag);
+ Talkgroup *find_talkgroup_by_freq(double freq);
+ std::vector get_talkgroups();
};
#endif // TALKGROUPS_H