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