Sim900 + длинное смс

KorPaEv
Offline
Зарегистрирован: 24.11.2014

Была как то давно создана подобная тема и никто ничего не ответил.

Собственно, есть вот такой вот примерчик отсюда http://wiki.amperka.ru/%D0%B1%D0%B5%D1%81%D0%BF%D1%80%D0%BE%D0%B2%D0%BE%D0%B4%D0%BD%D0%B0%D1%8F-%D1%81%D0%B2%D1%8F%D0%B7%D1%8C:gprs-shield

#include <SoftwareSerial.h>
 
SoftwareSerial gprsSerial(7, 8);
 
//для зелёного светодиода будем использовать второй цифровой вход,
//а для жёлтого - третий
int greenPin = 2;
int yellowPin = 3;
 
void setup()
{
    gprsSerial.begin(19200);
    pinMode(greenPin, OUTPUT);
    pinMode(yellowPin, OUTPUT);
 
    // Настраиваем приём сообщений с других устройств
    // Между командами даём время на их обработку
    gprsSerial.print("AT+CMGF=1\r");
    delay(300);
    gprsSerial.print("AT+IFC=1, 1\r");
    delay(300);
    gprsSerial.print("AT+CPBS=\"SM\"\r");
    delay(300);
    gprsSerial.print("AT+CNMI=1,2,2,1,0\r");
    delay(500);
}
 
String currStr = "";
// Переменная принимает значение True, если текущая строка является сообщением
boolean isStringMessage = false;
 
void loop()
{
    if (!gprsSerial.available())
        return;
 
    char currSymb = gprsSerial.read();    
    if ('\r' == currSymb) {
        if (isStringMessage) {
            //если текущая строка - SMS-сообщение,
            //отреагируем на него соответствующим образом
            if (!currStr.compareTo("Green on")) {
                digitalWrite(greenPin, HIGH);
            } else if (!currStr.compareTo("Green off")) {
                digitalWrite(greenPin, LOW);
            } else if (!currStr.compareTo("Yellow on")) {
                digitalWrite(yellowPin, HIGH);
            } else if (!currStr.compareTo("Yellow off")) {
                digitalWrite(yellowPin, LOW);
            }
            isStringMessage = false;
        } else {
            if (currStr.startsWith("+CMT")) {
                //если текущая строка начинается с "+CMT",
                //то следующая строка является сообщением
                isStringMessage = true;
            }
        }
        currStr = "";
    } else if ('\n' != currSymb) {
        currStr += String(currSymb);
    }
}

Читаем сериал GSM, собираем  строку и отлавливаем по окончании строки флажок - СМС сообщение (+CMT)

Далее читаем продолжение этого самого смс сообщения...Но вот в чем проблема - Когда приходит первая часть смс в виде

+CMT: "+79999999999","NAME","16/01/28,00:36:38+24"

эта самая часть видимо умещается в 64 символа и все бы ничего, если бы вторая часть сообщения умещалась в эти же самые 64 символа. Не знаю почему, но модуль не умеет скорее всего принимать все 160 символов разрешенные на одну смс и пересылает 160 символов частями по 64...

Поэтому запустив данный пример и отослав просто сообщение длинной в 140 символов ничего кроме вышеупомянутой строки в монитере порта я не увидел. Отослав же сообщение длинной в 100 символов мы видим все красиво

+CMT: "+79999999999","NAME","16/01/28,00:36:38+24"

qwerty qwerty qwerty qwerty

Вопрос - каким образом можно собрать строку из этих частей оставшихся, если сообщение больше 64 символов?

Пробовал таким способом, непосредственно с вики

 if (gprsSerial.available()) // if date is comming from softwareserial port ==> data is comming from gprs shield
  {
    while (gprsSerial.available()) // reading data into char array
    {
      bufGsm[countBufGsm++] = gprsSerial.read(); // writing data into array
      if (countBufGsm == 64) 
      {
        break;
      }
    }
     Serial.write(buffer, count);    
    clearBufferArray(); // call clearBufferArray function to clear the storaged data from the array
    countBufGsm = 0; // set counter of while loop to zero
  }
И вроде даже в Serial.write(buffer, count); выводится полное сообщение но опять же каким образом тут можно собрать строку?
Пытался сделать следующее
char bufGsm[64]; // buffer array for data recieve over serial port
String inputGsmStr = ""; //входящая строка с gsm модема
int countBufGsm = 0;

