Skip to content

Commit

Permalink
Merge pull request #441 from rosecitytransit/master
Browse files Browse the repository at this point in the history
Finished unit logging script (fixes #181, can close #440)
  • Loading branch information
robotastic authored Mar 28, 2021
2 parents 3d8beef + e7ef026 commit a4e5cd2
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ Here are the different arguments:
- **recordUnknown** - record talkgroups if they are not listed in the Talkgroups File. The options are *true* and *false* (without quotes). The default is *true*.
- **shortName** - this is a nickname for the system. It is used to help name and organize the recordings from this system. It should be 4-6 letters with no spaces.
- **uploadScript** - this script is called after each recording has finished. Checkout *encode-upload.sh.sample* as an example. The script should be located in the same directory as the trunk-recorder executable.
- **unitScript** - *(Optional)* run a script when a unit radio registers (is turned on), affiliates (joins a talk group), deregisters (is turned off), sends an acknowledgment response or transmits. Passed as parameters: `shortName` `radio ID` `on|join|off|ackresp|call`. On joins and transmissions, `<talk group>` is passed as a fourth parameter.
- **unitScript** - *(Optional)* run a script when a radio (unit) registers (is turned on), affiliates (joins a talk group), deregisters (is turned off), sends an acknowledgment response or transmits. Passed as parameters: `shortName radioID on|join|off|ackresp|call`. On joins and transmissions, `talkgroup` is passed as a fourth parameter. See *examples/unit-script.sh* for a logging example. Note that for paths relative to recorder, this should start with `./`( or `../`).
- **apiKey** - *(Optional, only if uploadServer set)* System-specific API key for uploading calls to OpenMHz.com. See the Config tab for your system in OpenMHz to find what the value should be.
- **broadcastifyApiKey** - *(Optional)* System-specific API key for Broadcastify Calls
- **broadcastifySystemId** - *(Optional)* System ID for Broadcastify Calls (this is an integer, and different from the RadioReference system ID)
Expand Down
21 changes: 11 additions & 10 deletions examples/unit-script.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#!/bin/bash

#README: unit-script.txt

CAPTUREDIR=""

printf -v TRDATE '%(%Y/%-m/%-d)T'
printf -v NOWTIME '%(%s)T'
SHORTNAME=$1
RADIOID=$2
ACTION=$3
TALKGROUP=$4
if $3 != "ackresp"
sed <capture_dir>/$1/radiolist.csv 's/^$RADIOID,(.*)/$RADIOID,$NOWTIME,$ACTION,$TALKGROUP,/'
elif
sed <capture_dir>/$1/radiolist.csv 's/$RADIOID,(\d+),([on|join|off|call]),(\d+),(\d+)/$RADIOID,$1,$2,$3,$NOWTIME'
done
echo "$2,$3,$4" >> <capture_dir>/$1/$TRDATE/radiolog.csv
if [ ! "$3" == "ackresp" ]; then
sed -i -e '/^'${2}',.*/{s//'${2}','${NOWTIME}','${3}','${4}',/;:a;n;ba;q}' -e '$a'${2}','${NOWTIME}','${3}','${4}',' $CAPTUREDIR/$1/radiolist.csv
else
sed -i -e '/^'${2}',\([0-9]*\),ackresp,,/{s//'${2}','${NOWTIME}',ackresp,,/;:a;n;ba;q}' -e '/^'${2}',\([0-9]*\),\([a-z]*\),\([0-9]*\),\([0-9]*\)/{s//'${2}',\1,\2,\3,'${NOWTIME}'/;:a;n;ba;q}' -e '$a'${2}','${NOWTIME}',ackresp,,' $CAPTUREDIR/$1/radiolist.csv
fi
echo "$2,$NOWTIME,$3,$4" >> $CAPTUREDIR/$1/$TRDATE/radiolog.csv
21 changes: 21 additions & 0 deletions examples/unit-script.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
unit-script.sh README:

Creates a list of radio IDs in a file named "radiolist.csv" located in the
shortName directory along side the recordings, and logs radio activity to
"radiolog.csv" files located in each day's recordings directory

Make sure to fill in the CAPTUREDIR="" line with the path used in config.json, no ending /

file format: radioID,timestamp,action,talkgroup,
for radiolist.csv, acknowledgment response timestamps are added at the end
when they are seen after a different action

Feel free to customize the script; to use for multiple systems, include in
each system's config.json section

NOTE: You need to run "echo > radiolist.csv" where the file(s) is going to be
beforehand as sed doesn't work on empty files, and to capture actions before
trunk-recorder makes the daily directory upon recording the first call, set
up a cron task of: 0 0 * * * mkdir -p <capturedir>/$(date +\%Y/\%-m/\%-d/)

sed usage based on https://stackoverflow.com/a/49852337
38 changes: 20 additions & 18 deletions trunk-recorder/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -857,17 +857,17 @@ void current_system_status(TrunkMessage message, System *sys) {
}
}

