feat(modem): Add enhanced URC observer API

This commit is contained in:
David Cermak
2025-09-04 10:46:30 +02:00
parent 134247d88f
commit 4889dd6fcb
7 changed files with 441 additions and 41 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -97,10 +97,21 @@ void wakeup_modem(void)
}
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
command_result handle_urc(uint8_t *data, size_t len)
esp_modem::DTE::UrcConsumeInfo handle_enhanced_urc(const esp_modem::DTE::UrcBufferInfo &info)
{
ESP_LOG_BUFFER_HEXDUMP("on_read", data, len, ESP_LOG_INFO);
return command_result::TIMEOUT;
// Log buffer information for debugging
ESP_LOGI(TAG, "URC Buffer Info: total_size=%zu, processed_offset=%zu, new_data_size=%zu, command_active=%s",
info.buffer_total_size, info.processed_offset, info.new_data_size,
info.is_command_active ? "true" : "false");
// Log the new data content
if (info.new_data_size > 0) {
ESP_LOG_BUFFER_HEXDUMP("on_read", info.new_data_start, info.new_data_size, ESP_LOG_INFO);
}
// For console example, we just log and don't consume anything
// This allows the data to be processed by command handlers
return {esp_modem::DTE::UrcConsumeResult::CONSUME_NONE, 0};
}
#endif
@@ -381,14 +392,14 @@ extern "C" void app_main(void)
CHECK_ERR(dce->reset(), ESP_LOGI(TAG, "OK"));
});
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
const ConsoleCommand HandleURC("urc", "toggle urc handling", no_args, [&](ConsoleCommand * c) {
const ConsoleCommand HandleURC("urc", "toggle enhanced urc handling", no_args, [&](ConsoleCommand * c) {
static int cnt = 0;
if (++cnt % 2) {
ESP_LOGI(TAG, "Adding URC handler");
dce->set_urc(handle_urc);
ESP_LOGI(TAG, "Adding enhanced URC handler");
dce->set_enhanced_urc(handle_enhanced_urc);
} else {
ESP_LOGI(TAG, "URC removed");
dce->set_urc(nullptr);
ESP_LOGI(TAG, "Enhanced URC removed");
dce->set_enhanced_urc(nullptr);
}
return 0;
});

View File

@@ -103,6 +103,11 @@ public:
{
dte->set_urc_cb(on_read_cb);
}
void set_enhanced_urc(esp_modem::DTE::enhanced_urc_cb enhanced_cb)
{
dte->set_enhanced_urc_cb(enhanced_cb);
}
#endif
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -115,6 +115,42 @@ public:
{
command_cb.urc_handler = std::move(line_cb);
}
/**
* @brief Enhanced URC handler with buffer consumption control
* @param buffer_info Information about the current buffer state
* @return Information about how much of the buffer to consume
*/
struct UrcBufferInfo {
const uint8_t* buffer_start; // Start of entire buffer
size_t buffer_total_size; // Total buffer size
size_t processed_offset; // Offset of already processed data
size_t new_data_size; // Size of new data since last call
const uint8_t* new_data_start; // Pointer to start of new data
bool is_command_active; // Whether a command is currently waiting for response
};
enum class UrcConsumeResult {
CONSUME_NONE, // Don't consume anything, continue waiting
CONSUME_PARTIAL, // Consume only part of the buffer
CONSUME_ALL // Consume entire buffer
};
struct UrcConsumeInfo {
UrcConsumeResult result;
size_t consume_size; // How many bytes to consume (0 = none, SIZE_MAX = all)
};
typedef std::function<UrcConsumeInfo(const UrcBufferInfo &)> enhanced_urc_cb;
/**
* @brief Set enhanced URC callback with buffer consumption control
* @param enhanced_cb Enhanced callback that can control buffer consumption
*/
void set_enhanced_urc_cb(enhanced_urc_cb enhanced_cb)
{
command_cb.enhanced_urc_handler = std::move(enhanced_cb);
}
#endif
/**
@@ -171,6 +207,33 @@ private:
[[nodiscard]] bool exit_cmux(); /*!< Exit of CMUX mode and cleanup */
void exit_cmux_internal(); /*!< Cleanup CMUX */
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
/**
* @brief Buffer state tracking for enhanced URC processing
*/
struct BufferState {
size_t total_processed = 0; /*!< Total bytes processed by URC handlers */
size_t last_urc_processed = 0; /*!< Last offset processed by URC */
bool command_waiting = false; /*!< Whether command is waiting for response */
size_t command_start_offset = 0; /*!< Where current command response started */
} buffer_state;
/**
* @brief Update buffer state when new data arrives
* @param new_data_size Size of new data added to buffer
*/
void update_buffer_state(size_t new_data_size);
/**
* @brief Create URC buffer information for enhanced handlers
* @param data Buffer data pointer
* @param consumed Already consumed bytes
* @param len New data length
* @return UrcBufferInfo structure with complete buffer context
*/
UrcBufferInfo create_urc_info(uint8_t* data, size_t consumed, size_t len);
#endif
Lock internal_lock{}; /*!< Locks DTE operations */
unique_buffer buffer; /*!< DTE buffer */
std::shared_ptr<CMux> cmux_term; /*!< Primary terminal for this DTE */
@@ -216,6 +279,7 @@ private:
struct command_cb {
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
got_line_cb urc_handler {}; /*!< URC callback if enabled */
enhanced_urc_cb enhanced_urc_handler {}; /*!< Enhanced URC callback with consumption control */
#endif
static const size_t GOT_LINE = SignalGroup::bit0; /*!< Bit indicating response available */
got_line_cb got_line; /*!< Supplied command callback */
@@ -223,7 +287,7 @@ private:
char separator{}; /*!< Command reply separator (end of line/processing unit) */
command_result result{}; /*!< Command return code */
SignalGroup signal; /*!< Event group used to signal request-response operations */
bool process_line(uint8_t *data, size_t consumed, size_t len); /*!< Lets the processing callback handle one line (processing unit) */
bool process_line(uint8_t *data, size_t consumed, size_t len, DTE* dte = nullptr); /*!< Lets the processing callback handle one line (processing unit) */
bool wait_for_line(uint32_t time_ms) /*!< Waiting for command processing */
{
return signal.wait_any(command_cb::GOT_LINE, time_ms);

View File

@@ -65,6 +65,10 @@ void DTE::set_command_callbacks()
{
primary_term->set_read_cb([this](uint8_t *data, size_t len) {
Scoped<Lock> l(command_cb.line_lock);
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
// Update buffer state when new data arrives
update_buffer_state(len);
#endif
#ifndef CONFIG_ESP_MODEM_URC_HANDLER
if (command_cb.got_line == nullptr || command_cb.result != command_result::TIMEOUT) {
return false; // this line has been processed already (got OK or FAIL previously)
@@ -80,7 +84,7 @@ void DTE::set_command_callbacks()
std::memcpy(inflatable.current(), data, len);
data = inflatable.begin();
}
if (command_cb.process_line(data, inflatable.consumed, len)) {
if (command_cb.process_line(data, inflatable.consumed, len, this)) {
return true;
}
// at this point we're sure that the data processing hasn't finished,
@@ -92,7 +96,7 @@ void DTE::set_command_callbacks()
inflatable.consumed += len;
return false;
#else
if (command_cb.process_line(data, 0, len)) {
if (command_cb.process_line(data, 0, len, this)) {
return true;
}
// cannot inflate and the processing hasn't finishes in the first iteration, but continue
@@ -105,7 +109,7 @@ void DTE::set_command_callbacks()
if (buffer.size > buffer.consumed) {
data = buffer.get();
len = primary_term->read(data + buffer.consumed, buffer.size - buffer.consumed);
if (command_cb.process_line(data, buffer.consumed, len)) {
if (command_cb.process_line(data, buffer.consumed, len, this)) {
return true;
}
buffer.consumed += len;
@@ -121,7 +125,7 @@ void DTE::set_command_callbacks()
inflatable.grow(inflatable.consumed + len);
}
len = primary_term->read(inflatable.current(), len);
if (command_cb.process_line(inflatable.begin(), inflatable.consumed, len)) {
if (command_cb.process_line(inflatable.begin(), inflatable.consumed, len, this)) {
return true;
}
inflatable.consumed += len;
@@ -150,10 +154,19 @@ void DTE::set_command_callbacks()
command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator)
{
Scoped<Lock> l1(internal_lock);
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
// Track command start
buffer_state.command_waiting = true;
buffer_state.command_start_offset = buffer_state.total_processed;
#endif
command_cb.set(got_line, separator);
primary_term->write((uint8_t *)command.c_str(), command.length());
command_cb.wait_for_line(time_ms);
command_cb.set(nullptr);
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
// Track command end
buffer_state.command_waiting = false;
#endif
buffer.consumed = 0;
#ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
inflatable.deflate();
@@ -365,18 +378,54 @@ void DTE::on_read(got_line_cb on_read_cb)
});
}
bool DTE::command_cb::process_line(uint8_t *data, size_t consumed, size_t len)
bool DTE::command_cb::process_line(uint8_t *data, size_t consumed, size_t len, DTE* dte)
{
// returning true indicates that the processing finished and lower layers can destroy the accumulated buffer
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
bool consume_buffer = false;
if (urc_handler) {
consume_buffer = urc_handler(data, consumed + len) != command_result::TIMEOUT;
// Call enhanced URC handler if registered
if (enhanced_urc_handler && dte) {
// Create buffer info for enhanced URC handler
UrcBufferInfo buffer_info = dte->create_urc_info(data, consumed, len);
// Call enhanced URC handler
UrcConsumeInfo consume_info = enhanced_urc_handler(buffer_info);
// Handle consumption control
switch (consume_info.result) {
case UrcConsumeResult::CONSUME_NONE:
// Don't consume anything, continue with command processing
break;
case UrcConsumeResult::CONSUME_PARTIAL:
// Consume only specified amount
dte->buffer_state.last_urc_processed += consume_info.consume_size;
// Adjust data pointers for command processing
data += consume_info.consume_size;
consumed = (consumed + len) - consume_info.consume_size;
len = 0;
break;
case UrcConsumeResult::CONSUME_ALL:
// Consume entire buffer
dte->buffer_state.last_urc_processed = consumed + len;
return true; // Signal buffer consumption
}
}
if (result != command_result::TIMEOUT || got_line == nullptr) {
return consume_buffer; // this line has been processed already (got OK or FAIL previously)
// Fallback to legacy URC handler if enhanced handler not set
if (urc_handler) {
bool consume_buffer = urc_handler(data, consumed + len) != command_result::TIMEOUT;
if (result != command_result::TIMEOUT || got_line == nullptr) {
return consume_buffer; // this line has been processed already (got OK or FAIL previously)
}
}
#endif
// Continue with normal command processing
if (result != command_result::TIMEOUT || got_line == nullptr) {
return false; // Command processing continues
}
if (memchr(data + consumed, separator, len)) {
result = got_line(data, consumed + len);
if (result == command_result::OK || result == command_result::FAIL) {
@@ -423,3 +472,22 @@ void DTE::extra_buffer::grow(size_t need_size)
*/
unique_buffer::unique_buffer(size_t size):
data(std::make_unique<uint8_t[]>(size)), size(size), consumed(0) {}
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
void DTE::update_buffer_state(size_t new_data_size)
{
buffer_state.total_processed += new_data_size;
}
DTE::UrcBufferInfo DTE::create_urc_info(uint8_t* data, size_t consumed, size_t len)
{
return {
.buffer_start = data,
.buffer_total_size = consumed + len,
.processed_offset = buffer_state.last_urc_processed,
.new_data_size = (consumed + len) - buffer_state.last_urc_processed,
.new_data_start = data + buffer_state.last_urc_processed,
.is_command_active = buffer_state.command_waiting
};
}
#endif

View File

@@ -0,0 +1,152 @@
# ESP Modem Enhanced URC Test
## Overview
This test validates the enhanced URC (Unsolicited Result Code) interface with buffer consumption control. It demonstrates the new `set_enhanced_urc()` API that provides granular control over buffer consumption and complete buffer visibility.
## Test Configuration
- **Target**: ESP-AT device with HTTP server
- **UART**: 115200 baud, 8N1, TX=17, RX=18
- **Buffer Size**: 1024 bytes
- **Timeout**: 15 seconds
## Test Cases
### 1. Enhanced URC Handler Registration
- **Objective**: Verify enhanced URC handler can be registered
- **Method**: Call `set_enhanced_urc()` with custom handler
- **Expected**: Handler receives `UrcBufferInfo` with complete buffer context
### 2. Buffer Visibility
- **Objective**: Verify URC handler receives complete buffer information
- **Method**: Log buffer state information in handler
- **Expected**: Handler receives `buffer_start`, `buffer_total_size`, `processed_offset`, `new_data_size`, `is_command_active`
### 3. Granular Consumption Control
- **Objective**: Verify handler can consume partial buffer data
- **Method**: Process HTTP URCs line-by-line using `CONSUME_PARTIAL`
- **Expected**: Each complete line is consumed individually, remaining data preserved
### 4. Multi-part Response Handling
- **Objective**: Verify handling of chunked HTTP responses
- **Method**: Process 9 HTTP chunks from ESP-AT server
- **Expected**: All chunks processed correctly with proper offset tracking
### 5. Transfer Completion Detection
- **Objective**: Verify detection of transfer completion message
- **Method**: Search for "Transfer completed" in buffer
- **Expected**: Completion detected and event group signaled
### 6. Command State Awareness
- **Objective**: Verify handler knows command state
- **Method**: Check `is_command_active` flag during processing
- **Expected**: Flag correctly reflects command state
## Test Implementation
The test uses an ESP-AT device running an HTTP server that sends chunked responses. The enhanced URC handler processes each HTTP URC line individually and detects completion.
### Key Components
```cpp
// Enhanced URC handler registration
set_enhanced_urc(handle_enhanced_urc);
// Handler implementation
static esp_modem::DTE::UrcConsumeInfo handle_enhanced_urc(const esp_modem::DTE::UrcBufferInfo& info)
{
// Process HTTP URCs with granular consumption control
if (line.starts_with("+HTTPCGET:")) {
// Consume this line only
return {esp_modem::DTE::UrcConsumeResult::CONSUME_PARTIAL, line_end + 1};
}
// Check for completion
if (buffer.find("Transfer completed") != std::string_view::npos) {
xEventGroupSetBits(s_event_group, transfer_completed);
return {esp_modem::DTE::UrcConsumeResult::CONSUME_ALL, 0};
}
return {esp_modem::DTE::UrcConsumeResult::CONSUME_NONE, 0};
}
```
## Example Output
### Successful Test Run
```
I (908) urc_test: Starting Enhanced URC Test
I (938) urc_test: Start HTTP server...(0)
I (948) urc_test: HTTP GET...(43)
I (1228) urc_test: HTTP URC: +HTTPCGET:27,=== Async Response #4 ===
I (2778) urc_test: HTTP URC: +HTTPCGET:61,[1/9] [633135 ms] This is a simulated slow server response.
I (4288) urc_test: HTTP URC: +HTTPCGET:71,[2/9] [634639 ms] Chunk 1: The ESP-AT HTTP server is demonstrating...
I (5788) urc_test: HTTP URC: +HTTPCGET:73,[3/9] [636143 ms] Chunk 2: ...asynchronous chunked transfer encoding...
I (7288) urc_test: HTTP URC: +HTTPCGET:72,[4/9] [637647 ms] Chunk 3: ...with artificial delays between chunks...
I (8788) urc_test: HTTP URC: +HTTPCGET:74,[5/9] [639151 ms] Chunk 4: ...to simulate real-world network conditions.
I (10288) urc_test: HTTP URC: +HTTPCGET:62,[6/9] [640655 ms] Chunk 5: Processing data... please wait...
I (11788) urc_test: HTTP URC: +HTTPCGET:63,[7/9] [642159 ms] Chunk 6: Still processing... almost done...
I (13288) urc_test: HTTP URC: +HTTPCGET:61,[8/9] [643663 ms] Chunk 7: Final chunk - transfer complete!
I (14758) urc_test: HTTP URC: +HTTPCGET:43,[9/9] [645168 ms] === END OF RESPONSE ===
I (15258) urc_test: Transfer completed detected in buffer!
I (15298) urc_test: Enhanced URC test completed successfully!
I (15308) urc_test: The enhanced URC handler successfully processed all HTTP chunks
I (15308) urc_test: with granular buffer consumption control
```
### Debug Output (with ESP_LOG_LEVEL_DEBUG)
```
D (958) urc_test: URC Buffer Info: total_size=43, processed_offset=0, new_data_size=43, command_active=false
D (958) urc_test: Buffer content (first 43 chars): AT+HTTPCGET="http://127.0.0.1:8080/async"
D (968) urc_test: Other data: AT+HTTPCGET="http://127.0.0.1:8080/async"
D (1218) urc_test: URC Buffer Info: total_size=85, processed_offset=43, new_data_size=42, command_active=false
D (1228) urc_test: Consuming 40 bytes (line_end=82, processed_offset=43)
D (2778) urc_test: Consuming 76 bytes (line_end=158, processed_offset=83)
```
### Failed Test (Timeout)
```
I (908) urc_test: Starting Enhanced URC Test
I (948) urc_test: HTTP GET...(43)
E (15385) urc_test: Enhanced URC test timed out
I (15385) urc_test: Enhanced URC test done
```
## Test Validation
### Success Criteria
- All 9 HTTP chunks processed successfully
- Transfer completion detected within 15 seconds
- No buffer arithmetic errors (no negative `new_data_size`)
- Proper consumption control (line-by-line processing)
### Failure Indicators
- Test timeout (15 seconds)
- Buffer arithmetic errors (negative `new_data_size`)
- Missing HTTP chunks
- Transfer completion not detected
## Dependencies
- ESP-AT device with HTTP server capability
- UART connection configured
- `CONFIG_ESP_MODEM_URC_HANDLER=y`
- FreeRTOS event groups
## Build and Run
```bash
idf.py build
idf.py flash monitor
```
## Comparison with Legacy URC
| Feature | Legacy URC | Enhanced URC |
|---------|------------|--------------|
| Buffer Consumption | All or nothing | Granular (partial) |
| Buffer Visibility | None | Complete context |
| Command State | Unknown | Known (`is_command_active`) |
| Processing State | Unknown | Tracked (`processed_offset`) |
| Multi-part Support | Limited | Full support |

View File

@@ -3,7 +3,26 @@
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/**
* @file urc_test.cpp
* @brief Enhanced URC (Unsolicited Result Code) Test
*
* This test demonstrates the new enhanced URC interface with buffer consumption control.
* It tests the following features:
*
* 1. Enhanced URC Handler Registration: Uses set_enhanced_urc() instead of set_urc()
* 2. Buffer Visibility: URC handler receives complete buffer information
* 3. Granular Consumption Control: Handler can consume none, partial, or all buffer data
* 4. Processing State Awareness: Handler knows what data is new vs. already processed
* 5. Command State Awareness: Handler knows if a command is currently active
*
* The test works with ESP-AT HTTP server that sends chunked responses, demonstrating
* how the enhanced URC handler can process multi-part responses with precise control
* over buffer consumption.
*/
#include <cstring>
#include <algorithm>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_netif.h"
@@ -67,7 +86,7 @@ public:
bool http_get(const std::string &url)
{
std::string command = "AT+HTTPCGET=\"" + url + "\"\r\n";
set_urc(handle_urc);
set_enhanced_urc(handle_enhanced_urc);
auto ret = dte->write(esp_modem::DTE_Command(command));
ESP_LOGI(TAG, "HTTP GET...(%d)", static_cast<int>(ret));
return ret > 0;
@@ -82,25 +101,88 @@ public:
static constexpr int transfer_completed = 1;
private:
static esp_modem::command_result handle_urc(uint8_t *data, size_t len)
static esp_modem::DTE::UrcConsumeInfo handle_enhanced_urc(const esp_modem::DTE::UrcBufferInfo &info)
{
static int start_chunk = 0;
static int end_chunk = 0;
std::string_view chunk((const char*)data + start_chunk, len - start_chunk);
int newline = chunk.find('\n');
if (newline == std::string_view::npos) {
end_chunk = len; // careful, this grows buffer usage
printf(".");
return esp_modem::command_result::TIMEOUT;
// Log buffer information for debugging
ESP_LOGD(TAG, "URC Buffer Info: total_size=%zu, processed_offset=%zu, new_data_size=%zu, command_active=%s",
info.buffer_total_size, info.processed_offset, info.new_data_size,
info.is_command_active ? "true" : "false");
// Debug: Show buffer content (first 200 chars)
if (info.buffer_total_size > 0) {
size_t debug_len = std::min(info.buffer_total_size, (size_t)200);
ESP_LOGD(TAG, "Buffer content (first %zu chars): %.*s",
debug_len, (int)debug_len, (const char*)info.buffer_start);
}
printf("%.*s\n", newline, (char*)data + start_chunk);
start_chunk = end_chunk;
// check for the last one
constexpr char last_chunk[] = "Transfer completed";
if (memmem(data, len, last_chunk, sizeof(last_chunk) - 1) != nullptr) {
// Create string view of the entire buffer for processing
std::string_view buffer((const char*)info.buffer_start, info.buffer_total_size);
// First, check if we have the completion message anywhere in the buffer
if (buffer.find("Transfer completed") != std::string_view::npos) {
ESP_LOGI(TAG, "Transfer completed detected in buffer!");
xEventGroupSetBits(s_event_group, transfer_completed);
// Consume everything
return {esp_modem::DTE::UrcConsumeResult::CONSUME_ALL, 0};
}
return esp_modem::command_result::OK;
// Process from the last processed offset
size_t search_start = info.processed_offset;
// Look for complete lines starting from the processed offset
while (search_start < info.buffer_total_size) {
size_t line_end = buffer.find('\n', search_start);
if (line_end == std::string_view::npos) {
// No complete line found, wait for more data
ESP_LOGD(TAG, "Waiting for more data... (search_start=%zu, total_size=%zu)",
search_start, info.buffer_total_size);
return {esp_modem::DTE::UrcConsumeResult::CONSUME_NONE, 0};
}
// Found a complete line, process it
std::string_view line = buffer.substr(search_start, line_end - search_start);
// Remove carriage return if present
if (!line.empty() && line.back() == '\r') {
line.remove_suffix(1);
}
// Check if this is an HTTP URC
if (line.starts_with("+HTTPCGET:")) {
ESP_LOGI(TAG, "HTTP URC: %.*s", (int)line.length(), line.data());
// Check for transfer completion - look for "Transfer completed" anywhere in the line
if (line.find("Transfer completed") != std::string_view::npos) {
ESP_LOGI(TAG, "Transfer completed detected!");
xEventGroupSetBits(s_event_group, transfer_completed);
}
// Consume this line (including the newline)
size_t consume_size = line_end + 1 - info.processed_offset;
ESP_LOGD(TAG, "Consuming %zu bytes (line_end=%zu, processed_offset=%zu)",
consume_size, line_end, info.processed_offset);
return {esp_modem::DTE::UrcConsumeResult::CONSUME_PARTIAL, consume_size};
} else if (line.starts_with("+HTTPCGET")) {
// Partial HTTP URC, don't consume yet
ESP_LOGD(TAG, "Partial HTTP URC: %.*s", (int)line.length(), line.data());
return {esp_modem::DTE::UrcConsumeResult::CONSUME_NONE, 0};
} else if (!line.empty()) {
// Other data, log and consume
ESP_LOGD(TAG, "Other data: %.*s", (int)line.length(), line.data());
size_t consume_size = line_end + 1 - info.processed_offset;
return {esp_modem::DTE::UrcConsumeResult::CONSUME_PARTIAL, consume_size};
}
// Move to next line
search_start = line_end + 1;
}
// Processed all available data
ESP_LOGD(TAG, "Processed all available data");
return {esp_modem::DTE::UrcConsumeResult::CONSUME_NONE, 0};
}
};
@@ -131,8 +213,8 @@ extern "C" void app_main(void)
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
dte_config.dte_buffer_size = 1024;
dte_config.uart_config.tx_io_num = 18;
dte_config.uart_config.rx_io_num = 17;
dte_config.uart_config.tx_io_num = 17;
dte_config.uart_config.rx_io_num = 18;
auto uart_dte = esp_modem::create_uart_dte(&dte_config);
if (uart_dte == nullptr) {
ESP_LOGE(TAG, "Failed to create UART DTE");
@@ -144,15 +226,24 @@ extern "C" void app_main(void)
return;
}
ESP_LOGI(TAG, "Starting Enhanced URC Test");
ESP_LOGI(TAG, "This test demonstrates the new enhanced URC interface with buffer consumption control");
dce->start_http_server();
ESP_LOGI(TAG, "Sending HTTP GET request with enhanced URC handler");
dce->http_get("http://127.0.0.1:8080/async");
EventBits_t bits = xEventGroupWaitBits(s_event_group, 1, pdTRUE, pdFALSE, pdMS_TO_TICKS(15000));
if (bits & DCE::transfer_completed) {
ESP_LOGI(TAG, "Request finished!");
ESP_LOGI(TAG, "Enhanced URC test completed successfully!");
ESP_LOGI(TAG, "The enhanced URC handler successfully processed all HTTP chunks");
ESP_LOGI(TAG, "with granular buffer consumption control");
} else {
ESP_LOGE(TAG, "Enhanced URC test timed out");
}
dce->sync();
vEventGroupDelete(s_event_group);
ESP_LOGI(TAG, "Done");
ESP_LOGI(TAG, "Enhanced URC test done");
}