Анализ AT-команд и прослушивание входящих SMS Arduino Leonardo SIM800H

Я пытаюсь создать программу, которая принимает команды, содержащиеся в SMS. Команды могут быть $CMD1 и $CMD2. Конечно, мне нужно проверить номер телефона отправителя по его последним 6 цифрам. Помимо этого мне нужно запросить и получить информацию о часах rtc от модема. Формат AT-команд: +CCLK: "ГГ/ММ/ДД,ЧЧ:ММ:СС+ТТ" (работает правильно) +CMTI: "SM",N (где N — порядковый номер смс в памяти телефона) +CMGR: "REC READ","+1234567890","","04/01/01,00:00:00+00" (достигает только 15-го символа и зависает)

Мой код:

const long interval = 1000;
static long currentMillis;

byte searchcharpos = 0; //Чтобы определить, где находится + в +CCLK в массиве символов

char serialdata[256]; //Массив для хранения символов перед анализом

char rtcy1[3]; //Текущий год Формат: yy\0
char rtcm1[3]; //Текущий месяц Формат: mm\0
char rtcd1[3]; //Текущий день Формат: dd\0
char rtch1[3]; //Текущий час Формат: hh\0
char rtcmm1[3]; //Текущая минута Формат: mm\0
char rtcs1[3]; //Текущая секунда Формат: ss\0

char esemesemes[3];

byte pointingfinger = 0;

char enabledtime = 0;

char cclkenabl = 0;

char foundchar[6];

byte cmtienabl = 0;

byte witdqt = 0;

byte acceptsms = 0;

byte ocpos = 0;

byte occurence = 0;

byte cmgrenabl = 0;

byte esemindex[3];

char phone1[6] = {'5', '6', '7', '8', '9', '0'};

char phone2[6];

byte enableclock = 1;

void setup() {
  Serial.begin(9600); //USB к компьютеру
  Serial1.begin(9600); //UART к модему
  Serial1.print("ATE0\r"); //Отключить эхо
}

