From 6d68897cc3b8cfbadbb65eeea8f76704a6382015 Mon Sep 17 00:00:00 2001 From: Luke Berndt Date: Sat, 27 May 2023 09:29:21 -0400 Subject: [PATCH] Release/new call mgmt (#817) * Group ID Check in Transmission Sink * last voice update * Update main.cc * Update call.h * Update call.h * debug * Update p25_recorder_decode.cc * accurate time diff on writes * Update transmission_sink.cc * Update transmission_sink.cc * additional group id spot * Update transmission_sink.cc * no Forecasts! * Revert "no Forecasts!" This reverts commit eca65e53ec52bae4a412d6c94840ad78eaa74ba1. * let it rip * Update transmission_sink.cc * Update transmission_sink.cc * removed record_more stuff * better dbug * Update main.cc * Update main.cc * fixed loop * fix grp compare for smartnet and p25 * Update call_impl.cc * Update transmission_sink.cc * Update transmission_sink.cc * Update p25_recorder_decode.cc * Update main.cc * print out state of recorder during group mismatch * Update transmission_sink.cc * count Termination tooo * Update transmission_sink.cc * Update main.cc * Update main.cc * Update main.cc * Update main.cc * Update main.cc * Update main.cc * Update transmission_sink.cc * Update main.cc * Update main.cc * refining the messages * Switching back to processing UPDATEs as UPDATEs * Update p25p1_fdma.cc * Update transmission_sink.cc * I am going to totally forget to set this back * Update main.cc * different messages * Update main.cc * Update main.cc * upgrades * Update main.cc * Update transmission_sink.cc * might clear the buffer of blocks on stop * Update p25_recorder_impl.cc * not clean * adding latency manager * only start recording when the correct group ID is seen * Ignore TG Mismatch If Recorder gets a mismatched TG it will ignore til end of the transmission * Latency measurements seems to break when you have the tags go through a lot of downsampling * slight fixes * new FSK4 * different * cleaned up * Update p25_recorder_decode.cc * not having Updates start Calls * or maybe we should do updates * update FLL Band Edge * backed out most of the debugging * clean up for compiling * Update p25p2_tdma.cc * Config Option to turn on/off new calls from UPDATE --- CMakeLists.txt | 6 +- docs/CONFIGURE.md | 4 +- docs/notes/CALL-HANDLING.md | 2 + lib/gr-latency-manager/include/CMakeLists.txt | 15 ++ lib/gr-latency-manager/include/api.h | 22 +++ .../include/latency_manager.h | 47 +++++ lib/gr-latency-manager/include/tag_to_msg.h | 74 ++++++++ lib/gr-latency-manager/lib/CMakeLists.txt | 48 +++++ .../lib/latency_manager_impl.cc | 94 ++++++++++ .../lib/latency_manager_impl.h | 55 ++++++ lib/gr-latency-manager/lib/tag_to_msg_impl.cc | 171 +++++++++++++++++ lib/gr-latency-manager/lib/tag_to_msg_impl.h | 67 +++++++ lib/gr-latency/latency_probe.cc | 172 ++++++++++++++++++ lib/gr-latency/latency_probe.h | 86 +++++++++ lib/gr-latency/latency_tagger.cc | 83 +++++++++ lib/gr-latency/latency_tagger.h | 64 +++++++ .../include/op25_repeater/fsk4_demod_ff.h | 14 +- lib/op25_repeater/lib/fsk4_demod_ff_impl.cc | 143 ++++++++------- lib/op25_repeater/lib/fsk4_demod_ff_impl.h | 22 ++- .../lib/p25_frame_assembler_impl.cc | 11 +- .../lib/p25_frame_assembler_impl.h | 1 - lib/op25_repeater/lib/p25p1_fdma.cc | 6 +- lib/op25_repeater/lib/p25p1_fdma.h | 1 + lib/op25_repeater/lib/p25p2_tdma.cc | 6 + lib/op25_repeater/lib/p25p2_tdma.h | 1 + trunk-recorder/call.h | 3 +- trunk-recorder/call_impl.cc | 45 +++-- trunk-recorder/call_impl.h | 4 +- trunk-recorder/formatter.cc | 2 + trunk-recorder/global_structs.h | 1 + trunk-recorder/gr_blocks/transmission_sink.cc | 160 +++++++++------- trunk-recorder/gr_blocks/transmission_sink.h | 8 +- trunk-recorder/main.cc | 155 +++++----------- trunk-recorder/recorders/analog_recorder.cc | 4 - trunk-recorder/recorders/analog_recorder.h | 1 - trunk-recorder/recorders/dmr_recorder.h | 1 - trunk-recorder/recorders/dmr_recorder_impl.cc | 5 - trunk-recorder/recorders/dmr_recorder_impl.h | 1 - trunk-recorder/recorders/p25_recorder.h | 1 - .../recorders/p25_recorder_decode.cc | 30 ++- .../recorders/p25_recorder_decode.h | 6 +- .../recorders/p25_recorder_fsk4_demod.cc | 40 +++- .../recorders/p25_recorder_fsk4_demod.h | 11 +- trunk-recorder/recorders/p25_recorder_impl.cc | 62 +++++-- trunk-recorder/recorders/p25_recorder_impl.h | 10 +- .../recorders/p25_recorder_qpsk_demod.cc | 13 ++ .../recorders/p25_recorder_qpsk_demod.h | 3 + trunk-recorder/recorders/recorder.h | 1 - trunk-recorder/state.h | 3 +- trunk-recorder/systems/smartnet_parser.cc | 80 ++++---- 50 files changed, 1489 insertions(+), 376 deletions(-) create mode 100644 lib/gr-latency-manager/include/CMakeLists.txt create mode 100644 lib/gr-latency-manager/include/api.h create mode 100644 lib/gr-latency-manager/include/latency_manager.h create mode 100644 lib/gr-latency-manager/include/tag_to_msg.h create mode 100644 lib/gr-latency-manager/lib/CMakeLists.txt create mode 100644 lib/gr-latency-manager/lib/latency_manager_impl.cc create mode 100644 lib/gr-latency-manager/lib/latency_manager_impl.h create mode 100644 lib/gr-latency-manager/lib/tag_to_msg_impl.cc create mode 100644 lib/gr-latency-manager/lib/tag_to_msg_impl.h create mode 100644 lib/gr-latency/latency_probe.cc create mode 100644 lib/gr-latency/latency_probe.h create mode 100644 lib/gr-latency/latency_tagger.cc create mode 100644 lib/gr-latency/latency_tagger.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 88cc9aad6..213982682 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -256,6 +256,10 @@ list(APPEND trunk_recorder_sources trunk-recorder/call_concluder/call_concluder.cc lib/lfsr/lfsr.cxx + lib/gr-latency/latency_probe.cc + lib/gr-latency/latency_tagger.cc + lib/gr-latency-manager/lib/latency_manager_impl.cc + lib/gr-latency-manager/lib/tag_to_msg_impl.cc trunk-recorder/gr_blocks/freq_xlating_fft_filter.cc trunk-recorder/gr_blocks/transmission_sink.cc trunk-recorder/gr_blocks/decoders/fsync_decode.cc @@ -334,7 +338,7 @@ add_subdirectory(plugins/rdioscanner_uploader) add_subdirectory(plugins/simplestream) -add_executable(trunk-recorder trunk-recorder/main.cc ${trunk_recorder_sources}) +add_executable(trunk-recorder trunk-recorder/main.cc) # ${trunk_recorder_sources}) target_link_libraries(trunk-recorder git trunk_recorder_library gnuradio-op25_repeater ${CMAKE_DL_LIBS} ssl crypto ${CURL_LIBRARIES} ${Boost_LIBRARIES} ${GNURADIO_PMT_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES} ${GNURADIO_DIGITAL_LIBRARIES} ${GNURADIO_ANALOG_LIBRARIES} ${GNURADIO_AUDIO_LIBRARIES} ${GNURADIO_UHD_LIBRARIES} ${UHD_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES} ${GNURADIO_OSMOSDR_LIBRARIES} ) # gRPC::grpc++_reflection protobuf::libprotobuf) diff --git a/docs/CONFIGURE.md b/docs/CONFIGURE.md index 93a4252cf..9b6a7f45d 100644 --- a/docs/CONFIGURE.md +++ b/docs/CONFIGURE.md @@ -127,8 +127,8 @@ Here is a map of the different sections of the *config.json* file: | debugRecorder | | true | **true** / **false** | Will attach a debug recorder to each Source. The debug recorder will allow you to examine the channel of a call be recorded. There is a single Recorder per Source. It will monitor a recording and when it is done, it will monitor the next recording started. The information is sent over a network connection and can be viewed using the `udp-debug.grc` graph in GnuRadio Companion | | debugRecorderPort | | 1234 | number | The network port that the Debug Recorders will start on. For each Source an additional Debug Recorder will be added and the port used will be one higher than the last one. For example the ports for a system with 3 Sources would be: 1234, 12345, 1236. | | debugRecorderAddress | | "127.0.0.1" | string | The network address of the computer that will be monitoring the Debug Recorders. UDP packets will be sent from Trunk Recorder to this computer. The default is *"127.0.0.1"* which is the address used for monitoring on the same computer as Trunk Recorder. | -| audioStreaming | | false | **true** / **false** | whether or not to enable the audio streaming callbacks for plugins. | - +| audioStreaming | | false | **true** / **false** | Whether or not to enable the audio streaming callbacks for plugins. | +| newCallFromUpdate | | true | **true** / **false** | Allow for UPDATE trunking messages to start a new Call, in addition to GRANT messages. This may result in more Calls with no transmisions, and use more Recorders. The flipside is that it may catch parts of a Call that would have otherwise been missed. Turn this off if you are running out of Recorders. | #### Source Object diff --git a/docs/notes/CALL-HANDLING.md b/docs/notes/CALL-HANDLING.md index 642bac8d7..7dec672f2 100644 --- a/docs/notes/CALL-HANDLING.md +++ b/docs/notes/CALL-HANDLING.md @@ -1,3 +1,5 @@ +Use [Mermaid Live](https://mermaid.live/) to edit the charts. + ```mermaid flowchart TD A[Control Channel] -->|GRANT| B["handle_call_grant()"] diff --git a/lib/gr-latency-manager/include/CMakeLists.txt b/lib/gr-latency-manager/include/CMakeLists.txt new file mode 100644 index 000000000..368280534 --- /dev/null +++ b/lib/gr-latency-manager/include/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright 2011,2012 Free Software Foundation, Inc. +# +# This file was generated by gr_modtool, a tool from the GNU Radio framework +# This file is a part of gr-latency_manager +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +######################################################################## +# Install public header files +######################################################################## +install(FILES + api.h + DESTINATION include/gnuradio/latency_manager +) diff --git a/lib/gr-latency-manager/include/api.h b/lib/gr-latency-manager/include/api.h new file mode 100644 index 000000000..d3475a1c6 --- /dev/null +++ b/lib/gr-latency-manager/include/api.h @@ -0,0 +1,22 @@ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file was generated by gr_modtool, a tool from the GNU Radio framework + * This file is a part of gr-latency_manager + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_LATENCY_MANAGER_API_H +#define INCLUDED_LATENCY_MANAGER_API_H + +#include + +#ifdef gnuradio_latency_manager_EXPORTS +#define LATENCY_MANAGER_API __GR_ATTR_EXPORT +#else +#define LATENCY_MANAGER_API __GR_ATTR_IMPORT +#endif + +#endif /* INCLUDED_LATENCY_MANAGER_API_H */ diff --git a/lib/gr-latency-manager/include/latency_manager.h b/lib/gr-latency-manager/include/latency_manager.h new file mode 100644 index 000000000..115b306af --- /dev/null +++ b/lib/gr-latency-manager/include/latency_manager.h @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Derek Kozel. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_LATENCY_MANAGER_LATENCY_MANAGER_H +#define INCLUDED_LATENCY_MANAGER_LATENCY_MANAGER_H + +#include "./api.h" +#include + +namespace gr { + namespace latency_manager { + + /*! + * \brief <+description of block+> + * \ingroup latency_manager + * + */ + class LATENCY_MANAGER_API latency_manager : virtual public gr::sync_block + { + public: + typedef std::shared_ptr sptr; + + static sptr make(int max_tags_in_flight, int tag_interval, int itemsize); + }; + + } // namespace latency_manager +} // namespace gr + +#endif /* INCLUDED_LATENCY_MANAGER_LATENCY_MANAGER_H */ + diff --git a/lib/gr-latency-manager/include/tag_to_msg.h b/lib/gr-latency-manager/include/tag_to_msg.h new file mode 100644 index 000000000..b2e100db0 --- /dev/null +++ b/lib/gr-latency-manager/include/tag_to_msg.h @@ -0,0 +1,74 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Derek Kozel. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_LATENCY_MANAGER_TAG_TO_MSG_H +#define INCLUDED_LATENCY_MANAGER_TAG_TO_MSG_H + +#include "./api.h" +#include + +namespace gr { + namespace latency_manager { + + /*! + * \brief <+description of block+> + * \ingroup latency_manager + * + */ + class LATENCY_MANAGER_API tag_to_msg : virtual public gr::sync_block + { + public: + typedef std::shared_ptr sptr; + + static sptr make(size_t sizeof_stream_item, + const std::string& name, + const std::string& key_filter = ""); + + /*! + * \brief Returns a vector of tag_t items as of the last call to + * work. + */ + virtual std::vector current_tags() = 0; + + /*! + * \brief Return the total number of tags in the tag queue. + */ + virtual int num_tags() = 0; + + /*! + * \brief Set the display of tags to stdout on/off. + */ + virtual void set_display(bool d) = 0; + + /*! + * \brief Set a new key to filter with. + */ + virtual void set_key_filter(const std::string& key_filter) = 0; + + /*! + * \brief Get the current filter key. + */ + virtual std::string key_filter() const = 0; + }; + } // namespace latency_manager +} // namespace gr + +#endif /* INCLUDED_LATENCY_MANAGER_TAG_TO_MSG_H */ + diff --git a/lib/gr-latency-manager/lib/CMakeLists.txt b/lib/gr-latency-manager/lib/CMakeLists.txt new file mode 100644 index 000000000..b129270d2 --- /dev/null +++ b/lib/gr-latency-manager/lib/CMakeLists.txt @@ -0,0 +1,48 @@ +# Copyright 2011,2012,2016,2018,2019 Free Software Foundation, Inc. +# +# This file was generated by gr_modtool, a tool from the GNU Radio framework +# This file is a part of gr-latency_manager +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +######################################################################## +# Setup library +######################################################################## +include(GrPlatform) #define LIB_SUFFIX +list(APPEND latency_manager_sources + tag_to_msg_impl.cc + latency_manager_impl.cc +) + +set(latency_manager_sources "${latency_manager_sources}" PARENT_SCOPE) +if(NOT latency_manager_sources) + MESSAGE(STATUS "No C++ sources... skipping lib/") + return() +endif(NOT latency_manager_sources) + +add_library(gnuradio-latency_manager SHARED ${latency_manager_sources}) +target_link_libraries(gnuradio-latency_manager gnuradio::gnuradio-runtime) +target_include_directories(gnuradio-latency_manager + PUBLIC $ + PUBLIC $ + ) +set_target_properties(gnuradio-latency_manager PROPERTIES DEFINE_SYMBOL "gnuradio_latency_manager_EXPORTS") + +if(APPLE) + set_target_properties(gnuradio-latency_manager PROPERTIES + INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" + ) +endif(APPLE) + +######################################################################## +# Install built library files +######################################################################## +include(GrMiscUtils) +GR_LIBRARY_FOO(gnuradio-latency_manager) + +######################################################################## +# Print summary +######################################################################## +message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") +message(STATUS "Building for version: ${VERSION} / ${LIBVER}") diff --git a/lib/gr-latency-manager/lib/latency_manager_impl.cc b/lib/gr-latency-manager/lib/latency_manager_impl.cc new file mode 100644 index 000000000..80c07dd5f --- /dev/null +++ b/lib/gr-latency-manager/lib/latency_manager_impl.cc @@ -0,0 +1,94 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Derek Kozel. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "latency_manager_impl.h" +#include + +namespace gr { + namespace latency_manager { + + latency_manager::sptr + latency_manager::make(int max_tags_in_flight, int tag_interval, int itemsize) + { + return gnuradio::get_initial_sptr + (new latency_manager_impl(max_tags_in_flight, tag_interval, itemsize)); + } + + void latency_manager_impl::add_token(pmt::pmt_t msg) + { + d_tokens++; + //std::cout << "Tokens: " << d_tokens << " : Added one\n"; + } + + latency_manager_impl::latency_manager_impl(int max_tags_in_flight, int tag_interval, int itemsize) + : gr::sync_block("latency_manager", + gr::io_signature::make(1, 1, itemsize), + gr::io_signature::make(1, 1, itemsize)), + d_itemsize(itemsize), + d_tag_interval(tag_interval), + d_tag_phase(0) + { + d_tokens = max_tags_in_flight; + message_port_register_in(pmt::mp("token")); + set_msg_handler(pmt::mp("token"), [this](pmt::pmt_t msg) { this->add_token(msg); }); + d_tag.key = pmt::intern("latency_strobe"); + d_tag.srcid = alias_pmt(); + + } + + latency_manager_impl::~latency_manager_impl() + { + } + + int + latency_manager_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const char *in = (const char*) input_items[0]; + char *out = (char *) output_items[0]; + + int copy_count = std::min(noutput_items, d_tag_phase + d_tokens * d_tag_interval); + std::memcpy(out, in, copy_count * d_itemsize); + //std::cout << "Copied: " << copy_count << "\n"; + int tag_loc = d_tag_phase; + while (tag_loc < copy_count) { + + d_tag.offset = nitems_written(0) + tag_loc; + d_tag.value = pmt::from_long(tag_loc); + //std::cout << "Add Tag: " << tag_loc << " nitems_written: " << nitems_written(0) << "\n"; + add_item_tag(0,d_tag); + tag_loc += d_tag_interval; + d_tokens--; + } + d_tag_phase = tag_loc - copy_count; + if(copy_count == 0) { + boost::this_thread::sleep(boost::posix_time::microseconds(long(100))); + } + return copy_count; + } + } /* namespace latency_manager */ +} /* namespace gr */ + diff --git a/lib/gr-latency-manager/lib/latency_manager_impl.h b/lib/gr-latency-manager/lib/latency_manager_impl.h new file mode 100644 index 000000000..5c53ea25f --- /dev/null +++ b/lib/gr-latency-manager/lib/latency_manager_impl.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Derek Kozel. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_LATENCY_MANAGER_LATENCY_MANAGER_IMPL_H +#define INCLUDED_LATENCY_MANAGER_LATENCY_MANAGER_IMPL_H + +#include "../include/latency_manager.h" + +namespace gr { + namespace latency_manager { + + class latency_manager_impl : public latency_manager + { + private: + int d_tokens; + void add_token(pmt::pmt_t tag); + int d_itemsize; + int d_tag_interval; + int d_tag_phase; + tag_t d_tag; + + public: + latency_manager_impl(int max_tags_in_flight, int tag_interval, int itemsize); + ~latency_manager_impl(); + + // Where all the action really happens + int work( + int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ); + }; + + } // namespace latency_manager +} // namespace gr + +#endif /* INCLUDED_LATENCY_MANAGER_LATENCY_MANAGER_IMPL_H */ + diff --git a/lib/gr-latency-manager/lib/tag_to_msg_impl.cc b/lib/gr-latency-manager/lib/tag_to_msg_impl.cc new file mode 100644 index 000000000..999032548 --- /dev/null +++ b/lib/gr-latency-manager/lib/tag_to_msg_impl.cc @@ -0,0 +1,171 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Derek Kozel. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "tag_to_msg_impl.h" +#include +#include + +namespace gr { + namespace latency_manager { + + tag_to_msg::sptr + tag_to_msg::make(size_t sizeof_stream_item, + const std::string& name, + const std::string& key_filter) + { + return gnuradio::get_initial_sptr + (new tag_to_msg_impl(sizeof_stream_item, name, key_filter)); + } + + tag_to_msg_impl::tag_to_msg_impl(size_t sizeof_stream_item, + const std::string& name, + const std::string& key_filter) + : sync_block("tag_to_msg", + io_signature::make(1, -1, sizeof_stream_item), + io_signature::make(0, 0, 0)), + d_name(name), + d_display(true), + d_port(pmt::mp("msg")) +{ + set_key_filter(key_filter); + message_port_register_out(d_port); +} + + + tag_to_msg_impl::~tag_to_msg_impl() + { + } + +std::vector tag_to_msg_impl::current_tags() +{ + gr::thread::scoped_lock l(d_mutex); + return d_tags; +} + +int tag_to_msg_impl::num_tags() +{ + std::vector t; + get_tags_in_range(t, 0, 0, nitems_read(0)); + return static_cast(t.size()); +} + +void tag_to_msg_impl::set_display(bool d) { d_display = d; } + +void tag_to_msg_impl::set_key_filter(const std::string& key_filter) +{ + if (key_filter.empty()) + d_filter = pmt::PMT_NIL; + else + d_filter = pmt::intern(key_filter); +} + +std::string tag_to_msg_impl::key_filter() const { return pmt::symbol_to_string(d_filter); } + int + tag_to_msg_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr::thread::scoped_lock l(d_mutex); + bool toprint = false; + d_display = false; + std::stringstream sout; + if (d_display) { + sout << std::endl + << "----------------------------------------------------------------------"; + sout << std::endl << "Tag Debug: " << d_name << std::endl; + } + + uint64_t abs_N, end_N; + for (size_t i = 0; i < input_items.size(); i++) { + abs_N = nitems_read(i); + end_N = abs_N + (uint64_t)(noutput_items); + + d_tags.clear(); + if (pmt::is_null(d_filter)) + get_tags_in_range(d_tags, i, abs_N, end_N); + else + get_tags_in_range(d_tags, i, abs_N, end_N, d_filter); + + if (!d_tags.empty()) { + toprint = true; + } + + if (d_display) { + sout << "Input Stream: " << std::setw(2) << std::setfill('0') << i + << std::setfill(' ') << std::endl; + for (d_tags_itr = d_tags.begin(); d_tags_itr != d_tags.end(); d_tags_itr++) { + sout << std::setw(10) << "Offset: " << d_tags_itr->offset << std::setw(10) + << "Source: " + << (pmt::is_symbol(d_tags_itr->srcid) + ? pmt::symbol_to_string(d_tags_itr->srcid) + : "n/a") + << std::setw(10) << "Key: " << pmt::symbol_to_string(d_tags_itr->key) + << std::setw(10) << "Value: "; + sout << d_tags_itr->value << std::endl; + } + + } + + if (true /*d_publish_msgs*/) { + for (d_tags_itr = d_tags.begin(); d_tags_itr != d_tags.end(); d_tags_itr++) { + pmt::pmt_t d = pmt::make_dict(); + d = pmt::dict_add(d, pmt::mp(d_tags_itr->key), pmt::mp(d_tags_itr->value)); + message_port_pub(d_port, pmt::cons(d, pmt::PMT_NIL)); + } + } + } + + if (d_display) { + sout << "----------------------------------------------------------------------"; + sout << std::endl; + + if (toprint) { + std::cout << sout.str(); + } + } + + return noutput_items; + } + +void tag_to_msg_impl::setup_rpc() +{ +#ifdef GR_CTRLPORT + add_rpc_variable(rpcbasic_sptr( + new rpcbasic_register_get(alias(), + "num. tags", + &tag_to_msg::num_tags, + pmt::from_long(0), + pmt::from_long(10000), + pmt::from_long(0), + "", + "Number of Tags", + RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); +#endif /* GR_CTRLPORT */ +} + + } /* namespace latency_manager */ +} /* namespace gr */ + diff --git a/lib/gr-latency-manager/lib/tag_to_msg_impl.h b/lib/gr-latency-manager/lib/tag_to_msg_impl.h new file mode 100644 index 000000000..19abbfc23 --- /dev/null +++ b/lib/gr-latency-manager/lib/tag_to_msg_impl.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Derek Kozel. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_LATENCY_MANAGER_TAG_TO_MSG_IMPL_H +#define INCLUDED_LATENCY_MANAGER_TAG_TO_MSG_IMPL_H + +#include "../include/tag_to_msg.h" + +namespace gr { + namespace latency_manager { + + class tag_to_msg_impl : public tag_to_msg + { +private: + std::string d_name; + std::vector d_tags; + std::vector::iterator d_tags_itr; + bool d_display; + pmt::pmt_t d_filter; + gr::thread::mutex d_mutex; + const pmt::pmt_t d_port; + + public: + tag_to_msg_impl(size_t sizeof_stream_item, + const std::string& name, + const std::string& key_filter = ""); + ~tag_to_msg_impl(); + + void setup_rpc(); + + std::vector current_tags(); + int num_tags(); + + void set_display(bool d); + + void set_key_filter(const std::string& key_filter); + std::string key_filter() const; + + int work( + int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ); + }; + + } // namespace latency_manager +} // namespace gr + +#endif /* INCLUDED_LATENCY_MANAGER_TAG_TO_MSG_IMPL_H */ + diff --git a/lib/gr-latency/latency_probe.cc b/lib/gr-latency/latency_probe.cc new file mode 100644 index 000000000..5366582b7 --- /dev/null +++ b/lib/gr-latency/latency_probe.cc @@ -0,0 +1,172 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 <+YOU OR YOUR COMPANY+>. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "./latency_probe.h" + +#include "boost/date_time/local_time/local_time.hpp" +#include "boost/date_time/posix_time/posix_time.hpp" + +using boost::posix_time::ptime; +using boost::posix_time::time_from_string; +using boost::posix_time::time_duration; +namespace gr { + namespace gr_latency { + latency_probe::sptr latency_probe::make (int item_size, std::vector keys) { + return gnuradio::get_initial_sptr(new latency_probe (item_size, keys)); + } + + +latency_probe::latency_probe (int item_size, std::vector keys) + : gr::sync_block ("probe", + gr::io_signature::make(1,1, item_size), + gr::io_signature::make (0,1, item_size)), + d_itemsize(item_size) +{ + for(size_t i=0; i(); + } +} + + +latency_probe::~latency_probe () +{ +} + + +int +latency_probe::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + + std::vector tags; + /* + get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0) + noutput_items); + for(int i=0; i 0){ + memcpy(output_items[0], input_items[0], noutput_items*d_itemsize); + } + return noutput_items; +} + +typedef latmes_t lm; +typedef std::vector lmv; +typedef std::map< pmt::pmt_t, lmv > mt; + +std::vector latency_probe::get_keys(){ + std::vector keys; + for(mt::iterator i = d_measurements.begin(); i!=d_measurements.end(); i++){ + keys.push_back( pmt::symbol_to_string( (*i).first ) ); + } + return keys; +} + + +std::vector latency_probe::get_offsets(std::string key){ + if(d_measurements.find(pmt::intern(key)) == d_measurements.end()) + throw std::runtime_error("latency_probe::get_offsets() called with invalid key"); + lmv pv = d_measurements[pmt::intern(key)]; + std::vector offsets(pv.size()); + for(lmv::iterator i = pv.begin(); i != pv.end(); i++){ + offsets.push_back( (*i).offset ); + } + return offsets; +} + +std::vector latency_probe::get_delays(std::string key){ + if(d_measurements.find(pmt::intern(key)) == d_measurements.end()) + throw std::runtime_error("latency_probe::get_delays() called with invalid key"); + lmv pv = d_measurements[pmt::intern(key)]; + std::vector delays(pv.size()); + for(lmv::iterator i = pv.begin(); i != pv.end(); i++){ + delays.push_back( (*i).delay ); + } + return delays; +} + +std::vector latency_probe::get_t_start(std::string key){ + if(d_measurements.find(pmt::intern(key)) == d_measurements.end()) + throw std::runtime_error("latency_probe::get_t_start() called with invalid key"); + lmv pv = d_measurements[pmt::intern(key)]; + std::vector times(pv.size()); + for(lmv::iterator i = pv.begin(); i != pv.end(); i++){ + times.push_back( (*i).t_start ); + } + return times; +} + +std::vector latency_probe::get_t_end(std::string key){ + if(d_measurements.find(pmt::intern(key)) == d_measurements.end()) + throw std::runtime_error("latency_probe::get_t_end() called with invalid key"); + lmv pv = d_measurements[pmt::intern(key)]; + std::vector times(pv.size()); + for(lmv::iterator i = pv.begin(); i != pv.end(); i++){ + times.push_back( (*i).t_end ); + } + return times; +} + +void latency_probe::reset(){ + d_measurements.clear(); +} + + } /* namespace latency_probe */ +} /* namespace gr */ \ No newline at end of file diff --git a/lib/gr-latency/latency_probe.h b/lib/gr-latency/latency_probe.h new file mode 100644 index 000000000..d392acc91 --- /dev/null +++ b/lib/gr-latency/latency_probe.h @@ -0,0 +1,86 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 <+YOU OR YOUR COMPANY+>. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_LATENCY_PROBE_H +#define INCLUDED_LATENCY_PROBE_H + + +#include +#include +#include "boost/tuple/tuple.hpp" + + +#include + +#ifdef gnuradio_latency_probe_EXPORTS +#define LATENCY_PROBE_API __GR_ATTR_EXPORT +#else +#define LATENCY_PROBE_API __GR_ATTR_IMPORT +#endif + +namespace gr { + namespace gr_latency { + + /*! + * \brief <+description of block+> + * \ingroup latency_manager + * + */ + + +typedef struct { + uint64_t offset; + double delay; + double t_start; + double t_end; +} latmes_t; + +/*! + * \brief <+description+> + * + */ + +class LATENCY_PROBE_API latency_probe : public gr::sync_block +{ + + + latency_probe (int item_size, std::vector keys); + std::vector d_keys; + int d_itemsize; + std::map< pmt::pmt_t, std::vector< latmes_t > > d_measurements; + public: + typedef std::shared_ptr sptr; + static sptr make(int item_size, std::vector keys); + ~latency_probe (); + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + std::vector get_keys(); + std::vector get_offsets(std::string key); + std::vector get_delays(std::string key); + std::vector get_t_start(std::string key); + std::vector get_t_end(std::string key); + + void reset(); +}; + } +} +#endif /* INCLUDED_LATENCY_PROBE_H */ diff --git a/lib/gr-latency/latency_tagger.cc b/lib/gr-latency/latency_tagger.cc new file mode 100644 index 000000000..f58a338c7 --- /dev/null +++ b/lib/gr-latency/latency_tagger.cc @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 <+YOU OR YOUR COMPANY+>. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "./latency_tagger.h" + +#include "boost/date_time/local_time/local_time.hpp" +#include "boost/date_time/posix_time/posix_time.hpp" + +using boost::posix_time::ptime; +using boost::posix_time::time_from_string; +using boost::posix_time::time_duration; +namespace gr { + namespace gr_latency { + +latency_tagger::sptr latency_tagger::make (int item_size, int tag_frequency, std::string tag) +{ + return gnuradio::get_initial_sptr(new latency_tagger (item_size, tag_frequency, tag)); +} + + +latency_tagger::latency_tagger (int item_size, int tag_frequency, std::string tag) + : gr::sync_block ("latency_tagger", + gr::io_signature::make (1, 1, item_size), + gr::io_signature::make (1, 1, item_size)), + d_tag_frequency(tag_frequency), + d_key(pmt::intern(tag)), + d_src(pmt::intern(name())), + d_itemsize(item_size) +{ +} + + +latency_tagger::~latency_tagger () +{ +} + + +int +latency_tagger::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + // add time tags where appropriate + uint64_t start(nitems_written(0)); + for(uint64_t i=start; i. + * + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_LATENCY_TAGGER_H +#define INCLUDED_LATENCY_TAGGER_H + + +#include + +#include + +#ifdef gnuradio_latency_tagger_EXPORTS +#define LATENCY_TAGGER_API __GR_ATTR_EXPORT +#else +#define LATENCY_TAGGER_API __GR_ATTR_IMPORT +#endif + + +/*! + * \brief <+description+> + * + */ + +namespace gr { + namespace gr_latency { +class LATENCY_TAGGER_API latency_tagger : public gr::sync_block +{ + + + latency_tagger (int item_size, int tag_frequency, std::string tag); + int d_tag_frequency; + int d_itemsize; + pmt::pmt_t d_key; + pmt::pmt_t d_src; + + public: + typedef std::shared_ptr sptr; + static sptr make(int item_size, int tag_frequency, std::string tag); + ~latency_tagger (); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + } +} +#endif /* INCLUDED_LATENCY_TAGGER_H */ diff --git a/lib/op25_repeater/include/op25_repeater/fsk4_demod_ff.h b/lib/op25_repeater/include/op25_repeater/fsk4_demod_ff.h index 95b7c1fc7..181563898 100644 --- a/lib/op25_repeater/include/op25_repeater/fsk4_demod_ff.h +++ b/lib/op25_repeater/include/op25_repeater/fsk4_demod_ff.h @@ -1,17 +1,17 @@ /* -*- c++ -*- */ -/* +/* * Copyright 2010,2011 Steve Glass - * + * * This 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. - * + * * This software 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 this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, @@ -58,11 +58,13 @@ namespace gr { * * Nominal levels are -3, -1, +1, and +3. */ - static sptr make(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz); - virtual void reset() {}; + static sptr make(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz, bool bfsk = false); + virtual void reset() {} + virtual void set_rate(const float sample_rate_Hz, const float symbol_rate_Hz) {} }; } // namespace op25 } // namespace gr #endif /* INCLUDED_OP25_FSK4_DEMOD_FF_H */ + diff --git a/lib/op25_repeater/lib/fsk4_demod_ff_impl.cc b/lib/op25_repeater/lib/fsk4_demod_ff_impl.cc index 96d2a01bf..ce01792ee 100644 --- a/lib/op25_repeater/lib/fsk4_demod_ff_impl.cc +++ b/lib/op25_repeater/lib/fsk4_demod_ff_impl.cc @@ -172,16 +172,16 @@ namespace gr { namespace op25_repeater { fsk4_demod_ff::sptr - fsk4_demod_ff::make(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz) + fsk4_demod_ff::make(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz, bool bfsk) { return gnuradio::get_initial_sptr - (new fsk4_demod_ff_impl(queue, sample_rate_Hz, symbol_rate_Hz)); + (new fsk4_demod_ff_impl(queue, sample_rate_Hz, symbol_rate_Hz, bfsk)); } /* * The private constructor */ - fsk4_demod_ff_impl::fsk4_demod_ff_impl(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz) + fsk4_demod_ff_impl::fsk4_demod_ff_impl(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz, bool bfsk) : gr::block("fsk4_demod_ff", gr::io_signature::make(1, 1, sizeof(float)), gr::io_signature::make(1, 1, sizeof(float))), @@ -191,7 +191,8 @@ namespace gr { d_queue(queue), d_symbol_clock(0.0), d_symbol_spread(2.0), // nominal symbol spread of 2.0 gives outputs at -3, -1, +1, +3 - d_symbol_time(symbol_rate_Hz / sample_rate_Hz) + d_symbol_time(symbol_rate_Hz / sample_rate_Hz), + d_bfsk(bfsk) { fine_frequency_correction = 0.0; coarse_frequency_correction = 0.0; @@ -200,20 +201,31 @@ namespace gr { } /* - * Our virtual destructor. + * Reset tracking loops. */ - fsk4_demod_ff_impl::~fsk4_demod_ff_impl() - { + void + fsk4_demod_ff_impl::reset() { + fine_frequency_correction = 0.0; + coarse_frequency_correction = 0.0; + d_symbol_clock = 0.0; + d_symbol_spread = 2.0; + } + + /* + * Change rate. + */ + void + fsk4_demod_ff_impl::set_rate(const float sample_rate_Hz, const float symbol_rate_Hz) { + d_block_rate = sample_rate_Hz / symbol_rate_Hz; + d_symbol_time = symbol_rate_Hz / sample_rate_Hz; + reset(); } - void fsk4_demod_ff_impl::reset() + /* + * Our virtual destructor. + */ + fsk4_demod_ff_impl::~fsk4_demod_ff_impl() { - d_history_last = 0; - d_symbol_clock = 0; - fine_frequency_correction = 0.0; - coarse_frequency_correction = 0.0; - std::fill(&d_history[0], &d_history[NTAPS], 0.0); - std::fill(&d_history[0], &d_history[NTAPS], 0.0); } void @@ -241,8 +253,8 @@ namespace gr { } } - // send frequency adjusment request if needed - send_frequency_correction(); + // send frequency adjusment request if needed + //send_frequency_correction(); consume_each (noutput_items); @@ -254,53 +266,54 @@ namespace gr { fsk4_demod_ff_impl::send_frequency_correction() { double arg1, arg2; + // if the queue is full, don't block, drop the data... if(d_queue->full_p()) return; - const double COARSE_FREQUENCY_DEADBAND = 1.66; // gnuradio frequency adjust messages will not be emitted until we exceed this threshold + const double COARSE_FREQUENCY_DEADBAND = 1.66; // gnuradio frequency adjust messages will not be emitted until we exceed this threshold if((coarse_frequency_correction < COARSE_FREQUENCY_DEADBAND) && (coarse_frequency_correction > -COARSE_FREQUENCY_DEADBAND)) return; - + arg1 = coarse_frequency_correction; arg2 = 0.0; coarse_frequency_correction = 0.0; - + // build & send a message gr::message::sptr msg = gr::message::make(0, arg1, arg2, 0); // vlen() * sizeof(float)); d_queue->insert_tail(msg); msg.reset(); } - + bool fsk4_demod_ff_impl::tracking_loop_mmse(float input, float *output) { d_symbol_clock += d_symbol_time; - + d_history[d_history_last++] = input; d_history_last %= NTAPS; - + if(d_symbol_clock > 1.0) { - + d_symbol_clock -= 1.0; - + // at this point we state that linear interpolation was tried // but found to be slightly inferior. Using MMSE // interpolation shouldn't be a terrible burden - + #if 0 int imu = min(static_cast(floor(0.5 + (NSTEPS * (d_symbol_clock / d_symbol_time)))), NSTEPS - 1); int imu_p1 = imu + 1; #else int imu = (int) floor(0.5 + (NSTEPS * ((d_symbol_clock / d_symbol_time)))); int imu_p1 = imu + 1; - if (imu >= NSTEPS) { + if (imu >= NSTEPS) { imu = NSTEPS - 1; imu_p1 = NSTEPS; } #endif - + #if 0 double interp = 0.0; double interp_p1 = 0.0; @@ -313,79 +326,86 @@ namespace gr { size_t j = d_history_last; double interp = 0.0; double interp_p1 = 0.0; - if ((j >= NTAPS) || (imu >= NSTEPS) || (imu < 0)) { - std::cout << "j: " << j << " Imu: " << imu << " symbol cloc: " << d_symbol_clock << " Time: " << d_symbol_time << std::endl; - d_symbol_clock = 0; - d_history_last = 0; - } else { for(int i=0; i d_history; size_t d_history_last; gr::msg_queue::sptr d_queue; double d_symbol_clock; double d_symbol_spread; - const float d_symbol_time; + float d_symbol_time; double fine_frequency_correction; double coarse_frequency_correction; + bool d_bfsk; /** * Called when we want the input frequency to be adjusted. @@ -56,12 +57,14 @@ namespace gr { bool tracking_loop_mmse(float input, float *output); public: - fsk4_demod_ff_impl(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz); + fsk4_demod_ff_impl(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz, bool bfsk = false); ~fsk4_demod_ff_impl(); + void reset(); + void set_rate(const float sample_rate_Hz, const float symbol_rate_Hz); // Where all the action really happens void forecast (int noutput_items, gr_vector_int &ninput_items_required); - void reset(); + int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, @@ -72,3 +75,4 @@ namespace gr { } // namespace gr #endif /* INCLUDED_OP25_FSK4_DEMOD_FF_IMPL_H */ + diff --git a/lib/op25_repeater/lib/p25_frame_assembler_impl.cc b/lib/op25_repeater/lib/p25_frame_assembler_impl.cc index 00ba1c31f..21e490003 100644 --- a/lib/op25_repeater/lib/p25_frame_assembler_impl.cc +++ b/lib/op25_repeater/lib/p25_frame_assembler_impl.cc @@ -122,12 +122,6 @@ static const int MAX_IN = 1; // maximum number of input streams if (d_do_phase2_tdma && !d_do_audio_output) fprintf(stderr, "p25_frame_assembler: error: do_audio_output must be enabled if do_phase2_tdma is enabled\n"); - - if (d_do_audio_output) - set_output_multiple(864); - - if (!d_do_audio_output && !d_do_imbe) - set_output_multiple(160); } @@ -143,7 +137,6 @@ p25_frame_assembler_impl::general_work (int noutput_items, { const uint8_t *in = (const uint8_t *) input_items[0]; - bool terminate_call = false; long p2_ptt_src_id = -1; long p2_ptt_grp_id = -1; @@ -154,6 +147,7 @@ p25_frame_assembler_impl::general_work (int noutput_items, int rc = p2tdma.handle_frame(); if (p2tdma.get_call_terminated()) { terminate_call = true; + p2tdma.reset_call_terminated(); } p2_ptt_src_id = p2tdma.get_ptt_src_id(); @@ -168,6 +162,7 @@ p25_frame_assembler_impl::general_work (int noutput_items, } else { if (p1fdma.get_call_terminated()) { terminate_call = true; + p1fdma.reset_call_terminated(); } } @@ -249,10 +244,8 @@ p25_frame_assembler_impl::general_work (int noutput_items, if (d_do_audio_output) { if (d_do_phase2_tdma) { d_input_rate = 6000; - set_output_multiple(640); } else { d_input_rate = 4800; - set_output_multiple(864); } } } diff --git a/lib/op25_repeater/lib/p25_frame_assembler_impl.h b/lib/op25_repeater/lib/p25_frame_assembler_impl.h index 99c42de8a..d0914b78e 100644 --- a/lib/op25_repeater/lib/p25_frame_assembler_impl.h +++ b/lib/op25_repeater/lib/p25_frame_assembler_impl.h @@ -60,7 +60,6 @@ namespace gr { long total_produced; pmt::pmt_t d_tag_key; pmt::pmt_t d_tag_src; - // internal functions void set_xormask(const char*p) ; diff --git a/lib/op25_repeater/lib/p25p1_fdma.cc b/lib/op25_repeater/lib/p25p1_fdma.cc index 57a3ef848..e9dff9eaa 100644 --- a/lib/op25_repeater/lib/p25p1_fdma.cc +++ b/lib/op25_repeater/lib/p25p1_fdma.cc @@ -241,6 +241,9 @@ namespace gr { return rx_status; } + void p25p1_fdma::reset_call_terminated() { + terminate_call = false; + } bool p25p1_fdma::get_call_terminated() { return terminate_call; } @@ -310,6 +313,7 @@ namespace gr { ess_keyid = ((HB[j+2] & 0x03) << 14) + (HB[j+3] << 8) + (HB[j+4] << 2) + (HB[j+5] >> 4); // 16 bit KeyId vf_tgid = ((HB[j+5] & 0x0f) << 12) + (HB[j+6] << 6) + HB[j+7]; // 16 bit TGID + curr_grp_id = vf_tgid; if (d_debug >= 10) { fprintf (stderr, "ESS: tgid=%d, mfid=%x, algid=%x, keyid=%x, mi=%02x %02x %02x %02x %02x %02x %02x %02x %02x", vf_tgid, MFID, ess_algid, ess_keyid, @@ -521,7 +525,7 @@ namespace gr { uint16_t ch_T = (lcw[5] << 8) + lcw[6]; uint16_t ch_R = (lcw[7] << 8) + lcw[8]; - curr_grp_id = grpaddr; + // Don't use this grpaddr, you can get Updates for Talkgroups that are on other frequencies, the GRP here may not be the one the being recordered if (d_debug >= 10) fprintf(stderr, ", svcopts=0x%02x, grpaddr=%d, ch_T=%d, ch_R=%d", svcopts, grpaddr, ch_T, ch_R); tsbk[0] = 0xff; tsbk[1] = 0xff; diff --git a/lib/op25_repeater/lib/p25p1_fdma.h b/lib/op25_repeater/lib/p25p1_fdma.h index 330031a3b..ea80f2928 100644 --- a/lib/op25_repeater/lib/p25p1_fdma.h +++ b/lib/op25_repeater/lib/p25p1_fdma.h @@ -135,6 +135,7 @@ namespace gr { long get_curr_grp_id(); void reset_rx_status(); bool get_call_terminated(); + void reset_call_terminated(); Rx_Status get_rx_status(); void clear(); diff --git a/lib/op25_repeater/lib/p25p2_tdma.cc b/lib/op25_repeater/lib/p25p2_tdma.cc index 7ea4a75b5..972ad4944 100644 --- a/lib/op25_repeater/lib/p25p2_tdma.cc +++ b/lib/op25_repeater/lib/p25p2_tdma.cc @@ -145,6 +145,10 @@ void p25p2_tdma::crypt_key(uint16_t keyid, uint8_t algid, const std::vectorupdate_talkgroup_display(); @@ -76,6 +77,11 @@ Call_impl::Call_impl(TrunkMessage message, System *s, Config c) { mode = message.mode; is_analog = false; priority = message.priority; + if (message.message_type == GRANT) { + was_update = false; + } else { + was_update = true; + } set_freq(message.freq); add_source(message.source); this->update_talkgroup_display(); @@ -88,24 +94,6 @@ Call_impl::~Call_impl() { void Call_impl::restart_call() { } -void Call_impl::set_record_more_transmissions(bool more) { - if (this->get_recorder() != NULL) { - this->get_recorder()->set_record_more_transmissions(more); - } -} - -void Call_impl::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_impl, 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_impl::stop_call() { if (this->get_recorder() != NULL) { @@ -114,10 +102,7 @@ void Call_impl::stop_call() { 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_impl, 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()) << "\tTrying to COMPLETE, Recorder still active, setting call state to INACTIVE - Last Update: " << this->since_last_update() << "s"; - this->set_state(INACTIVE); - } + } } } long Call_impl::get_call_num() { @@ -136,6 +121,9 @@ void Call_impl::conclude_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()) << "\t\u001b[33mConcluding Recorded Call\u001b[0m - Last Update: " << this->since_last_update() << "s\tCall Elapsed: " << this->elapsed(); + if (was_update) { + 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()) << "\t\u001b[33mCall was UPDATE not GRANT\u001b[0m"; + } this->get_recorder()->stop(); transmission_list = this->get_recorder()->get_transmission_list(); if (this->get_sigmf_recording() == true) { @@ -350,6 +338,17 @@ int Call_impl::since_last_update() { return time(NULL) - last_update; } +double Call_impl::since_last_voice_update() { + if (state == RECORDING) { + Recorder *rec = this->get_recorder(); + if (rec != NULL) { + return rec->since_last_write(); + } + } + return -1; +} + + long Call_impl::elapsed() { return time(NULL) - start_time; } @@ -371,7 +370,7 @@ long Call_impl::get_stop_time() { } std::string Call_impl::get_system_type() { - return sys->get_system_type().c_str(); + return sys->get_system_type(); } void Call_impl::set_talkgroup_tag(std::string tag) { diff --git a/trunk-recorder/call_impl.h b/trunk-recorder/call_impl.h index 797fd63ba..97ee80541 100644 --- a/trunk-recorder/call_impl.h +++ b/trunk-recorder/call_impl.h @@ -26,8 +26,6 @@ class Call_impl : public Call { long get_call_num(); 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); @@ -47,6 +45,7 @@ class Call_impl : public Call { int get_idle_count(); void increase_idle_count(); void reset_idle_count(); + double since_last_voice_update(); int since_last_update(); long elapsed(); @@ -105,6 +104,7 @@ class Call_impl : public Call { time_t start_time; bool debug_recording; bool sigmf_recording; + bool was_update; bool encrypted; bool emergency; bool mode; diff --git a/trunk-recorder/formatter.cc b/trunk-recorder/formatter.cc index 5eabce405..bec3b0f6b 100644 --- a/trunk-recorder/formatter.cc +++ b/trunk-recorder/formatter.cc @@ -48,6 +48,8 @@ std::string format_state(State state) { return "stopped"; else if (state == AVAILABLE) return "available"; + else if (state == IGNORE) + return "ignore"; return "Unknown"; } return boost::lexical_cast(state); diff --git a/trunk-recorder/global_structs.h b/trunk-recorder/global_structs.h index 7de0f5767..2add5eb98 100644 --- a/trunk-recorder/global_structs.h +++ b/trunk-recorder/global_structs.h @@ -27,6 +27,7 @@ struct Config { std::string capture_dir; std::string debug_recorder_address; std::string log_dir; + bool new_call_from_update; bool debug_recorder; int debug_recorder_port; int call_timeout; diff --git a/trunk-recorder/gr_blocks/transmission_sink.cc b/trunk-recorder/gr_blocks/transmission_sink.cc index b385c3ae2..9c602c9f2 100644 --- a/trunk-recorder/gr_blocks/transmission_sink.cc +++ b/trunk-recorder/gr_blocks/transmission_sink.cc @@ -77,6 +77,7 @@ transmission_sink::transmission_sink(int n_channels, unsigned int sample_rate, i state = AVAILABLE; } + // static int rec_counter=0; void transmission_sink::create_base_filename() { time_t work_start_time = d_start_time; @@ -121,12 +122,18 @@ bool transmission_sink::start_recording(Call *call) { d_current_call_freq = call->get_freq(); d_current_call_talkgroup = call->get_talkgroup(); d_current_call_talkgroup_display = call->get_talkgroup_display(); + if (call->get_system_type() == "smartnet") { + d_current_call_talkgroup_encoded = (call->get_talkgroup() >> 4); + } else { + d_current_call_talkgroup_encoded = call->get_talkgroup(); + } 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; + d_last_write_time = std::chrono::steady_clock::now(); // we want to make sure the call doesn't get cleaned up before data starts coming in. + this->clear_transmission_list(); d_conventional = call->is_conventional(); @@ -239,6 +246,8 @@ void transmission_sink::end_transmission() { strcpy(transmission.base_filename, current_base_filename); this->add_transmission(transmission); + // Reset the recorder to be ready to record the next Transmission + state = IDLE; d_sample_count = 0; d_error_count = 0; d_spike_count = 0; @@ -257,13 +266,14 @@ void transmission_sink::end_transmission() { void transmission_sink::stop_recording() { gr::thread::scoped_lock guard(d_mutex); + if (state == RECORDING) { + BOOST_LOG_TRIVIAL(trace) << "stop_recording() - stopping wavfile sink but recorder state is: " << state << std::endl; + } + if (d_sample_count > 0) { end_transmission(); } - if (state == RECORDING) { - BOOST_LOG_TRIVIAL(trace) << "stop_recording() - stopping wavfile sink but recorder state is: " << state << std::endl; - } d_current_call = NULL; d_termination_flag = false; state = AVAILABLE; @@ -290,7 +300,7 @@ State transmission_sink::get_state() { 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 + gr::thread::scoped_lock guard(d_mutex); // hold mutex for duration of this function // it is possible that we could get part of a transmission after a call has stopped. We shouldn't do any recording if this happens.... this could mean that we miss part of the recording though if (!d_current_call) { @@ -321,8 +331,9 @@ int transmission_sink::work(int noutput_items, gr_vector_const_void_star &input_ } std::vector tags; - pmt::pmt_t src_id_key(pmt::intern("src_id")); - pmt::pmt_t ptt_src_id_key(pmt::intern("ptt_src_id")); + pmt::pmt_t src_id_key(pmt::intern("src_id")); // This is the src id from Phase 1 and DMR + pmt::pmt_t grp_id_key(pmt::intern("grp_id")); // This is the src id from Phase 1 and DMR + pmt::pmt_t ptt_src_id_key(pmt::intern("ptt_src_id")); // This is the src id from Phase 2 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")); @@ -335,6 +346,21 @@ int transmission_sink::work(int noutput_items, gr_vector_const_void_star &input_ for (unsigned int i = 0; i < tags.size(); i++) { // BOOST_LOG_TRIVIAL(info) << "TAG! " << tags[i].key; + if (pmt::eq(grp_id_key, tags[i].key)) { + long grp_id = pmt::to_long(tags[i].value); + + if ((state == RECORDING) || (state == IDLE)) { + if(d_current_call_talkgroup_encoded != grp_id) { + BOOST_LOG_TRIVIAL(info) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tGROUP MISMATCH - Recorder TG: " << d_current_call_talkgroup_encoded << " Recieved TG: " << grp_id << " Recorder state: " << format_state(state) << " incoming: " << noutput_items; + if (d_sample_count > 0) { + BOOST_LOG_TRIVIAL(info) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tEnding Transmission and IGNORING Rest - count: " << d_sample_count; + end_transmission(); + } + state = IGNORE; + + } + } + } 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)); @@ -364,6 +390,7 @@ int transmission_sink::work(int noutput_items, gr_vector_const_void_star &input_ // BOOST_LOG_TRIVIAL(info) << "Updated Voice Channel source id: " << src_id << " pos: " << pos << " offset: " << tags[i].offset - nitems_read(0); } } + if (pmt::eq(terminate_key, tags[i].key)) { d_termination_flag = true; pos = d_sample_count + (tags[i].offset - nitems_read(0)); @@ -372,6 +399,7 @@ int transmission_sink::work(int noutput_items, gr_vector_const_void_star &input_ // BOOST_LOG_TRIVIAL(info) << "TERMINATOR!!"; } + if (pmt::eq(ptt_src_id_key, tags[i].key)) { long src_id = pmt::to_long(tags[i].value); if (src_id != curr_src_id) { @@ -381,7 +409,6 @@ int transmission_sink::work(int noutput_items, gr_vector_const_void_star &input_ //BOOST_LOG_TRIVIAL(info) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tPTT Termination - 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) { @@ -401,7 +428,6 @@ int transmission_sink::work(int noutput_items, gr_vector_const_void_star &input_ // if the System for this call is in Transmission Mode, and we have a recording and we got a flag that a Transmission ended... int nwritten = dowork(noutput_items, input_items, output_items); - d_stop_time = time(NULL); return nwritten; } @@ -414,21 +440,12 @@ time_t transmission_sink::get_stop_time() { return d_stop_time; } -void transmission_sink::add_transmission(Transmission t) { - transmission_list.push_back(t); +std::chrono::time_point transmission_sink::get_last_write_time() { + return d_last_write_time; } -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 transmission_sink::add_transmission(Transmission t) { + transmission_list.push_back(t); } void transmission_sink::clear_transmission_list() { @@ -446,72 +463,78 @@ int transmission_sink::dowork(int noutput_items, gr_vector_const_void_star &inpu int16_t sample_buf_s; int nwritten = 0; + if (state == STOPPED) { + return noutput_items; + } + // A Termination Tag was receive if (d_termination_flag) { d_termination_flag = false; if (d_current_call == NULL) { - BOOST_LOG_TRIVIAL(error) << "wav - no current call, but in temination loop"; + BOOST_LOG_TRIVIAL(error) << "wav - no current call, but in termination loop"; state = STOPPED; return noutput_items; } + if (state == IGNORE ) { + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tResetting state from IGNORE to IDLE: " << noutput_items; + state = IDLE; + } if (d_sample_count > 0) { - BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tTERM - record_more_transmissions = false, setting Recorder More: " << record_more_transmissions << " - count: " << d_sample_count; - + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tTERMINATING! - 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) { - BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tTERM - skipped: " << noutput_items; + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tTERM - there were some items to output: " << noutput_items; } + } else { + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tTERM - skipped.... - count: " << d_sample_count; } // 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) { - BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tWAV - Weird! State was IDLE but record_more_transmissions was FALSE - count: " << d_sample_count; - } - 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 STATE was IDLE: " << current_filename << std::endl; - - close_wav(false); - } - - time_t current_time = time(NULL); - if (current_time == d_start_time) { - d_start_time = current_time + 1; - } else { - d_start_time = current_time; - } - - // create a new filename, based on the current time and source. - create_base_filename(); - strcpy(current_filename, current_base_filename); - strcat(current_filename, ".wav"); - if (!open_internal(current_filename)) { - BOOST_LOG_TRIVIAL(error) << "can't open file"; - return noutput_items; - } - - BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tStarting new Transmission \tSrc ID: " << curr_src_id; + if (state == IGNORE ) { + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tIGNORE missing count: " << noutput_items; + return noutput_items; + } - // curr_src_id = d_current_call->get_current_source_id(); - record_more_transmissions = false; - state = RECORDING; + if (state == IDLE) { + //BOOST_LOG_TRIVIAL(info) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tIDLE but haven't seen Group ID yet, missing count: " << noutput_items; + //return noutput_items; + 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 STATE was IDLE: " << current_filename << std::endl; + + close_wav(false); + } + + time_t current_time = time(NULL); + if (current_time == d_start_time) { + d_start_time = current_time + 1; + } else { + d_start_time = current_time; + } + + // create a new filename, based on the current time and source. + create_base_filename(); + strcpy(current_filename, current_base_filename); + strcat(current_filename, ".wav"); + if (!open_internal(current_filename)) { + BOOST_LOG_TRIVIAL(error) << "can't open file"; + return noutput_items; + } + + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\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(); + state = RECORDING; + } + if (!d_fp) // drop output on the floor { BOOST_LOG_TRIVIAL(error) << "Wav - Dropping items, no fp or Current Call: " << noutput_items << " Filename: " << current_filename << " Current sample count: " << d_sample_count << std::endl; @@ -537,8 +560,13 @@ int transmission_sink::dowork(int noutput_items, gr_vector_const_void_star &inpu } } + d_stop_time = time(NULL); + d_last_write_time = std::chrono::steady_clock::now(); + if (nwritten < noutput_items) { BOOST_LOG_TRIVIAL(error) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\tFailed to Write! Wrote: " << nwritten << " of " << noutput_items; + } else { + BOOST_LOG_TRIVIAL(trace) << "[" << d_current_call_short_name << "]\t\033[0;34m" << d_current_call_num << "C\033[0m\tTG: " << d_current_call_talkgroup_display << "\tFreq: " << format_freq(d_current_call_freq) << "\t Wrote: " << nwritten << " of " << noutput_items; } return noutput_items; } diff --git a/trunk-recorder/gr_blocks/transmission_sink.h b/trunk-recorder/gr_blocks/transmission_sink.h index 88e3b6a49..4fcaf788c 100644 --- a/trunk-recorder/gr_blocks/transmission_sink.h +++ b/trunk-recorder/gr_blocks/transmission_sink.h @@ -52,6 +52,7 @@ class BLOCKS_API transmission_sink : virtual public sync_block { bool d_termination_flag; time_t d_start_time; time_t d_stop_time; + std::chrono::time_point d_last_write_time; long d_spike_count; long d_error_count; long curr_src_id; @@ -66,8 +67,9 @@ class BLOCKS_API transmission_sink : virtual public sync_block { double d_current_call_freq; double d_prior_transmission_length; long d_current_call_talkgroup; + long d_current_call_talkgroup_encoded; std::string d_current_call_talkgroup_display; - bool record_more_transmissions; + protected: unsigned d_sample_count; @@ -94,6 +96,7 @@ class BLOCKS_API transmission_sink : virtual public sync_block { protected: bool stop(); bool open_internal(const char *filename); + std::vector transmission_list; State state; @@ -127,7 +130,6 @@ class BLOCKS_API transmission_sink : virtual public sync_block { void set_source(long src); void set_sample_rate(unsigned int sample_rate); void set_bits_per_sample(int bits_per_sample); - void set_record_more_transmissions(bool more); void clear_transmission_list(); std::vector get_transmission_list(); void add_transmission(Transmission t); @@ -143,6 +145,8 @@ class BLOCKS_API transmission_sink : virtual public sync_block { State get_state(); time_t get_start_time(); time_t get_stop_time(); + std::chrono::time_point get_last_write_time(); + }; } /* namespace blocks */ diff --git a/trunk-recorder/main.cc b/trunk-recorder/main.cc index 560cfec6d..292c85e28 100644 --- a/trunk-recorder/main.cc +++ b/trunk-recorder/main.cc @@ -200,8 +200,11 @@ bool load_config(string config_file) { BOOST_LOG_TRIVIAL(info) << "Enable Audio Streaming: " << config.enable_audio_streaming; config.record_uu_v_calls = pt.get("recordUUVCalls", true); BOOST_LOG_TRIVIAL(info) << "Record Unit to Unit Voice Calls: " << config.record_uu_v_calls; + config.new_call_from_update = pt.get("newCallFromUpdate", true); + BOOST_LOG_TRIVIAL(info) << "New Call from UPDATE Messages" << config.new_call_from_update; std::string frequency_format_string = pt.get("frequencyFormat", "mhz"); + if (boost::iequals(frequency_format_string, "mhz")) { frequency_format = 1; } else if (boost::iequals(frequency_format_string, "hz")) { @@ -868,91 +871,59 @@ void manage_calls() { } // Handle Trunked Calls - 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(); - } - // we do not need to stop Monitoring Calls, we can just delete them - if (state == MONITORING) { + if ((state == MONITORING) && (call->since_last_update() > config.call_timeout)) { ended_call = true; it = calls.erase(it); delete call; continue; - } - } - - // 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) { - - call->conclude_call(); - - // The State of the Recorders has changed, so lets send an update - ended_call = true; - Recorder *recorder = call->get_recorder(); - if (recorder != NULL) { - plugman_setup_recorder(recorder); - } - it = calls.erase(it); - delete call; - continue; } - // We are checking to make sure a Call hasn't gotten stuck. If it is in the INACTIVE state - if (state == INACTIVE) { + if (state == RECORDING) { 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 (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(); + // Stop the call if: + // - there hasn't been an UPDATE for it on the Control Channel in X seconds AND the recorder hasn't written anything in X seconds + // OR + // - the recorder has been stopped + // actually, we don't want to remove a recorder as soon as it is stopped because we want to drain everything from the gnuradio flowgraph + if (recorder->since_last_write() > config.call_timeout) { + 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 Stopping Call because of Recorder \u001b[0m Rec last write: " << recorder->since_last_write() << " State: " << format_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 call->set_state(COMPLETED); call->conclude_call(); // The State of the Recorders has changed, so lets send an update ended_call = true; - if (recorder != NULL) { plugman_setup_recorder(recorder); } it = calls.erase(it); delete call; continue; - } + } else { + //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[36m Still good!! \u001b[0m Rec last write: " << recorder->since_last_write() << " State: " << format_state(recorder->get_state()); - // 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)) { - //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 - // set the Call state to COMPLETED - call->set_state(COMPLETED); + } + } else if (call->since_last_update() > config.call_timeout) { + Recorder *recorder = call->get_recorder(); + // 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 Call UPDATEs has been inactive for more than " << config.call_timeout << " Sec \u001b[0m Rec last write: " << recorder->since_last_write() << " State: " << format_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 + /* call->set_state(COMPLETED); call->conclude_call(); - if (recorder != NULL) { - plugman_setup_recorder(recorder); - } // The State of the Recorders has changed, so lets send an update ended_call = true; + if (recorder != NULL) { + plugman_setup_recorder(recorder); + } it = calls.erase(it); delete call; - continue; - }*/ - } else { - BOOST_LOG_TRIVIAL(error) << "[" << 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 Call set to Inactive, but has no recorder\u001b[0m"; - } + continue;*/ } + ++it; // if rx is active @@ -997,7 +968,7 @@ void unit_location(System *sys, long source_id, long talkgroup_num) { plugman_unit_location(sys, source_id, talkgroup_num); } -void handle_call_grant(TrunkMessage message, System *sys) { +void handle_call_grant(TrunkMessage message, System *sys, bool grant_message) { bool call_found = false; bool duplicate_grant = false; bool superseding_grant = false; @@ -1030,7 +1001,8 @@ void handle_call_grant(TrunkMessage message, System *sys) { continue; } - if ((call->get_talkgroup() == message.talkgroup) && (call->get_phase2_tdma() == message.phase2_tdma)) { + if (call->get_talkgroup() == message.talkgroup) { + if ((call->get_phase2_tdma() == message.phase2_tdma) && (call->get_tdma_slot() == message.tdma_slot) ) { if (call->get_sys_num() != message.sys_num) { if (call->get_system()->get_multiSite() && sys->get_multiSite()) { if (call->get_system()->get_wacn() == sys->get_wacn()) { @@ -1079,21 +1051,12 @@ void handle_call_grant(TrunkMessage message, System *sys) { } } } + } } } 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\033[0m\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); @@ -1108,31 +1071,15 @@ void handle_call_grant(TrunkMessage message, System *sys) { 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\033[0m\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"; - + 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[36mShould be Stopping 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; + 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\033[0m\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++; } @@ -1171,8 +1118,10 @@ void handle_call_grant(TrunkMessage message, System *sys) { } else { recording_started = start_recorder(call, message, sys); - } - + if (recording_started && !grant_message) { + 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[36mThis was an UPDATE"; + } + } calls.push_back(call); plugman_call_start(call); plugman_calls_active(calls); @@ -1202,19 +1151,6 @@ void handle_call_update(TrunkMessage message, System *sys) { 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\033[0m\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\033[0m\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); @@ -1223,7 +1159,8 @@ void handle_call_update(TrunkMessage message, System *sys) { } if (!call_found) { - // BOOST_LOG_TRIVIAL(error) << "Weird - call not found for UPDATE\tFreq: " << format_freq(message.freq) << "\tTG:" << message.freq; + // Note: some calls maybe removed before the UPDATEs stop on the trunking channel if there is some GAP in the updates. + // BOOST_LOG_TRIVIAL(info) << "Call not found for UPDATE mesg - either we missed GRANT or removed Call too soon\tFreq: " << format_freq(message.freq) << "\tTG:" << message.talkgroup << "\tSource: " << message.source << "\tSys Num: " << message.sys_num << "\tTDMA Slot: " << message.tdma_slot << "\tTDMA: " << message.phase2_tdma; } } @@ -1233,16 +1170,22 @@ void handle_message(std::vector messages, System *sys) { switch (message.message_type) { case GRANT: - handle_call_grant(message, sys); + handle_call_grant(message, sys, true); break; case UPDATE: - handle_call_update(message, sys); + if (config.new_call_from_update) { + // Treat UPDATE as a GRANT and start a new call if we don't have one for this TG + handle_call_grant(message, sys, false); + } else { + // Treat UPDATE as an UPDATE and only update existing calls + handle_call_update(message, sys); + } break; case UU_V_GRANT: if (config.record_uu_v_calls) { - handle_call_grant(message, sys); + handle_call_grant(message, sys, true); } break; diff --git a/trunk-recorder/recorders/analog_recorder.cc b/trunk-recorder/recorders/analog_recorder.cc index 8d4da0b2d..5af62cbb9 100644 --- a/trunk-recorder/recorders/analog_recorder.cc +++ b/trunk-recorder/recorders/analog_recorder.cc @@ -274,10 +274,6 @@ std::vector analog_recorder::get_transmission_list() { return wav_sink->get_transmission_list(); } -void analog_recorder::set_record_more_transmissions(bool more) { - wav_sink->set_record_more_transmissions(more); -} - void analog_recorder::stop() { if (state == ACTIVE) { recording_duration += wav_sink->length_in_seconds(); diff --git a/trunk-recorder/recorders/analog_recorder.h b/trunk-recorder/recorders/analog_recorder.h index daa841c36..732b050bb 100644 --- a/trunk-recorder/recorders/analog_recorder.h +++ b/trunk-recorder/recorders/analog_recorder.h @@ -91,7 +91,6 @@ class analog_recorder : public gr::hier_block2, public Recorder { int lastupdate(); long elapsed(); static bool logging; - void set_record_more_transmissions(bool more); void process_message_queues(void); void decoder_callback_handler(long unitId, const char *signaling_type, gr::blocks::SignalType signal); void plugin_callback_handler(int16_t *samples, int sampleCount); diff --git a/trunk-recorder/recorders/dmr_recorder.h b/trunk-recorder/recorders/dmr_recorder.h index ff94abe65..e7c071936 100644 --- a/trunk-recorder/recorders/dmr_recorder.h +++ b/trunk-recorder/recorders/dmr_recorder.h @@ -42,7 +42,6 @@ class dmr_recorder : virtual public gr::hier_block2, virtual public Recorder { virtual void set_tdma(bool phase2) = 0; virtual void switch_tdma(bool phase2) = 0; virtual void set_tdma_slot(int slot) = 0; - virtual void set_record_more_transmissions(bool more) = 0; virtual double since_last_write() = 0; virtual void generate_arb_taps() = 0; virtual double get_current_length() = 0; diff --git a/trunk-recorder/recorders/dmr_recorder_impl.cc b/trunk-recorder/recorders/dmr_recorder_impl.cc index c5f5ce448..b895a4cc2 100644 --- a/trunk-recorder/recorders/dmr_recorder_impl.cc +++ b/trunk-recorder/recorders/dmr_recorder_impl.cc @@ -357,11 +357,6 @@ void dmr_recorder_impl::tune_offset(double f) { } } -void dmr_recorder_impl::set_record_more_transmissions(bool more) { - - return wav_sink_slot0->set_record_more_transmissions(more); -} - bool compareTransmissions(Transmission t1, Transmission t2) { return (t1.start_time < t2.start_time); } diff --git a/trunk-recorder/recorders/dmr_recorder_impl.h b/trunk-recorder/recorders/dmr_recorder_impl.h index 0cdb0e6c9..fbe336a28 100644 --- a/trunk-recorder/recorders/dmr_recorder_impl.h +++ b/trunk-recorder/recorders/dmr_recorder_impl.h @@ -100,7 +100,6 @@ class dmr_recorder_impl : public dmr_recorder { void set_tdma(bool phase2); void switch_tdma(bool phase2); void set_tdma_slot(int slot); - void set_record_more_transmissions(bool more); double since_last_write(); void generate_arb_taps(); double get_current_length(); diff --git a/trunk-recorder/recorders/p25_recorder.h b/trunk-recorder/recorders/p25_recorder.h index 6289aef74..5747f36e5 100644 --- a/trunk-recorder/recorders/p25_recorder.h +++ b/trunk-recorder/recorders/p25_recorder.h @@ -45,7 +45,6 @@ class p25_recorder : virtual public gr::hier_block2, virtual public Recorder { virtual void set_tdma(bool phase2) = 0; virtual void switch_tdma(bool phase2) = 0; virtual void set_tdma_slot(int slot) = 0; - virtual void set_record_more_transmissions(bool more) = 0; virtual void set_source(long src) = 0; virtual double since_last_write() = 0; virtual double get_current_length() = 0; diff --git a/trunk-recorder/recorders/p25_recorder_decode.cc b/trunk-recorder/recorders/p25_recorder_decode.cc index 91c10b11e..148f178c7 100644 --- a/trunk-recorder/recorders/p25_recorder_decode.cc +++ b/trunk-recorder/recorders/p25_recorder_decode.cc @@ -33,9 +33,6 @@ void p25_recorder_decode::start(Call *call) { void p25_recorder_decode::set_xor_mask(const char *mask) { op25_frame_assembler->set_xormask(mask); } -void p25_recorder_decode::set_record_more_transmissions(bool more) { - wav_sink->set_record_more_transmissions(more); -} void p25_recorder_decode::set_source(long src) { wav_sink->set_source(src); @@ -59,8 +56,9 @@ State p25_recorder_decode::get_state() { } double p25_recorder_decode::since_last_write() { - time_t now = time(NULL); - return now - wav_sink->get_stop_time(); + auto end = std::chrono::steady_clock::now(); + std::chrono::duration diff = end - wav_sink->get_last_write_time(); + return diff.count(); } void p25_recorder_decode::switch_tdma(bool phase2_tdma) { @@ -94,7 +92,6 @@ void p25_recorder_decode::initialize(int silence_frames) { bool do_nocrypt = 1; op25_frame_assembler = gr::op25_repeater::p25_frame_assembler::make(silence_frames, udp_host, udp_port, verbosity, do_imbe, do_output, do_msgq, rx_queue, do_audio_output, do_tdma, do_nocrypt); - levels = gr::blocks::multiply_const_ss::make(1); if (use_streaming) { @@ -108,7 +105,6 @@ void p25_recorder_decode::initialize(int silence_frames) { if (use_streaming) { connect(levels, 0, plugin_sink, 0); } - connect(levels, 0, wav_sink, 0); } @@ -121,3 +117,23 @@ void p25_recorder_decode::plugin_callback_handler(int16_t *samples, int sampleCo double p25_recorder_decode::get_output_sample_rate() { return 8000; } + +// This lead to weird Segfaults. The concept is trying to clear out the buffers for a new call +void p25_recorder_decode::reset_block(gr::basic_block_sptr block) { + gr::block_detail_sptr detail; + gr::block_sptr grblock = cast_to_block_sptr(block); + detail = grblock->detail(); + detail->reset_nitem_counters(); + detail->clear_tags(); +} + +void p25_recorder_decode::reset() { + reset_block(op25_frame_assembler); + reset_block(slicer); + reset_block(levels); + reset_block(wav_sink); +} + +gr::op25_repeater::p25_frame_assembler::sptr p25_recorder_decode::get_transmission_sink() { + return op25_frame_assembler; +} \ No newline at end of file diff --git a/trunk-recorder/recorders/p25_recorder_decode.h b/trunk-recorder/recorders/p25_recorder_decode.h index d46461210..fd6452d0a 100644 --- a/trunk-recorder/recorders/p25_recorder_decode.h +++ b/trunk-recorder/recorders/p25_recorder_decode.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -56,13 +57,14 @@ class p25_recorder_decode : public gr::hier_block2 { p25_recorder_decode(Recorder *recorder); void set_tdma_slot(int slot); std::vector get_transmission_list(); - void set_record_more_transmissions(bool more); void set_source(long src); void set_xor_mask(const char *mask); void switch_tdma(bool phase2_tdma); void start(Call *call); double since_last_write(); void stop(); + void reset(); + void reset_block(gr::basic_block_sptr block); int tdma_slot; bool delay_open; virtual ~p25_recorder_decode(); @@ -70,5 +72,7 @@ class p25_recorder_decode : public gr::hier_block2 { void plugin_callback_handler(int16_t *samples, int sampleCount); double get_output_sample_rate(); State get_state(); + gr::op25_repeater::p25_frame_assembler::sptr get_transmission_sink(); + }; #endif \ No newline at end of file diff --git a/trunk-recorder/recorders/p25_recorder_fsk4_demod.cc b/trunk-recorder/recorders/p25_recorder_fsk4_demod.cc index f10dc2ac9..adbfe1dbc 100644 --- a/trunk-recorder/recorders/p25_recorder_fsk4_demod.cc +++ b/trunk-recorder/recorders/p25_recorder_fsk4_demod.cc @@ -15,8 +15,18 @@ p25_recorder_fsk4_demod::p25_recorder_fsk4_demod() p25_recorder_fsk4_demod::~p25_recorder_fsk4_demod() { } - +void p25_recorder_fsk4_demod::reset_block(gr::basic_block_sptr block) { + gr::block_detail_sptr detail; + gr::block_sptr grblock = cast_to_block_sptr(block); + detail = grblock->detail(); + detail->reset_nitem_counters(); +} void p25_recorder_fsk4_demod::reset() { + reset_block(pll_freq_lock); + reset_block(pll_amp); + reset_block(noise_filter); + reset_block(sym_filter); + reset_block(fsk4_demod); /* pll_freq_lock->update_gains(); pll_freq_lock->frequency_limit(); @@ -47,6 +57,8 @@ void p25_recorder_fsk4_demod::initialize() { #endif noise_filter = gr::filter::fft_filter_fff::make(1.0, baseband_noise_filter_taps); + baseband_amp = gr::op25_repeater::rmsagc_ff::make(0.01, 1.00); + // FSK4: Symbol Taps double symbol_decim = 1; @@ -56,13 +68,33 @@ void p25_recorder_fsk4_demod::initialize() { sym_filter = gr::filter::fir_filter_fff::make(symbol_decim, sym_taps); // FSK4: FSK4 Demod - locked at Phase 1 rates, since it can only be Phase 1 - tune_queue = gr::msg_queue::make(20); + int omega = phase1_samples_per_symbol; + float gain_mu = 0.175; + float mu = 0.5; + float gain_omega = .25 * gain_mu * gain_mu; //critically damped + float omega_relative_limit = 0.005; + clock_recovery = gr::digital::clock_recovery_mm_ff::make(omega, gain_omega, mu, gain_mu, omega_relative_limit); fsk4_demod = gr::op25_repeater::fsk4_demod_ff::make(tune_queue, phase1_channel_rate, phase1_symbol_rate); - + int def_symbol_deviation = 600.0; + float fm_demod_gain = phase1_channel_rate / (2 * pi * def_symbol_deviation); + fm_demod = gr::analog::quadrature_demod_cf::make(fm_demod_gain); + + + // This is the original Approach connect(self(), 0, pll_freq_lock, 0); connect(pll_freq_lock, 0, pll_amp, 0); connect(pll_amp, 0, noise_filter, 0); connect(noise_filter, 0, sym_filter, 0); - connect(sym_filter, 0, fsk4_demod, 0); + connect(sym_filter, 0,fsk4_demod, 0); + connect(fsk4_demod, 0, self(), 0); + +/* + // This is the current approch in OP25, but they generate some of the filters differently + connect(self(), 0, fm_demod,0); + connect(fm_demod, 0, baseband_amp,0); + connect(baseband_amp, 0, sym_filter, 0); + connect(sym_filter, 0,fsk4_demod, 0); connect(fsk4_demod, 0, self(), 0); +*/ + } \ No newline at end of file diff --git a/trunk-recorder/recorders/p25_recorder_fsk4_demod.h b/trunk-recorder/recorders/p25_recorder_fsk4_demod.h index 950ba7eaa..bd324e814 100644 --- a/trunk-recorder/recorders/p25_recorder_fsk4_demod.h +++ b/trunk-recorder/recorders/p25_recorder_fsk4_demod.h @@ -3,7 +3,9 @@ #include #include +#include #include +#include #include #include #include @@ -19,9 +21,11 @@ #include #include #endif - +#include "../gr_blocks/rms_agc.h" #include +#include #include +#include class p25_recorder_fsk4_demod; @@ -53,11 +57,14 @@ class p25_recorder_fsk4_demod : public gr::hier_block2 { std::vector cutoff_filter_coeffs; gr::filter::fft_filter_fff::sptr noise_filter; gr::filter::fir_filter_fff::sptr sym_filter; - gr::filter::fft_filter_ccf::sptr cutoff_filter; gr::blocks::multiply_const_ff::sptr pll_amp; gr::analog::pll_freqdet_cf::sptr pll_freq_lock; + gr::analog::quadrature_demod_cf::sptr fm_demod; + gr::op25_repeater::rmsagc_ff::sptr baseband_amp; gr::op25_repeater::fsk4_demod_ff::sptr fsk4_demod; gr::op25_repeater::fsk4_slicer_fb::sptr slicer; + gr::digital::clock_recovery_mm_ff::sptr clock_recovery; + void reset_block(gr::basic_block_sptr block); }; #endif \ No newline at end of file diff --git a/trunk-recorder/recorders/p25_recorder_impl.cc b/trunk-recorder/recorders/p25_recorder_impl.cc index 07a3547df..bea6e4429 100644 --- a/trunk-recorder/recorders/p25_recorder_impl.cc +++ b/trunk-recorder/recorders/p25_recorder_impl.cc @@ -155,8 +155,7 @@ void p25_recorder_impl::initialize_prefilter() { rms_agc = gr::blocks::rms_agc::make(0.45, 0.85); //rms_agc = gr::op25_repeater::rmsagc_ff::make(0.45, 0.85); - fll_band_edge = gr::digital::fll_band_edge_cc::make(sps, def_excess_bw, 2*sps+1, (2.0*pi)/sps/250); - + fll_band_edge = gr::digital::fll_band_edge_cc::make(sps, def_excess_bw, 2*sps+1, (2.0*pi)/sps/350); connect(self(), 0, valve, 0); @@ -165,10 +164,10 @@ void p25_recorder_impl::initialize_prefilter() { connect(bandpass_filter, 0, mixer, 0); connect(bfo, 0, mixer, 1); } else { - connect(valve, 0, mixer, 0); + connect(valve, 0, mixer, 0); connect(lo, 0, mixer, 1); } - connect(mixer, 0, lowpass_filter, 0); + connect(mixer, 0,lowpass_filter, 0); if (arb_rate == 1.0) { connect(lowpass_filter, 0, cutoff_filter, 0); } else { @@ -177,7 +176,7 @@ void p25_recorder_impl::initialize_prefilter() { } connect(cutoff_filter,0, squelch, 0); connect(squelch, 0, rms_agc, 0); - connect(rms_agc,0, fll_band_edge, 0); + connect(rms_agc,0, fll_band_edge, 0); } @@ -218,11 +217,13 @@ void p25_recorder_impl::initialize(Source *src) { modulation_selector->set_enabled(true); - connect(fll_band_edge, 0, modulation_selector, 0); + connect(fll_band_edge,0, modulation_selector, 0); connect(modulation_selector, 0, fsk4_demod, 0); connect(fsk4_demod, 0, fsk4_p25_decode, 0); connect(modulation_selector, 1, qpsk_demod, 0); connect(qpsk_demod, 0, qpsk_p25_decode, 0); + + } void p25_recorder_impl::switch_tdma(bool phase2) { @@ -260,8 +261,45 @@ void p25_recorder_impl::set_tdma(bool phase2) { } } +void p25_recorder_impl::reset_block(gr::basic_block_sptr block) { + gr::block_detail_sptr detail; + gr::block_sptr grblock = cast_to_block_sptr(block); + detail = grblock->detail(); + detail->reset_nitem_counters(); +} void p25_recorder_impl::clear() { - // op25_frame_assembler->clear(); + // This lead to weird SegFaults, but the goal was to clear out buffers inbetween transmissions. + /* + if (double_decim) { + //reset_block(bandpass_filter); + //reset_block(bfo); + } else { + //reset_block(lo); + } + reset_block(lowpass_filter); + reset_block(mixer); + + if (arb_rate != 1.0) { + reset_block(arb_resampler); + } + + reset_block(cutoff_filter); + reset_block(squelch); + //reset_block(rms_agc); // RMS AGC cant be made into a basic block + reset_block(fll_band_edge); + reset_block(modulation_selector); + + + //reset_block(qpsk_demod); // bad - Seg Faults + //reset_block(qpsk_p25_decode); // bad - Seg Faults + //reset_block(fsk4_demod); // bad - Seg Faults + //reset_block(fsk4_p25_decode); // bad - Seg Faults + + + qpsk_demod->reset(); + qpsk_p25_decode->reset(); + fsk4_demod->reset(); + fsk4_p25_decode->reset();*/ } void p25_recorder_impl::autotune() { @@ -398,13 +436,6 @@ void p25_recorder_impl::tune_offset(double f) { }*/ } -void p25_recorder_impl::set_record_more_transmissions(bool more) { - if (qpsk_mod) { - return qpsk_p25_decode->set_record_more_transmissions(more); - } else { - return fsk4_p25_decode->set_record_more_transmissions(more); - } -} void p25_recorder_impl::set_source(long src) { if (qpsk_mod) { @@ -429,12 +460,13 @@ void p25_recorder_impl::stop() { } else { recording_duration += fsk4_p25_decode->get_current_length(); } - clear(); + BOOST_LOG_TRIVIAL(info) << "[" << call->get_short_name() << "]\t\033[0;34m" << call->get_call_num() << "C\033[0m\tTG: " << this->call->get_talkgroup_display() << "\tFreq: " << format_freq(chan_freq) << "\t\u001b[33mStopping P25 Recorder Num [" << rec_num << "]\u001b[0m\tTDMA: " << d_phase2_tdma << "\tSlot: " << tdma_slot << "\tHz Error: " << this->get_freq_error(); state = INACTIVE; valve->set_enabled(false); + clear(); if (qpsk_mod) { qpsk_p25_decode->stop(); } else { diff --git a/trunk-recorder/recorders/p25_recorder_impl.h b/trunk-recorder/recorders/p25_recorder_impl.h index f968899b6..ce35d4338 100644 --- a/trunk-recorder/recorders/p25_recorder_impl.h +++ b/trunk-recorder/recorders/p25_recorder_impl.h @@ -44,8 +44,10 @@ #endif #include +#include #include #include +#include #include #include @@ -57,6 +59,10 @@ #include "p25_recorder_decode.h" #include "p25_recorder_fsk4_demod.h" #include "p25_recorder_qpsk_demod.h" +#include "../../lib/gr-latency-manager/include/latency_manager.h" +#include "../../lib/gr-latency-manager/include/tag_to_msg.h" +#include "../../lib/gr-latency/latency_probe.h" +#include "../../lib/gr-latency/latency_tagger.h" #include "recorder.h" class Source; @@ -87,7 +93,6 @@ class p25_recorder_impl : public p25_recorder { void set_tdma(bool phase2); void switch_tdma(bool phase2); void set_tdma_slot(int slot); - void set_record_more_transmissions(bool more); void set_source(long src); double since_last_write(); void generate_arb_taps(); @@ -121,6 +126,7 @@ class p25_recorder_impl : public p25_recorder { gr::blocks::copy::sptr valve; gr::digital::fll_band_edge_cc::sptr fll_band_edge; gr::blocks::rms_agc::sptr rms_agc; + //gr::op25_repeater::rmsagc_ff::sptr rms_agc; // gr::blocks::multiply_const_ss::sptr levels; @@ -130,6 +136,7 @@ class p25_recorder_impl : public p25_recorder { p25_recorder_decode_sptr qpsk_p25_decode; + private: double system_channel_rate; double arb_rate; @@ -169,6 +176,7 @@ class p25_recorder_impl : public p25_recorder { gr::filter::pfb_arb_resampler_ccf::sptr arb_resampler; gr::blocks::multiply_const_ff::sptr rescale; + void reset_block(gr::basic_block_sptr block); }; #endif // ifndef P25_RECORDER_H diff --git a/trunk-recorder/recorders/p25_recorder_qpsk_demod.cc b/trunk-recorder/recorders/p25_recorder_qpsk_demod.cc index 686e9c4a0..9bab015cf 100644 --- a/trunk-recorder/recorders/p25_recorder_qpsk_demod.cc +++ b/trunk-recorder/recorders/p25_recorder_qpsk_demod.cc @@ -20,10 +20,23 @@ p25_recorder_qpsk_demod::p25_recorder_qpsk_demod() p25_recorder_qpsk_demod::~p25_recorder_qpsk_demod() { } +void p25_recorder_qpsk_demod::reset_block(gr::basic_block_sptr block) { + gr::block_detail_sptr detail; + gr::block_sptr grblock = cast_to_block_sptr(block); + detail = grblock->detail(); + detail->reset_nitem_counters(); +} + void p25_recorder_qpsk_demod::reset() { costas->set_phase(0); costas->set_frequency(0); clock->reset(); + + reset_block(clock); + reset_block(costas); + reset_block(diffdec); + reset_block(to_float); + reset_block(rescale); } void p25_recorder_qpsk_demod::switch_tdma(bool phase2) { diff --git a/trunk-recorder/recorders/p25_recorder_qpsk_demod.h b/trunk-recorder/recorders/p25_recorder_qpsk_demod.h index a8016e1d9..20029ad01 100644 --- a/trunk-recorder/recorders/p25_recorder_qpsk_demod.h +++ b/trunk-recorder/recorders/p25_recorder_qpsk_demod.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -68,5 +69,7 @@ class p25_recorder_qpsk_demod : public gr::hier_block2 { gr::digital::diff_phasor_cc::sptr diffdec; gr::blocks::complex_to_arg::sptr to_float; gr::blocks::multiply_const_ff::sptr rescale; + + void reset_block(gr::basic_block_sptr block); }; #endif \ No newline at end of file diff --git a/trunk-recorder/recorders/recorder.h b/trunk-recorder/recorders/recorder.h index 13c3f56d0..f1c56dcf2 100644 --- a/trunk-recorder/recorders/recorder.h +++ b/trunk-recorder/recorders/recorder.h @@ -85,7 +85,6 @@ class Recorder { virtual long get_source_count() { return 0; }; virtual long get_wav_hz() { return 8000; }; virtual long get_talkgroup() { return 0; }; - virtual void set_record_more_transmissions(bool more){}; virtual State get_state() { return INACTIVE; }; std::string get_type_string(); Recorder_Type get_type() { return type; } diff --git a/trunk-recorder/state.h b/trunk-recorder/state.h index e1d29f4e7..ee497f4fc 100644 --- a/trunk-recorder/state.h +++ b/trunk-recorder/state.h @@ -8,7 +8,8 @@ enum State { MONITORING = 0, IDLE = 4, COMPLETED = 5, STOPPED = 6, - AVAILABLE = 7 }; + AVAILABLE = 7, + IGNORE = 8 }; enum MonitoringState { UNSPECIFIED = 0, diff --git a/trunk-recorder/systems/smartnet_parser.cc b/trunk-recorder/systems/smartnet_parser.cc index 241b28a1c..b300d3755 100644 --- a/trunk-recorder/systems/smartnet_parser.cc +++ b/trunk-recorder/systems/smartnet_parser.cc @@ -58,7 +58,7 @@ double SmartnetParser::getfreq(int cmd, System *sys) { freq = sys->get_bandplan_base() + (sys->get_bandplan_spacing() * (cmd - sys->get_bandplan_offset())); } - // cout << "Orig: " < SmartnetParser::parse_message(std::string s, vector().swap(x); // raw OSW stream - // BOOST_LOG_TRIVIAL(warning) - // << "[" << system->get_short_name() - // << "] [OSW!] [[["<< std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << "]]]"; + //BOOST_LOG_TRIVIAL(info) + // << "[" << system->get_short_name() + // << "] [OSW!] [[["<< std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << "]]]"; // Message parsing strategy // OSW stack: [0 1 2 3 4] (consume) - consume is how many OSWs to consume. This includes the 1-OSW regular increment. @@ -229,13 +229,13 @@ std::vector SmartnetParser::parse_message(std::string s, // this is a call continue if (stack[3].grp) { // this is a group call continue - // BOOST_LOG_TRIVIAL(warning) - // << "[" << system->get_short_name() << "] [group call continue] [ " - // << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " - // << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | " - // << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | >" - // << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " - // << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; + BOOST_LOG_TRIVIAL(trace) + << "[" << system->get_short_name() << "] [group call continue] [ " + << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::dec << stack[0].full_address << " " << stack[0].address << " | " + << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::dec << stack[1].full_address << " " << stack[1].address << " | " + << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::dec << stack[2].full_address << " " << stack[2].address << " | >" + << getfreq(stack[3].cmd, system) << " " << std::hex << stack[3].grp << " " << std::dec << stack[3].full_address << " " << stack[3].address << "< | " + << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::dec << stack[4].full_address << " " << stack[4].address << " ]"; message.message_type = UPDATE; message.freq = getfreq(stack[3].cmd, system); message.talkgroup = stack[3].address; @@ -252,13 +252,13 @@ std::vector SmartnetParser::parse_message(std::string s, return messages; } else { // this is an individual call continue - // BOOST_LOG_TRIVIAL(warning) - // << "[" << system->get_short_name() << "] [individual call continue] [ " - // << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " - // << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | " - // << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | >" - // << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " - // << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; + BOOST_LOG_TRIVIAL(trace) + << "[" << system->get_short_name() << "] [individual call continue] [ " + << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " + << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | " + << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | >" + << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " + << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; message.message_type = UNKNOWN; messages.push_back(message); return messages; @@ -336,13 +336,13 @@ std::vector SmartnetParser::parse_message(std::string s, ++numConsumed; if (stack[2].grp) { // this is a group call grant - // BOOST_LOG_TRIVIAL(warning) - // << "[" << system->get_short_name() << "] [group call grant] [ " - // << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " - // << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | >" - // << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | " - // << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " - // << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; + BOOST_LOG_TRIVIAL(trace) + << "[" << system->get_short_name() << "] [group call grant] [ " + << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " + << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | >" + << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | " + << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " + << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; message.message_type = GRANT; message.freq = getfreq(stack[2].cmd, system); message.talkgroup = stack[2].address; @@ -360,13 +360,13 @@ std::vector SmartnetParser::parse_message(std::string s, return messages; } else { // this is an individual call grant - // BOOST_LOG_TRIVIAL(warning) - // << "[" << system->get_short_name() << "] [individual call grant] [ " - // << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " - // << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | >" - // << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | " - // << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " - // << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; + BOOST_LOG_TRIVIAL(trace) + << "[" << system->get_short_name() << "] [individual call grant] [ " + << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " + << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | >" + << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | " + << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " + << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; message.message_type = UNKNOWN; messages.push_back(message); return messages; @@ -488,14 +488,14 @@ std::vector SmartnetParser::parse_message(std::string s, // Adding the logic to test for this might be nice to have (test could be "if we got here, // this OSW is is missing a header or other OSWs that comprise a valid message - // test if we know this OSW command though, and if we do, discard the OSW and move on") - // BOOST_LOG_TRIVIAL(warning) - // << "[" << system->get_short_name() - // << "] [Unknown OSW!] [ " - // << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " - // << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | " - // << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | >" - // << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " - // << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; + BOOST_LOG_TRIVIAL(trace) + << "[" << system->get_short_name() + << "] [Unknown OSW!] [ " + << std::hex << stack[0].cmd << " " << std::hex << stack[0].grp << " " << std::hex << stack[0].full_address << " | " + << std::hex << stack[1].cmd << " " << std::hex << stack[1].grp << " " << std::hex << stack[1].full_address << " | " + << std::hex << stack[2].cmd << " " << std::hex << stack[2].grp << " " << std::hex << stack[2].full_address << " | >" + << std::hex << stack[3].cmd << " " << std::hex << stack[3].grp << " " << std::hex << stack[3].full_address << "< | " + << std::hex << stack[4].cmd << " " << std::hex << stack[4].grp << " " << std::hex << stack[4].full_address << " ]"; message.message_type = UNKNOWN; messages.push_back(message); return messages;