Побеждаем кольцевой буфер

@WladDrakula посмотри пож мой пример. Ссылка выше. Можно его рекомендовать или мне лучше заткнуться?

подозреваю, что этот алгоритм Иринке будет еще сложнее, чем просто поиск в буфере с последнего символа. И да, беда в том, что искать приходиться разные значения в потоке, в зависимости от текущей логики.
Например ответ на подписанный топик MQTT совмещенный с командой исполнительному устройству.

ты словами напиши вкратце, ОК? Там же от маркера начала ищешь, если не путаю? а это вообще другая задача, в 100500 раз проще, чем просто вхождение подстроки где-то.

Меня совсем запутали, что такое хорошо и что такое плохо :grinning:
Пока - что разбираюсь с кодом andycat, массив из 6 байт, работаемс)

Это будет понятно только в реальной работе

Я не видел что Иринке нужно найти именно начало подстроки. У меня подстрока ищется.

любопытная реализация :thinking:
надо будет взять на вооружение/попробовать.

Добавить/создать список ответов, совместить его с режимом работы, добавить маленький буфер если необходимо получение произвольных данных (типа имя оператора) для парсинга и получится очень даже быстродействующая вещь.

???

  1. Я отвечал Андриано. Что нужно ТС - мне безразлично. В дамском угодничестве на форуме - участие не принимаю.

  2. Что касается твоего алгоритма, то мне читать код сейчас некогда. Хочешь ответ? - Я попросил объяснить словами. Не хочешь - твое дело.

  3. Таки оторвали меня от работы. Радуйтесь! Можно было сказать, что нужно искать код функции isMarker(). Для гиперпростых маркеров - это ровно то, что я написал. Слово “гиперпросто” если никакое его конец не является началом. Сложный откат назад по образцу нужен для НЕ гиперпростых слов.

1 лайк

Вот

Спойлер
#define MAX_BUF 6
char buffers[MAX_BUF];
bool send_flag;
uint32_t tmr;
uint8_t pos;


void setup() {
  Serial.begin(9600);
}


void modem_reading(char temp) {
  if (pos >= MAX_BUF) pos = 0;
  buffers[pos] = temp;

  if (substring_search(temp)) {
    send_flag = false;
    Serial.println("OK_found");
    delay(1000);
  }
  pos++;
}


bool substring_search(char temp) {
  const char string[] = "OKrn";
  uint8_t len_string =  strlen(string);//4

  if (temp == string[len_string - 1]) {
    for (uint8_t i = 0; i < len_string - 1 ; i++) {
      if (buffers[pos - i - 1] != string[len_string - i - 2])return false;
    }
  } else {
    return false;
  }
  return true;
}



void loop() {

  //Отправляю АТ, получаю в ответ ОКrn
  static char text[] = "OKrn";
  if (!send_flag && millis() - tmr >= 1000) {
    send_flag = true;
    for (uint8_t i = 0; i < 4; i++) {
      modem_reading(text[i]);
      delay(200);
    }
  }
  //Отправляю АТ, получаю в ответ ОКrn

}

Код с выводом сообщений

Спойлер
#define MAX_BUF 6
char buffers[MAX_BUF];
bool send_flag;
uint32_t tmr;
uint8_t pos;


void setup() {
  Serial.begin(9600);
}


void modem_reading(char temp) {
  if (pos >= MAX_BUF) pos = 0;
  buffers[pos] = temp;

  if (substring_search(temp)) {
    send_flag = false;
    Serial.println("OK_found");
    delay(1000);
  }
  pos++;
}