void loop() {
  if (millis() - currentMillis >= interval) //Это делается каждую секунду
  {
    if (enableclock == 1) {
      Serial1.print("AT+CCLK?\r");
    }
    Serial.println("=========");
    Serial.print(serialdata[searchcharpos]);
    Serial.print(serialdata[searchcharpos + 1]);
    Serial.print(serialdata[searchcharpos + 2]);
    Serial.print(serialdata[searchcharpos + 3]);
    Serial.print(serialdata[searchcharpos + 4]);
    Serial.print(serialdata[searchcharpos + 5]);
    Serial.print(serialdata[searchcharpos + 6]);
    Serial.print(serialdata[searchcharpos + 7]);
    Serial.print(serialdata[searchcharpos + 8]);
    Serial.print(serialdata[searchcharpos + 9]);
    Serial.print(serialdata[searchcharpos + 10]);
    Serial.print(serialdata[searchcharpos + 11]);
    Serial.print(serialdata[searchcharpos + 12]);
    Serial.print(serialdata[searchcharpos + 13]);
    Serial.print(serialdata[searchcharpos + 14]);
    Serial.print(serialdata[searchcharpos + 15]);
    Serial.print(serialdata[searchcharpos + 16]);
    Serial.print(serialdata[searchcharpos + 17]);
    Serial.print(serialdata[searchcharpos + 18]);
    Serial.print(serialdata[searchcharpos + 19]);
    Serial.print(serialdata[searchcharpos + 20]);
    Serial.print(serialdata[searchcharpos + 21]);
    Serial.print(serialdata[searchcharpos + 22]);
    Serial.print(serialdata[searchcharpos + 23]);
    Serial.print(serialdata[searchcharpos + 24]);
    Serial.print(serialdata[searchcharpos + 25]);
    Serial.print(serialdata[searchcharpos + 26]);
    Serial.print(serialdata[searchcharpos + 27]);
    Serial.print(serialdata[searchcharpos + 28]);
    Serial.print(serialdata[searchcharpos + 29]);
    Serial.print(serialdata[searchcharpos + 30]);
    Serial.print ("=========");
    //Serial1.print("AT+CCLK?\r"); //спросить время
    //задержка(50);
    Serial.println("");
    Serial.println("=====");
    Serial.println(millis());

    if (enableclock == 1) {
      Serial.println("YEAR: ");
      Serial.print(rtcy1[0]);
      Serial.println(rtcy1[1]);
      Serial.println("MONTH: ");
      Serial.print(rtcm1[0]);
      Serial.println(rtcm1[1]);
      Serial.println("DAY: ");
      Serial.print(rtcd1[0]);
      Serial.println(rtcd1[1]);
      Serial.println("HOUR: ");
      Serial.print(rtch1[0]);
      Serial.println(rtch1[1]);
      Serial.println("MINUTE: ");
      Serial.print(rtcmm1[0]);
      Serial.println(rtcmm1[1]);
      Serial.println("SECOND: ");
      Serial.print(rtcs1[0]);
      Serial.println(rtcs1[1]);
    }
    enabledtime = 1;

    currentMillis = millis();
  }

  if (enabledtime == 1) {
    if (Serial1.available () > 0) {
      foundchar[0] = foundchar[1];
      foundchar[1] = foundchar[2];
      foundchar[2] = foundchar[3];
      foundchar[3] = foundchar[4];
      foundchar[4] = foundchar[5];
      foundchar[5] = Serial1.read();

      if (foundchar[0] == '+' && foundchar[1] == 'C' && foundchar[2] == 'C' && foundchar[3] == 'L' && foundchar[4] == 'K' && foundchar[5] == ':' && enableclock == 1) {
        cclkenabl = 1;
        pointingfinger = 0;
      }

      if (foundchar[0] == '+' && foundchar[1] == 'C' && foundchar[2] == 'M' && foundchar[3] == 'T' && foundchar[4] == 'I' && foundchar[5] == ':') {
        cmtienabl = 1;
        pointingfinger = 0;
        enableclock = 0;
      }

      if (foundchar[0] == '+' && foundchar[1] == 'C' && foundchar[2] == 'M' && foundchar[3] == 'G' && foundchar[4] == 'R' && foundchar[5] == ':') {
        cmgrenabl = 1;
        pointingfinger = 0;
      }

      if (foundchar[0] == '$' && foundchar[1] == 'C' && foundchar[2] == 'M' && foundchar[3] == 'D' && foundchar[4] == '1') {
        if (acceptsms == 1) {
          while (true) {
            Serial.println("CMD1");
          }
        }
      }

      if (foundchar[0] == '$' && foundchar[1] == 'C' && foundchar[2] == 'M' && foundchar[3] == 'D' && foundchar[4] == '2') {
        if (acceptsms == 1) {
          Serial.println("CMD2");
        }
      }

      if (cclkenabl == 1) {
        while (foundchar[0] != '\n') {
          if (Serial1.available() > 0) {
            serialdata[pointingfinger] = foundchar[0];
            serialdata[pointingfinger + 1] = 0;
            pointingfinger++;
            foundchar[0] = foundchar[1];
            foundchar[1] = foundchar[2];
            foundchar[2] = foundchar[3];
            foundchar[3] = foundchar[4];
            foundchar[4] = foundchar[5];
            foundchar[5] = Serial1.read();

          }
        }
        cmgrenabl = 0;
        cclkenabl = 0;
        //указывающий палец = 0;
        enabledtime = 0;
        rtcy1[0] = serialdata[searchcharpos + 8]; //получение первого символа с его смещением
        rtcy1[1] = serialdata[searchcharpos + 9];
        rtcy1[2] = '\0';
        rtcm1[0] = serialdata[searchcharpos + 11];
        rtcm1[1] = serialdata[searchcharpos + 12];
        rtcm1[2] = '\0';
        rtcd1[0] = serialdata[searchcharpos + 14];
        rtcd1[1] = serialdata[searchcharpos + 15];
        rtcd1[2] = '\0';
        rtch1[0] = serialdata[searchcharpos + 17];
        rtch1[1] = serialdata[searchcharpos + 18];
        rtch1[2] = '\0';
        rtcmm1[0] = serialdata[searchcharpos + 20];
        rtcmm1[1] = serialdata[searchcharpos + 21];
        rtcmm1[2] = '\0';
        rtcs1[0] = serialdata[searchcharpos + 23];
        rtcs1[1] = serialdata[searchcharpos + 24];
        rtcs1[2] = '\0';
      }

      if (cmtienabl == 1) {
        while (foundchar[0] != '\n') {
          if (Serial1.available() > 0) {
            serialdata[pointingfinger] = foundchar[0];
            serialdata[pointingfinger + 1] = 0;
            pointingfinger++;
            foundchar[0] = foundchar[1];
            foundchar[1] = foundchar[2];
            foundchar[2] = foundchar[3];
            foundchar[3] = foundchar[4];
            foundchar[4] = foundchar[5];
            foundchar[5] = Serial1.read();

          }
        }
        cmtienabl = 0;
        //указывающий палец = 0;
        enabledtime = 0;
        enableclock = 0;
        esemesemes[0] = serialdata[searchcharpos + 8]; //получение первого символа с его смещением
        esemesemes[1] = serialdata[searchcharpos + 9];
        esemesemes[2] = '\0';
        esemindex[0] = serialdata[searchcharpos + 12];
        esemindex[1] = '\0';
        Serial.println("CMTI");
        Serial.println(esemesemes[0]);
        Serial.println(esemesemes[1]);
        Serial.println(esemindex[1]);
        if (esemesemes[0] == 'S' && esemesemes[1] == 'M') {
          Serial1.println("AT+CMGF=1");
          Serial.println("AT+CMGF=1");
          delay(100);
          Serial1.println("AT+CMGR=1");
          Serial.println("AT+CMGR=1");
        }
        if (esemesemes[0] != 'S' || esemesemes[1] != 'M') {
          Serial1.println("AT+CMGD=4,1");
          Serial.println("Deleted");
        }
      }

      if (cmgrenabl == 1) {
        while (foundchar[0] != '\n') {
          if (Serial1.available() > 0) {
            serialdata[pointingfinger] = foundchar[0];
            serialdata[pointingfinger + 1] = 0;
            pointingfinger++;
            foundchar[0] = foundchar[1];
            foundchar[1] = foundchar[2];
            foundchar[2] = foundchar[3];
            foundchar[3] = foundchar[4];
            foundchar[4] = foundchar[5];
            foundchar[5] = Serial1.read(); // Я ДУМАЮ, ЗДЕСЬ У НАС КАКАЯ-ТО ПРОБЛЕМА
            Serial.println("Searching");
            Serial.println(serialdata[pointingfinger]);
            Serial.println(pointingfinger);
            Serial.print(serialdata[searchcharpos]);
            Serial.print(serialdata[searchcharpos + 1]);
            Serial.print(serialdata[searchcharpos + 2]);
            Serial.print(serialdata[searchcharpos + 3]);
            Serial.print(serialdata[searchcharpos + 4]);
            Serial.print(serialdata[searchcharpos + 5]);
            Serial.print(serialdata[searchcharpos + 6]);
            Serial.print(serialdata[searchcharpos + 7]);
            Serial.print(serialdata[searchcharpos + 8]);
            Serial.print(serialdata[searchcharpos + 9]);
            Serial.print(serialdata[searchcharpos + 10]);
            Serial.print(serialdata[searchcharpos + 11]);
            Serial.print(serialdata[searchcharpos + 12]);
            Serial.print(serialdata[searchcharpos + 13]);
            Serial.print(serialdata[searchcharpos + 14]);
            Serial.print(serialdata[searchcharpos + 15]);
            Serial.print(serialdata[searchcharpos + 16]);
            Serial.print(serialdata[searchcharpos + 17]);
            Serial.print(serialdata[searchcharpos + 18]);
            Serial.print(serialdata[searchcharpos + 19]);
            Serial.print(serialdata[searchcharpos + 20]);
            Serial.print(serialdata[searchcharpos + 21]);
            Serial.print(serialdata[searchcharpos + 22]);
            Serial.print(serialdata[searchcharpos + 23]);
            Serial.print(serialdata[searchcharpos + 24]);
            Serial.print(serialdata[searchcharpos + 25]);
            Serial.print(serialdata[searchcharpos + 26]);
            Serial.print(serialdata[searchcharpos + 27]);
            Serial.print(serialdata[searchcharpos + 28]);
            Serial.print(serialdata[searchcharpos + 29]);
            Serial.print(serialdata[searchcharpos + 30]);
          }
        }
        //указывающий палец = 0;
        enabledtime = 1;
        occurence = 0;
        ocpos = 0;
        Serial.println("mode1");
        while (occurence < 7) {
          Serial.println("mode2");
          if (serialdata[ocpos] == '\"') {
            Serial.println("mode3");
            occurence++;
            Serial.println(occurence);
          }
          Serial.println("mode4");
          ocpos++;
          Serial.println(ocpos);
        }
        witdqt = ocpos;
        Serial.println("PHONE1: ");
        Serial.print(serialdata[witdqt - 1]);
        Serial.print(serialdata[witdqt - 2]);
        Serial.print(serialdata[witdqt - 3]);
        Serial.print(serialdata[witdqt - 4]);
        Serial.print(serialdata[witdqt - 5]);
        Serial.print(serialdata[witdqt - 6]);
        Serial.println("");
      }
      acceptsms = 0;

      if (serialdata[witdqt - 1] == phone1[5] && serialdata[witdqt - 2] == phone1[4] && serialdata[witdqt - 3] == phone1[3] && serialdata[witdqt - 4] == phone1[2] && serialdata[witdqt - 5] == phone1[1] && serialdata[witdqt - 6] == phone1[0])
      {
        acceptsms = 1;
        Serial.println("Accepted");
      }

      if (serialdata[witdqt - 1] == phone2[5] && serialdata[witdqt - 2] == phone2[4] && serialdata[witdqt - 3] == phone2[3] && serialdata[witdqt - 4] == phone2[2] && serialdata[witdqt - 5] == phone2[1] && serialdata[witdqt - 6] == phone2[0])
      {
        acceptsms = 1;
        Serial.println("Accepted");
      }

      /*Serial.println("");
        Serial.print(foundchar[0]);
        Serial.print(foundchar[1]);
        Serial.print(foundchar[2]);
        Serial.print(foundchar[3]);
        Serial.print(foundchar[4]);
        Serial.print(foundchar[5]);
        Serial.println("");*/

    }
  }
}

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