void Manage()
{
if (gprsSerial.available()) // if date is comming from softwareserial port ==> data is comming from gprs shield
  {
    while (gprsSerial.available()) // reading data into char array
    {
      bufGsm[countBufGsm++] = gprsSerial.read(); // writing data into array
      if (countBufGsm == 64) 
      {
        break;
      }
    }
     inputGsmStr +=   bufGsm;
    clearBufferArray(); // call clearBufferArray function to clear the storaged data from the array
    countBufGsm = 0; // set counter of while loop to zero
  }
}

void clearBufferArray() // function to clear buffer array
{
  for (int i = 0; i < countBufGsm; i++)
  {
    bufGsm[i] = NULL;
  }
}

 Но выходит что каждый раз когда мы отрезаем часть по 64 и дописываем в строку, то в inputGsmStr записываются те самые части по 64, потом 128 и т.д..она растетпостоянно до тех пор пока не получим полную строку. В таком случае функция проверки, что это СМС сообщение запустится столько раз, сколько у нас частей по 64...

Какие идеи?

 

KorPaEv
Offline
Зарегистрирован: 24.11.2014

KorPaEv пишет:

Отослав же сообщение длинной в 100 символов

Опечатался - не 100, а 60 символов...

KorPaEv
Offline
Зарегистрирован: 24.11.2014

Победил проблему, может кому и понадобится...
А смысл вот в чем. Как сказано выше gsm посылает любую смс - будь то одинарная или составная превышающая 160 для латиницы или 64 для кириллицы символов, частями по 64 символа...
Поэтому ваша смс придет в виде - заголовок + основное тело смс.
Основное тело смс может опять же состоять из нескольких строк, если встретился символ конца строки то его надо добавить в строку которую мы собираем и будем дальше анализировать.
Например пришла смс в виде

\r\n +CMT: "+79999999999","NAME","16/01/28,00:36:38+24" \r\n
1234567890 \n

Что произойдет? Сначала я собираю всю строку с заголовком и телом смс.
Далее бегу по каждому символу строки и собираю подстроку. Как только отлавливаю конец строки, дописываю кего в подстроку и получаю подстроку вида

+CMT: "+79999999999","NAME","16/01/28,00:36:38+24" \r\n

Анализирую то что в ней лежит и поднимаю флажок, что дальше будет тело самой СМС..
Бежим дальше по циклу, отловили опять конец строки - собрали новую подстроку вида

1234567890 \n

Соответственно флажок поднят и мы анализируем уже, то что лежит в теле самомй СМС - в моем случае подстрока состояла из нескольких строк, поэтому я внутри уже разбивал данную подстроку на отдельные строки...
Как то так.

 

#include <SoftwareSerial.h>
SoftwareSerial gprsSerial(10, 11); //На меге работает у меня на 10 и 11 пинах, потому как 7 и 8 занят прерываниями
 
//инициализация
void setup(void)
{
  // Стартуем порт COM
  Serial.begin(9600);
 //Стартуем GSM
  InitGprs();
}
 
//Инициализация и старт GSM модуля
void InitGprs()
{
  gprsSerial.begin(9600);
  gprsSerial.print("AT+CMGF=1\r");
  delay(300);
  gprsSerial.print("AT+IFC=1, 1\r");
  delay(300);
  gprsSerial.print("AT+CPBS="SM"\r");
  delay(300);
  gprsSerial.print("AT+CNMI=1,2,2,1,0\r");
  delay(500);
  //Включаем GPRS Shield, эмулируя нажатие кнопки POWER
  pinMode(9, OUTPUT);
  digitalWrite(9, HIGH);    // Подаем High на пин 9
  delay(3000);              // на 3 секунды
  digitalWrite(9, LOW);     // и отпускаем в Low.
  delay(5000);              // Ждём 5 секунд для старта шилда
}
 
void loop(void)
{
  GsmShieldManage();
}
 
