diff --git a/CMakeLists.txt b/CMakeLists.txt index 662a03e62..2b40c5b83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,7 +246,7 @@ list(APPEND trunk_recorder_sources lib/lfsr/lfsr.cxx lib/gr_blocks/freq_xlating_fft_filter.cc - lib/gr_blocks/nonstop_wavfile_sink_impl.cc + lib/gr_blocks/transmission_sink.cc lib/gr_blocks/decoders/fsync_decode.cc lib/gr_blocks/decoders/mdc_decode.cc lib/gr_blocks/decoders/star_decode.cc diff --git a/docs/notes/CALL-HANDLING.md b/docs/notes/CALL-HANDLING.md new file mode 100644 index 000000000..642bac8d7 --- /dev/null +++ b/docs/notes/CALL-HANDLING.md @@ -0,0 +1,73 @@ +```mermaid +flowchart TD +A[Control Channel] -->|GRANT| B["handle_call_grant()"] +B --> C{Existing Call on Freq?} +C -.->|Yes| D{Same Talkgroup?} +C -.->|No| G["new Call()"] +D -.->|Yes| E["call->set_record_more_transmissions(True)"] +D -.->|No| F[Delete Existing Call] +F -.-> G +G -.-> H["start_recording()"] +``` + +```mermaid +flowchart TD +A1[Voice Channel] --> B1[Transmission Sink] +B1 -.->|Samples| C1{State} +C1 -.->|STOPPED| D1[Drop Samples] +C1 -.->|IDLE| F1["Setup files\nrecord_more_transmissions = false;\nd_first_work = false;\nstate = RECORDING"] +C1 -.->|RECORDING| G1[Write Samples] +F1 -.-> G1 +B1 -.->|TERMINATOR| H1["End Transmission"] +H1 -.-> I1{"record_more_transmissions"} +I1 -.->|False| J1["state = STOPPED"] +I1 -.->|True| K1["state = IDLE"] +L1["set_record_more_transmissions(True)"] -.-> N1{state == STOPPED} +N1 -.->|True| O1["state == IDLE"] +N1 -.->|False| P1["record_mode_transmissions = True"] +O1 -.-> P1 +``` + + + + +```mermaid +flowchart TD +A[Control Channel] -->|UPDATE| B["handle_call_update()"] +B -.-> C[Find Call] +C -.-> D{"call->state"} +D -.->|COMPLETED| E[Do Nothing] +D -.->|INACTIVE| F["call->state==RECORDING"] +F -.-> G["call->update()"] +D -.->|RECORDING| G +G -.-> H["call->set_record_more_transmissions(True)"] + +``` + + +```mermaid +flowchart TD +A[For Each Call] -->|Call| B{state} + + + +B -.->|RECORDING| C{"last_update > 1.0"} +C -.->|True| E["call->set_record_more_transmissions(false)\nstate = INACTIVE"] +C -.->|False| D[Next] +E -.-> D +B -.->|MONITORING| F{"last_update > 1.0"} +F -.->|True| G["Delete Call"] +G -.-> D +F -.->|False| D +B -.->|COMPLETED| H["Conclude Call"] +H -.-> Z["Delete Call"] +Z -.-> D +B -.->|INACTIVE| I{"since last_update > 5.0"} +I -.->|True| J[state = COMPLETED] +J -.-> K[Conclude Call] +K -.-> L[Delete Call] +I -.->|False| D +L -.-> D + + +``` diff --git a/docs/notes/STATES.md b/docs/notes/STATES.md index 9c519b0fa..181c22ac7 100644 --- a/docs/notes/STATES.md +++ b/docs/notes/STATES.md @@ -25,13 +25,13 @@ If there is an existing Call that covers all of this, then it will simply be upd If not, a new Call is created and an attempt to start a recording is made by calling **start_recorder()**. **start_recorder()** first checks to see if a talkgroup entry is defined in the *talkgroup.csv* file for the talkgroup number in the message. If the **recordUnknown** flag is set to false in the *config.json* and a talkgroup entry is not found, then a recording will not be started. Encrypted transmissions are not recorded. If a talkgroup entry does exist and the talkgroup is marked as encrypted, it will be skipped. The same is true if the message's encrypted flag is set. -After these checks, **start_recorder()** will now try to assign a recorder. It does this by going through the Sources and finding the first one that covers the frequency in the message. The function will then try to get either an analog or digital recorder from the Source by calling **get_analog_recorder()** or **get_digital_recorder()**, respectively. The **get_analog_recorder()** and **get_digital_recorder()** functions in *source.cc* simply go through the vector of Recorders that were created for that Source and checking their state. The first recorder with the state of **available** is returned. For both types of recorders, their state actually comes from nonstop_wavefile_sink block that is at the end of the recorders gnuradio graph. We will dive into that lifecycle later. The nonstop_wavefile_sink block that part of the recorder, will receive some information about the call and will set its state to **idle** +After these checks, **start_recorder()** will now try to assign a recorder. It does this by going through the Sources and finding the first one that covers the frequency in the message. The function will then try to get either an analog or digital recorder from the Source by calling **get_analog_recorder()** or **get_digital_recorder()**, respectively. The **get_analog_recorder()** and **get_digital_recorder()** functions in *source.cc* simply go through the vector of Recorders that were created for that Source and checking their state. The first recorder with the state of **available** is returned. For both types of recorders, their state actually comes from transmission_sink block that is at the end of the recorders gnuradio graph. We will dive into that lifecycle later. The transmission_sink block that part of the recorder, will receive some information about the call and will set its state to **idle** Back in *main.cc*, if a recorder was return, it is associated with the call and the call's state is set to **recording**. If it wasn't possible to get a recorder, the call's state is set to **monitoring**. This serves to track that the Talkgroup will be on that frequency and that Trunk Recorder does not have to try and assign a recorder everytime it gets an **UPDATE** trunking message. When a **GRANT** or **UPDATE** message comes in and goes through **handle_call()**, the function will see that a call has already been assigned and will call that call's **update()** function. This function simply sets the call's *last_update* variable to the current time. -As voice samples make their way through the recorder, they eventually end up in the **nonstop_wav_file_sink_impl.cc** block. When a wav_sink and its recorder are first associated with a call, its state is initially set to **idle**. When in **idle** and a voice sample comes in, the wav_sink will change its state to **recording**, open a new file and being writing samples to it. The wav_sink starts a *Transmission* which tracks each of the indivdiual transmissions that make up a call on a digital system. The variable *d_stop_time* is also updated with the current time. This is used in analog systems to determine is there has been a break in writing to the file, signaling a new file should be started. +As voice samples make their way through the recorder, they eventually end up in the **transmission_sink.cc** block. When a wav_sink and its recorder are first associated with a call, its state is initially set to **idle**. When in **idle** and a voice sample comes in, the wav_sink will change its state to **recording**, open a new file and being writing samples to it. The wav_sink starts a *Transmission* which tracks each of the indivdiual transmissions that make up a call on a digital system. The variable *d_stop_time* is also updated with the current time. This is used in analog systems to determine is there has been a break in writing to the file, signaling a new file should be started. In digital system, a Terminator Data Unit (TDU) is sent on the voice channel at the start and end of the call. The digital recorder processes this and passes it along to the wav_sink. When the wav_sink is in the state **recording**, signifying it has written samples to a file, and it receieves a TDU it will end the current transmission. The wav_sink has an internal flag called *record_more_transmissions*. If this flag is set to *false* the wav_sink's state will be set to **stopped**, otherwise it will be set to **idle**. When a wav_sink is in state **stopped**, any voice samples that come in will be dropped and not written to a file, and new Transmission will not be created. However, when the state is **idle**, it will operate like it was just created. diff --git a/lib/gr_blocks/nonstop_wavfile_sink.h b/lib/gr_blocks/nonstop_wavfile_sink.h deleted file mode 100644 index d29871375..000000000 --- a/lib/gr_blocks/nonstop_wavfile_sink.h +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2009,2013 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_GR_NONSTOP_WAVFILE_SINK_H -#define INCLUDED_GR_NONSTOP_WAVFILE_SINK_H - -#include "../../trunk-recorder/global_structs.h" -#include "../../trunk-recorder/formatter.h" - -//#include "../trunk-recorder/call_conventional.h" -#include -#include -#include - -class Call; -struct Transmission; -namespace gr { -namespace blocks { - -/*! - * \brief Write stream to a Microsoft PCM (.wav) file. - * \ingroup audio_blk - * - * \details - * Values must be floats within [-1;1]. - * Check gr_make_wavfile_sink() for extra info. - */ -class BLOCKS_API nonstop_wavfile_sink : virtual public sync_block -{ -public: - // gr::blocks::wavfile_sink::sptr - - #if GNURADIO_VERSION < 0x030900 - typedef boost::shared_ptr sptr; - #else - typedef std::shared_ptr sptr; - #endif - - - /*! - * \brief Opens a new file and writes a WAV header. Thread-safe. - */ - virtual bool start_recording(Call* call) = 0; - virtual bool start_recording(Call* call, int slot) = 0; - /*! - * \brief Closes the currently active file and completes the WAV - * header. Thread-safe. - */ - virtual void stop_recording() = 0; - - /*! - * \brief Set the sample rate. This will not affect the WAV file - * currently opened. Any following open() calls will use this new - * sample rate. - */ - virtual void set_sample_rate(unsigned int sample_rate) = 0; - - /*! - * \brief Set bits per sample. This will not affect the WAV file - * currently opened (see set_sample_rate()). If the value is - * neither 8 nor 16, the call is ignored and the current value - * is kept. - */ - - virtual void set_source(long src) {}; - virtual void set_bits_per_sample(int bits_per_sample) = 0; - virtual double total_length_in_seconds() = 0; - virtual double length_in_seconds() = 0; - virtual State get_state() = 0; - virtual std::vector get_transmission_list() = 0; - virtual time_t get_stop_time() = 0; - virtual void set_record_more_transmissions(bool more) = 0; - -}; - -} /* namespace blocks */ -} /* namespace gr */ - -#endif /* INCLUDED_GR_WAVFILE_SINK_H */ diff --git a/lib/gr_blocks/nonstop_wavfile_sink_impl.cc b/lib/gr_blocks/transmission_sink.cc similarity index 60% rename from lib/gr_blocks/nonstop_wavfile_sink_impl.cc rename to lib/gr_blocks/transmission_sink.cc index b1a7ce553..fd0aacd8d 100644 --- a/lib/gr_blocks/nonstop_wavfile_sink_impl.cc +++ b/lib/gr_blocks/transmission_sink.cc @@ -22,8 +22,7 @@ */ -#include "nonstop_wavfile_sink.h" -#include "nonstop_wavfile_sink_impl.h" +#include "transmission_sink.h" #include "../../trunk-recorder/call.h" #include #include @@ -54,33 +53,32 @@ namespace gr { namespace blocks { -nonstop_wavfile_sink_impl::sptr -nonstop_wavfile_sink_impl::make(int n_channels, unsigned int sample_rate, int bits_per_sample) { - return gnuradio::get_initial_sptr(new nonstop_wavfile_sink_impl(n_channels, sample_rate, bits_per_sample)); +transmission_sink::sptr +transmission_sink::make(int n_channels, unsigned int sample_rate, int bits_per_sample) { + return gnuradio::get_initial_sptr(new transmission_sink(n_channels, sample_rate, bits_per_sample)); } -nonstop_wavfile_sink_impl::nonstop_wavfile_sink_impl( +transmission_sink::transmission_sink( int n_channels, unsigned int sample_rate, int bits_per_sample) - : sync_block("nonstop_wavfile_sink", + : sync_block("transmission_sink", io_signature::make(1, n_channels, sizeof(int16_t)), io_signature::make(0, 0, 0)), d_sample_rate(sample_rate), d_nchans(n_channels), - d_fp(0), d_current_call(NULL) { + d_current_call(NULL), d_fp(0) { if ((bits_per_sample != 8) && (bits_per_sample != 16)) { throw std::runtime_error("Invalid bits per sample (supports 8 and 16)"); } d_bytes_per_sample = bits_per_sample / 8; d_sample_count = 0; d_slot = -1; - d_first_work = true; d_termination_flag = false; state = AVAILABLE; } //static int rec_counter=0; -void nonstop_wavfile_sink_impl::create_base_filename() { +void transmission_sink::create_base_filename() { time_t work_start_time = d_start_time; std::stringstream path_stream; tm *ltm = localtime(&work_start_time); @@ -102,17 +100,17 @@ void nonstop_wavfile_sink_impl::create_base_filename() { } } -char *nonstop_wavfile_sink_impl::get_filename() { +char *transmission_sink::get_filename() { return current_filename; } -bool nonstop_wavfile_sink_impl::start_recording(Call *call, int slot) { +bool transmission_sink::start_recording(Call *call, int slot) { this->d_slot = slot; this->start_recording(call); return true; } -bool nonstop_wavfile_sink_impl::start_recording(Call *call) { +bool transmission_sink::start_recording(Call *call) { gr::thread::scoped_lock guard(d_mutex); if (d_current_call && d_fp) { BOOST_LOG_TRIVIAL(trace) << "Start() - Current_Call & fp are not null! current_filename is: " << current_filename << " Length: " << d_sample_count << std::endl; @@ -125,13 +123,14 @@ bool nonstop_wavfile_sink_impl::start_recording(Call *call) { d_current_call_short_name = call->get_short_name(); d_current_call_capture_dir = call->get_capture_dir(); d_prior_transmission_length = 0; + d_error_count = 0; + d_spike_count = 0; record_more_transmissions = true; this->clear_transmission_list(); d_conventional = call->is_conventional(); curr_src_id = d_current_call->get_current_source_id(); d_sample_count = 0; - d_first_work = true; // when a wav_sink first gets associated with a call, set its lifecycle to idle; state = IDLE; @@ -140,12 +139,12 @@ bool nonstop_wavfile_sink_impl::start_recording(Call *call) { char formattedTalkgroup[62]; snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); - BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tStarting wavfile sink "; + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tStarting wavfile sink SRC ID: " << curr_src_id; return true; } -bool nonstop_wavfile_sink_impl::open_internal(const char *filename) { +bool transmission_sink::open_internal(const char *filename) { int d_first_sample_pos; unsigned d_samples_per_chan; @@ -169,7 +168,7 @@ bool nonstop_wavfile_sink_impl::open_internal(const char *filename) { } if (strlen(filename) >= 255) { - BOOST_LOG_TRIVIAL(error) << "nonstop_wavfile_sink: Error! filename longer than 255"; + BOOST_LOG_TRIVIAL(error) << "transmission_sink: Error! filename longer than 255"; } if ((d_fp = fdopen(fd, "rb+")) == NULL) { @@ -180,7 +179,6 @@ bool nonstop_wavfile_sink_impl::open_internal(const char *filename) { } d_sample_count = 0; - d_first_work = true; if (!wavheader_write(d_fp, d_sample_rate, d_nchans, d_bytes_per_sample)) { fprintf(stderr, "[%s] could not write to WAV file\n", __FILE__); @@ -202,7 +200,7 @@ bool nonstop_wavfile_sink_impl::open_internal(const char *filename) { return true; } -void nonstop_wavfile_sink_impl::set_source(long src) { +void transmission_sink::set_source(long src) { gr::thread::scoped_lock guard(d_mutex); char formattedTalkgroup[62]; @@ -219,22 +217,22 @@ void nonstop_wavfile_sink_impl::set_source(long src) { BOOST_LOG_TRIVIAL(error) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tUnit ID externally set, ext: "<< src << "\tcurrent: " << curr_src_id << "\t samples: " << d_sample_count; - if (d_sample_count > 0) { + /*if (d_sample_count > 0) { end_transmission(); - } - - if (!record_more_transmissions) { + }*/ + BOOST_LOG_TRIVIAL(info) << "ENDING TRANSMISSION Voice Channel mismatch source id - current: "<< curr_src_id << " new: " << src; + //state = STOPPED; + /*if (!record_more_transmissions) { state = STOPPED; } else { state = IDLE; - d_first_work = true; - } + }*/ } curr_src_id = src; } } -void nonstop_wavfile_sink_impl::end_transmission() { +void transmission_sink::end_transmission() { if (d_sample_count > 0) { if (d_fp) { close_wav(false); @@ -247,6 +245,8 @@ void nonstop_wavfile_sink_impl::end_transmission() { transmission.start_time = d_start_time; // Start time of the Call transmission.stop_time = d_stop_time; // when the Call eneded transmission.sample_count = d_sample_count; + transmission.spike_count = d_spike_count; + transmission.error_count = d_error_count; transmission.length = length_in_seconds(); // length in seconds d_prior_transmission_length = d_prior_transmission_length + transmission.length; strcpy(transmission.filename, current_filename); // Copy the filename @@ -254,13 +254,15 @@ void nonstop_wavfile_sink_impl::end_transmission() { this->add_transmission(transmission); d_sample_count = 0; - d_first_work = true; + d_error_count = 0; + d_spike_count = 0; + curr_src_id = -1; } else { BOOST_LOG_TRIVIAL(error) << "Trying to end a Transmission, but the sample_count is 0" << std::endl; } } -void nonstop_wavfile_sink_impl::stop_recording() { +void transmission_sink::stop_recording() { gr::thread::scoped_lock guard(d_mutex); if (d_sample_count > 0) { @@ -271,31 +273,30 @@ void nonstop_wavfile_sink_impl::stop_recording() { BOOST_LOG_TRIVIAL(trace) << "stop_recording() - stopping wavfile sink but recorder state is: " << state << std::endl; } d_current_call = NULL; - d_first_work = true; d_termination_flag = false; state = AVAILABLE; } -void nonstop_wavfile_sink_impl::close_wav(bool close_call) { +void transmission_sink::close_wav(bool close_call) { unsigned int byte_count = d_sample_count * d_bytes_per_sample; wavheader_complete(d_fp, byte_count); fclose(d_fp); d_fp = NULL; } -nonstop_wavfile_sink_impl::~nonstop_wavfile_sink_impl() { +transmission_sink::~transmission_sink() { stop_recording(); } -bool nonstop_wavfile_sink_impl::stop() { +bool transmission_sink::stop() { return true; } -State nonstop_wavfile_sink_impl::get_state() { +State transmission_sink::get_state() { return this->state; } -int nonstop_wavfile_sink_impl::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { +int transmission_sink::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { gr::thread::scoped_lock guard(d_mutex); // hold mutex for duration of this @@ -319,7 +320,7 @@ int nonstop_wavfile_sink_impl::work(int noutput_items, gr_vector_const_void_star char formattedTalkgroup[62]; snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); - BOOST_LOG_TRIVIAL(error) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tDropping samples - Recorder state is: " << format_state(this->state); + BOOST_LOG_TRIVIAL(error) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tDropping " << noutput_items << " samples - Recorder state is: " << format_state(this->state); //BOOST_LOG_TRIVIAL(info) << "WAV - state is: " << format_state(this->state) << "\t Dropping samples: " << noutput_items << " Since close: " << its_been << std::endl; } @@ -327,46 +328,81 @@ int nonstop_wavfile_sink_impl::work(int noutput_items, gr_vector_const_void_star } std::vector tags; - pmt::pmt_t this_key(pmt::intern("src_id")); - pmt::pmt_t that_key(pmt::intern("terminate")); + pmt::pmt_t src_id_key(pmt::intern("src_id")); + pmt::pmt_t terminate_key(pmt::intern("terminate")); + pmt::pmt_t spike_count_key(pmt::intern("spike_count")); + pmt::pmt_t error_count_key(pmt::intern("error_count")); //pmt::pmt_t squelch_key(pmt::intern("squelch_eob")); - get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0) + noutput_items); - + //get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0) + noutput_items); + get_tags_in_window(tags, 0, 0, noutput_items); unsigned pos = 0; //long curr_src_id = 0; for (unsigned int i = 0; i < tags.size(); i++) { //BOOST_LOG_TRIVIAL(info) << "TAG! " << tags[i].key; - if (pmt::eq(this_key, tags[i].key)) { + if (pmt::eq(src_id_key, tags[i].key)) { long src_id = pmt::to_long(tags[i].value); pos = d_sample_count + (tags[i].offset - nitems_read(0)); if (curr_src_id == -1) { - BOOST_LOG_TRIVIAL(info) << "Updated Voice Channel source id: " << src_id << " pos: " << pos << " offset: " << tags[i].offset - nitems_read(0); + //BOOST_LOG_TRIVIAL(info) << "Updated Voice Channel source id: " << src_id << " pos: " << pos << " offset: " << tags[i].offset - nitems_read(0); curr_src_id = src_id; } else if (src_id != curr_src_id) { if (state == RECORDING) { - if (d_sample_count > 0) { - end_transmission(); - } + //BOOST_LOG_TRIVIAL(info) << "ENDING TRANSMISSION from TAGS Voice Channel mismatch source id - current: "<< curr_src_id << " new: " << src_id << " pos: " << pos << " offset: " << tags[i].offset - nitems_read(0); + /* + if (d_conventional && (d_sample_count > 0)) { + end_transmission(); + state = IDLE; + } + state = STOPPED; if (!record_more_transmissions) { state = STOPPED; } else { state = IDLE; - d_first_work = true; - } + }*/ + + curr_src_id = src_id; } - BOOST_LOG_TRIVIAL(info) << "Updated Voice Channel source id: " << src_id << " pos: " << pos << " offset: " << tags[i].offset - nitems_read(0); + //BOOST_LOG_TRIVIAL(info) << "Updated Voice Channel source id: " << src_id << " pos: " << pos << " offset: " << tags[i].offset - nitems_read(0); - curr_src_id = src_id; } - + } - if (pmt::eq(that_key, tags[i].key)) { + if (pmt::eq(terminate_key, tags[i].key)) { d_termination_flag = true; + pos = d_sample_count + (tags[i].offset - nitems_read(0)); + char formattedTalkgroup[62]; + snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); + std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); + + //BOOST_LOG_TRIVIAL(info) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tTermination - rec sample count " << d_sample_count << " pos: " << pos << " offset: " << tags[i].offset; + + + //BOOST_LOG_TRIVIAL(info) << "TERMINATOR!!"; + } + + // Only process Spike and Error Count tags if the sink is currently recording + if (state == RECORDING) { + if (pmt::eq(spike_count_key, tags[i].key)) { + d_spike_count = pmt::to_long(tags[i].value); + char formattedTalkgroup[62]; + snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); + std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); + + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tSpike Count: " << d_spike_count << " pos: " << pos << " offset: " << tags[i].offset; + } + if (pmt::eq(error_count_key, tags[i].key)) { + d_error_count = pmt::to_long(tags[i].value); + char formattedTalkgroup[62]; + snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); + std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); + + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tError Count: " << d_error_count << " pos: " << pos << " offset: " << tags[i].offset; + } } } tags.clear(); @@ -378,71 +414,103 @@ int nonstop_wavfile_sink_impl::work(int noutput_items, gr_vector_const_void_star return nwritten; } -time_t nonstop_wavfile_sink_impl::get_start_time() { +time_t transmission_sink::get_start_time() { return d_start_time; } -time_t nonstop_wavfile_sink_impl::get_stop_time() { +time_t transmission_sink::get_stop_time() { return d_stop_time; } -void nonstop_wavfile_sink_impl::add_transmission(Transmission t) { +void transmission_sink::add_transmission(Transmission t) { transmission_list.push_back(t); } -void nonstop_wavfile_sink_impl::set_record_more_transmissions(bool more) { +void transmission_sink::set_record_more_transmissions(bool more) { + if (record_more_transmissions != more) { + BOOST_LOG_TRIVIAL(trace) << "wav - setting record_more to: " << more << ", State: " << format_state(state) << " sample count: " << d_sample_count; + } + // If a Recorder is STOPPED and record_more_transmissions is false, prep it so it is ready to go. + if ((record_more_transmissions == false) && (more == true) && (state == STOPPED)) { + d_sample_count = 0; + state = IDLE; + } + + record_more_transmissions = more; + } -void nonstop_wavfile_sink_impl::clear_transmission_list() { +void transmission_sink::clear_transmission_list() { transmission_list.clear(); transmission_list.shrink_to_fit(); } -std::vector nonstop_wavfile_sink_impl::get_transmission_list() { +std::vector transmission_sink::get_transmission_list() { return transmission_list; } -int nonstop_wavfile_sink_impl::dowork(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { +int transmission_sink::dowork(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { // block int n_in_chans = input_items.size(); int16_t sample_buf_s; - int nwritten; + int nwritten=0; - + // A Termination Tag was receive if (d_termination_flag) { + d_termination_flag = false; + + char formattedTalkgroup[62]; + snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); + std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); if (d_current_call == NULL) { - BOOST_LOG_TRIVIAL(error) << "wav - no current call in temination loop"; + BOOST_LOG_TRIVIAL(error) << "wav - no current call, but in temination loop"; state = STOPPED; + return noutput_items; } if (d_sample_count > 0) { - end_transmission(); + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tTERM - record_more_transmissions = false, setting Recorder More: " << record_more_transmissions << " - count: " << d_sample_count; + + end_transmission(); + + + + // If it is a conventional call or an UPDATE or GRANT message has been received recently, + // then set it in IDLE state, which allows a new transmission to start. + if (d_conventional || (record_more_transmissions == true)) { + state = IDLE; + } else { + state = STOPPED; + } + + if (noutput_items > 1) { + char formattedTalkgroup[62]; + snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); + std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tTERM - skipped: " << noutput_items; + + } } + // In order to actually transmit the Tag, you need to attach it to a sample. An empty sample is used and it should be discarded. + return noutput_items; + } + + + + if (state == IDLE) { if (!record_more_transmissions) { char formattedTalkgroup[62]; snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); - BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\trecord_more_transmissions is false, setting recorder state to STOPPED"; - BOOST_LOG_TRIVIAL(trace) << "Call completed - putting recorder into state Completed - we had samples"; - - state = STOPPED; - } else { - state = IDLE; - d_first_work = true; + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tWAV - Weird! State was IDLE but record_more_transmissions was FALSE - count: " << d_sample_count; } - d_termination_flag = false; - - return noutput_items; - } - - if (d_first_work) { if (d_fp) { // if we are already recording a file for this call, close it before starting a new one. - BOOST_LOG_TRIVIAL(info) << "WAV - Weird! we have an existing FP, but d_first_work was true: " << current_filename << std::endl; + BOOST_LOG_TRIVIAL(info) << "WAV - Weird! we have an existing FP, but STATE was IDLE: " << current_filename << std::endl; close_wav(false); } @@ -465,11 +533,11 @@ int nonstop_wavfile_sink_impl::dowork(int noutput_items, gr_vector_const_void_st char formattedTalkgroup[62]; snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); - BOOST_LOG_TRIVIAL(info) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tStarting new Transmission \tSrc ID: " << curr_src_id; + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tStarting new Transmission \tSrc ID: " << curr_src_id; //curr_src_id = d_current_call->get_current_source_id(); - - d_first_work = false; + record_more_transmissions = false; + state = RECORDING; } if (!d_fp) // drop output on the floor @@ -478,31 +546,35 @@ int nonstop_wavfile_sink_impl::dowork(int noutput_items, gr_vector_const_void_st return noutput_items; } - for (nwritten = 0; nwritten < noutput_items; nwritten++) { - for (int chan = 0; chan < d_nchans; chan++) { - // Write zeros to channels which are in the WAV file - // but don't have any inputs here - if (chan < n_in_chans) { - int16_t **in = (int16_t **)&input_items[0]; - sample_buf_s = in[chan][nwritten]; - } else { - sample_buf_s = 0; - } + if (state == RECORDING) { + for (nwritten = 0; nwritten < noutput_items; nwritten++) { + for (int chan = 0; chan < d_nchans; chan++) { + // Write zeros to channels which are in the WAV file + // but don't have any inputs here + if (chan < n_in_chans) { + int16_t **in = (int16_t **)&input_items[0]; + sample_buf_s = in[chan][nwritten]; + } else { + sample_buf_s = 0; + } - wav_write_sample(d_fp, sample_buf_s, d_bytes_per_sample); + wav_write_sample(d_fp, sample_buf_s, d_bytes_per_sample); - d_sample_count++; + d_sample_count++; + } } } - if (nwritten > 0) { - state = RECORDING; + if (nwritten < noutput_items) { + char formattedTalkgroup[62]; + snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, d_current_call_talkgroup, 0x1B); + std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); + BOOST_LOG_TRIVIAL(error) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << formattedTalkgroup << "\tFreq: " << format_freq(d_current_call_freq) << "\tFailed to Write! Wrote: " << nwritten << " of " << noutput_items; } - // fflush (d_fp); // this is added so unbuffered content is written. - return nwritten; + return noutput_items; } -void nonstop_wavfile_sink_impl::set_bits_per_sample(int bits_per_sample) { +void transmission_sink::set_bits_per_sample(int bits_per_sample) { gr::thread::scoped_lock guard(d_mutex); if ((bits_per_sample == 8) || (bits_per_sample == 16)) { @@ -510,26 +582,26 @@ void nonstop_wavfile_sink_impl::set_bits_per_sample(int bits_per_sample) { } } -void nonstop_wavfile_sink_impl::set_sample_rate(unsigned int sample_rate) { +void transmission_sink::set_sample_rate(unsigned int sample_rate) { gr::thread::scoped_lock guard(d_mutex); d_sample_rate = sample_rate; } -int nonstop_wavfile_sink_impl::bits_per_sample() { +int transmission_sink::bits_per_sample() { return d_bytes_per_sample * 8; } unsigned int -nonstop_wavfile_sink_impl::sample_rate() { +transmission_sink::sample_rate() { return d_sample_rate; } -double nonstop_wavfile_sink_impl::total_length_in_seconds() { +double transmission_sink::total_length_in_seconds() { return this->length_in_seconds() + d_prior_transmission_length; } -double nonstop_wavfile_sink_impl::length_in_seconds() { +double transmission_sink::length_in_seconds() { // std::cout << "Filename: "<< current_filename << "Sample #: " << // d_sample_count << " rate: " << d_sample_rate << " bytes: " << // d_bytes_per_sample << "\n"; @@ -539,6 +611,6 @@ double nonstop_wavfile_sink_impl::length_in_seconds() { // d_sample_rate; } -void nonstop_wavfile_sink_impl::do_update() {} +void transmission_sink::do_update() {} } /* namespace blocks */ } /* namespace gr */ diff --git a/lib/gr_blocks/nonstop_wavfile_sink_impl.h b/lib/gr_blocks/transmission_sink.h similarity index 87% rename from lib/gr_blocks/nonstop_wavfile_sink_impl.h rename to lib/gr_blocks/transmission_sink.h index fd81a5682..a776cec07 100644 --- a/lib/gr_blocks/nonstop_wavfile_sink_impl.h +++ b/lib/gr_blocks/transmission_sink.h @@ -20,20 +20,28 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_GR_nonstop_wavfile_SINK_IMPL_H -#define INCLUDED_GR_nonstop_wavfile_SINK_IMPL_H +#ifndef INCLUDED_TRANSMISSION_SINK_H +#define INCLUDED_TRANSMISSION_SINK_H + -#include "nonstop_wavfile_sink.h" #include -//#include "wavfile.h" -#include #include +#include "../../trunk-recorder/global_structs.h" +#include "../../trunk-recorder/formatter.h" + +#include +#include +#include + +class Call; +struct Transmission; namespace gr { namespace blocks { -class nonstop_wavfile_sink_impl : public nonstop_wavfile_sink + +class BLOCKS_API transmission_sink : virtual public sync_block { private: @@ -49,6 +57,8 @@ class nonstop_wavfile_sink_impl : public nonstop_wavfile_sink bool d_termination_flag; time_t d_start_time; time_t d_stop_time; + long d_spike_count; + long d_error_count; long curr_src_id; char current_filename[255]; char current_base_filename[255]; @@ -92,9 +102,9 @@ class nonstop_wavfile_sink_impl : public nonstop_wavfile_sink #if GNURADIO_VERSION < 0x030900 - typedef boost::shared_ptr sptr; + typedef boost::shared_ptr sptr; #else - typedef std::shared_ptr sptr; + typedef std::shared_ptr sptr; #endif @@ -108,10 +118,10 @@ class nonstop_wavfile_sink_impl : public nonstop_wavfile_sink unsigned int sample_rate, int bits_per_sample = 16); - nonstop_wavfile_sink_impl(int n_channels, + transmission_sink(int n_channels, unsigned int sample_rate, int bits_per_sample); - virtual ~nonstop_wavfile_sink_impl(); + virtual ~transmission_sink(); void create_base_filename(); char *get_filename(); bool start_recording(Call *call); @@ -142,4 +152,5 @@ class nonstop_wavfile_sink_impl : public nonstop_wavfile_sink } /* namespace blocks */ } /* namespace gr */ -#endif /* INCLUDED_GR_nonstop_wavfile_SINK_IMPL_H */ +#endif + diff --git a/lib/op25_repeater/include/op25_repeater/p25_frame_assembler.h b/lib/op25_repeater/include/op25_repeater/p25_frame_assembler.h index 1d261a719..781764410 100644 --- a/lib/op25_repeater/include/op25_repeater/p25_frame_assembler.h +++ b/lib/op25_repeater/include/op25_repeater/p25_frame_assembler.h @@ -60,8 +60,6 @@ namespace gr { virtual void set_debug(int debug) {} virtual void reset_timer() {} virtual void set_phase2_tdma(bool p) {} - virtual void reset_rx_status() {} - virtual Rx_Status get_rx_status() {Rx_Status rx_status; return rx_status; } virtual void clear() {}; virtual void clear_silence_frame_count() {}; }; diff --git a/lib/op25_repeater/include/op25_repeater/rx_status.h b/lib/op25_repeater/include/op25_repeater/rx_status.h index 79e64b584..d7092751a 100644 --- a/lib/op25_repeater/include/op25_repeater/rx_status.h +++ b/lib/op25_repeater/include/op25_repeater/rx_status.h @@ -4,8 +4,8 @@ #include struct Rx_Status{ double total_len; - double error_count; - double spike_count; + long error_count; + long spike_count; time_t last_update; }; #endif diff --git a/lib/op25_repeater/lib/p25_frame_assembler_impl.cc b/lib/op25_repeater/lib/p25_frame_assembler_impl.cc index aa7d8d656..1f8fc2346 100644 --- a/lib/op25_repeater/lib/p25_frame_assembler_impl.cc +++ b/lib/op25_repeater/lib/p25_frame_assembler_impl.cc @@ -150,15 +150,6 @@ p25_frame_assembler_impl::forecast(int nof_output_items, gr_vector_int &nof_inpu std::fill(&nof_input_items_reqd[0], &nof_input_items_reqd[nof_inputs], nof_samples_reqd); } - - void p25_frame_assembler_impl::reset_rx_status() { - p1fdma.reset_rx_status(); - } - - Rx_Status p25_frame_assembler_impl::get_rx_status() { - return p1fdma.get_rx_status(); - } - void p25_frame_assembler_impl::clear() { p1fdma.clear(); } @@ -202,38 +193,44 @@ p25_frame_assembler_impl::general_work (int noutput_items, BOOST_LOG_TRIVIAL(trace) << "P25 Frame Assembler - Amt Prod: " << amt_produce << " output_queue: " << output_queue.size() << " noutput_items: " << noutput_items; + // output_queue.size() is the number of samples that were actually generated + // amt_produce just defaults to the standard amount expected for the block if (amt_produce > (int)output_queue.size()) { amt_produce = output_queue.size(); - } + } + if (amt_produce > 0) { long src_id = p1fdma.get_curr_src_id(); - if (src_id) { - // fprintf(stderr, "tagging source: %ld at %lu\n", src_id, - // nitems_written(0)); + // If a SRC wasn't received on the voice channel since the last check, it will be -1 + if (src_id > 0) { add_item_tag(0, nitems_written(0), d_tag_key, pmt::from_long(src_id), d_tag_src); } - + for (int i = 0; i < amt_produce; i++) { out[i] = output_queue[i]; } output_queue.erase(output_queue.begin(), output_queue.begin() + amt_produce); - /* - if (amt_produce < noutput_items) { - std::fill(out + amt_produce, out + noutput_items, 0); - amt_produce = noutput_items; - }*/ + BOOST_LOG_TRIVIAL(trace) << "setting silence_frame_count " << silence_frame_count << " to d_silence_frames: " << d_silence_frames << std::endl; silence_frame_count = d_silence_frames; } else { - - if (terminate_call) { - add_item_tag(0, nitems_written(0), pmt::intern("terminate"), pmt::from_long(1), d_tag_src); - std::fill(out, out + 1, 0); - amt_produce = 1; - //BOOST_LOG_TRIVIAL(info) << "Call Terminated, NO amount produced: " << amt_produce << " SRC: " << p1fdma.get_curr_src_id() << " n written " << nitems_written(0); + if (terminate_call) { + add_item_tag(0, nitems_written(0), pmt::intern("terminate"), pmt::from_long(1), d_tag_src ); + + Rx_Status status = p1fdma.get_rx_status(); + + // If something was recorded, send the number of Errors and Spikes that were counted during that period + if (status.total_len > 0 ) { + add_item_tag(0, nitems_written(0), pmt::intern("spike_count"), pmt::from_long(status.spike_count), d_tag_src); + add_item_tag(0, nitems_written(0), pmt::intern("error_count"), pmt::from_long(status.error_count), d_tag_src); + p1fdma.reset_rx_status(); + } + + std::fill(out, out + 1, 0); + amt_produce = 1; } if (silence_frame_count > 0) { std::fill(out, out + noutput_items, 0); @@ -243,7 +240,7 @@ p25_frame_assembler_impl::general_work (int noutput_items, } } consume_each(ninput_items[0]); - // Tell runtime system how many output items we produced. + // Tell runtime system how many output items we actually produced. return amt_produce; } diff --git a/lib/op25_repeater/lib/p25_frame_assembler_impl.h b/lib/op25_repeater/lib/p25_frame_assembler_impl.h index daeaa7d60..6040893a2 100644 --- a/lib/op25_repeater/lib/p25_frame_assembler_impl.h +++ b/lib/op25_repeater/lib/p25_frame_assembler_impl.h @@ -74,8 +74,6 @@ namespace gr { void p25p2_queue_msg(int duid); void set_phase2_tdma(bool p); - void reset_rx_status(); - Rx_Status get_rx_status(); public: diff --git a/lib/op25_repeater/lib/p25p1_fdma.cc b/lib/op25_repeater/lib/p25p1_fdma.cc index 6a4c9d9b3..ab92f5296 100644 --- a/lib/op25_repeater/lib/p25p1_fdma.cc +++ b/lib/op25_repeater/lib/p25p1_fdma.cc @@ -245,7 +245,10 @@ namespace gr { } long p25p1_fdma::get_curr_src_id() { - return curr_src_id; + long addr = curr_src_id; + curr_src_id = -1; + // This makes it easy to tell when a new Src Address has been received, all other times it will be -1 + return addr; } void p25p1_fdma::clear() { p1voice_decode.clear(); diff --git a/plugins/openmhz_uploader/openmhz_uploader.cc b/plugins/openmhz_uploader/openmhz_uploader.cc index c8738ddf9..42a818636 100644 --- a/plugins/openmhz_uploader/openmhz_uploader.cc +++ b/plugins/openmhz_uploader/openmhz_uploader.cc @@ -61,12 +61,6 @@ class Openmhz_Uploader : public Plugin_Api { source_list << std::fixed << std::setprecision(2); source_list << "["; - char formattedTalkgroup[62]; - snprintf(formattedTalkgroup, 61, "%c[%dm%10ld%c[0m", 0x1B, 35, call_info.talkgroup, 0x1B); - std::string talkgroup_display = boost::lexical_cast(formattedTalkgroup); - time_t start_time = call_info.start_time; - - if (call_info.transmission_source_list.size() != 0) { for (int i = 0; i < call_info.transmission_source_list.size(); i++) { @@ -82,6 +76,35 @@ class Openmhz_Uploader : public Plugin_Api { source_list << "]"; } + + std::ostringstream freq_list; + std::string freq_list_string; + freq_list << std::fixed << std::setprecision(2); + freq_list << "["; + + if (call_info.transmission_error_list.size() != 0) { + for (std::size_t i = 0; i < call_info.transmission_error_list.size(); i++) { + freq_list << "{\"freq\": " << std::fixed << std::setprecision(0) << call_info.freq << ", \"time\": " << call_info.transmission_error_list[i].time << ", \"pos\": " << std::fixed << std::setprecision(2) << call_info.transmission_error_list[i].position << ", \"len\": " << call_info.transmission_error_list[i].total_len << ", \"error_count\": \"" << std::setprecision(0) <(formattedTalkgroup); + time_t start_time = call_info.start_time; + + + //BOOST_LOG_TRIVIAL(error) << "Got source list: " << source_list.str(); CURL *curl; CURLMcode res; @@ -91,6 +114,7 @@ class Openmhz_Uploader : public Plugin_Api { freq_string = freq.str(); source_list_string = source_list.str(); + freq_list_string = freq_list.str(); call_length_string = call_length.str(); struct curl_httppost *formpost = NULL; @@ -156,7 +180,7 @@ class Openmhz_Uploader : public Plugin_Api { curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "freq_list", - CURLFORM_COPYCONTENTS, "[]", + CURLFORM_COPYCONTENTS, freq_list_string.c_str(), CURLFORM_END); curl = curl_easy_init(); diff --git a/plugins/rdioscanner_uploader/rdioscanner_uploader.cc b/plugins/rdioscanner_uploader/rdioscanner_uploader.cc index 3910552fd..f96f4de4b 100644 --- a/plugins/rdioscanner_uploader/rdioscanner_uploader.cc +++ b/plugins/rdioscanner_uploader/rdioscanner_uploader.cc @@ -122,6 +122,28 @@ class Rdio_Scanner_Uploader : public Plugin_Api { patch_list << "]"; } + + std::ostringstream freq_list; + std::string freq_list_string; + freq_list << std::fixed << std::setprecision(2); + freq_list << "["; + + if (call_info.transmission_error_list.size() != 0) { + for (std::size_t i = 0; i < call_info.transmission_error_list.size(); i++) { + freq_list << "{\"freq\": " << std::fixed << std::setprecision(0) << call_info.freq << ", \"time\": " << call_info.transmission_error_list[i].time << ", \"pos\": " << std::fixed << std::setprecision(2) << call_info.transmission_error_list[i].position << ", \"len\": " << call_info.transmission_error_list[i].total_len << ", \"errorCount\": " << std::setprecision(0) <get_recorder() != NULL) { + this->get_recorder()->set_record_more_transmissions(more); + } +} + +void Call::inactive_call() { + if (this->get_recorder() != NULL) { + // If the call is being recorded, check to see if the recorder is currently in an INACTIVE state. This means that the recorder is not + // doing anything and can be stopped. + if ((state == RECORDING) && this->get_recorder()->is_idle()) { + BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << this->get_call_num() << "C\033[0m\tTG: " << this->get_talkgroup_display() << "\tFreq: " << format_freq(get_freq()) << "\tStopping Recorded Call, setting call state to INACTIVE - Last Update: " << this->since_last_update() << "s"; + this->set_state(INACTIVE); + } + this->get_recorder()->set_record_more_transmissions(false); + } +} + void Call::stop_call() { if (this->get_recorder() != NULL) { @@ -87,10 +105,9 @@ void Call::stop_call() { BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << this->get_call_num() << "C\033[0m\tTG: " << this->get_talkgroup_display() << "\tFreq: " << format_freq(get_freq()) << "\tStopping Recorded Call, setting call state to COMPLETED - Last Update: " << this->since_last_update() << "s"; this->set_state(COMPLETED); } else { - BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << this->get_call_num() << "C\033[0m\tTG: " << this->get_talkgroup_display() << "\tFreq: " << format_freq(get_freq()) << "\tStopping Recorded Call, setting call state to INACTIVE - Last Update: " << this->since_last_update() << "s"; + BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << this->get_call_num() << "C\033[0m\tTG: " << this->get_talkgroup_display() << "\tFreq: " << format_freq(get_freq()) << "\tTrying to COMPLETE, Recorder still active, setting call state to INACTIVE - Last Update: " << this->since_last_update() << "s"; this->set_state(INACTIVE); } - this->get_recorder()->set_record_more_transmissions(false); } } long Call::get_call_num() { @@ -104,14 +121,6 @@ void Call::conclude_call() { if (state == COMPLETED) { final_length = recorder->get_current_length(); - if (freq_count > 0) { - Rx_Status rx_status = recorder->get_rx_status(); - if (rx_status.last_update > 0) - stop_time = rx_status.last_update; - freq_list[freq_count - 1].total_len = rx_status.total_len; - freq_list[freq_count - 1].spike_count = rx_status.spike_count; - freq_list[freq_count - 1].error_count = rx_status.error_count; - } if (!recorder) { BOOST_LOG_TRIVIAL(error) << "Call::end_call() State is recording, but no recorder assigned!"; } @@ -194,15 +203,6 @@ System *Call::get_system() { void Call::set_freq(double f) { if (f != curr_freq) { - - // if there call is being recorded and it isn't the first time the freq is being set - if (recorder && (freq_count > 0)) { - Rx_Status rx_status = recorder->get_rx_status(); - freq_list[freq_count - 1].total_len = rx_status.total_len; - freq_list[freq_count - 1].spike_count = rx_status.spike_count; - freq_list[freq_count - 1].error_count = rx_status.error_count; - } - curr_freq = f; } } @@ -351,15 +351,8 @@ bool Call::update(TrunkMessage message) { } int Call::since_last_update() { - /*long last_rx; - if (get_recorder() && (last_rx = recorder->get_rx_status().last_update)) { - BOOST_LOG_TRIVIAL(trace) << "temp.last_update: " << last_rx << " diff: " << time(NULL) - last_rx; - return time(NULL) - last_rx; - //last_update = temp.last_update; - } else {*/ BOOST_LOG_TRIVIAL(trace) << "last_update: " << last_update << " diff: " << time(NULL) - last_update; return time(NULL) - last_update; - //} } long Call::elapsed() { diff --git a/trunk-recorder/call.h b/trunk-recorder/call.h index 64ca88554..beba3a5b8 100644 --- a/trunk-recorder/call.h +++ b/trunk-recorder/call.h @@ -29,6 +29,8 @@ class Call { long get_call_num(); virtual ~Call(); virtual void restart_call(); + void set_record_more_transmissions(bool more); + void inactive_call(); void stop_call(); void conclude_call(); void set_sigmf_recorder(Recorder *r); diff --git a/trunk-recorder/call_concluder/call_concluder.cc b/trunk-recorder/call_concluder/call_concluder.cc index 3904fcc96..0b492d9d2 100644 --- a/trunk-recorder/call_concluder/call_concluder.cc +++ b/trunk-recorder/call_concluder/call_concluder.cc @@ -82,17 +82,21 @@ int create_call_json(Call_Data_t call_info) { } json_file << "],\n"; } - - json_file << "\"freqList\": ["; - json_file << "{ \"freq\": " << std::fixed << std::setprecision(0) << call_info.freq << ", \"time\": " << call_info.start_time << ", \"pos\": 0.0, \"len\": " << call_info.length << ", \"error_count\": 0.0, \"spike_count\": 0.0}"; - json_file << "],\n"; + json_file << "\"freqList\": [ "; + for (std::size_t i = 0; i < call_info.transmission_error_list.size(); i++) { + if (i != 0) { + json_file << ", "; + } + json_file << "{\"freq\": " << std::fixed << std::setprecision(0) << call_info.freq << ", \"time\": " << call_info.transmission_error_list[i].time << ", \"pos\": " << std::fixed << std::setprecision(2) << call_info.transmission_error_list[i].position << ", \"len\": " << call_info.transmission_error_list[i].total_len << ", \"error_count\": \"" << std::fixed << std::setprecision(0) << call_info.transmission_error_list[i].error_count << "\", \"spike_count\": \"" << call_info.transmission_error_list[i].spike_count << "\"}"; + } + json_file << " ],\n"; json_file << "\"srcList\": [ "; for (std::size_t i = 0; i < call_info.transmission_source_list.size(); i++) { if (i != 0) { json_file << ", "; } - json_file << "{\"src\": " << std::fixed << call_info.transmission_source_list[i].source << ", \"time\": " << call_info.transmission_source_list[i].time << ", \"pos\": " << call_info.transmission_source_list[i].position << ", \"emergency\": " << call_info.transmission_source_list[i].emergency << ", \"signal_system\": \"" << call_info.transmission_source_list[i].signal_system << "\", \"tag\": \"" << call_info.transmission_source_list[i].tag << "\"}"; + json_file << "{\"src\": " << std::fixed << call_info.transmission_source_list[i].source << ", \"time\": " << call_info.transmission_source_list[i].time << ", \"pos\": " << std::fixed << std::setprecision(2) << call_info.transmission_source_list[i].position << ", \"emergency\": " << call_info.transmission_source_list[i].emergency << ", \"signal_system\": \"" << call_info.transmission_source_list[i].signal_system << "\", \"tag\": \"" << call_info.transmission_source_list[i].tag << "\"}"; } json_file << " ]\n"; json_file << "}\n"; @@ -306,8 +310,9 @@ Call_Data_t Call_Concluder::create_call_data(Call *call, System *sys, Config con UnitTag *unit_tag = sys->find_unit_tag(t.source); std::string tag = (unit_tag == NULL || unit_tag->tag.empty() ? "" : unit_tag->tag); Call_Source call_source = {t.source, t.start_time, total_length, false, "", tag}; - + Call_Error call_error = {t.start_time,total_length,t.length, t.error_count, t.spike_count}; call_info.transmission_source_list.push_back(call_source); + call_info.transmission_error_list.push_back(call_error); total_length = total_length + t.length; } diff --git a/trunk-recorder/call_concluder/call_concluder.h b/trunk-recorder/call_concluder/call_concluder.h index 9999d0117..0aa6e5982 100644 --- a/trunk-recorder/call_concluder/call_concluder.h +++ b/trunk-recorder/call_concluder/call_concluder.h @@ -32,6 +32,8 @@ struct Call_Data_t { double freq; long start_time; long stop_time; + long error_count; + long spike_count; bool encrypted; bool emergency; bool audio_archive; @@ -53,6 +55,7 @@ struct Call_Data_t { bool phase2_tdma; std::vector transmission_source_list; + std::vector transmission_error_list; std::vector transmission_list; Call_Data_Status status; diff --git a/trunk-recorder/global_structs.h b/trunk-recorder/global_structs.h index b86a1e80e..33b73ebd4 100644 --- a/trunk-recorder/global_structs.h +++ b/trunk-recorder/global_structs.h @@ -7,6 +7,8 @@ struct Transmission { long start_time; long stop_time; long sample_count; + long spike_count; + long error_count; double freq; double length; char filename[255]; @@ -56,8 +58,9 @@ struct Call_Freq { }; struct Call_Error { - double freq; - double sample_count; + long time; + double position; + double total_len; double error_count; double spike_count; }; diff --git a/trunk-recorder/main.cc b/trunk-recorder/main.cc index 0fc34c5eb..949584f3a 100755 --- a/trunk-recorder/main.cc +++ b/trunk-recorder/main.cc @@ -611,7 +611,7 @@ bool start_recorder(Call *call, TrunkMessage message, System *sys) { if (!talkgroup && (sys->get_record_unknown() == false)) { if (sys->get_hideUnknown() == false) { - BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[33mNot Recording: TG not in Talkgroup File\u001b[0m "; + //BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[33mNot Recording: TG not in Talkgroup File\u001b[0m "; } return false; } @@ -624,7 +624,7 @@ bool start_recorder(Call *call, TrunkMessage message, System *sys) { if (call->get_encrypted() == true || (talkgroup && (talkgroup->mode.compare("E") == 0 || talkgroup->mode.compare("TE") == 0 || talkgroup->mode.compare("DE") == 0 ))) { if (sys->get_hideEncrypted() == false) { - BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[31mNot Recording: ENCRYPTED\u001b[0m "; + //BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[31mNot Recording: ENCRYPTED\u001b[0m "; } return false; } @@ -719,7 +719,7 @@ bool start_recorder(Call *call, TrunkMessage message, System *sys) { } if (!source_found) { - BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36mNot Recording: no source covering Freq\u001b[0m"; + //BOOST_LOG_TRIVIAL(info) << "[" << sys->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36mNot Recording: no source covering Freq\u001b[0m"; return false; } return false; @@ -820,12 +820,17 @@ void manage_calls() { } // Handle Trunked Calls - if ((call->since_last_update() > config.call_timeout) && ((state == RECORDING) || (state == MONITORING))) { + if ((call->since_last_update() > 1.0/*config.call_timeout*/) && ((state == RECORDING) || (state == MONITORING))) { if (state == RECORDING) { ended_call = true; - + call->set_record_more_transmissions(false); + call->set_state(INACTIVE); + // set the call state to inactive + + + // If the call is being recorded and the wav_sink is already hit a termination flag, the call state is set to COMPLETED - call->stop_call(); + //call->stop_call(); } // we do not need to stop Monitoring Calls, we can just delete them @@ -837,6 +842,8 @@ void manage_calls() { } } + + // If a call's state has been set to COMPLETED, we can conclude the call and delete it // we need to check the Call State again because it could have been updated by the previous command. if (call->get_state() == COMPLETED) { @@ -854,15 +861,15 @@ void manage_calls() { continue; } - // We are checking to make sure a Call has gotten stuck. If it is in the INACTIVE state + // We are checking to make sure a Call hasn't gotten stuck. If it is in the INACTIVE state if (state == INACTIVE) { Recorder *recorder = call->get_recorder(); if (recorder != NULL) { // if the recorder has simply been going for a while and a call is inactive, end things - if (recorder->since_last_write() > 10) { - BOOST_LOG_TRIVIAL(info) << "Recorder state: " << recorder->get_state(); - BOOST_LOG_TRIVIAL(error) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m Rec Num: " << recorder->get_num() << "\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36m Removing call with stuck recorder \u001b[0m"; + if (call->since_last_update() > config.call_timeout) { + //BOOST_LOG_TRIVIAL(info) << "Recorder state: " << recorder->get_state(); + BOOST_LOG_TRIVIAL(trace) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36m Removing call that has been inactive for more than " << config.call_timeout << " Sec \u001b[0m Rec last write: " << recorder->since_last_write() << " State: " << recorder->get_state(); // since the Call state is INACTIVE and the Recorder has been going on for a while, we can now // set the Call state to COMPLETED @@ -881,7 +888,7 @@ void manage_calls() { // In this case, the Call is inactive and was waiting for the recorder to finish. In this // case you can now conclude the call. - if ((recorder->get_state() == IDLE) || (recorder->get_state() == STOPPED)) { + /*if ((recorder->get_state() == IDLE) || (recorder->get_state() == STOPPED)) { //BOOST_LOG_TRIVIAL(info) << "Recorder state: " << format_state(recorder->get_state()); //BOOST_LOG_TRIVIAL(info) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36mCompleting Call, its state is INACTIVE and its recorder state is STOPPED or IDLE\u001b[0m"; // since the Call state is INACTIVE and the Recorder has reached a state of IDLE or STOPPED, we can now @@ -898,9 +905,9 @@ void manage_calls() { it = calls.erase(it); delete call; continue; - } + }*/ } else { - BOOST_LOG_TRIVIAL(error) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "\tTTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36m Call set to Inactive, but has no recorder\u001b[0m"; + BOOST_LOG_TRIVIAL(error) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36m Call set to Inactive, but has no recorder\u001b[0m"; } } @@ -960,16 +967,29 @@ void handle_call(TrunkMessage message, System *sys) { going until it gets a termination flag. */ - for (vector::iterator it = calls.begin(); it != calls.end(); ++it) { + //BOOST_LOG_TRIVIAL(info) << "TG: " << message.talkgroup << " sys num: "<< message.sys_num << " freq: " << message.freq << " TDMA Slot" << message.tdma_slot << " TDMA: " << message.phase2_tdma; + + for (vector::iterator it = calls.begin(); it != calls.end();) { Call *call = *it; - if ((call->get_state() != RECORDING) && (call->get_state() != MONITORING)) { + /* This will skip all calls that are not currently acitve */ + if (call->get_state() == COMPLETED) { + ++it; continue; } - //BOOST_LOG_TRIVIAL(info) << "TG: " << call->get_talkgroup() << " | " << message.talkgroup << " sys num: " << call->get_sys_num() << " | " << message.sys_num << " freq: " << call->get_freq() << " | " << message.freq << " TDMA Slot" << call->get_tdma_slot() << " | " << message.tdma_slot << " TDMA: " << call->get_phase2_tdma() << " | " << message.phase2_tdma; if ((call->get_talkgroup() == message.talkgroup) && (call->get_sys_num() == message.sys_num) && (call->get_freq() == message.freq) && (call->get_tdma_slot() == message.tdma_slot) && (call->get_phase2_tdma() == message.phase2_tdma)) { call_found = true; + + //BOOST_LOG_TRIVIAL(info) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36m GRANT Message for existing Call\u001b[0m"; + + if (call->get_state() == RECORDING) { + call->set_record_more_transmissions(true); + } + if (call->get_state() == INACTIVE) { + call->set_record_more_transmissions(true); + call->set_state(RECORDING); + } bool source_updated = call->update(message); if (source_updated) { plugman_call_start(call); @@ -979,10 +999,37 @@ void handle_call(TrunkMessage message, System *sys) { // There is an existing call on freq and slot that the new call will be started on. We should stop the older call. The older recorder will // keep writing to the file until it hits a termination flag, so no packets should be dropped. if ((call->get_state() == RECORDING) && (call->get_talkgroup() != message.talkgroup) && (call->get_sys_num() == message.sys_num) && (call->get_freq() == message.freq) && (call->get_tdma_slot() == message.tdma_slot) && (call->get_phase2_tdma() == message.phase2_tdma)) { - BOOST_LOG_TRIVIAL(info) << "\t - Stopping call because of overlapping Freq"; - call->stop_call(); + Recorder *recorder = call->get_recorder(); + string recorder_state = "UNKNOWN"; + if (recorder != NULL) { + recorder_state = format_state(recorder->get_state()); + } + BOOST_LOG_TRIVIAL(info) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36mStopping RECORDING call, Recorder State: " << recorder_state << " RX overlapping TG message Freq, TG:" << message.talkgroup << "\u001b[0m"; + + call->set_state(COMPLETED); + call->conclude_call(); + it = calls.erase(it); + delete call; + continue; } + // There is an existing call on freq and slot that the new call will be started on. We should stop the older call. The older recorder will + // keep writing to the file until it hits a termination flag, so no packets should be dropped. + if ((call->get_state() == INACTIVE) && (call->get_talkgroup() != message.talkgroup) && (call->get_sys_num() == message.sys_num) && (call->get_freq() == message.freq) && (call->get_tdma_slot() == message.tdma_slot) && (call->get_phase2_tdma() == message.phase2_tdma)) { + Recorder *recorder = call->get_recorder(); + string recorder_state = "UNKNOWN"; + if (recorder != NULL) { + recorder_state = format_state(recorder->get_state()); + } + BOOST_LOG_TRIVIAL(info) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36mStopping INACTIVE call, Recorder State: " << recorder_state << " RX overlapping TG message Freq TG:" << message.talkgroup << "\u001b[0m"; + + call->set_state(COMPLETED); + call->conclude_call(); + it = calls.erase(it); + delete call; + continue; + } + it++; } if (!call_found) { @@ -992,6 +1039,59 @@ void handle_call(TrunkMessage message, System *sys) { plugman_call_start(call); plugman_calls_active(calls); } + +} + + +void handle_call_update(TrunkMessage message, System *sys) { + bool call_found = false; + bool call_retune = false; + bool recording_started = false; + + /* Notes: it is possible for 2 Calls to exist for the same talkgroup on different freq. This happens when a Talkgroup starts on a freq + that current recorder can't retune to. In this case, the current orig Talkgroup reocrder will keep going on the old freq, while a new + recorder is start on a source that can cover that freq. This makes sure any of the remaining transmission that it is in the buffer + of the original recorder gets flushed. + UPDATED: however if we have 2 different talkgroups on the same freq we should do a stop_call on the original call since it is being used by another TG now. This will let the recorder keep + going until it gets a termination flag. + */ + + for (vector::iterator it = calls.begin(); it != calls.end(); ++it) { + Call *call = *it; + + /* This will skip all calls that are not currently acitve */ + if (call->get_state() == COMPLETED) { + continue; + } + + //BOOST_LOG_TRIVIAL(info) << "TG: " << call->get_talkgroup() << " | " << message.talkgroup << " sys num: " << call->get_sys_num() << " | " << message.sys_num << " freq: " << call->get_freq() << " | " << message.freq << " TDMA Slot" << call->get_tdma_slot() << " | " << message.tdma_slot << " TDMA: " << call->get_phase2_tdma() << " | " << message.phase2_tdma; + if ((call->get_talkgroup() == message.talkgroup) && (call->get_sys_num() == message.sys_num) && (call->get_freq() == message.freq) && (call->get_tdma_slot() == message.tdma_slot) && (call->get_phase2_tdma() == message.phase2_tdma)) { + call_found = true; + + if (call->get_state() == INACTIVE) { + // Only a RECORDING call can be set to INACTIVE + // We should be safe to set it to RECORDING if it starts to get UPDATE messages + call->set_state(RECORDING); + BOOST_LOG_TRIVIAL(trace) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36m Reactivating an INACTIVE Call \u001b[0m"; + } + //BOOST_LOG_TRIVIAL(info) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\tTG: " << call->get_talkgroup_display() << "\tFreq: " << format_freq(call->get_freq()) << "\t\u001b[36m Updating Call \u001b[0m"; + + + // It is helpful to have both GRANT and UPDATE messages allow for new calls to be started + // This is because GRANT message can be sometimes dropped if the control channel is not perfect + // In either event, when a Call times out and goes INACTIVE, then record_more_transmissions gets set to false + call->set_record_more_transmissions(true); + + bool source_updated = call->update(message); + if (source_updated) { + plugman_call_start(call); + } + } + } + + if (!call_found) { + //BOOST_LOG_TRIVIAL(error) << "Weird - call not found for UPDATE\tFreq: " << format_freq(message.freq) << "\tTG:" << message.freq; + } } @@ -1001,8 +1101,11 @@ void handle_message(std::vector messages, System *sys) { switch (message.message_type) { case GRANT: + handle_call_grant(message, sys); + break; + case UPDATE: - handle_call(message, sys); + handle_call_update(message, sys); break; case CONTROL_CHANNEL: @@ -1299,16 +1402,16 @@ bool setup_convetional_channel(System *system, double frequency, long channel_in if (system->has_channel_file()) { Talkgroup *tg = system->find_talkgroup_by_freq(frequency); call = new Call_conventional(tg->number, tg->freq, system, config); + call->set_talkgroup_tag(tg->alpha_tag); } 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; - } + BOOST_LOG_TRIVIAL(info) << "[" << system->get_short_name() << "]\tMonitoring " << system->get_system_type() << " 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); diff --git a/trunk-recorder/recorders/analog_recorder.cc b/trunk-recorder/recorders/analog_recorder.cc index 1e9de4627..55492bda3 100644 --- a/trunk-recorder/recorders/analog_recorder.cc +++ b/trunk-recorder/recorders/analog_recorder.cc @@ -2,7 +2,7 @@ #include "analog_recorder.h" #include #include -#include +#include #include "../formatter.h" #include "../recorder_globals.h" #include "../plugin_manager/plugin_manager.h" @@ -202,7 +202,7 @@ analog_recorder::analog_recorder(Source *src) //tm *ltm = localtime(&starttime); - wav_sink = gr::blocks::nonstop_wavfile_sink_impl::make(1, wav_sample_rate, 16); // Configurable + wav_sink = gr::blocks::transmission_sink::make(1, wav_sample_rate, 16); // Configurable if(use_streaming) { BOOST_LOG_TRIVIAL(info) << "Creating plugin sink..." << std::endl; diff --git a/trunk-recorder/recorders/analog_recorder.h b/trunk-recorder/recorders/analog_recorder.h index 9b3856990..dfc505540 100644 --- a/trunk-recorder/recorders/analog_recorder.h +++ b/trunk-recorder/recorders/analog_recorder.h @@ -49,7 +49,7 @@ class analog_recorder; #include #include #include -#include +#include #if GNURADIO_VERSION < 0x030900 @@ -150,7 +150,7 @@ class analog_recorder : public gr::hier_block2, public Recorder { gr::analog::quadrature_demod_cf::sptr demod; gr::blocks::float_to_short::sptr converter; - gr::blocks::nonstop_wavfile_sink::sptr wav_sink; + gr::blocks::transmission_sink::sptr wav_sink; gr::blocks::copy::sptr valve; gr::blocks::decoder_wrapper::sptr decoder_sink; diff --git a/trunk-recorder/recorders/debug_recorder.h b/trunk-recorder/recorders/debug_recorder.h index a7e84f3c6..0b5a37f07 100644 --- a/trunk-recorder/recorders/debug_recorder.h +++ b/trunk-recorder/recorders/debug_recorder.h @@ -58,7 +58,7 @@ #include "recorder.h" #include -#include + class Source; class debug_recorder; diff --git a/trunk-recorder/recorders/dmr_recorder.cc b/trunk-recorder/recorders/dmr_recorder.cc index d9654432b..33d0ea7c3 100644 --- a/trunk-recorder/recorders/dmr_recorder.cc +++ b/trunk-recorder/recorders/dmr_recorder.cc @@ -212,8 +212,8 @@ void dmr_recorder::initialize(Source *src) { const float l[] = {-2.0, 0.0, 2.0, 4.0}; std::vector slices(l, l + sizeof(l) / sizeof(l[0])); slicer = gr::op25_repeater::fsk4_slicer_fb::make(slices); - wav_sink_slot0 = gr::blocks::nonstop_wavfile_sink_impl::make(1, 8000, 16); - wav_sink_slot1 = gr::blocks::nonstop_wavfile_sink_impl::make(1, 8000, 16); + wav_sink_slot0 = gr::blocks::transmission_sink::make(1, 8000, 16); + wav_sink_slot1 = gr::blocks::transmission_sink::make(1, 8000, 16); //recorder->initialize(src); //OP25 Frame Assembler @@ -376,7 +376,6 @@ void dmr_recorder::tune_offset(double f) { lo->set_frequency(freq); } - //op25_frame_assembler->reset_rx_status(); } void dmr_recorder::set_record_more_transmissions(bool more) { @@ -403,9 +402,6 @@ std::vector dmr_recorder::get_transmission_list() { } -Rx_Status dmr_recorder::get_rx_status() { - return op25_frame_assembler->get_rx_status(); -} void dmr_recorder::stop() { @@ -419,8 +415,6 @@ void dmr_recorder::stop() { valve->set_enabled(false); wav_sink_slot0->stop_recording(); wav_sink_slot1->stop_recording(); - //op25_frame_assembler->reset_rx_status(); - } else { BOOST_LOG_TRIVIAL(error) << "dmr_recorder.cc: Trying to Stop an Inactive Logger!!!"; } diff --git a/trunk-recorder/recorders/dmr_recorder.h b/trunk-recorder/recorders/dmr_recorder.h index c0eadd1f0..190d1fb40 100644 --- a/trunk-recorder/recorders/dmr_recorder.h +++ b/trunk-recorder/recorders/dmr_recorder.h @@ -76,7 +76,7 @@ #include "recorder.h" #include -#include +#include #include class Source; @@ -125,7 +125,6 @@ class dmr_recorder : public gr::hier_block2, public Recorder { bool is_squelched(); std::vector get_transmission_list(); State get_state(); - Rx_Status get_rx_status(); int lastupdate(); long elapsed(); Source *get_source(); @@ -222,8 +221,8 @@ gr::op25_repeater::gardner_costas_cc::sptr costas_clock; gr::blocks::short_to_float::sptr converter_slot0; gr::blocks::short_to_float::sptr converter_slot1; gr::blocks::multiply_const_ff::sptr levels; - gr::blocks::nonstop_wavfile_sink::sptr wav_sink_slot0; - gr::blocks::nonstop_wavfile_sink::sptr wav_sink_slot1; + gr::blocks::transmission_sink::sptr wav_sink_slot0; + gr::blocks::transmission_sink::sptr wav_sink_slot1; gr::blocks::plugin_wrapper::sptr plugin_sink; }; diff --git a/trunk-recorder/recorders/p25_recorder.cc b/trunk-recorder/recorders/p25_recorder.cc index de2f21422..e51771c4a 100644 --- a/trunk-recorder/recorders/p25_recorder.cc +++ b/trunk-recorder/recorders/p25_recorder.cc @@ -359,10 +359,8 @@ void p25_recorder::tune_offset(double f) { if (!qpsk_mod) { fsk4_demod->reset(); - fsk4_p25_decode->reset_rx_status(); } else { qpsk_demod->reset(); - qpsk_p25_decode->reset_rx_status(); } } @@ -382,15 +380,6 @@ std::vector p25_recorder::get_transmission_list() { } } -Rx_Status p25_recorder::get_rx_status() { - if (qpsk_mod) { - return qpsk_p25_decode->get_rx_status(); - } else { - return fsk4_p25_decode->get_rx_status(); - } -} - - void p25_recorder::stop() { if (state == ACTIVE) { if (qpsk_mod) { @@ -405,10 +394,8 @@ void p25_recorder::stop() { valve->set_enabled(false); if (qpsk_mod) { qpsk_p25_decode->stop(); - qpsk_p25_decode->reset_rx_status(); } else { fsk4_p25_decode->stop(); - fsk4_p25_decode->reset_rx_status(); } } else { BOOST_LOG_TRIVIAL(error) << "p25_recorder.cc: Trying to Stop an Inactive Logger!!!"; diff --git a/trunk-recorder/recorders/p25_recorder.h b/trunk-recorder/recorders/p25_recorder.h index 0538b694a..c24d29ee1 100644 --- a/trunk-recorder/recorders/p25_recorder.h +++ b/trunk-recorder/recorders/p25_recorder.h @@ -54,7 +54,7 @@ #include "p25_recorder_decode.h" #include "p25_recorder_fsk4_demod.h" #include "p25_recorder_qpsk_demod.h" -#include +#include #include class Source; @@ -104,7 +104,6 @@ class p25_recorder : public gr::hier_block2, public Recorder { bool is_squelched(); std::vector get_transmission_list(); State get_state(); - Rx_Status get_rx_status(); int lastupdate(); long elapsed(); Source *get_source(); diff --git a/trunk-recorder/recorders/p25_recorder_decode.cc b/trunk-recorder/recorders/p25_recorder_decode.cc index d2c59242d..f97a7c123 100644 --- a/trunk-recorder/recorders/p25_recorder_decode.cc +++ b/trunk-recorder/recorders/p25_recorder_decode.cc @@ -64,19 +64,13 @@ void p25_recorder_decode::switch_tdma(bool phase2_tdma) { op25_frame_assembler->set_phase2_tdma(phase2_tdma); } -void p25_recorder_decode::reset_rx_status() { - op25_frame_assembler->reset_rx_status(); -} -Rx_Status p25_recorder_decode::get_rx_status() { - return op25_frame_assembler->get_rx_status(); -} void p25_recorder_decode::initialize( int silence_frames) { //OP25 Slicer const float l[] = {-2.0, 0.0, 2.0, 4.0}; std::vector slices(l, l + sizeof(l) / sizeof(l[0])); slicer = gr::op25_repeater::fsk4_slicer_fb::make(slices); - wav_sink = gr::blocks::nonstop_wavfile_sink_impl::make(1, 8000, 16); + wav_sink = gr::blocks::transmission_sink::make(1, 8000, 16); //recorder->initialize(src); bool use_streaming = d_recorder->get_enable_audio_streaming(); diff --git a/trunk-recorder/recorders/p25_recorder_decode.h b/trunk-recorder/recorders/p25_recorder_decode.h index b0e991576..77917f375 100644 --- a/trunk-recorder/recorders/p25_recorder_decode.h +++ b/trunk-recorder/recorders/p25_recorder_decode.h @@ -22,8 +22,7 @@ #include #endif -#include -#include +#include #include #include "recorder.h" @@ -52,7 +51,7 @@ class p25_recorder_decode : public gr::hier_block2 { gr::op25_repeater::fsk4_slicer_fb::sptr slicer; gr::blocks::short_to_float::sptr converter; gr::blocks::multiply_const_ss::sptr levels; - gr::blocks::nonstop_wavfile_sink::sptr wav_sink; + gr::blocks::transmission_sink::sptr wav_sink; gr::blocks::plugin_wrapper::sptr plugin_sink; public: p25_recorder_decode(Recorder* recorder); @@ -63,8 +62,6 @@ class p25_recorder_decode : public gr::hier_block2 { void switch_tdma(bool phase2_tdma); void start(Call *call); double since_last_write(); - void reset_rx_status(); - Rx_Status get_rx_status(); void stop(); int tdma_slot; bool delay_open; diff --git a/trunk-recorder/recorders/p25_recorder_fsk4_demod.cc b/trunk-recorder/recorders/p25_recorder_fsk4_demod.cc index 225107928..6d1dd792c 100644 --- a/trunk-recorder/recorders/p25_recorder_fsk4_demod.cc +++ b/trunk-recorder/recorders/p25_recorder_fsk4_demod.cc @@ -2,7 +2,7 @@ p25_recorder_fsk4_demod_sptr make_p25_recorder_fsk4_demod() { p25_recorder_fsk4_demod *recorder = new p25_recorder_fsk4_demod(); - //recorder->initialize(src, gr::blocks::nonstop_wavfile_sink_impl::make(1, 8000, 16, false)); + recorder->initialize(); return gnuradio::get_initial_sptr(recorder); } diff --git a/trunk-recorder/recorders/recorder.cc b/trunk-recorder/recorders/recorder.cc index 17540d468..a8354d3f0 100644 --- a/trunk-recorder/recorders/recorder.cc +++ b/trunk-recorder/recorders/recorder.cc @@ -15,11 +15,5 @@ boost::property_tree::ptree Recorder::get_stats() { node.put("count", recording_count); node.put("duration", recording_duration); node.put("state", get_state()); - - Rx_Status status = get_rx_status(); - node.put("status_len", status.total_len); - node.put("status_error", status.error_count); - node.put("status_spike", status.spike_count); - return node; } \ No newline at end of file diff --git a/trunk-recorder/recorders/recorder.h b/trunk-recorder/recorders/recorder.h index 8702f9d6a..19ad86bd9 100644 --- a/trunk-recorder/recorders/recorder.h +++ b/trunk-recorder/recorders/recorder.h @@ -58,7 +58,7 @@ #include "../state.h" #include "../call.h" -#include +#include #include @@ -91,10 +91,6 @@ class Recorder { virtual long get_talkgroup() { return 0; }; virtual void set_record_more_transmissions(bool more){}; virtual State get_state() { return INACTIVE; }; - virtual Rx_Status get_rx_status() { - Rx_Status rx_status = {0, 0, 0, 0}; - return rx_status; - } virtual std::string get_type() { return type; } virtual bool is_active() { return false; }; virtual bool is_analog() { return false; }; diff --git a/trunk-recorder/recorders/sigmf_recorder.cc b/trunk-recorder/recorders/sigmf_recorder.cc index aca59296f..7477feac8 100644 --- a/trunk-recorder/recorders/sigmf_recorder.cc +++ b/trunk-recorder/recorders/sigmf_recorder.cc @@ -54,7 +54,7 @@ long sigmf_recorder::get_source_count() { } Call_Source *sigmf_recorder::get_source_list() { - return NULL; //wav_sink->get_source_list(); + return NULL; } Source *sigmf_recorder::get_source() { @@ -78,7 +78,7 @@ double sigmf_recorder::get_freq() { } double sigmf_recorder::get_current_length() { - return 0; //wav_sink->length_in_seconds(); + return 0; } int sigmf_recorder::lastupdate() { @@ -101,7 +101,6 @@ State sigmf_recorder::get_state() { void sigmf_recorder::stop() { if (state == ACTIVE) { - recording_duration += wav_sink->length_in_seconds(); BOOST_LOG_TRIVIAL(error) << "sigmf_recorder.cc: Stopping Logger \t[ " << rec_num << " ] - freq[ " << freq << "] \t talkgroup[ " << talkgroup << " ]"; state = INACTIVE; valve->set_enabled(false); diff --git a/trunk-recorder/recorders/sigmf_recorder.h b/trunk-recorder/recorders/sigmf_recorder.h index b16f1e884..edab053d2 100644 --- a/trunk-recorder/recorders/sigmf_recorder.h +++ b/trunk-recorder/recorders/sigmf_recorder.h @@ -74,7 +74,6 @@ #include "recorder.h" #include -#include class Source; class sigmf_recorder; @@ -161,7 +160,6 @@ class sigmf_recorder : public gr::hier_block2, public Recorder { gr::analog::feedforward_agc_cc::sptr agc; gr::analog::agc2_ff::sptr demod_agc; gr::analog::agc2_cc::sptr pre_demod_agc; - gr::blocks::nonstop_wavfile_sink::sptr wav_sink; gr::blocks::file_sink::sptr raw_sink; gr::blocks::short_to_float::sptr converter; gr::blocks::copy::sptr valve;