diff --git a/firmware/application/analog_audio_app.cpp b/firmware/application/analog_audio_app.cpp index 199c68d9..29be3f9c 100644 --- a/firmware/application/analog_audio_app.cpp +++ b/firmware/application/analog_audio_app.cpp @@ -333,12 +333,11 @@ void AnalogAudioView::squelched() { } void AnalogAudioView::handle_coded_squelch(const uint32_t value) { - //const std::string value_string = to_string_dec_uint(value / 10) + "." + to_string_dec_uint(value % 10); float diff, min_diff = value; size_t min_idx { 0 }; size_t c; - for (c = 0; c < KEY_TONES_NB; c++) { + for (c = 0; c < tone_keys.size(); c++) { diff = abs(((float)value / 100.0) - tone_keys[c].second); if (diff < min_diff) { min_idx = c; diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 3bfc3dc8..cf502e43 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -27,6 +27,7 @@ //TEST: Check AFSK transmit end, skips last bits ? //TEST: Imperial in whipcalc +//BUG: Crash on rename file with long filename //BUG: Auto backlight off doesn't work anymore //BUG: CPLD-related rx ok, tx bad, see portapack.cpp lines 214+ to disable CPLD overlay //BUG: REPLAY See what's wrong with quality (format, or need for interpolation filter ?) diff --git a/firmware/application/replay_app.cpp b/firmware/application/replay_app.cpp index b54e2bb3..ed4592cf 100644 --- a/firmware/application/replay_app.cpp +++ b/firmware/application/replay_app.cpp @@ -51,7 +51,7 @@ ReplayAppView::ReplayAppView( &field_frequency_step, &field_rf_amp, &replay_view, - //&waterfall, + &waterfall, }); replay_view.set_file_list(file_list); @@ -89,17 +89,16 @@ ReplayAppView::~ReplayAppView() { void ReplayAppView::on_hide() { // TODO: Terrible kludge because widget system doesn't notify Waterfall that // it's being shown or hidden. - - //waterfall.on_hide(); + waterfall.on_hide(); View::on_hide(); } -/*void ReplayAppView::set_parent_rect(const Rect new_parent_rect) { +void ReplayAppView::set_parent_rect(const Rect new_parent_rect) { View::set_parent_rect(new_parent_rect); - const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), static_cast(new_parent_rect.height() - header_height) }; + const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height }; waterfall.set_parent_rect(waterfall_rect); -}*/ +} void ReplayAppView::focus() { if (!file_error) { diff --git a/firmware/application/replay_app.hpp b/firmware/application/replay_app.hpp index 0404350a..b5f4634a 100644 --- a/firmware/application/replay_app.hpp +++ b/firmware/application/replay_app.hpp @@ -41,7 +41,7 @@ public: void on_hide() override; - //void set_parent_rect(const Rect new_parent_rect) override; + void set_parent_rect(const Rect new_parent_rect) override; void focus() override; @@ -54,9 +54,6 @@ private: static constexpr ui::Dim header_height = 2 * 16; - static constexpr uint32_t sampling_rate = 500000; - static constexpr uint32_t baseband_bandwidth = 2500000; - void on_target_frequency_changed(rf::Frequency f); rf::Frequency target_frequency() const; @@ -79,7 +76,7 @@ private: 16384, 3 }; - //spectrum::WaterfallWidget waterfall { }; + spectrum::WaterfallWidget waterfall { }; }; } /* namespace ui */ diff --git a/firmware/application/replay_thread.cpp b/firmware/application/replay_thread.cpp index 0942a58d..8c43e6eb 100644 --- a/firmware/application/replay_thread.cpp +++ b/firmware/application/replay_thread.cpp @@ -76,16 +76,48 @@ msg_t ReplayThread::static_fn(void* arg) { Optional ReplayThread::run() { BasebandReplay replay { &config }; BufferExchange buffers { &config }; + + StreamBuffer* prefill_buffer { nullptr }; + + // TESTING: Prefill + // While empty buffers fifo is not empty... + while (!buffers.empty()) { + prefill_buffer = buffers.get_prefill(); + + if (prefill_buffer == nullptr) { + buffers.put_app(prefill_buffer); + } else { + size_t blocks = prefill_buffer->capacity() / 512; + + for (size_t c = 0; c < blocks; c++) { + auto read_result = reader->read(&((uint8_t*)prefill_buffer->data())[c * 512], 512); + if( read_result.is_error() ) { + return read_result.error(); + } + } + + prefill_buffer->set_size(prefill_buffer->capacity()); + + buffers.put(prefill_buffer); + //if (!buffers.put(prefill_buffer)) for(;;) {}; + + } + }; while( !chThdShouldTerminate() ) { auto buffer = buffers.get(); - auto read_result = reader->read(buffer->data(), buffer->capacity()); - buffer->set_size(buffer->capacity()); - if( read_result.is_error() ) { - return read_result.error(); + size_t blocks = buffer->capacity() / 512; + + for (size_t c = 0; c < blocks; c++) { + auto read_result = reader->read(&((uint8_t*)buffer->data())[c * 512], 512); + if( read_result.is_error() ) { + return read_result.error(); + } } + buffer->set_size(buffer->capacity()); + buffers.put(buffer); } diff --git a/firmware/application/tone_key.cpp b/firmware/application/tone_key.cpp index 60f7a6a4..b53c0749 100644 --- a/firmware/application/tone_key.cpp +++ b/firmware/application/tone_key.cpp @@ -20,12 +20,12 @@ * Boston, MA 02110-1301, USA. */ -#include "tone_key.hpp" #include "string_format.hpp" +#include "tone_key.hpp" namespace tonekey { - -const tone_key_t tone_keys[] = { + +const tone_key_t tone_keys = { { "None", 0.0 }, { "0 XZ", 67.000 }, { "1 WZ", 69.400 }, @@ -90,14 +90,22 @@ void tone_keys_populate(OptionsField& field) { options_t tone_key_options; std::string tone_name; - for (size_t c = 0; c < KEY_TONES_NB; c++) { - if (c && (c < 51)) - tone_name = "CTCSS " + tone_keys[c].first; - else + for (size_t c = 0; c < tone_keys.size(); c++) { + if (c && c < 51) { + auto f = tone_keys[c].second; + tone_name = "CTCSS " + tone_keys[c].first + " " + to_string_dec_uint(f) + "." + to_string_dec_uint((uint32_t)(f * 10) % 10); + } else { tone_name = tone_keys[c].first; + } + tone_key_options.emplace_back(tone_name, c); } + field.set_options(tone_key_options); } +float tone_key_frequency(const uint32_t index) { + return tone_keys[index].second; +} + } diff --git a/firmware/application/tone_key.hpp b/firmware/application/tone_key.hpp index 41fdcd67..70438d86 100644 --- a/firmware/application/tone_key.hpp +++ b/firmware/application/tone_key.hpp @@ -28,15 +28,14 @@ using namespace ui; -#define KEY_TONES_NB 56 - namespace tonekey { -using tone_key_t = std::pair; +using tone_key_t = std::vector>; -extern const tone_key_t tone_keys[]; +extern const tone_key_t tone_keys; void tone_keys_populate(OptionsField& field); +float tone_key_frequency(const uint32_t index); } diff --git a/firmware/application/ui_mictx.cpp b/firmware/application/ui_mictx.cpp index f0d41808..fe150225 100644 --- a/firmware/application/ui_mictx.cpp +++ b/firmware/application/ui_mictx.cpp @@ -59,7 +59,7 @@ void MicTXView::configure_baseband() { sampling_rate / 20, // Update vu-meter at 20Hz transmitting ? transmitter_model.channel_bandwidth() : 0, mic_gain_x10, - TONES_F2D(tone_keys[tone_key_index].second), + TONES_F2D(tone_key_frequency(tone_key_index)), 0.2 // 20% mix ); } diff --git a/firmware/application/ui_replay_view.cpp b/firmware/application/ui_replay_view.cpp index 87cc2218..eba4d816 100644 --- a/firmware/application/ui_replay_view.cpp +++ b/firmware/application/ui_replay_view.cpp @@ -91,7 +91,7 @@ void ReplayView::set_file_list(const std::vector& file_li for (const auto& file : file_list) { bbd_file.open("/" + file.string()); - duration = bbd_file.size() / (2 * 2 * sampling_rate / 4); + duration = bbd_file.size() / (2 * 2 * sampling_rate / 8); file_options.emplace_back(file.string().substr(0, 8), duration); } options_files.set_options(file_options); diff --git a/firmware/application/ui_replay_view.hpp b/firmware/application/ui_replay_view.hpp index 607ea862..1db4330f 100644 --- a/firmware/application/ui_replay_view.hpp +++ b/firmware/application/ui_replay_view.hpp @@ -105,7 +105,7 @@ private: std::unique_ptr replay_thread { }; - MessageHandlerRegistration message_handler_capture_thread_error { + MessageHandlerRegistration message_handler_replay_thread_error { Message::ID::CaptureThreadDone, [this](const Message* const p) { const auto message = *reinterpret_cast(p); diff --git a/firmware/application/ui_soundboard.cpp b/firmware/application/ui_soundboard.cpp index d4adfd65..97f5f86a 100644 --- a/firmware/application/ui_soundboard.cpp +++ b/firmware/application/ui_soundboard.cpp @@ -127,7 +127,7 @@ void SoundBoardView::play_sound(uint16_t id) { divider, number_bw.value() * 1000, 10, - TONES_F2D(tone_keys[tone_key_index].second), + TONES_F2D(tone_key_frequency(tone_key_index)), 0.2 // 20% mix ); } diff --git a/firmware/baseband/proc_replay.cpp b/firmware/baseband/proc_replay.cpp index 601af9ac..0b3c8235 100644 --- a/firmware/baseband/proc_replay.cpp +++ b/firmware/baseband/proc_replay.cpp @@ -21,19 +21,20 @@ */ #include "proc_replay.hpp" +#include "sine_table_int8.hpp" #include "event_m4.hpp" #include "utility.hpp" ReplayProcessor::ReplayProcessor() { - // TODO: Interpolation filter needed ! + channel_filter_pass_f = taps_200k_decim_1.pass_frequency_normalized * 1000000; // 162760.416666667 + channel_filter_stop_f = taps_200k_decim_1.stop_frequency_normalized * 1000000; // 337239.583333333 - /*spectrum_interval_samples = baseband_fs / spectrum_rate_hz; + spectrum_interval_samples = (baseband_fs / 8) / spectrum_rate_hz; spectrum_samples = 0; - channel_spectrum.set_decimation_factor(1);*/ - + channel_spectrum.set_decimation_factor(1); } void ReplayProcessor::execute(const buffer_c8_t& buffer) { @@ -43,13 +44,13 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) { // File data is in C16 format, we need C8 // File samplerate is 500kHz, we're at 4MHz - // iq_buffer can only be 512 samples (RAM limitation) - // For a full 2048-sample C8 buffer, we need: + // iq_buffer can only be 512 C16 samples (RAM limitation) + // To fill up the 2048-sample C8 buffer, we need: // 2048 samples * 2 bytes per sample = 4096 bytes - // Since we're oversampling by 4M/500k = 8, we only need 2048/8 = 256 samples from the file + // Since we're oversampling by 4M/500k = 8, we only need 2048/8 = 256 samples from the file and duplicate them 8 times each // So 256 * 4 bytes per sample (C16) = 1024 bytes from the file if( stream ) { - const size_t bytes_to_read = sizeof(*buffer.p) * 2 * (buffer.count / 8); // *2 (C16), /8 (oversampling) + const size_t bytes_to_read = sizeof(*buffer.p) * 2 * (buffer.count / 8); // *2 (C16), /8 (oversampling) should be == 1024 const auto result = stream->read(iq_buffer.p, bytes_to_read); } @@ -57,25 +58,39 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) { // Zero-stuff for (size_t i = 0; i < buffer.count; i++) { - if (i & 3) - buffer.p[i] = { 0, 0 }; - else - buffer.p[i] = { iq_buffer.p[i >> 3].real() >> 8, iq_buffer.p[i >> 3].imag() >> 8 }; + + // DEBUG: This works. Transmits a 1kHz tone + /*sample = (sine_table_i8[(tone_phase & 0xFF000000) >> 24]); + tone_phase += (1000 * ((1ULL << 32) / baseband_fs)); + // Do FM + delta = sample * 30000 * (0xFFFFFFULL / baseband_fs); + phase += delta; + sphase = phase + (64 << 24); + iq_buffer.p[i >> 3] = { (int16_t)(sine_table_i8[(sphase & 0xFF000000) >> 24]) << 8, (int16_t)(sine_table_i8[(phase & 0xFF000000) >> 24]) << 8 }; + */ + + /*if (i & 3) + buffer.p[i] = buffer.p[i - 1]; + else {*/ + auto re_out = iq_buffer.p[i >> 3].real() >> 8; + auto im_out = iq_buffer.p[i >> 3].imag() >> 8; + buffer.p[i] = { re_out, im_out }; + //} } - /*spectrum_samples += channel.count; + spectrum_samples += buffer.count; if( spectrum_samples >= spectrum_interval_samples ) { spectrum_samples -= spectrum_interval_samples; - channel_spectrum.feed(channel, channel_filter_pass_f, channel_filter_stop_f); - }*/ + channel_spectrum.feed(iq_buffer, channel_filter_pass_f, channel_filter_stop_f); + } } void ReplayProcessor::on_message(const Message* const message) { switch(message->id) { - /*case Message::ID::UpdateSpectrum: + case Message::ID::UpdateSpectrum: case Message::ID::SpectrumStreamingConfig: channel_spectrum.on_message(message); - break;*/ + break; case Message::ID::ReplayConfig: replay_config(*reinterpret_cast(message)); diff --git a/firmware/baseband/proc_replay.hpp b/firmware/baseband/proc_replay.hpp index ebf7e69f..eed84209 100644 --- a/firmware/baseband/proc_replay.hpp +++ b/firmware/baseband/proc_replay.hpp @@ -43,21 +43,28 @@ public: private: static constexpr size_t baseband_fs = 4000000; - //static constexpr auto spectrum_rate_hz = 50.0f; + static constexpr auto spectrum_rate_hz = 50.0f; BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit }; - std::array iq { }; // This fits in just right in allocated RAM + std::array iq { }; // This fits in just right in allocated RAM - Too big ? const buffer_c16_t iq_buffer { iq.data(), iq.size() }; + + uint32_t channel_filter_pass_f = 0; + uint32_t channel_filter_stop_f = 0; + + // DEBUG + //uint32_t tone_phase { 0 }, phase { 0 }, delta { 0 }, sphase { 0 }; + //int8_t sample { 0 }; std::unique_ptr stream { }; - /*SpectrumCollector channel_spectrum; + SpectrumCollector channel_spectrum { }; size_t spectrum_interval_samples = 0; - size_t spectrum_samples = 0;*/ + size_t spectrum_samples = 0; void replay_config(const ReplayConfigMessage& message); }; diff --git a/firmware/baseband/stream_output.cpp b/firmware/baseband/stream_output.cpp index db65024e..dbb5f254 100644 --- a/firmware/baseband/stream_output.cpp +++ b/firmware/baseband/stream_output.cpp @@ -35,7 +35,9 @@ StreamOutput::StreamOutput(ReplayConfig* const config) : config->fifo_buffers_full = &fifo_buffers_full; for(size_t i=0; ibuffer_count; i++) { + // Set buffers to point consecutively in previously allocated unique_ptr "data" buffers[i] = { &(data.get()[i * config->read_size]), config->read_size }; + // Put all buffer pointers in the "empty buffer" FIFO fifo_buffers_empty.in(&buffers[i]); } } @@ -49,6 +51,8 @@ size_t StreamOutput::read(void* const data, const size_t length) { // We need a full buffer... if( !fifo_buffers_full.out(active_buffer) ) { // ...but none are available. Hole in transmission (inform app and stop ?) + //active_buffer = nullptr; + //creg::m4txevent::assert(); break; } } diff --git a/firmware/common/buffer_exchange.cpp b/firmware/common/buffer_exchange.cpp index 4f71b84e..88509805 100644 --- a/firmware/common/buffer_exchange.cpp +++ b/firmware/common/buffer_exchange.cpp @@ -69,3 +69,10 @@ StreamBuffer* BufferExchange::get(FIFO* fifo) { chSysUnlock(); } } + +StreamBuffer* BufferExchange::get_prefill(FIFO* fifo) { + StreamBuffer* p { nullptr }; + fifo->out(p); + + return p; +} diff --git a/firmware/common/buffer_exchange.hpp b/firmware/common/buffer_exchange.hpp index d3377295..0e41dc6d 100644 --- a/firmware/common/buffer_exchange.hpp +++ b/firmware/common/buffer_exchange.hpp @@ -46,10 +46,19 @@ public: StreamBuffer* get() { return get(fifo_buffers_for_application); } + + StreamBuffer* get_prefill() { + return get_prefill(fifo_buffers_for_application); + } bool put(StreamBuffer* const p) { return fifo_buffers_for_baseband->in(p); } + + // TESTING... + bool put_app(StreamBuffer* const p) { + return fifo_buffers_for_application->in(p); + } #endif #if defined(LPC43XX_M4) @@ -99,4 +108,6 @@ private: } StreamBuffer* get(FIFO* fifo); + + StreamBuffer* get_prefill(FIFO* fifo); }; diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index da5dac8c..2cb3886a 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -541,7 +541,7 @@ public: size_t read(void* p, const size_t count) { const auto copy_size = std::min(used_, count); - memcpy(p, &data_[used_ - copy_size], copy_size); + memcpy(p, &data_[capacity_ - used_], copy_size); used_ -= copy_size; return copy_size; } diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index 76756ed2..b1bf50e9 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