//Обработка смс приемника-передатчика
//----------------------------------
boolean isStringMessage = false;
String currentNumber = ""; //Текущий номер с которого пришло смс
char bufGsm[64]; // Буфер для данных из смс поому что модуль GSM посылает кусками любую смс
String inputGsmFullStr = ""; //входящая строка с gsm модема - полная
String lineFullStr = ""; // Входная строка построчно из inputGsmFullStr
int countBufGsm = 0; // счетчик символов для буфера
//----------------------------------
void GsmShieldManage()
{
  // Если что то начало падать в GSM
  if (gprsSerial.available())
  {
    // Читаем данные частями в буфер
    while (gprsSerial.available())
    {
      // Пишем буфер по 64 символа
      bufGsm[countBufGsm++] = gprsSerial.read();
      if (countBufGsm == 64)
      {
        break;
      }
    }
    // Собираем строку полную - в том числе и заголовок
    inputGsmFullStr += bufGsm;
    // Функция очистки буфера
    clearBufferArray();
    // Сбрасываем счетчик символов
    countBufGsm = 0;
  }
  // иначе если прекращена передача данных то строка собрана
  else
  {
    //Если строка не пустая
    if (inputGsmFullStr != "")
    {
      //Очистили подстроку главной строки
      lineFullStr = "";
Serial.println("Curr str = " + inputGsmFullStr);
      //Читаем посимвольно нашу полную СМС и выдергиваем оттуда подстроки
      //А вид она имеет следующий  \r\n +CMT: "+79999999999","NAME","16/01/28,00:36:38+24" \r\n
      //                            1234567890 \n
      //                            1234567890 \r\n
      for (int i = 0; i < inputGsmFullStr.length(); i++)
      {
        //Если находим символ возврата каретки
        if (inputGsmFullStr.charAt(i) == '\r')
        {
Serial.println("SEPARATOR END LINE (R) FOUND");
          // если это продолжение полной смс - само тело без заголовка - 1234567890 \n - то обрабатываем то что внутри (команды)
          if (isStringMessage)
          {          
Serial.println("IS STR MESSAGE OK: " + lineFullStr);
            //Обработка команд
            if (!lineFullStr.compareTo("BAL"))
            {
              // делаем запрос баланса (мтс), а ответ ловится в блоке ниже...
              gprsSerial.print("ATD#100#;\r");
            }
             //Если входная строка содержит "ADD" значит там команда может  быть составной
            //Она имеет вид ADDNUM;1;+79999999999;1;1;1
            //                     ADDINF;Ard001; SomeTEXT
            else if (StringContains(lineFullStr, "ADD"))
            {
              //Ищем количество разделителей в lineFullStr (Тело смс) - это может быть и несколько строк
              byte countStr = 0;
              for (int j = 0; j < lineFullStr.length(); j++)
              {
                if (lineFullStr.charAt(j) == '\n')
                  countStr++;
              }
              String subLineFullStr = ""; // отдельная подстрока lineFullStr
              for (int i = 0; i < countStr; i++)
              {
                //Нашли строку по символу конца строки
                subLineFullStr = splitString(lineFullStr, '\n', i);
                //Смотрим команду
                if (StringContains(subLineFullStr, "ADDNUM"))
                {
                  //ЧТО ТО ДЕЛАЕМ
                }
                //Если строка содержит "ADDINF"
                if (StringContains(currSubStr, "ADDINF"))
                {
                  //ЧТО ТО ДЕЛАЕМ
                }
              }
            }
            isStringMessage = false;
          }
          else
          {
            // если это текстовое сообщение
            if (StringContains(lineFullStr, "+CMT"))
            {             
Serial.println("IS MESSAGE: " + lineFullStr);             
              // читаем текущий номер с которого смс пришло
              currentNumber = lineFullStr.substring(lineFullStr.indexOf(""") + 1, lineFullStr.indexOf(",") - 1);
Serial.println(currentNumber);      
              //Подняли флажок что это текстовое сообщение       
              isStringMessage = true;
            }
            // если это звонок
            if (lineFullStr.startsWith("+CLIP"))
            {
Serial.println("CALL");
              //считали текущий номер и просто ждем 3 сек и скидываем
              currentNumber = lineFullStr.substring(lineFullStr.indexOf("""), lineFullStr.indexOf(","));
Serial.println(currentNumber);
              delay(3000);
              gprsSerial.println("ATH0");
            }
            // этот блок отлавливает ответ на запрос баланса и отправляет его смской
            if (lineFullStr.startsWith("+CUSD"))
            {
              lineFullStr = lineFullStr.substring(lineFullStr.indexOf("Balance"), lineFullStr.indexOf("r"));
              delay(1500);
              lineFullStr += " is your balance of number " + currentNumber;
              SendSms(currentNumber, lineFullStr);
            }
          }
          lineFullStr = "";
        } // end if (inputGsmFullStr.charAt(i) == '\r')
        else if ('\n' != inputGsmFullStr.charAt(i))
        {
          lineFullStr += inputGsmFullStr.charAt(i);
        }
        else if ('\n' == inputGsmFullStr.charAt(i))
        {
          lineFullStr += '\n';
        }
      }
    }
    inputGsmFullStr = ""; //Очищаем то что пришло с GSM
  }
}
 
void clearBufferArray() // function to clear buffer array
{
  for (int i = 0; i < countBufGsm; i++)
  {
    bufGsm[i] = NULL;
  }
}