Stream.findUntil()
findUntil() ищет строку target в потоке данных и возвращает true, если нашла её раньше, чем встретился terminator или истёк таймаут.
Полная статья
Описание
findUntil() просматривает входящие данные из потока побайтово и ищет целевую строку target. В отличие от обычного find(), у этой функции есть дополнительный ограничитель — терминатор terminator. Поиск завершится в одном из трёх случаев: целевая последовательность найдена, в потоке раньше появился терминатор, или истёк таймаут ожидания новых данных. Таймаут настраивается через Stream.setTimeout().
Если target найден раньше терминатора, функция возвращает true. Если первым пришёл terminator или время ожидания вышло — false.
Метод принадлежит классу Stream и доступен во всех классах, которые его наследуют: Serial, Wire, сетевые клиенты и другие. Подробнее о классе см. на странице Stream.
Важно понимать: как и find(), этот метод потребляет данные из буфера. Все байты, которые функция просмотрела в процессе поиска, удаляются из потока и недоступны для повторного чтения.
Синтаксис
stream.findUntil(target, terminator)
Параметры
target— строка символов, которую нужно найти в потоке. Тип данных:char*.terminator— строка-ограничитель, при появлении которой поиск немедленно прекращается, даже еслиtargetещё не найден. Тип данных:char*.
Возвращает
true — если target обнаружен в потоке раньше terminator и до истечения таймаута. false — если первым встретился terminator, либо таймаут истёк прежде, чем был найден target.
Тип данных: bool.
Пример кода
Скетч ожидает слово OK в ответе устройства, но прекращает ожидание сразу, как только в потоке появится строка ERROR:
void setup() {
Serial.begin(9600);
Serial.setTimeout(2000);
}
void loop() {
Serial.println("AT");
if (Serial.findUntil("OK", "ERROR")) {
Serial.println("Command accepted");
} else {
Serial.println("OK was not found before ERROR or timeout");
}
delay(1000);
}
Где применяется
- AT-команды и модемы — ждём
OKв ответе, но немедленно выходим, если раньше пришёлERROR. - Текстовые протоколы с маркерами — ищем нужный тег или ключевое слово строго внутри текущего блока данных, не заходя в следующий.
- Потоковый разбор данных — терминатор служит границей полезного блока и не даёт функции читать лишнее.
- Быстрая проверка ответа устройства — удобно убедиться, что ответ содержит нужную фразу, прежде чем появится признак ошибки.
Практические замечания
- Функция блокирует выполнение. Пока ни
target, ниterminatorне получены, скетч стоит на месте и ждёт. Проектируйте логику с учётом этого поведения. - Прочитанные байты теряются. После вызова вернуться к данным, через которые прошёл поиск, уже нельзя. Если содержимое потока нужно сохранить, читайте его вручную через
read()до вызова функции. - Терминатор — главное отличие от
find(). Он позволяет ограничить область поиска одним сообщением и не «проваливаться» в следующие данные, если нужный маркер так и не появился. - Выбирайте уникальные маркеры. Однобуквенные строки вроде
"O"или"E"могут случайно встретиться внутри полезных данных. Надёжнее использовать полные строки:"OK\r\n","ERROR\r\n","</packet>". - Подбирайте таймаут под устройство. Если устройство отвечает медленно, увеличьте значение через
Stream.setTimeout(). Если важна отзывчивость скетча — уменьшите его, чтобы не зависать надолго в ожидании.
Примечания и предупреждения
findUntil() сообщает только о факте нахождения целевой строки — true или false. Она не возвращает найденный текст и не запоминает промежуточные данные. Если нужно получить само содержимое сообщения, читайте поток вручную или используйте функции чтения строк, подходящие для вашего сценария.