bool substring_search(char temp) {
  const char string[] = "OKrn";
  uint8_t len_string =  strlen(string);//4

  if (temp == string[len_string - 1]) {

    //Последний символ искомой строки = n
    Serial.print("Last_char = ");
    Serial.print(string[len_string - 1]);
    Serial.println("");

    //Позиция искомого символа в основном буфере = 6
    Serial.print("Pos_last_char_buf = ");
    Serial.print(pos);
    Serial.println("");

    for (uint8_t i = 0; i < len_string - 1 ; i++) {

      if (buffers[pos - i - 1] != string[len_string - i - 2])return false;

      //SB - символ в буфере SS - символ в искомой строке
      Serial.print("SB ");
      Serial.print(pos - i - 1);
      Serial.print(" = ");
      Serial.print(buffers[pos - i - 1]);
      Serial.print(" --- ");

      Serial.print("SS ");
      Serial.print(len_string - i - 2);
      Serial.print(" = ");
      Serial.print(string[len_string - i - 2]);
      Serial.println("");

    }

  } else {
    //Если пришедший символ НЕ равен последнему символу искомой строки
    return false;
  }
  return true;
}



void loop() {

  //Отправляю АТ, получаю в ответ ОКrn
  static char text[] = "OKrn";
  if (!send_flag && millis() - tmr >= 1000) {
    send_flag = true;
    for (uint8_t i = 0; i < 4; i++) {
      modem_reading(text[i]);
      delay(200);
    }
  }
  //Отправляю АТ, получаю в ответ ОКrn

}

Соответственно первый раз срабатывает, второй раз нет

ужас :frowning:
никаких delay
где весь код с serial.available() serial.read()? Модема

Модема нет сейчас под рукой.
Моделирую в протеус.
Паузы для меня только, смотрю код.

Как тут рядом в ветке ЕвгенийП правильно сказал: нет того лампового наслаждения прочуствовать работу в железе, как дымок из МК идет и т.д…
Тем более без модема.

я не знаю как объяснить мою мысль :frowning:

Ира! Я наступаю на горло своей мизогинии…
в строке 44 по второму коду нужно вот так:

if (buffers[(MAX_BUF + pos - i - 1) % MAX_BUF] != string[len_string - i - 2])return false;

Это же КОЛЬЦЕВОЙ буфер! Значит нужно в кольце вычетов работать.
Поэтому выбирают степени 2 как размер, тогда вместо остатка можно просто битовое “и” использовать.

Например для буфера длиной 8 будет так:

if (buffers[(8 + pos - i - 1) & 0b111] != string[len_string - i - 2])return false;

Вот такой смысл?

Спойлер

bool substring_search(char temp) {
const char string[] = “OKrn”;
uint8_t len_string = strlen(string);//4

if (temp == string[len_string - 1]) {

//Последний символ искомой строки = n
Serial.print("Last_char = ");
Serial.print(string[len_string - 1]);
Serial.println("");

//Позиция искомого символа в основном буфере = 6
Serial.print("Pos_last_char_buf = ");
Serial.print(pos);
Serial.println("");

if (pos < len_string - 1) {
  for (uint8_t i = 0; i < len_string - 1 ; i++) {
    int8_t new_pos = pos - i - 1;
    if (new_pos < 0) new_pos = MAX_BUF - i;
    if (buffers[new_pos] != string[len_string - i - 2])return false;
  }
} else {

  for (uint8_t i = 0; i < len_string - 1 ; i++) {
    if (buffers[pos - i - 1] != string[len_string - i - 2])return false;
  }
}

} else {
return false;
}
return true;
}

Супер! :innocent:

теперь больше времени на малыша останется )))

не проверял, стенд занят, минимальный пример:

Спойлер
#include <SoftwareSerial.h>
#define GSM_RX (byte)3 // пин RX на модуле подключаем к указаному пину на Ардуино TX
#define GSM_TX (byte)2 // пин TX на модуле подключаем к указаному пину на Ардуино RX

SoftwareSerial gsm(GSM_TX, GSM_RX); // установка контактовGSM_TX->RX и GSM_RX->TX для программного порта

