From 9cd7cbac3b2beb3fac5252c08ba2f921b5821272 Mon Sep 17 00:00:00 2001 From: Johnathon Slightham Date: Wed, 4 Mar 2026 04:26:06 -0500 Subject: [PATCH] Fix watchdog on rmt task --- components/dataLink/DataLinkFrames.cpp | 15 +++- components/dataLink/include/Scheduler.h | 2 +- components/rmt/RMTManager.cpp | 106 ++++++++++++------------ main/include/LoopManager.h | 6 ++ main/main.cpp | 1 + 5 files changed, 72 insertions(+), 58 deletions(-) diff --git a/components/dataLink/DataLinkFrames.cpp b/components/dataLink/DataLinkFrames.cpp index 8745e80..0a13edd 100644 --- a/components/dataLink/DataLinkFrames.cpp +++ b/components/dataLink/DataLinkFrames.cpp @@ -514,12 +514,21 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){ res = link_layer_obj->start_receive_frames_rmt(i); } while(!link_layer_obj->stop_tasks){ + bool any_received = false; for (uint8_t i = 0; i < link_layer_obj->num_channels; i++){ - res = link_layer_obj->receive_rmt(i); - res = link_layer_obj->start_receive_frames_rmt(i); + esp_err_t r = link_layer_obj->receive_rmt(i); + if (r == ESP_OK){ + any_received = true; + } + link_layer_obj->start_receive_frames_rmt(i); + taskYIELD(); // feed the watchdog and yield to other tasks between channel polls } - vTaskDelay(pdMS_TO_TICKS(RECEIVE_TASK_PERIOD_MS)); + if (!any_received){ + // Nothing received on any channel — sleep briefly to avoid busy-spinning + // and give the watchdog / idle task guaranteed CPU time. + vTaskDelay(pdMS_TO_TICKS(RECEIVE_TASK_PERIOD_MS)); + } } vTaskDelete(nullptr); diff --git a/components/dataLink/include/Scheduler.h b/components/dataLink/include/Scheduler.h index 1783037..4676415 100644 --- a/components/dataLink/include/Scheduler.h +++ b/components/dataLink/include/Scheduler.h @@ -5,7 +5,7 @@ #define SCHEDULER_MUTEX_WAIT 10 //max time duration to wait #define SCHEDULER_PERIOD_MS 10 -#define RECEIVE_TASK_PERIOD_MS 2 +#define RECEIVE_TASK_PERIOD_MS 5 #define GENERIC_FRAME_SLIDING_WINDOW_SIZE 5 //defines the maximum size of the sliding window before resending previously un-ack'd fragments #define SLIDING_WINDOW_MUTEX_TIMEOUT_MS 5 diff --git a/components/rmt/RMTManager.cpp b/components/rmt/RMTManager.cpp index 3ffc301..8e5997d 100644 --- a/components/rmt/RMTManager.cpp +++ b/components/rmt/RMTManager.cpp @@ -8,7 +8,7 @@ /** * @brief Construct a new RMTManager::RMTManager object - * + * * @param num_channels Number of channels to init (1-4) inclusive */ RMTManager::RMTManager(uint8_t num_channels = MAX_CHANNELS){ @@ -39,17 +39,17 @@ esp_err_t RMTManager::init_tx_channel(){ .callback = encoder_callback, .arg = &channels[i].encoder_context }; - + //create encoder res_tx = rmt_new_simple_encoder(&encoder_config, &channels[i].encoder); - + if (res_tx != ESP_OK){ // printf("Failed to create encoder\n"); ESP_LOGE(DEBUG_TAG, "Failed to create encoder"); channels[i].encoder = NULL; return ESP_FAIL; } - + //enable the callback rmt_tx_event_callbacks_t tx_cbs = { .on_trans_done = RMTManager::rmt_tx_done_callback @@ -65,8 +65,8 @@ esp_err_t RMTManager::init_tx_channel(){ .invert_out = 0, .with_dma = 0, } - }; - + }; + channels[i].tx_gpio = tx_gpio[i]; channels[i].status = CHANNEL_NOT_READY_STATUS; @@ -83,23 +83,23 @@ esp_err_t RMTManager::init_tx_channel(){ channels[i].tx_queue = xQueueCreate(QUEUE_SIZE, sizeof(TxBuffer)); //can store up to 10 queued transmissions (each transmission size being 192B; based ont he RMT_SYMBOL_BLOCK_SIZE) res_tx = rmt_new_tx_channel(&tx_channel_config_template, &channels[i].tx_rmt_handle); - + //init tx channel if (res_tx != ESP_OK) { // printf("Failed to init TX channel\n"); ESP_LOGE(DEBUG_TAG, "Failed to init TX channel %d", i); continue; } - + if (channels[i].tx_rmt_handle == NULL) { // printf("TX channel handle is NULL\n"); ESP_LOGE(DEBUG_TAG, "TX channel handle is NULL on channel %d", i); continue; } - + channels[i].tx_done_semaphore = xSemaphoreCreateBinary(); //create a binary sem - + channels[i].tx_context = { .tx_done_sem = channels[i].tx_done_semaphore, .transmit_queue = channels[i].tx_queue, @@ -146,11 +146,11 @@ bool RMTManager::rmt_tx_done_callback(rmt_channel_handle_t channel, const rmt_tx SemaphoreHandle_t sem = args->tx_done_sem; QueueHandle_t queue = args->transmit_queue; rmt_encoder_context_t* encoder_context = args->tx_context; - + QueueHandle_t free_queue = args->free_mem_queue; - + TxBuffer buf = {}; - + BaseType_t xTaskWokenByReceive = pdFALSE; // xSemaphoreTakeFromISR(mutex, &xTaskWokenByReceive); xQueueReceiveFromISR(queue, static_cast(&buf), &xTaskWokenByReceive); //remove from the queue @@ -165,7 +165,7 @@ bool RMTManager::rmt_tx_done_callback(rmt_channel_handle_t channel, const rmt_tx encoder_context->byte_index = 0; encoder_context->num_symbols = 0; } - + xSemaphoreGiveFromISR(sem, &high_task_wakeup); return high_task_wakeup == pdTRUE; } @@ -213,33 +213,33 @@ esp_err_t RMTManager::init_rx_channel(){ .with_dma = 0 } }; //temp for one rx channel - + //temp channels[i].rx_gpio = rx_gpio[i]; - + esp_err_t res_rx = rmt_new_rx_channel(&rx_channel_config, &channels[i].rx_rmt_handle); - + if (res_rx != ESP_OK) { // printf("Failed to init RX channel - reason %s\n", esp_err_to_name(res_rx)); ESP_LOGE(DEBUG_TAG, "Failed to init RX channel - reason %s", esp_err_to_name(res_rx)); return ESP_FAIL; } - + if (channels[i].rx_rmt_handle == NULL) { // printf("RX channel handle is NULL\n"); ESP_LOGE(DEBUG_TAG, "RX channel handle is NULL"); return ESP_FAIL; } - + channels[i].rx_queue = xQueueCreate(QUEUE_SIZE, sizeof(rmt_rx_done_event_data_t)); //creating queue with some random size - + rmt_rx_event_callbacks_t cbs = { .on_recv_done = RMTManager::rmt_rx_done_callback }; rmt_rx_register_event_callbacks(channels[i].rx_rmt_handle, &cbs, channels[i].rx_queue); res_rx = rmt_enable(channels[i].rx_rmt_handle); - + if (res_rx != ESP_OK) { // printf("Failed to enable RX channel\n"); ESP_LOGE(DEBUG_TAG, "Failed to enable RX channel"); @@ -259,7 +259,7 @@ esp_err_t RMTManager::init(){ ESP_LOGE(DEBUG_TAG, "Failed to init TX channel"); return ESP_FAIL; } - + res = this->init_rx_channel(); if (res != ESP_OK) { // printf("Failed to init RX channel\n"); @@ -273,7 +273,7 @@ esp_err_t RMTManager::init(){ channels[i].status = CHANNEL_READY_STATUS; } } - + // printf("Free heap before encoder creation: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_DEFAULT)); // heap_caps_print_heap_info(MALLOC_CAP_DEFAULT); // printf("Free DMA-capable heap before encoder creation: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_DMA)); @@ -299,7 +299,7 @@ esp_err_t RMTManager::init(){ /** * @brief This is a callback function called by RMT when transmitting. This function will encode the user data `data` with rising and falling edges based on the bit.a64l * The symbols are defined in `RMTManager.h`, where a bit 1 is transmitted as a `RMT_SYMBOL_ONE` and a bit 0 is transmitted as a `RMT_SYMBOL_ZERO` - * + * * @param data * @param data_size * @param symbols_written @@ -308,8 +308,8 @@ esp_err_t RMTManager::init(){ * @param done * @param arg */ -size_t RMTManager::encoder_callback(const void* data, size_t data_size, size_t symbols_written, - size_t symbols_free, rmt_symbol_word_t* symbols, bool* done, void* arg){ +size_t RMTManager::encoder_callback(const void* data, size_t data_size, size_t symbols_written, + size_t symbols_free, rmt_symbol_word_t* symbols, bool* done, void* arg){ rmt_encoder_context_t* ctx = (rmt_encoder_context_t*) arg; //get the current context if (symbols_free == 0){ //no space in the tx buffer; don't encode any more bytes until there is space left @@ -321,13 +321,13 @@ size_t RMTManager::encoder_callback(const void* data, size_t data_size, size_t s while (ctx->byte_index < data_size && symbols_used < symbols_free){ //loop until we have reached the end of the data or filled the RMT symbol buffer (`symbols_free`) uint8_t byte = bytes[ctx->byte_index]; //get the byte from the data uint8_t bit = (byte >> (7 - ctx->bit_index)) & 0x01; //get the current bit, as determined from the bit index (MSB first) - - //Manchester (Ethernet Standard) Encoding + + //Manchester (Ethernet Standard) Encoding symbols[symbols_used++] = bit ? RMT_SYMBOL_ONE : RMT_SYMBOL_ZERO; //if the bit is a 1, transmit a 1 symbol; otherwise, transmit 0 symbol ctx->num_symbols++; ctx->bit_index++; - if (ctx->bit_index >= 8) { + if (ctx->bit_index >= 8) { //reached the end of the byte; go to the next byte ctx->bit_index = 0; ctx->byte_index++; @@ -347,11 +347,11 @@ void RMTManager::reset_encoder_context(rmt_encoder_context_t* ctx){ /** * @brief Sends the string `data` of size `size`, with config `config` - * - * @param data - * @param size - * @param config - * @return int + * + * @param data + * @param size + * @param config + * @return int */ esp_err_t RMTManager::send(uint8_t* data, size_t size, rmt_transmit_config_t* config, uint8_t channel_num){ if (channel_num >= num_channels){ @@ -406,7 +406,7 @@ esp_err_t RMTManager::send(uint8_t* data, size_t size, rmt_transmit_config_t* co vPortFree(new_data_to_send_buf.data); ESP_LOGE(DEBUG_TAG, "Failed to queue data"); return ESP_FAIL; - } + } esp_err_t res = rmt_transmit(this->channels[channel_num].tx_rmt_handle, this->channels[channel_num].encoder, new_data_to_send_buf.data, new_data_to_send_buf.length, config); @@ -426,7 +426,7 @@ esp_err_t RMTManager::send(uint8_t* data, size_t size, rmt_transmit_config_t* co /** * @brief This function, given the `symbols` and the length `num`, will convert the received symbols into the symbols defined in `RMTSymbols.h` * this somehow works first try????? (tested with 't', 'O', and 'THIS IS A SAMPLE TEXT MESSAGE') - * @param symbols received symbols + * @param symbols received symbols * @param num number of received symbols * @param decoded decoded symbol string * @param output_num size of `decoded` @@ -445,7 +445,7 @@ int RMTManager::decode_symbols(rmt_symbol_word_t* symbols, size_t num, rmt_symbo // printf("duration0 %d level0 %d duration1 %d level1 %d\n", symbols[i].duration0, symbols[i].level0, symbols[i].duration1, symbols[i].level1); //dummy print receive //manchester encoding /*there are two cases in the beginning: - 1. if duration0 = 20, then we are in between two symbols (low to high and high to low). + 1. if duration0 = 20, then we are in between two symbols (low to high and high to low). in this case, we need to insert a low in the beginning and "split" the current symbol into 2 2. if duration0 = 10, then the first symbol should be high to low */ @@ -461,21 +461,21 @@ int RMTManager::decode_symbols(rmt_symbol_word_t* symbols, size_t num, rmt_symbo //need to insert a 0 before received symbols decoded[output_index++] = RMT_SYMBOL_ZERO; } - + } - + if (curr_high_low){ decoded[output_index++] = RMT_SYMBOL_ONE; } else { decoded[output_index++] = RMT_SYMBOL_ZERO; } - + //if duration1 = 20, then we are starting low if (symbols[i].duration1 != RMT_DURATION_SYMBOL){ curr_high_low = !curr_high_low; } i++; - + } return (int)output_index; @@ -483,7 +483,7 @@ int RMTManager::decode_symbols(rmt_symbol_word_t* symbols, size_t num, rmt_symbo /** * @brief This converts the parsed symbols into a string of size `output_index` - * + * * @param symbols Parsed received symbols (see `RMTSymbols.h` for the definitions of the symbols) * @param num Length of `symbols` * @param string Output string encoded by the symbols @@ -498,7 +498,7 @@ int RMTManager::convert_symbols_to_char(rmt_symbol_word_t* symbols, size_t num, char byte = 0; size_t output_index = 0; int i = 0; - + while (i < num && output_index < output_num){ if (symbols[i].level0 == 0 && symbols[i].level1 == 1){ //zero @@ -525,8 +525,8 @@ int RMTManager::convert_symbols_to_char(rmt_symbol_word_t* symbols, size_t num, /** * @brief Start async RX job - * - * @return esp_err_t + * + * @return esp_err_t */ esp_err_t RMTManager::start_receiving(uint8_t channel_num){ if (channel_num >= num_channels){ @@ -560,13 +560,13 @@ esp_err_t RMTManager::start_receiving(uint8_t channel_num){ /** * @brief Function to get the received messages - * + * * @param recv_buf Byte array of the received bytes * @param size Size of the byte array * @param output_size Pointer containing the received bytes (will be written) * @param channel_num Physical channel pair to receive from - * - * @return esp_err_t + * + * @return esp_err_t */ esp_err_t RMTManager::receive(uint8_t* recv_buf, size_t size, size_t* output_size, uint8_t channel_num){ if (channel_num >= num_channels){ @@ -579,9 +579,7 @@ esp_err_t RMTManager::receive(uint8_t* recv_buf, size_t size, size_t* output_siz } rmt_rx_done_event_data_t rx_data; - if (xQueueReceive(channels[channel_num].rx_queue, &rx_data, pdMS_TO_TICKS(5)) != pdTRUE){ //this will wait until a message has arrived or not - // printf("Timeout occurred while waiting for RX event\n"); - // ESP_LOGE(DEBUG_TAG, "Timeout occurred while waiting for RX event - didn't receive a message in time"); + if (xQueueReceive(channels[channel_num].rx_queue, &rx_data, 0) != pdTRUE){ // non-blocking poll return ESP_FAIL; } @@ -597,12 +595,12 @@ esp_err_t RMTManager::receive(uint8_t* recv_buf, size_t size, size_t* output_siz if (num < 0){ return ESP_FAIL; } - + *output_size = this->convert_symbols_to_char(channels[channel_num].decoded_recv_symbols, num, recv_buf, size); if (*output_size < 0){ return ESP_FAIL; } - + //UNCOMMENT HERE TO GET RAW BITS TO USE IN `components/dataLink/test_scripts/parse_bit_frame.py` // printf("\n\nparsed characters:\n"); // for (int i = 0; i < *output_size; i++) { @@ -630,4 +628,4 @@ RMTManager::~RMTManager(){ vQueueDelete(channels[i].rx_queue); } } -} \ No newline at end of file +} diff --git a/main/include/LoopManager.h b/main/include/LoopManager.h index 3563973..8977e0d 100644 --- a/main/include/LoopManager.h +++ b/main/include/LoopManager.h @@ -33,6 +33,12 @@ public: std::vector return_value(msg.begin(), msg.end()); writer.write(return_value); }); + const auto bandwidth_test_fn_tag = 101; + m_messaging_interface->register_function(bandwidth_test_fn_tag, [](const uint8_t *parameters, size_t parameter_size, Writer& writer) { + std::string msg = ""; + std::vector return_value(msg.begin(), msg.end()); + writer.write(return_value); + }); } MessagingInterface &get_messaging_interface(); diff --git a/main/main.cpp b/main/main.cpp index 268ae81..194be5c 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -21,6 +21,7 @@ extern "C" [[noreturn]] void app_main(void) { auto& config_manager = ConfigManager::get_instance(); // NOLINT - here for easily adding temporary config config_manager.set_communication_method(CommunicationMethod::Wireless); + esp_log_set_vprintf(RemoteDebugging::custom_log_write); const auto loop_manager = std::make_unique();