roboforum.ru

Технический форум по робототехнике.

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

Как собрать и запрограммировать робота на Arduino(Freeduino, Roboduino, Seeduino ...). Используем Wiring и Processing.

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

Сообщение KorPaEv » 28 янв 2016, 10:36

Доброго времени суток, уважаемые!
Собственно, есть вот такой вот примерчик отсюда
http://wiki.amperka.....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 символов ничего кроме вышеупомянутой строки в монитере порта я не увидел. Отослав же сообщение длинной в 60 символов мы видим все красиво

+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
 
Сообщения: 4
Зарегистрирован: 28 янв 2016, 10:34

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

Сообщение elmot » 28 янв 2016, 13:18

Это не модуль не умеет. это GSM такой, длинные смс - это всегда серия коротких. а вот умеет ли модуль их клеить обратно - сие вопрос.
Аватара пользователя
elmot
 
Сообщения: 5691
Зарегистрирован: 10 ноя 2011, 12:02
Откуда: Turku, Finland
Skype: elmot73
прог. языки: Java и все-все=все
ФИО: Илья

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

Сообщение KorPaEv » 28 янв 2016, 13:45

elmot писал(а):Это не модуль не умеет. это GSM такой, длинные смс - это всегда серия коротких. а вот умеет ли модуль их клеить обратно - сие вопрос.


В том то и дело, что это даже не составная смс - это стандартная единичная 160 символьная смс, странно что GSM не умеет переслать целиком одну смс...
Причем сериал умеет дописывать остаток того что пришло - Serial.write(buffer, count);
поэтому и вопрос - как мне собрать строку из этих самых частей, чтобы потом отправить эту строку в функцию проверки - что это пришла СМС и дальнейшего парсинга?
KorPaEv
 
Сообщения: 4
Зарегистрирован: 28 янв 2016, 10:34

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

Сообщение Madf » 28 янв 2016, 14:08

Да, есть ограничение на длину СМС, причем если это по латински, если по русски пытаться пихать, то длина знаков резко сокращается из-за кодировки.
Если вам нужно устройством уметь собирать длинные СМС отосланные другим устройством, то протокол обмена можете сами придумать.
А вообще вот: http://electronix.ru/forum/lofiversion/ ... 90245.html
В общем, прежде чем играться с кодом, попробуйте в обычном терминале, командами получить требуемый результат.
Последний раз редактировалось Madf 28 янв 2016, 14:18, всего редактировалось 1 раз.
Madf
 
Сообщения: 3298
Зарегистрирован: 03 янв 2012, 12:55
Откуда: Москва
прог. языки: VB6, BASCOM, ASM...

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

Сообщение Myp » 28 янв 2016, 14:18

KorPaEv писал(а):стандартная единичная 160 символьная смс

а что подразумевается под 160 символами?
всего в смс 160 символов, но из них только 153 символа это полезная нагрузка, остальное это заголовок.
тоесть если ты попытаешься отправить смску с 160 буквами то отправится составная смска, 153 символа + 7 символов.

сим900 умеет принимать смс в разных режимах, в одном из них как раз умеет склеивать длинные смс.
тока вероятно надо определиться что конкретно будет использоваться, ато наскока я знаю "длинные" смс могут быть разные и сим900 будет ждать не такое "длинное" смс которое ты отправил.
<telepathmode>На вопросы отвечает Бригадир Телепатов!</telepathmode>
Всё уже придумано до нас!
Аватара пользователя
Myp
скрытый хозяин вселенной :)
 
Сообщения: 18018
Зарегистрирован: 18 сен 2006, 12:26
Откуда: Тверь по прозвищу Дверь
прог. языки: псевдокод =) сила в алгоритме!
ФИО: глубокоуважаемый Фёдор Анатольевич

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

Сообщение KorPaEv » 28 янв 2016, 14:55

Madf писал(а):Да, есть ограничение на длину СМС, причем если это по латински, если по русски пытаться пихать, то длина знаков резко сокращается из-за кодировки.
Если вам нужно устройством уметь собирать длинные СМС отосланные другим устройством, то протокол обмена можете сами придумать.
А вообще вот: http://electronix.ru/forum/lofiversion/ ... 90245.html
В общем, прежде чем играться с кодом, попробуйте в обычном терминале, командами получить требуемый результат.