void unit_registration(string unit_script, long unit) {
void unit_registration(string unit_script, string shortName, long unit) {
unit_affiliations[unit] = 0;

if (unit_script.length() != 0) {
if ((unit_script.length() != 0) && (unit != 0)) {
char shell_command[200];
sprintf(shell_command, "%s %li on &", unit_script.c_str(), unit);
sprintf(shell_command, "%s %s %li on &", unit_script.c_str(), shortName.c_str(), unit);
int rc = system(shell_command);
}
}

void unit_deregistration(string unit_script, long unit) {
void unit_deregistration(string unit_script, string shortName, long unit) {
/* std::map<long, long>::iterator it;
it = unit_affiliations.find(unit);
Expand All @@ -876,27 +876,27 @@ void unit_deregistration(string unit_script, long unit) {

unit_affiliations[unit] = -1;

if (unit_script.length() != 0) {
if ((unit_script.length() != 0) && (unit != 0)) {
char shell_command[200];
sprintf(shell_command, "%s %li off &", unit_script.c_str(), unit);
sprintf(shell_command, "%s %s %li off &", unit_script.c_str(), shortName.c_str(), unit);
int rc = system(shell_command);
}
}

void unit_ack(string unit_script, long unit) {
if (unit_script.length() != 0) {
void unit_ack(string unit_script, string shortName, long unit) {
if ((unit_script.length() != 0) && (unit != 0)) {
char shell_command[200];
sprintf(shell_command, "%s %li ackresp &", unit_script.c_str(), unit);
sprintf(shell_command, "%s %s %li ackresp &", unit_script.c_str(), shortName.c_str(), unit);
int rc = system(shell_command);
}
}

void group_affiliation(string unit_script, long unit, long talkgroup) {
void group_affiliation(string unit_script, string shortName, long unit, long talkgroup) {
unit_affiliations[unit] = talkgroup;

if (unit_script.length() != 0) {
if ((unit_script.length() != 0) && (unit != 0)) {
char shell_command[200];
sprintf(shell_command, "%s %li join %li &", unit_script.c_str(), unit, talkgroup);
sprintf(shell_command, "%s %s %li join %li &", unit_script.c_str(), shortName.c_str(), unit, talkgroup);
int rc = system(shell_command);
}
}
Expand All @@ -914,7 +914,7 @@ void handle_call(TrunkMessage message, System *sys) {

unit_affiliations[message.source] = message.talkgroup;

if (sys->get_unit_script().length() != 0) {
if ((sys->get_unit_script().length() != 0) && (message.source != 0)) {
char shell_command[200];
sprintf(shell_command, "%s %s %li call %li &", sys->get_unit_script().c_str(), sys->get_short_name().c_str(), message.source, message.talkgroup);
int rc = system(shell_command);
Expand Down Expand Up @@ -1032,15 +1032,15 @@ void handle_message(std::vector<TrunkMessage> messages, System *sys) {
break;

case REGISTRATION:
unit_registration(sys->get_unit_script(), message.source);
unit_registration(sys->get_unit_script(), sys->get_short_name(), message.source);
break;

case DEREGISTRATION:
unit_deregistration(sys->get_unit_script(), message.source);
unit_deregistration(sys->get_unit_script(), sys->get_short_name(), message.source);
break;

case AFFILIATION:
group_affiliation(sys->get_unit_script(), message.source, message.talkgroup);
group_affiliation(sys->get_unit_script(), sys->get_short_name(), message.source, message.talkgroup);
break;

case SYSID:
Expand All @@ -1051,7 +1051,7 @@ void handle_message(std::vector<TrunkMessage> messages, System *sys) {
break;

case ACKRESP:
unit_ack(sys->get_unit_script(), message.source);
unit_ack(sys->get_unit_script(), sys->get_short_name(), message.source);
break;

case UNKNOWN:
Expand Down Expand Up @@ -1409,6 +1409,8 @@ int main(int argc, char **argv) {
logging::trivial::severity >= logging::trivial::info

);

boost::log::register_simple_formatter_factory< boost::log::trivial::severity_level, char >("Severity");

boost::log::add_common_attributes();
boost::log::core::get()->add_global_attribute("Scope",
Expand Down Expand Up @@ -1461,7 +1463,7 @@ int main(int argc, char **argv) {
if (config.log_file) {
logging::add_file_log(
keywords::file_name = "logs/%m-%d-%Y_%H%M_%2N.log",
keywords::format = "[%TimeStamp%]: %Message%",
keywords::format = "[%TimeStamp%] (%Severity%) %Message%",
keywords::rotation_size = 10 * 1024 * 1024,
keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
keywords::auto_flush = true);
Expand Down
14 changes: 7 additions & 7 deletions trunk-recorder/systems/p25_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ std::vector<TrunkMessage> P25Parser::decode_tsbk(boost::dynamic_bitset<> &tsbk,

BOOST_LOG_TRIVIAL(debug) << "tsbk04\tUnit to Unit Chan Grant\tChannel ID: " << std::setw(5) << ch << "\tFreq: " << FormatFreq(f) << "\tTarget ID: " << std::setw(7) << ta << "\tTDMA " << get_tdma_slot(ch, sys_num) << "\tSource ID: " << sa;
} else if (opcode == 0x05) { // Unit To Unit Answer Request
BOOST_LOG_TRIVIAL(debug) << "tsbk05";
BOOST_LOG_TRIVIAL(debug) << "tsbk05: Unit To Unit Answer Request";
} else if (opcode == 0x06) { // Unit to Unit Voice Channel Grant Update (UU_V_CH_GRANT_UPDT)
//unsigned long mfrid = bitset_shift_mask(tsbk, 80, 0xff);
// unsigned long opts = bitset_shift_mask(tsbk,72,0xff);
Expand Down Expand Up @@ -488,7 +488,7 @@ std::vector<TrunkMessage> P25Parser::decode_tsbk(boost::dynamic_bitset<> &tsbk,
unsigned long op = bitset_shift_mask(tsbk, 48, 0xff);
unsigned long sa = bitset_shift_mask(tsbk, 16, 0xffffff);

message.message_type = ACKRESP;
message.message_type = ACKRESP;
message.talkgroup = ga;
message.source = sa;

Expand Down Expand Up @@ -537,9 +537,9 @@ std::vector<TrunkMessage> P25Parser::decode_tsbk(boost::dynamic_bitset<> &tsbk,

BOOST_LOG_TRIVIAL(debug) << "tsbk29 secondary cc: rfid " << std::dec << rfid << " stid " << stid << " ch1 " << ch1 << "(" << channel_id_to_string(ch1, sys_num) << ") ch2 " << ch2 << "(" << channel_id_to_string(ch2, sys_num) << ") ";
} else if (opcode == 0x2a) { // Group Affiliation Query
BOOST_LOG_TRIVIAL(debug) << "tsbk2a";
BOOST_LOG_TRIVIAL(debug) << "tsbk2a Group Affiliation Query";
} else if (opcode == 0x2b) { // Location Registration Response
BOOST_LOG_TRIVIAL(debug) << "tsbk2b";
BOOST_LOG_TRIVIAL(debug) << "tsbk2b Location Registration Response";
} else if (opcode == 0x2c) { // Unit Registration Response
// unsigned long mfrid = bitset_shift_mask(tsbk,80,0xff);
// unsigned long opts = bitset_shift_mask(tsbk,72,0xff);
Expand Down Expand Up @@ -634,7 +634,7 @@ std::vector<TrunkMessage> P25Parser::decode_tsbk(boost::dynamic_bitset<> &tsbk,

BOOST_LOG_TRIVIAL(debug) << "tsbk34 iden vhf/uhf id " << std::dec << iden << " toff " << toff * spac * 0.125 * 1e-3 << " spac " << spac * 0.125 << " freq " << freq * 0.000005 << " [ " << txt[toff_sign] << "]";
} else if (opcode == 0x35) { // Time and Date Announcement
BOOST_LOG_TRIVIAL(debug) << "tsbk35 time date ann";
BOOST_LOG_TRIVIAL(debug) << "tsbk35 Time and Date Announcement";
} else if (opcode == 0x36) { //
BOOST_LOG_TRIVIAL(debug) << "tsbk36";
} else if (opcode == 0x37) { //
Expand Down Expand Up @@ -685,13 +685,13 @@ std::vector<TrunkMessage> P25Parser::decode_tsbk(boost::dynamic_bitset<> &tsbk,
message.sys_id = syid;
message.freq = f1;
}
BOOST_LOG_TRIVIAL(debug) << "tsbk3b net stat: wacn " << std::dec << wacn << " syid " << syid << " ch1 " << ch1 << "(" << channel_id_to_string(ch1, sys_num) << ") ";
BOOST_LOG_TRIVIAL(trace) << "tsbk3b net stat: wacn " << std::dec << wacn << " syid " << syid << " ch1 " << ch1 << "(" << channel_id_to_string(ch1, sys_num) << ") ";
} else if (opcode == 0x3c) { // adjacent status
unsigned long rfid = bitset_shift_mask(tsbk, 48, 0xff);
unsigned long stid = bitset_shift_mask(tsbk, 40, 0xff);
unsigned long ch1 = bitset_shift_mask(tsbk, 24, 0xffff);
unsigned long f1 = channel_id_to_frequency(ch1, sys_num);
BOOST_LOG_TRIVIAL(debug) << "tsbk3c\tAdjacent Status\t rfid " << std::dec << rfid << " stid " << stid << " ch1 " << ch1 << "(" << channel_id_to_string(ch1, sys_num) << ") ";
BOOST_LOG_TRIVIAL(trace) << "tsbk3c\tAdjacent Status\t rfid " << std::dec << rfid << " stid " << stid << " ch1 " << ch1 << "(" << channel_id_to_string(ch1, sys_num) << ") ";

if (f1) {
it = channels[stid].find((ch1 >> 12) & 0xf);
Expand Down

0 comments on commit a4e5cd2

Please sign in to comment.