From 59f1a32566fc0927dc4138121c73e5d11ae7cd77 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 9 Feb 2016 17:49:17 -0800 Subject: [PATCH] Semi-naive audio recording to SD card. --- firmware/application/Makefile | 1 + firmware/application/analog_audio_app.cpp | 2 + firmware/application/analog_audio_app.hpp | 4 + firmware/application/audio_thread.cpp | 24 ++++ firmware/application/audio_thread.hpp | 127 ++++++++++++++++++++ firmware/application/event_m0.cpp | 2 + firmware/baseband/audio_output.cpp | 10 +- firmware/baseband/audio_output.hpp | 5 +- firmware/baseband/stream_input.hpp | 54 +++++++++ firmware/common/portapack_shared_memory.hpp | 1 + 10 files changed, 227 insertions(+), 3 deletions(-) create mode 100644 firmware/application/audio_thread.cpp create mode 100644 firmware/application/audio_thread.hpp create mode 100644 firmware/baseband/stream_input.hpp diff --git a/firmware/application/Makefile b/firmware/application/Makefile index 312019084..697660c89 100755 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -183,6 +183,7 @@ CPPSRC = main.cpp \ file.cpp \ log_file.cpp \ png_writer.cpp \ + audio_thread.cpp \ manchester.cpp \ string_format.cpp \ temperature_logger.cpp \ diff --git a/firmware/application/analog_audio_app.cpp b/firmware/application/analog_audio_app.cpp index 89bbbd61b..f929ebfb8 100644 --- a/firmware/application/analog_audio_app.cpp +++ b/firmware/application/analog_audio_app.cpp @@ -135,6 +135,8 @@ AnalogAudioView::AnalogAudioView( audio::output::start(); update_modulation(static_cast(modulation)); + + audio_thread = std::make_unique("audio.s16"); } AnalogAudioView::~AnalogAudioView() { diff --git a/firmware/application/analog_audio_app.hpp b/firmware/application/analog_audio_app.hpp index 7fb934320..67b66cf6a 100644 --- a/firmware/application/analog_audio_app.hpp +++ b/firmware/application/analog_audio_app.hpp @@ -27,6 +27,8 @@ #include "ui_receiver.hpp" #include "ui_spectrum.hpp" +#include "audio_thread.hpp" + #include "ui_font_fixed_8x16.hpp" namespace ui { @@ -146,6 +148,8 @@ private: spectrum::WaterfallWidget waterfall; + std::unique_ptr audio_thread; + void on_tuning_frequency_changed(rf::Frequency f); void on_baseband_bandwidth_changed(uint32_t bandwidth_hz); void on_rf_amp_changed(bool v); diff --git a/firmware/application/audio_thread.cpp b/firmware/application/audio_thread.cpp new file mode 100644 index 000000000..eed061095 --- /dev/null +++ b/firmware/application/audio_thread.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "audio_thread.hpp" + +Thread* AudioThread::thread = nullptr; diff --git a/firmware/application/audio_thread.hpp b/firmware/application/audio_thread.hpp new file mode 100644 index 000000000..1d7374d12 --- /dev/null +++ b/firmware/application/audio_thread.hpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 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_THREAD_H__ +#define __AUDIO_THREAD_H__ + +#include "ch.h" + +#include "file.hpp" + +#include "event_m0.hpp" + +#include "portapack_shared_memory.hpp" + +#include "hackrf_gpio.hpp" +using namespace hackrf::one; + +#include + +class StreamOutput { +public: + StreamOutput( + FIFO* const fifo + ) : fifo { fifo } + { + } + + size_t available() { + return fifo->len(); + } + + size_t read(void* const data, const size_t length) { + return fifo->out(reinterpret_cast(data), length); + } + +private: + FIFO* const fifo; +}; + +class AudioThread { +public: + AudioThread( + std::string file_path + ) : file_path { std::move(file_path) } + { + // Need significant stack for FATFS + thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, AudioThread::static_fn, this); + } + + ~AudioThread() { + chThdTerminate(thread); + chThdWait(thread); + } + +private: + const std::string file_path; + + File file; + static Thread* thread; + + static msg_t static_fn(void* arg) { + auto obj = static_cast(arg); + obj->run(); + + return 0; + } + + void run() { + auto write_buffer = std::make_unique>(); + if( !write_buffer ) { + return; + } + + if( !file.open_for_append(file_path) ) { + return; + } + + while( !chThdShouldTerminate() ) { + // SUCH A HACK!!! + + auto fifo = reinterpret_cast*>(shared_memory.FIFO_HACK); + if( !fifo ) { + break; + } + + StreamOutput stream { fifo }; + + if( stream.available() >= write_buffer->size() ) { + led_usb.on(); + + const auto bytes_to_write = stream.read(write_buffer->data(), write_buffer->size()); + + if( bytes_to_write ) { + if( !file.write(write_buffer->data(), bytes_to_write) ) { + led_tx.on(); + break; + } + } + led_usb.off(); + } + + chThdSleepMilliseconds(25); + } + + file.close(); + } +}; + +#endif/*__AUDIO_THREAD_H__*/ diff --git a/firmware/application/event_m0.cpp b/firmware/application/event_m0.cpp index 023f06f4c..06890318d 100644 --- a/firmware/application/event_m0.cpp +++ b/firmware/application/event_m0.cpp @@ -251,4 +251,6 @@ void EventDispatcher::init_message_queues() { new (&shared_memory.application_queue) MessageQueue( shared_memory.application_queue_data, SharedMemory::application_queue_k ); + + shared_memory.FIFO_HACK = nullptr; } diff --git a/firmware/baseband/audio_output.cpp b/firmware/baseband/audio_output.cpp index 6f95cf557..a70473191 100644 --- a/firmware/baseband/audio_output.cpp +++ b/firmware/baseband/audio_output.cpp @@ -83,15 +83,21 @@ void AudioOutput::on_block( } } - fill_audio_buffer(audio); + fill_audio_buffer(audio, audio_present); } -void AudioOutput::fill_audio_buffer(const buffer_f32_t& audio) { +void AudioOutput::fill_audio_buffer(const buffer_f32_t& audio, const bool send_to_fifo) { + std::array audio_int; + auto audio_buffer = audio::dma::tx_empty_buffer(); for(size_t i=0; i +#include +#include + +class StreamInput { +public: + StreamInput() : fifo { std::make_unique>() } + { + // TODO: Send stream creation message. + shared_memory.FIFO_HACK = fifo.get(); + } + + ~StreamInput() { + // TODO: Send stream distruction message. + shared_memory.FIFO_HACK = nullptr; + } + + size_t write(const void* const data, const size_t length) { + return fifo->in(reinterpret_cast(data), length); + } + +private: + std::unique_ptr> fifo; +}; + +#endif/*__STREAM_INPUT_H__*/ diff --git a/firmware/common/portapack_shared_memory.hpp b/firmware/common/portapack_shared_memory.hpp index b7b97f390..612a3b276 100644 --- a/firmware/common/portapack_shared_memory.hpp +++ b/firmware/common/portapack_shared_memory.hpp @@ -40,6 +40,7 @@ struct SharedMemory { uint8_t baseband_queue_data[1 << baseband_queue_k]; MessageQueue application_queue; uint8_t application_queue_data[1 << application_queue_k]; + void* FIFO_HACK; // TODO: M0 should directly configure and control DMA channel that is // acquiring ADC samples.