In embedded development, we often need to parse serial data, such as reading the return information from ESP8266, identifying module status, and waiting for <span>"OK"</span> or <span>"ERROR"</span> to appear. However, this returned data often does not arrive all at once, but rather—in segments fed into the queue.
Thus, the concept of window search comes into play.
🔍 1. Why is there a “Window Search”?
For example, we send a command:
AT+CWLAP
The ESP8266 may return in multiple parts:
+CWAP:(...)OK If we only use<span>strcmp()</span>as a one-time comparison function, we might miss the intermediate data.
The idea of “window search” is:
Continuously take data from the receive queue and place it into a fixed-size buffer (window), then continuously search for the target string within this window.
This way, even if the target string spans multiple UART interrupt packets, we can accurately capture it.
🧩 2. The Most Common Implementation Approach
Here is a simple and practical example of a “window search” implementation👇
bool Queue_Search_Window(GQUEUE *q, const char *target, uint16_t window_size, uint32_t timeout_ms){ uint8_t window[256]; uint16_t index = 0; memset(window, 0, sizeof(window)); uint32_t start = xTaskGetTickCount(); while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(timeout_ms)) { if (!GqueueIsEmpty(q)) { uint8_t ch = GqueueOu(q); if (index < window_size) window[index++] = ch; else { memmove(window, window + 1, window_size - 1); window[window_size - 1] = ch; } window[index < window_size ? index : window_size - 1] = '\0'; if (strstr((char *)window, target)) return true; } else vTaskDelay(pdMS_TO_TICKS(10)); } return false;}
The core logic of this function is: 🪟 sliding window + real-time search. Each time new data arrives, the window slides forward, and then we use <span>strstr()</span> to search for the keyword.
🧠 3. The Algorithmic Truth Behind strstr()
Many students will ask:
“
<span>strstr()</span>uses the KMP algorithm, right? Is its performance very high?”
The answer is:
❌ Not necessarily!
In the C standard,
only the functional semantics are defined (finding the first substring), but no algorithm is specified.
The actual implementations in different C libraries vary greatly👇
| C Library | Implementation Algorithm | Description |
|---|---|---|
| newlib (commonly used in STM32 / GD32) | Naive brute-force matching (O(N×M)) | Small and simple |
| glibc (Linux) | Two-Way / SIMD optimization | Higher performance |
| musl libc | Two-Way algorithm | Stable and efficient |
| MSVC CRT | Brute-force matching | Compatibility first |
| ARMCC / Keil | Brute-force matching | Smallest size |
In the context of STM32, the commonly used newlib library employs the most naive algorithm. But don’t underestimate it— for AT responses of dozens to hundreds of bytes, this performance is completely sufficient.
⚙️ 4. If You Want to Go Faster, You Can Optimize Like This
If your project needs to handle longer strings or frequent matches, consider the following optimizations👇
✅ 1️⃣ Use Circular Buffer Instead of memmove
Avoid the O(W) time overhead of moving the window each time. Just update the pointer, significantly improving efficiency.
✅ 2️⃣ Use KMP Algorithm Instead of strstr
The KMP preprocessing part matches the table, reducing the search complexity to <span>O(N + M)</span>. Suitable for handling large-scale text.
✅ 3️⃣ Batch Matching Method
Read data blocks from the queue in batches and then search, which can reduce the number of calls to <span>strstr()</span>.
✅ 4️⃣ Boyer–Moore / Sunday Algorithm
If you are running on high-end Cortex-A with Linux or RTOS, these jump matching algorithms can further speed things up.
💬 5. In Summary
When you write “window search” on STM32, you are actually racing against time, using a few bytes of sliding window to keep an eye on that “OK”.
And behind it, that naive
<span>strstr()</span>is quietly doing the most critical task in the simplest way.
🧰 6. Author’s Note
In the embedded world, not all algorithms need to pursue “theoretically optimal”. Being able to run stably on a 48MHz MCU, without crashing and easy to debug, is the optimal solution.
📘 Remember this saying:
“The optimal algorithm is not necessarily the most practical; the simplest code is often the most reliable.”
✨ Little Surprise
👉 In the next issue, we will talk about how to implement window search without memmove using circular buffer + KMP, making the <span>ESP8266</span> response detection an order of magnitude faster 🚀