diff --git a/firmware/baseband/audio_stats_collector.hpp b/firmware/baseband/audio_stats_collector.hpp new file mode 100644 index 00000000..189fff80 --- /dev/null +++ b/firmware/baseband/audio_stats_collector.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program 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 2, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __AUDIO_STATS_COLLECTOR_H__ +#define __AUDIO_STATS_COLLECTOR_H__ + +#include "buffer.hpp" +#include "message.hpp" +#include "utility.hpp" + +#include +#include + +class AudioStatsCollector { +public: + template + void feed(buffer_s16_t src, Callback callback) { + consume_audio_buffer(src); + + if( update_stats(src.count, src.sampling_rate) ) { + callback(statistics); + } + } + + template + void mute(const size_t sample_count, const size_t sampling_rate, Callback callback) { + if( update_stats(sample_count, sampling_rate) ) { + callback(statistics); + } + } + +private: + static constexpr float update_interval { 0.1f }; + uint64_t squared_sum { 0 }; + uint32_t max_squared { 0 }; + size_t count { 0 }; + + AudioStatistics statistics; + + void consume_audio_buffer(buffer_s16_t src) { + auto src_p = src.p; + const auto src_end = &src.p[src.count]; + while(src_p < src_end) { + const auto sample = *(src_p++); + const uint64_t sample_squared = sample * sample; + squared_sum += sample_squared; + if( sample_squared > max_squared ) { + max_squared = sample_squared; + } + } + } + + bool update_stats(const size_t sample_count, const size_t sampling_rate) { + count += sample_count; + + const size_t samples_per_update = sampling_rate * update_interval; + + if( count >= samples_per_update ) { + const float squared_sum_f = squared_sum; + const float max_squared_f = max_squared; + const float squared_avg_f = squared_sum_f / count; + statistics.rms_db = complex16_mag_squared_to_dbv_norm(squared_avg_f); + statistics.max_db = complex16_mag_squared_to_dbv_norm(max_squared_f); + statistics.count = count; + + squared_sum = 0; + max_squared = 0; + count = 0; + + return true; + } else { + return false; + } + } +}; + +#endif/*__AUDIO_STATS_COLLECTOR_H__*/ diff --git a/firmware/baseband/baseband_stats_collector.hpp b/firmware/baseband/baseband_stats_collector.hpp new file mode 100644 index 00000000..6fc5439b --- /dev/null +++ b/firmware/baseband/baseband_stats_collector.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program 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 2, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __BASEBAND_STATS_COLLECTOR_H__ +#define __BASEBAND_STATS_COLLECTOR_H__ + +#include "ch.h" + +#include "dsp_types.hpp" +#include "message.hpp" +#include "utility.hpp" + +#include +#include + +class BasebandStatsCollector { +public: + template + void process(buffer_c8_t buffer, Callback callback) { + samples += buffer.count; + + const size_t report_samples = buffer.sampling_rate * report_interval; + const auto report_delta = samples - samples_last_report; + if( report_delta >= report_samples ) { + const auto idle_ticks = chSysGetIdleThread()->total_ticks; + statistics.idle_ticks = (idle_ticks - last_idle_ticks); + last_idle_ticks = idle_ticks; + + const auto baseband_ticks = chThdSelf()->total_ticks; + statistics.baseband_ticks = (baseband_ticks - last_baseband_ticks); + last_baseband_ticks = baseband_ticks; + + statistics.saturation = m4_flag_saturation(); + clear_m4_flag_saturation(); + + callback(statistics); + + samples_last_report = samples; + } + } + +private: + static constexpr float report_interval { 1.0f }; + BasebandStatistics statistics; + size_t samples { 0 }; + size_t samples_last_report { 0 }; + uint32_t last_idle_ticks { 0 }; + uint32_t last_baseband_ticks { 0 }; +}; + +#endif/*__BASEBAND_STATS_COLLECTOR_H__*/ diff --git a/firmware/baseband/channel_stats_collector.hpp b/firmware/baseband/channel_stats_collector.hpp new file mode 100644 index 00000000..4eecb5c9 --- /dev/null +++ b/firmware/baseband/channel_stats_collector.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program 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 2, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __CHANNEL_STATS_COLLECTOR_H__ +#define __CHANNEL_STATS_COLLECTOR_H__ + +#include "dsp_types.hpp" +#include "message.hpp" +#include "utility.hpp" + +#include +#include + +class ChannelStatsCollector { +public: + template + void feed(buffer_c16_t src, Callback callback) { + auto src_p = src.p; + while(src_p < &src.p[src.count]) { + const uint32_t sample = *__SIMD32(src_p)++; + const uint32_t mag_sq = __SMUAD(sample, sample); + if( mag_sq > max_squared ) { + max_squared = mag_sq; + } + } + count += src.count; + + const size_t samples_per_update = src.sampling_rate * update_interval; + + if( count >= samples_per_update ) { + const float max_squared_f = max_squared; + const float max_db_f = complex16_mag_squared_to_dbv_norm(max_squared_f); + const int32_t max_db = max_db_f; + const ChannelStatistics statistics { + .max_db = max_db, + .count = count, + }; + callback(statistics); + + max_squared = 0; + count = 0; + } + } + +private: + static constexpr float update_interval { 0.1f }; + uint32_t max_squared { 0 }; + size_t count { 0 }; +}; + +#endif/*__CHANNEL_STATS_COLLECTOR_H__*/ diff --git a/firmware/baseband/main.cpp b/firmware/baseband/main.cpp index 1b98df09..5e2e0df0 100755 --- a/firmware/baseband/main.cpp +++ b/firmware/baseband/main.cpp @@ -44,6 +44,11 @@ #include "dsp_fir_taps.hpp" #include "dsp_iir.hpp" +#include "baseband_stats_collector.hpp" +#include "rssi_stats_collector.hpp" +#include "channel_stats_collector.hpp" +#include "audio_stats_collector.hpp" + #include "block_decimator.hpp" #include "clock_recovery.hpp" #include "access_code_correlator.hpp" @@ -70,182 +75,6 @@ constexpr auto baseband_thread_priority = NORMALPRIO + 20; constexpr auto rssi_thread_priority = NORMALPRIO + 10; -class BasebandStatsCollector { -public: - template - void process(buffer_c8_t buffer, Callback callback) { - samples += buffer.count; - - const size_t report_samples = buffer.sampling_rate * report_interval; - const auto report_delta = samples - samples_last_report; - if( report_delta >= report_samples ) { - const auto idle_ticks = chSysGetIdleThread()->total_ticks; - statistics.idle_ticks = (idle_ticks - last_idle_ticks); - last_idle_ticks = idle_ticks; - - const auto baseband_ticks = chThdSelf()->total_ticks; - statistics.baseband_ticks = (baseband_ticks - last_baseband_ticks); - last_baseband_ticks = baseband_ticks; - - statistics.saturation = m4_flag_saturation(); - clear_m4_flag_saturation(); - - callback(statistics); - - samples_last_report = samples; - } - } - -private: - static constexpr float report_interval { 1.0f }; - BasebandStatistics statistics; - size_t samples { 0 }; - size_t samples_last_report { 0 }; - uint32_t last_idle_ticks { 0 }; - uint32_t last_baseband_ticks { 0 }; -}; - -class RSSIStatisticsCollector { -public: - template - void process(rf::rssi::buffer_t buffer, Callback callback) { - auto p = buffer.p; - if( p == nullptr ) { - return; - } - - const auto end = &p[buffer.count]; - while(p < end) { - const uint32_t value = *(p++); - - if( statistics.min > value ) { - statistics.min = value; - } - if( statistics.max < value ) { - statistics.max = value; - } - - statistics.accumulator += value; - } - statistics.count += buffer.count; - - const size_t samples_per_update = buffer.sampling_rate * update_interval; - - if( statistics.count >= samples_per_update ) { - callback(statistics); - statistics.accumulator = 0; - statistics.count = 0; - const auto value_0 = *p; - statistics.min = value_0; - statistics.max = value_0; - } - } - -private: - static constexpr float update_interval { 0.1f }; - RSSIStatistics statistics; -}; - -class ChannelStatsCollector { -public: - template - void feed(buffer_c16_t src, Callback callback) { - auto src_p = src.p; - while(src_p < &src.p[src.count]) { - const uint32_t sample = *__SIMD32(src_p)++; - const uint32_t mag_sq = __SMUAD(sample, sample); - if( mag_sq > max_squared ) { - max_squared = mag_sq; - } - } - count += src.count; - - const size_t samples_per_update = src.sampling_rate * update_interval; - - if( count >= samples_per_update ) { - const float max_squared_f = max_squared; - const float max_db_f = complex16_mag_squared_to_dbv_norm(max_squared_f); - const int32_t max_db = max_db_f; - const ChannelStatistics statistics { - .max_db = max_db, - .count = count, - }; - callback(statistics); - - max_squared = 0; - count = 0; - } - } - -private: - static constexpr float update_interval { 0.1f }; - uint32_t max_squared { 0 }; - size_t count { 0 }; -}; - -class AudioStatsCollector { -public: - template - void feed(buffer_s16_t src, Callback callback) { - consume_audio_buffer(src); - - if( update_stats(src.count, src.sampling_rate) ) { - callback(statistics); - } - } - - template - void mute(const size_t sample_count, const size_t sampling_rate, Callback callback) { - if( update_stats(sample_count, sampling_rate) ) { - callback(statistics); - } - } - -private: - static constexpr float update_interval { 0.1f }; - uint64_t squared_sum { 0 }; - uint32_t max_squared { 0 }; - size_t count { 0 }; - - AudioStatistics statistics; - - void consume_audio_buffer(buffer_s16_t src) { - auto src_p = src.p; - const auto src_end = &src.p[src.count]; - while(src_p < src_end) { - const auto sample = *(src_p++); - const uint64_t sample_squared = sample * sample; - squared_sum += sample_squared; - if( sample_squared > max_squared ) { - max_squared = sample_squared; - } - } - } - - bool update_stats(const size_t sample_count, const size_t sampling_rate) { - count += sample_count; - - const size_t samples_per_update = sampling_rate * update_interval; - - if( count >= samples_per_update ) { - const float squared_sum_f = squared_sum; - const float max_squared_f = max_squared; - const float squared_avg_f = squared_sum_f / count; - statistics.rms_db = complex16_mag_squared_to_dbv_norm(squared_avg_f); - statistics.max_db = complex16_mag_squared_to_dbv_norm(max_squared_f); - statistics.count = count; - - squared_sum = 0; - max_squared = 0; - count = 0; - - return true; - } else { - return false; - } - } -}; - class ChannelDecimator { public: enum class DecimationFactor { diff --git a/firmware/baseband/rssi_stats_collector.hpp b/firmware/baseband/rssi_stats_collector.hpp new file mode 100644 index 00000000..c89f3e17 --- /dev/null +++ b/firmware/baseband/rssi_stats_collector.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program 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 2, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __RSSI_STATS_COLLECTOR_H__ +#define __RSSI_STATS_COLLECTOR_H__ + +#include "rssi.hpp" +#include "message.hpp" + +#include +#include + +class RSSIStatisticsCollector { +public: + template + void process(rf::rssi::buffer_t buffer, Callback callback) { + auto p = buffer.p; + if( p == nullptr ) { + return; + } + + const auto end = &p[buffer.count]; + while(p < end) { + const uint32_t value = *(p++); + + if( statistics.min > value ) { + statistics.min = value; + } + if( statistics.max < value ) { + statistics.max = value; + } + + statistics.accumulator += value; + } + statistics.count += buffer.count; + + const size_t samples_per_update = buffer.sampling_rate * update_interval; + + if( statistics.count >= samples_per_update ) { + callback(statistics); + statistics.accumulator = 0; + statistics.count = 0; + const auto value_0 = *p; + statistics.min = value_0; + statistics.max = value_0; + } + } + +private: + static constexpr float update_interval { 0.1f }; + RSSIStatistics statistics; +}; + +#endif/*__RSSI_STATS_COLLECTOR_H__*/