Skip to content

Commit

Permalink
Merge pull request #652 from robotastic/conventional
Browse files Browse the repository at this point in the history
Conventional Channel Information
  • Loading branch information
robotastic authored Mar 20, 2022
2 parents 5d3da98 + 447e832 commit 7ae5966
Show file tree
Hide file tree
Showing 14 changed files with 346 additions and 105 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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


Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
17 changes: 16 additions & 1 deletion docs/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;<br />[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;<br />[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. |
Expand All @@ -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<br />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 |
Expand Down Expand Up @@ -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 |

22 changes: 22 additions & 0 deletions examples/channel.csv
Original file line number Diff line number Diff line change
@@ -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
24 changes: 24 additions & 0 deletions examples/config-frs-single.json
Original file line number Diff line number Diff line change
@@ -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
}
]
}
22 changes: 22 additions & 0 deletions examples/config-frs.json
Original file line number Diff line number Diff line change
@@ -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
}
]
}
2 changes: 1 addition & 1 deletion lib/gr_blocks/nonstop_wavfile_sink_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
164 changes: 91 additions & 73 deletions trunk-recorder/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,60 +229,47 @@ bool load_config(string config_file) {
system->set_system_type(node.second.get<std::string>("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<double>("", 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<std::string> channel_file_exist = node.second.get_optional<std::string>("channelFile");
boost::optional<boost::property_tree::ptree &> 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<std::string>("", "");
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<double>("", 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<double>("", 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<std::string>("", "");
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<std::string>("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<bool>("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")) {
double control_channel = sub_node.second.get<double>("", 0);

BOOST_LOG_TRIVIAL(info) << " " << format_freq(control_channel);
system->add_control_channel(control_channel);
system->set_talkgroups_file(node.second.get<std::string>("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;
Expand Down Expand Up @@ -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<bool>("transmissionArchive", false));
BOOST_LOG_TRIVIAL(info) << "Transmission Archive: " << system->get_transmission_archive();
system->set_talkgroups_file(node.second.get<std::string>("talkgroupsFile", ""));
BOOST_LOG_TRIVIAL(info) << "Talkgroups File: " << system->get_talkgroups_file();
system->set_unit_tags_file(node.second.get<std::string>("unitTagsFile", ""));
BOOST_LOG_TRIVIAL(info) << "Unit Tags File: " << system->get_unit_tags_file();
system->set_record_unknown(node.second.get<bool>("recordUnknown", true));
Expand Down Expand Up @@ -1248,49 +1233,37 @@ void monitor_messages() {
}
}

bool setup_systems() {

Source *source = NULL;

for (vector<System *>::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<double> channels = system->get_channels();
int tg_iterate_index = 0;

for (vector<double>::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<Source *>::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);
Expand Down Expand Up @@ -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<Talkgroup *> talkgroups = system->get_talkgroups();
for (vector<Talkgroup *>::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<double> channels = system->get_channels();
int channel_index = 0;
for (vector<double>::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<System *>::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();
Expand Down
Loading

0 comments on commit 7ae5966

Please sign in to comment.