Доброго времени суток, уважаемые! Собственно, есть вот такой вот примерчик отсюда http://wiki.amperka.....8C:gprs-shield Меня интересует прием смс Код (C++): #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 символов? Пробовал таким способом, непосредственно с вики Код (C++): 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); выводится полное сообщение но опять же каким образом тут можно собрать строку? Пытался сделать следующее Код (C++): 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... Какие идеи?
Победил проблему, может кому и понадобится... А смысл вот в чем. Как сказано выше 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 Соответственно флажок поднят и мы анализируем уже, то что лежит в теле самомй СМС - в моем случае подстрока состояла из нескольких строк, поэтому я внутри уже разбивал данную подстроку на отдельные строки... Как то так. Код (C++): #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; } }
Естественно не компилируется потому что я в исходник не добавлял функцию отправки смс... SendSms(currentNumber, lineFullStr); Если надо то вот она.. Код (C++): // Функция отправки смс void SendSms(String number, String text) { Serial.println(number + " ; " + text); delay(1500); gprsSerial.print("AT+CMGS="); // send the SMS the number gprsSerial.print((char)34); // передача в порт символа " gprsSerial.print(number); // передача номера телефона gprsSerial.print((char)34); // передача в порт символа " gprsSerial.print((char)13); delay(1500); gprsSerial.println(text); // передача текста сообщения delay(500); gprsSerial.print((char)26); // передача ^Z gprsSerial.print((char)13); // передача Enter }
+ функция которая разбивает строку на подстроки по указанному символу... + функция поиска подстроки в строке.. Я выкладывал для общего ознакомления принцип работы, а не весь исходник))) splitString(lineFullStr, '\n', i); Код (C++): //Функция разбивает строку по заданному символу и возвращает указанный индекс String splitString(String string, char separator, int index) { int found = 0; int strIndex[] = {0, -1}; int maxIndex = string.length() - 1; for (int i = 0; i <= maxIndex && found <= index; i++) { if (string.charAt(i) == separator || i == maxIndex) { found++; strIndex[0] = strIndex[1] + 1; strIndex[1] = (i == maxIndex) ? i + 1 : i; } } return found > index ? string.substring(strIndex[0], strIndex[1]) : ""; } //Функция разбивает строку по заданному символу и возвращает указанный индекс String splitString(String string, char separator, int index) { int found = 0; int strIndex[] = {0, -1}; int maxIndex = string.length() - 1; for (int i = 0; i <= maxIndex && found <= index; i++) { if (string.charAt(i) == separator || i == maxIndex) { found++; strIndex[0] = strIndex[1] + 1; strIndex[1] = (i == maxIndex) ? i + 1 : i; } } return found > index ? string.substring(strIndex[0], strIndex[1]) : ""; }