, 👍0

Обсуждение

В чём именно заключается вопрос? Вы представили свой проект и код. Вам нужен код для общего разбора AT-команд?, @Maximilian Gerhardt

У меня возникла ошибка, из-за которой я не могу увидеть и проанализировать весь массив символов и получить номер телефона для сравнения. Я не могу понять, в чём проблема с моим кодом., @A. Somov

Это самый странный код последовательного парсинга, который я когда-либо видел. Ты себе жизнь не облегчишь такими вещами..., @Majenko

Это может помочь вам написать лучший код для парсинга: https://hackingmajenkoblog.wordpress.com/2016/02/01/reading-serial-on-the-arduino/ и https://hackingmajenkoblog.wordpress.com/2017/04/08/splitting-up-text-in-c/, @Majenko

Я тоже не могу понять этот код парсинга. Возможно, вам стоит начать с работы над универсальным ATCmdParser, например, с [mbed-os](https://github.com/ARMmbed/mbed-os/blob/master/platform/ATCmdParser.cpp), или посмотреть код парсинга из других библиотек, принимающих AT-команды ([example](https://github.com/ekstrand/ESP8266wifi)), @Maximilian Gerhardt

Или, короче говоря, считываете всю строку в буфер, и только после завершения строки анализируете её и решаете, что с ней делать. Скользящее окно — это не то, что нужно для строчной ASCII-коммуникации., @Majenko

Как определить, какая у меня команда? Я сделал это, меняя значения, но есть ли способ лучше?, @A. Somov

Вы можете написать унифицированную функцию «отправить команду и проанализировать ответ», которая отправит команду, прочитает весь ответ в буфере, пока не встретится разделитель, а затем использует пользовательские функции анализа или простую sscanf для анализа данных в соответствии с отправленной командой., @Maximilian Gerhardt

strncmp() в буфере правильно отформатированной строки (строка C) — это то, что вам нужно., @Majenko

Спасибо вам обоим, я посмотрю, что можно сделать с новой информацией, и напишу здесь., @A. Somov

@Majenko, почему в вашем примере построчного чтения нет break; в операторе switch?, @A. Somov

Для '\r' есть возврат каретки, поэтому разрыв не нужен (он бы туда никогда не попал). Для default это последняя запись, поэтому разрыв не нужен (хотя вы можете его туда поставить, если хотите). Мне бы действительно стоило поменять местами записи \r и \n\n действительно подходит для определения конца строки., @Majenko

Вот, я обновил. Этот фрагмент я написал так давно..., @Majenko

Тьфу! Ненавижу Wordpress! Он просто испортил мой пост! Бл*дь! Надеюсь, я только что вернул его обратно., @Majenko

Мне очень жаль, надеюсь, с вашим сайтом все в порядке., @A. Somov


1 ответ


Лучший ответ:

2

Вы должны выбросить весь свой собственный код и читать последовательные данные по одной строке за раз. Только после получения полной строки вы должны проверить ее, чтобы увидеть, что у вас есть.

Например, вот что я только что собрал на основе фрагмента, который я разместил здесь:

int readline(int readch, char *buffer, int len) {
  static int pos = 0;
  int rpos;

  if (readch > 0) {
    switch (readch) {
      case '\r': // Игнорировать CR
        break;
      case '\n': // Возврат на новую строку
        rpos = pos;
        pos = 0;  // Сброс индекса позиции, готов к следующему разу
        return rpos;
      default:
        if (pos < len-1) {
            buffer[pos++] = readch;
            buffer[pos] = 0;
        }
        break;
    }
  }
  return 0;
}

// ... позже, в вашем цикле:

if (Serial1.available()) {
    // Считываем один символ и отправляем его в функцию readline.
    if (readline(Serial1.read(), serialdata, 512)) { // вам действительно нужно 512 байт буфера?!?!

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

        // Если строка начинается с '+CCLK: "'
        if (strncmp(serialdata, "+CCLK: \"", 8) == 0) {
            // Разрезаем его по разным разделителям
            // начиная с 9-го символа:
            char *cyear = strtok(serialdata + 8, "/");
            char *cmonth = strtok(NULL, "/");
            char *cday = strtok(NULL, ",");
            char *chour = strtok(NULL, ":");
            char *cmin = strtok(NULL, ":");
            char *csec = strtok(NULL, "+");

            // Проверяем, что последняя нарезка сработала
            if (sec != NULL) { // Анализ прошел успешно
                // И преобразуем каждый фрагмент в число.
                year = atoi(cyear);
                month = atoi(cmonth);
                day = atoi(cday);
                hour = atoi(chour);
                minute = atoi(cmin);
                sec = atoi(csec);

                // Показывать время.
                Serial.print(F("The time is "));
                Serial.print(minute);
                Serial.print(F(" minutes past "));
                Serial.println(hour);
            }     
        }
    }

    // Выполняем аналогичные операции для различных возможных сообщений
    // вы можете получить.

}
,