#define max_size_response_buf (byte)6 // размер буфера ответа от модема, должен быть чуть больше максимальной строки поиска, например SEND OK, ERROR, OK и т.д. для стандартных команд
char resp_buf[max_size_response_buf]; // буфер ответов от модема
byte pos_buf; // текущая позиция буфера ответов

void clearRespBuf() { // очистка приемного буфера
  memset(resp_buf, 0, max_size_response_buf);
  pos_buf = 0;
}

bool findOKfromBuf(const unsigned char inByte) { // поиск OK\r\n в циклическом буфере
  const char inStr[] = "OK\r\n"; // искомая строка
  byte slen = 4; // длина искомой строки
  if (inByte == inStr[slen - 1]) { // если последний символ совпадает - продолжаем искать всю строку
    byte abpos = pos_buf; // абсолютная позиция в буфере поиска-1  = последнему символу искомой строки
    if (!abpos) abpos = max_size_response_buf - 1; else --abpos; // ищем с предпоследнего символа
    for ( byte i = 0; i < (slen - 1); ++i) { // цикл по оставшимся символам
      if (inStr[slen - 1 - i] != resp_buf[abpos]) return false; // если не сопадабт символы - выходим
      if (!abpos) abpos = max_size_response_buf - 1; else --abpos; // уменьшаем счетчики
    }
  } else {
    return false;
  } return true;
}

void setup() {
  Serial.begin(115200);
  gsm.begin(9600);
  // put your setup code here, to run once:
  clearRespBuf();
  gsm.print("AT\r");
}

bool waitOKrnFromModem() {
  byte br = 0;
  if (gsm.available()) br = gsm.read();
  if (br) {
    // запись байта в буфер
    resp_buf[pos_buf] = br; // записали
    ++pos_buf; // увеличили счетчик
    if (pos_buf >= max_size_response_buf) pos_buf = 0; // если дошло до максимума - обнуляем
    Serial.write(br);
    return findOKfromBuf(br);
  }
  return false;
}

void loop() {
  // put your main code here, to run repeatedly:
  if (waitOKrnFromModem()) {
    delay(1000); // пауза для наблюдения результата
    gsm.print("AT\r");
  }
}

/*Скетч использует 3436 байт (11%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 318 байт (15%) динамической памяти, оставляя 1730 байт для локальных переменных. Максимум: 2048 байт.*/

Оххх, Вы, наверняка в силу возраста, не можете помнить драму Трофимова “Всё как у людей”, почитайте :slight_smile:

1 лайк

Сие мне неведомо.
(Сцена из КФ Монах и бес, где их полицмейстер поймал и повёл к старшему, сказать что они почту ограбили)

Я бы рекомендовал задавать размер кольцевого буфера кратным 2 (2,4,8,16,32,64,128 или 256 байт)

#define UART_RX_BUFFER_SIZE 64 /* 1,2,4,8,16,32,64,128 or 256 bytes */
#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1 )
#define UART_TX_BUFFER_SIZE 64 /* 1,2,4,8,16,32,64,128 or 256 bytes */
#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1 )

#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
#error RX buffer size is not a power of 2
#endif

static unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
static volatile unsigned char UART_RxHead;
static volatile unsigned char UART_RxTail;
static unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
static volatile unsigned char UART_TxHead;
static volatile unsigned char UART_TxTail;

static volatile unsigned char Tx_Active_Flag;

Тогда проще с ним работать используя маску.

unsigned char DataInReceiveBuffer( void )
{
  return ( UART_RxHead != UART_RxTail );
  /* return 0 (FALSE) if the receive buffer is empty */
}

/* Read and write functions */
unsigned char ReceiveByte( void )
{
  unsigned char tmptail;
  unsigned char data;

  if (DataInReceiveBuffer())
  {
    tmptail = ( UART_RxTail + 1 ) & UART_RX_BUFFER_MASK;/* calculate buffer index */
    UART_RxTail = tmptail; /* store new index */
    data = UART_RxBuf[tmptail];
    return data; /* return data */
  }
  return 0;
}