/* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2016 Furrtek * * 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. */ #include "proc_aprsrx.hpp" #include "portapack_shared_memory.hpp" #include "audio_dma.hpp" #include "event_m4.hpp" #include "stdio.h" void APRSRxProcessor::execute(const buffer_c8_t& buffer) { // This is called at 3072000 / 2048 = 1500Hz if (!configured) return; // FM demodulation const auto decim_0_out = decim_0.execute(buffer, dst_buffer); // 2048 / 8 = 256 (512 I/Q samples) const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); // 256 / 8 = 32 (64 I/Q samples) const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer); // 32 / 2 = 16 (32 I/Q samples) feed_channel_stats(channel_out); auto audio = demod.execute(channel_out, audio_buffer); audio_output.write(audio); // Audio signal processing for (size_t c = 0; c < audio.count; c++) { const int32_t sample_int = audio.p[c] * 32768.0f; int32_t current_sample = __SSAT(sample_int, 16); current_sample /= 128; // Delay line put delay_line[delay_line_index & 0x3F] = current_sample; // Delay line get, and LPF sample_mixed = (delay_line[(delay_line_index - (samples_per_bit / 2)) & 0x3F] * current_sample) / 4; sample_filtered = prev_mixed + sample_mixed + (prev_filtered / 2); delay_line_index++; prev_filtered = sample_filtered; prev_mixed = sample_mixed; // Slice sample_bits <<= 1; uint8_t bit = (sample_filtered < -20) ? 1 : 0; sample_bits |= bit; /* int16_t scaled = bit == 1 ? 32767 : -32767; if( stream ) { const size_t bytes_to_write = sizeof(scaled) * 1; const auto result = stream->write(&scaled, bytes_to_write); } */ // Check for "clean" transition: either 0011 or 1100 if ((((sample_bits >> 2) ^ sample_bits) & 3) == 3) { // Adjust phase if (phase < 0x8000) phase += 0x800; // Is this a proper value ? else phase -= 0x800; } phase += phase_inc; if (phase >= 0x10000) { phase &= 0xFFFF; if (true) { uint8_t bit; if (__builtin_popcount(sample_bits & 0xFF) >= 0x05) { bit = 0x1; } else { bit = 0x0; } if (parse_bit(bit)) { parse_packet(); } } } } } void APRSRxProcessor::parse_packet() { // validate crc if (packet_buffer_size >= aprs::APRS_MIN_LENGTH) { uint16_t crc = 0xFFFF; for (size_t i = 0; i < packet_buffer_size; i++) { uint8_t byte = packet_buffer[i]; crc = ((crc >> 8) ^ crc_ccitt_tab[(crc ^ byte) & 0xFF]) & 0xFFFF; } if (crc == 0xF0B8) { parse_ax25(); } } } void APRSRxProcessor::parse_ax25() { aprs_packet.clear(); aprs_packet.set_valid_checksum(true); for (size_t i = 0; i < packet_buffer_size; i++) { aprs_packet.set(i, packet_buffer[i]); } APRSPacketMessage packet_message{aprs_packet}; shared_memory.application_queue.push(packet_message); } bool APRSRxProcessor::parse_bit(const uint8_t current_bit) { uint8_t decoded_bit = ~(current_bit ^ last_bit) & 0x1; last_bit = current_bit; // int16_t log = decoded_bit == 0 ? -32768 : 32767; // if(stream){ // const size_t bytes_to_write = sizeof(log) * 1; // const auto result = stream->write(&log, bytes_to_write); // } if (decoded_bit & 0x1) { if (ones_count < 8) { ones_count++; } } else { if (ones_count > 6) { // not valid state = WAIT_FLAG; current_byte = 0; ones_count = 0; byte_index = 0; packet_buffer_size = 0; return false; } else if (ones_count == 6) { // flag bool done = false; if (state == IN_FRAME) { done = true; } else { packet_buffer_size = 0; } state = WAIT_FRAME; current_byte = 0; ones_count = 0; byte_index = 0; return done; } else if (ones_count == 5) { // bit stuff ones_count = 0; return false; } else { ones_count = 0; } } // store current_byte = current_byte >> 1; current_byte |= (decoded_bit == 0x1 ? 0x80 : 0x0); byte_index++; if (byte_index >= 8) { byte_index = 0; if (state == WAIT_FRAME) { state = IN_FRAME; } if (state == IN_FRAME) { if (packet_buffer_size + 1 >= 256) { state = WAIT_FLAG; current_byte = 0; ones_count = 0; byte_index = 0; packet_buffer_size = 0; return false; } packet_buffer[packet_buffer_size++] = current_byte; } } return false; } void APRSRxProcessor::on_message(const Message* const message) { if (message->id == Message::ID::APRSRxConfigure) configure(*reinterpret_cast(message)); if (message->id == Message::ID::CaptureConfig) capture_config(*reinterpret_cast(message)); } void APRSRxProcessor::capture_config(const CaptureConfigMessage& message) { if (message.config) { // stream = std::make_unique(message.config); audio_output.set_stream(std::make_unique(message.config)); } else { // stream.reset(); audio_output.set_stream(nullptr); } } void APRSRxProcessor::configure(const APRSRxConfigureMessage& message) { decim_0.configure(taps_11k0_decim_0.taps); decim_1.configure(taps_11k0_decim_1.taps); channel_filter.configure(taps_11k0_channel.taps, 2); demod.configure(audio_fs, 5000); audio_output.configure(audio_24k_hpf_300hz_config, audio_24k_deemph_300_6_config, 0); samples_per_bit = audio_fs / message.baudrate; phase_inc = (0x10000 * message.baudrate) / audio_fs; phase = 0; // Delay line delay_line_index = 0; state = WAIT_FLAG; configured = true; } int main() { audio::dma::init_audio_out(); EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; }