diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 0a0bc899b..d54c1ee70 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -443,6 +443,10 @@ void set_p25tx_data(const uint8_t* dibits, uint16_t frame_length) { static bool baseband_image_running = false; +bool is_image_running() { + return baseband_image_running; +} + void run_image(const spi_flash::image_tag_t image_tag) { if (baseband_image_running) { chDbgPanic("BBRunning"); diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 69a684a0a..f406eef59 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -125,6 +125,7 @@ void request_rssi_beep(); void request_beep_stop(); void request_audio_beep(uint32_t freq, uint32_t sample_rate, uint32_t duration_ms); +bool is_image_running(); void run_image(const portapack::spi_flash::image_tag_t image_tag); void run_prepared_image(const uint32_t m4_code); void shutdown(); diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index 46b68ed51..7d6da6b15 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -50,7 +50,7 @@ using namespace hackrf::one; #include "portapack.hpp" #include "portapack_persistent_memory.hpp" - +#include "baseband_api.hpp" #include "hal.h" // For LPC_SGPIO #include @@ -413,6 +413,19 @@ void set_rx_max283x_iq_phase_calibration(const size_t v) { } void disable() { + if (direction == rf::Direction::Transmit && baseband::is_image_running()) { + static constexpr uint32_t radio_tx_drain_timeout_ms = 100; + shared_memory.radio_tx_drain = 1; // Request drain of the current DMA queue. + for (uint32_t waited_ms = 0; + shared_memory.radio_tx_drain && (waited_ms < radio_tx_drain_timeout_ms); + ++waited_ms) { + chThdSleepMilliseconds(1); + } + } + /* Never allow shutdown to block indefinitely waiting for a drain + * acknowledgement that may never arrive in normal operation. */ + shared_memory.radio_tx_drain = 0; + set_antenna_bias(false); baseband_codec.set_mode(max5864::Mode::Shutdown); #ifdef PRALINE diff --git a/firmware/baseband/baseband_thread.cpp b/firmware/baseband/baseband_thread.cpp index 289e214c7..391fd904f 100644 --- a/firmware/baseband/baseband_thread.cpp +++ b/firmware/baseband/baseband_thread.cpp @@ -90,7 +90,7 @@ void BasebandThread::run() { #ifdef PRALINE shared_memory.m4_streaming_marker = 0xAA; // Phase 0 instrumentation #endif - + uint8_t buffer_drained = 0; // to count how many dma buffers we already emptied while (!chThdShouldTerminate()) { #ifdef PRALINE shared_memory.m4_baseband_loops++; // Phase 0 instrumentation @@ -117,11 +117,20 @@ void BasebandThread::run() { } if (baseband_processor_) { - baseband_processor_->execute(buffer); + if (shared_memory.radio_tx_drain == 0) { // only generate if not draining. + baseband_processor_->execute(buffer); + } + } + if (shared_memory.radio_tx_drain == 1) { + buffer_drained++; + if (buffer_drained >= 4) { // We have 4 buffers, so after draining 4 we should be safe to disable. + shared_memory.radio_tx_drain = 0; // Clear the drain request to allow normal operation to resume. + buffer_drained = 0; + } } } } - + shared_memory.radio_tx_drain = 0; i2s::i2s0::tx_mute(); baseband::dma::disable(); baseband_sgpio.streaming_disable(); diff --git a/firmware/common/portapack_shared_memory.hpp b/firmware/common/portapack_shared_memory.hpp index 5a3752213..8f5029e23 100644 --- a/firmware/common/portapack_shared_memory.hpp +++ b/firmware/common/portapack_shared_memory.hpp @@ -85,7 +85,7 @@ struct SharedMemory { uint16_t volatile m4_stack_usage{0}; uint32_t volatile m4_heap_usage{0}; uint16_t volatile m4_buffer_missed{0}; - + uint8_t volatile radio_tx_drain{0}; // to indicate the baseband thread to drain the tx buffer, and wait for it, before radio::disable() #ifdef PRALINE // Phase 0 instrumentation counters for PRALINE radio debugging uint32_t volatile m4_dma_xfr_count{0}; // DMA transfer_complete() calls