в том то и дело что в терминале я получил требуемый результат и разрешение gprsSerial.print("AT+CMGF=1\r"); у меня прописано
Так же смс у меня латиницей пересылается...Так вот получается когда я посылаю смс

qwerty...qwewewrewrsdfsdfdf (64 символа) то в терминал приходит заголовок + текст в виде

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

Если же я пытаюсь послать смс латиницей состоящую больше чем из 64 символов - aaaaaaaa....aaaaaaaaaa (например 120-140, где в остатке на одно сообщение еще 20 остается)
то терминал у меня все получает, именно тестируя этот код
Код: Выделить всёРазвернуть
    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
    }


Но мне нужно собирать строку а не выводить все в терминал - поэтому я и спрашиваю, кким образом мне собрать всю строку вида???

+CMT: "+79999999999","NAME","16/01/28,00:36:38+24"
qwerty...qwewewrewrsdfsdfdf (160 символов)

Добавлено спустя 7 минут 52 секунды:
Myp писал(а):
KorPaEv писал(а):стандартная единичная 160 символьная смс

а что подразумевается под 160 символами?
всего в смс 160 символов, но из них только 153 символа это полезная нагрузка, остальное это заголовок.
тоесть если ты попытаешься отправить смску с 160 буквами то отправится составная смска, 153 символа + 7 символов.

сим900 умеет принимать смс в разных режимах, в одном из них как раз умеет склеивать длинные смс.
тока вероятно надо определиться что конкретно будет использоваться, ато наскока я знаю "длинные" смс могут быть разные и сим900 будет ждать не такое "длинное" смс которое ты отправил.


7 символов я так полагаю это информация инициализации??
AT+CMGF=1
AT+IFC=1
....

Тут вы правы - когда в терминал вывожу инфу и пытаюсь строку собрать у меня получается следующая штука - Например шлю смс 150 символов - в терминале вижу
Код: Выделить всёРазвернуть
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;
         Serial.print(inputGsmStr);
        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;
  }
}


Получаю в Serial.print(inputGsmStr);

AT+CMGF=1
ОК
AT+IFC=1
ОК
....
+CMT: "+79999999999",

AT+CMGF=1
ОК
AT+IFC=1
ОК
....
+CMT: "+79999999999","NAME","16/01/28,00:36:38+24"
aaaaaaa

AT+CMGF=1
ОК
AT+IFC=1
ОК
+CMT: "+79999999999","NAME","16/01/28,00:36:38+24"
aaaaaaa...aaaaaaaaaaaaa (И уже на 3м шаге вся смс)

ПОЭТОМУ СПРАШИВАЮ КАК МНЕ ПОЛУЧИТЬ ОКОНЧАТЕЛЬНУЮ ПОЛНУЮ СТРОКУ ВИДА, чтобы далее запустить эту функцию

+CMT: "+79999999999","NAME","16/01/28,00:36:38+24"
aaaaaaa...aaaaaaaaaaaaa (ВСЯ СМС)

Код: Выделить всёРазвернуть
 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 = "";
KorPaEv
 
Сообщения: 4
Зарегистрирован: 28 янв 2016, 10:34

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

Сообщение Madf » 28 янв 2016, 15:33

KorPaEv писал(а):в том то и дело что в терминале я получил требуемый результат

Если так, то непонятна изначально проблема.
Выложите лог запрос/ответ из терминала длинной СМС.
Если модуль автоматом сокращает информацию, значит нужно уходить на ручной режим приёма (поиграться настройкой CMGF).
Madf
 
Сообщения: 3298
Зарегистрирован: 03 янв 2012, 12:55
Откуда: Москва
прог. языки: VB6, BASCOM, ASM...

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

Сообщение KorPaEv » 29 янв 2016, 14:33

Победил проблему, может кому и понадобится...
А смысл вот в чем. Как сказано выше 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;
  }
}
KorPaEv
 
Сообщения: 4
Зарегистрирован: 28 янв 2016, 10:34

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

Сообщение Madf » 29 янв 2016, 17:03

в примере так и не увидел длинной смс, обычный парсинг текста
Madf
 
Сообщения: 3298
Зарегистрирован: 03 янв 2012, 12:55
Откуда: Москва
прог. языки: VB6, BASCOM, ASM...


Вернуться в Arduino и другие Xduino

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5