Странная проблемма с SIM800
- Войдите на сайт для отправки комментариев
Вс, 24/10/2021 - 17:50
Здравствуйте господа. Зарание спасибо за помощь. Суть проблеммы в следующем. У меня Arduino и GSM SIM800, они отправляют смс на русском, и раньше они это даже делали, но появиласьб проюлемма... Модем пререстал отвечать на некоторые комманды (фото ниже)
. Как вы думаете что это и как это решить.
Скетч секретный? И на какую команду модем не отвечает?
Скетч конечно не секретный, тем более что большая часть взята с сайта: https://codius.ru/articles/GSM_%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C_SIM800L_%D1%87%D0%B0%D1%81%D1%82%D1%8C_3.
#include <SoftwareSerial.h> #define Restart_GSM_pin 16 #define Rx_out 3 // принимающая линия UART для работы GSM модуля (A1) #define Tx_out 2 // передающая линия UART для работы GSM модуля (A0) #define number_lim 5 // предел для создания номеров не больше 9 #define Stop_number "+00000000000" // условно пустой (не сушествуюший) номер String Phone_numbers [number_lim]; // Подключение GSM SoftwareSerial SIM800(Tx_out, Rx_out); String _response = ""; extern int __bss_end; extern void *__brkval; // Функция, возвращающая количество свободного ОЗУ (RAM) int memoryFree() { int freeValue; if((int)__brkval == 0) freeValue = ((int)&freeValue) - ((int)&__bss_end); else freeValue = ((int)&freeValue) - ((int)__brkval); return freeValue; } //========================================================= GSM funcs ====================================================================== String byteToHexString(byte i) { // Функция преобразования числового значения байта в шестнадцатиричное (HEX) String hex = String(i, HEX); if (hex.length() == 1) hex = "0" + hex; hex.toUpperCase(); return hex; } unsigned int getCharSize(unsigned char b) { // Функция получения количества байт, которыми кодируется символ // По правилам кодирования UTF-8, по старшим битам первого октета вычисляется общий размер символа // 1 0xxxxxxx - старший бит ноль (ASCII код совпадает с UTF-8) - символ из системы ASCII, кодируется одним байтом // 2 110xxxxx - два старших бита единицы - символ кодируется двумя байтами // 3 1110xxxx - 3 байта и т.д. // 4 11110xxx // 5 111110xx // 6 1111110x if (b < 128) return 1; // Если первый байт из системы ASCII, то он кодируется одним байтом // Дальше нужно посчитать сколько единиц в старших битах до первого нуля - таково будет количество байтов на символ. // При помощи маски, поочереди исключаем старшие биты, до тех пор пока не дойдет до нуля. for (int i = 1; i <= 7; i++) { if (((b << i) & 0xFF) >> 7 == 0) { return i; } } return 1; } unsigned int symbolToUInt(const String& bytes) { // Функция для получения DEC-представления символа unsigned int charSize = bytes.length(); // Количество байт, которыми закодирован символ unsigned int result = 0; if (charSize == 1) { return bytes[0]; // Если символ кодируется одним байтом, сразу отправляем его } else { unsigned char actualByte = bytes[0]; // У первого байта оставляем только значимую часть 1110XXXX - убираем в начале 1110, оставляем XXXX // Количество единиц в начале совпадает с количеством байт, которыми кодируется символ - убираем их // Например (для размера 2 байта), берем маску 0xFF (11111111) - сдвигаем её (>>) на количество ненужных бит (3 - 110) - 00011111 result = actualByte & (0xFF >> (charSize + 1)); // Было 11010001, далее 11010001&(11111111>>(2+1))=10001 // Каждый следующий байт начинается с 10XXXXXX - нам нужны только по 6 бит с каждого последующего байта // А поскольку остался только 1 байт, резервируем под него место: result = result << (6 * (charSize - 1)); // Было 10001, далее 10001<<(6*(2-1))=10001000000 // Теперь у каждого следующего бита, убираем ненужные биты 10XXXXXX, а оставшиеся добавляем к result в соответствии с расположением for (int i = 1; i < charSize; i++) { actualByte = bytes[i]; if ((actualByte >> 6) != 2) return 0; // Если байт не начинается с 10, значит ошибка - выходим // В продолжение примера, берется существенная часть следующего байта // Например, у 10011111 убираем маской 10 (биты в начале), остается - 11111 // Теперь сдвигаем их на 2-1-1=0 сдвигать не нужно, просто добавляем на свое место result |= ((actualByte & 0x3F) << (6 * (charSize - 1 - i))); // Было result=10001000000, actualByte=10011111. Маской actualByte & 0x3F (10011111&111111=11111), сдвигать не нужно // Теперь "пристыковываем" к result: result|11111 (10001000000|11111=10001011111) } return result; } } String StringToUCS2(String s) { String output = ""; // Переменная для хранения результата for (int k = 0; k < s.length(); k++) { // Начинаем перебирать все байты во входной строке byte actualChar = (byte)s[k]; // Получаем первый байт unsigned int charSize = getCharSize(actualChar); // Получаем длину символа - кличество байт. // Максимальная длина символа в UTF-8 - 6 байт плюс завершающий ноль, итого 7 char symbolBytes[charSize + 1]; // Объявляем массив в соответствии с полученным размером for (int i = 0; i < charSize; i++) symbolBytes[i] = s[k + i]; // Записываем в массив все байты, которыми кодируется символ symbolBytes[charSize] = '\0'; // Добавляем завершающий 0 unsigned int charCode = symbolToUInt(symbolBytes); // Получаем DEC-представление символа из набора байтов if (charCode > 0) { // Если все корректно преобразовываем его в HEX-строку // Остается каждый из 2 байт перевести в HEX формат, преобразовать в строку и собрать в кучу output += byteToHexString((charCode & 0xFF00) >> 8) + byteToHexString(charCode & 0xFF); } k += charSize - 1; // Передвигаем указатель на начало нового символа if (output.length() >= 280) break; // Строка превышает 70 (4 знака на символ * 70 = 280) символов, выходим } return output; // Возвращаем результат } String getDAfield(String *phone, bool fullnum) { String result = ""; for (int i = 0; i <= (*phone).length(); i++) { // Оставляем только цифры if (isDigit((*phone)[i])) { result += (*phone)[i]; } } int phonelen = result.length(); // Количество цифр в телефоне if (phonelen % 2 != 0) result += "F"; // Если количество цифр нечетное, добавляем F for (int i = 0; i < result.length(); i += 2) { // Попарно переставляем символы в номере char symbol = result[i + 1]; result = result.substring(0, i + 1) + result.substring(i + 2); result = result.substring(0, i) + (String)symbol + result.substring(i); } result = fullnum ? "91" + result : "81" + result; // Добавляем формат номера получателя, поле PR result = byteToHexString(phonelen) + result; // Добавляем длиу номера, поле PL return result; } void getPDUPack(String *phone, String *message, String *result, int *PDUlen) { // Поле SCA добавим в самом конце, после расчета длины PDU-пакета *result += "01"; // Поле PDU-type - байт 00000001b *result += "00"; // Поле MR (Message Reference) *result += getDAfield(phone, true); // Поле DA *result += "00"; // Поле PID (Protocol Identifier) *result += "08"; // Поле DCS (Data Coding Scheme) //*result += ""; // Поле VP (Validity Period) - не используется String msg = StringToUCS2(*message); // Конвертируем строку в UCS2-формат *result += byteToHexString(msg.length() / 2); // Поле UDL (User Data Length). Делим на 2, так как в UCS2-строке каждый закодированный символ представлен 2 байтами. *result += msg; *PDUlen = (*result).length() / 2; // Получаем длину PDU-пакета без поля SCA *result = "00" + *result; // Добавляем поле SCA } String waitResponse() { // Функция ожидания ответа и возврата полученного результата String _resp = ""; // Переменная для хранения результата long _timeout = millis() + 10000; // Переменная для отслеживания таймаута (10 секунд) while (!SIM800.available() && millis() < _timeout) {}; // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то... if (SIM800.available()) { // Если есть, что считывать... _resp = SIM800.readString(); // ... считываем и запоминаем } else { // Если пришел таймаут, то... Serial.println("Timeout..."); // ... оповещаем об этом и... } return _resp; // ... возвращаем результат. Пусто, если проблема } String sendATCommand(String cmd, bool waiting) { String _resp = ""; // Переменная для хранения результата Serial.println(cmd); // Дублируем команду в монитор порта SIM800.println(cmd); // Отправляем команду модулю if (waiting) { // Если необходимо дождаться ответа... _resp = waitResponse(); // ... ждем, когда будет передан ответ // Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать if (_resp.startsWith(cmd)) { // Убираем из ответа дублирующуюся команду _resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2); } Serial.println(_resp); // Дублируем ответ в монитор порта } return _resp; // Возвращаем результат. Пусто, если проблема } void sendSMSinPDU(String phone, String message) { Serial.println("Отправляем сообщение: " + message); // ============ Подготовка PDU-пакета ============================================================================================= // В целях экономии памяти будем использовать указатели и ссылки String *ptrphone = ☎ // Указатель на переменную с телефонным номером String *ptrmessage = &message; // Указатель на переменную с сообщением String PDUPack; // Переменная для хранения PDU-пакета String *ptrPDUPack = &PDUPack; // Создаем указатель на переменную с PDU-пакетом int PDUlen = 0; // Переменная для хранения длины PDU-пакета без SCA int *ptrPDUlen = &PDUlen; // Указатель на переменную для хранения длины PDU-пакета без SCA getPDUPack(ptrphone, ptrmessage, ptrPDUPack, ptrPDUlen); // Функция формирующая PDU-пакет, и вычисляющая длину пакета без SCA Serial.println("PDU-pack: " + PDUPack); Serial.println("PDU length without SCA:" + (String)PDUlen); // ============ Отправка PDU-сообщения ============================================================================================ sendATCommand("AT+CMGF=0", true); // Включаем PDU-режим sendATCommand("AT+CMGS=" + (String)PDUlen, true); // Отправляем длину PDU-пакета sendATCommand(PDUPack + (String)((char)26), true); // После PDU-пакета отправляем Ctrl+Z } // =================================== Блок декодирования UCS2 в читаемую строку UTF-8 ================================= unsigned char HexSymbolToChar(char c) { if ((c >= 0x30) && (c <= 0x39)) return (c - 0x30); else if ((c >= 'A') && (c <= 'F')) return (c - 'A' + 10); else return (0); } String UCS2ToString(String s) { // Функция декодирования UCS2 строки String result = ""; unsigned char c[5] = ""; // Массив для хранения результата for (int i = 0; i < s.length() - 3; i += 4) { // Перебираем по 4 символа кодировки unsigned long code = (((unsigned int)HexSymbolToChar(s[i])) << 12) + // Получаем UNICODE-код символа из HEX представления (((unsigned int)HexSymbolToChar(s[i + 1])) << 8) + (((unsigned int)HexSymbolToChar(s[i + 2])) << 4) + ((unsigned int)HexSymbolToChar(s[i + 3])); if (code <= 0x7F) { // Теперь в соответствии с количеством байт формируем символ c[0] = (char)code; c[1] = 0; // Не забываем про завершающий ноль } else if (code <= 0x7FF) { c[0] = (char)(0xC0 | (code >> 6)); c[1] = (char)(0x80 | (code & 0x3F)); c[2] = 0; } else if (code <= 0xFFFF) { c[0] = (char)(0xE0 | (code >> 12)); c[1] = (char)(0x80 | ((code >> 6) & 0x3F)); c[2] = (char)(0x80 | (code & 0x3F)); c[3] = 0; } else if (code <= 0x1FFFFF) { c[0] = (char)(0xE0 | (code >> 18)); c[1] = (char)(0xE0 | ((code >> 12) & 0x3F)); c[2] = (char)(0x80 | ((code >> 6) & 0x3F)); c[3] = (char)(0x80 | (code & 0x3F)); c[4] = 0; } result += String((char*)c); // Добавляем полученный символ к результату } return (result); } // =================================== Блок кодирования строки в представление UCS2 ================================= void restart_GSM(){ // Функция перезагрузки модема digitalWrite(Restart_GSM_pin, LOW); delay(500); digitalWrite(Restart_GSM_pin, HIGH); delay(500); } void number_list_creating(){ // создание списка номеров в микро контроллере int pos = 0; String string_to_mode = ""; int index = 0; while (index < number_lim){ //Serial.println("AT+CPBR="+String(index)); SIM800.println("AT+CPBR="+String(index)); string_to_mode = String(SIM800.readString()); string_to_mode.replace("\n",""); string_to_mode.replace(" ",""); string_to_mode.remove(string_to_mode.indexOf("+"),1); if (string_to_mode.indexOf("+") != -1){ pos = string_to_mode.indexOf("+"); string_to_mode = string_to_mode.substring(pos,pos+12); }else{ pos = string_to_mode.indexOf("8"); string_to_mode = string_to_mode.substring(pos,pos+11); pos = string_to_mode.indexOf("8"); string_to_mode[pos] = '7'; } if (index > 0){ Phone_numbers[index] = string_to_mode; } index++; SIM800.flush(); Serial.flush(); } } void number_creating_inSIM(){ // создание номеров на сим карте при необходимости int index_of_numbers = 1; SIM800.println("AT+CPBR=1"); if( SIM800.find('+') == false and SIM800.find('8') == false){ while (index_of_numbers < number_lim){ Serial.println(sendATCommand("AT+CPBW="+String(index_of_numbers)+","+'"'+Stop_number+'"'+","+"145,"+'"'+"Operator "+String(index_of_numbers)+'"'+"\r\n", true)); index_of_numbers+=1; } } SIM800.flush(); Serial.flush(); } float getFloatFromString(String str) { // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса bool flag = false; String result = ""; str.replace(",", "."); // Если в качестве разделителя десятичных используется запятая - меняем её на точку. for (int i = 0; i < str.length(); i++) { if (isDigit(str[i]) || (str[i] == (char)46 && flag)) { // Если начинается группа цифр (при этом, на точку без цифр не обращаем внимания), if (result == "" && i > 0 && (String)str[i - 1] == "-") { // Нельзя забывать, что баланс может быть отрицательным result += "-"; // Добавляем знак в начале } result += str[i]; // начинаем собирать их вместе if (!flag) flag = true; // Выставляем флаг, который указывает на то, что сборка числа началась. } else { // Если цифры закончились и флаг говорит о том, что сборка уже была, if (str[i] != (char)32) { // Если порядок числа отделен пробелом - игнорируем его, иначе... if (flag) break; // ...считаем, что все. } } } return result.toFloat(); // Возвращаем полученное число. } //=========================================================================================================================================== // 1 - Работа насоса 1 восcтановлена, 2 - Работа насоса 2 восcтановлена, 3 - Работа насосв не требуется // 4 - Насосы запущены в режиме чередования, 5 - Запущено два насоса одновременно, // 6 - Авария насоса 1, 7 - Авария насоса 2, 8 - Авария насоса 1 и 2 void SMS_sender(int choose) { // Функция отправки СМС по событию int index_for_send = 1; while (index_for_send < number_lim) { if (Phone_numbers[index_for_send] != Stop_number) { if (choose == 1) { sendSMSinPDU(Phone_numbers[index_for_send], F("Работа 1 восcтанов.")); } if (choose == 2) { sendSMSinPDU(Phone_numbers[index_for_send], F("Работа 2 восcтанов.")); } if (choose == 3) { sendSMSinPDU(Phone_numbers[index_for_send], F("Работа не требуется")); } if (choose == 4) { sendSMSinPDU(Phone_numbers[index_for_send], F("Насосы чередуются")); } if (choose == 5) { sendSMSinPDU(Phone_numbers[index_for_send], F("Запущено 2 насоса")); } if (choose == 6) { sendSMSinPDU(Phone_numbers[index_for_send], F("Авария насоса 1")); } if (choose == 7) { sendSMSinPDU(Phone_numbers[index_for_send], F("Авария насоса 2")); } if (choose == 8) { sendSMSinPDU(Phone_numbers[index_for_send], F("Авария насоса 1 и 2")); } } index_for_send += 1; } } void setup() { Serial.begin(9600); // Скорость обмена данными с компьютером SIM800.begin(9600); // Скорость обмена данными с модемом while ( sendATCommand("AT", true).indexOf("OK") == -1){ // продолжит выполнение если AT вернет True //Serial.println("GSM not responsing, restart"); Serial.println(sendATCommand("AT", true).indexOf("OK")); restart_GSM(); } Serial.println("Start!"); // number_creating_inSIM(); // number_list_creating(); // Serial.println(Phone_numbers[0]); // Serial.println(Phone_numbers[1]); // Serial.println(Phone_numbers[2]); // Serial.println(Phone_numbers[3]); // Serial.println(Phone_numbers[4]); sendATCommand("AT+CIMI",true); sendATCommand("ATI",true); sendATCommand("AT+CNUM",true); sendATCommand("ATX1",true); } void loop() { }Если конкретно нет ответа на команды AT+CNUM (AT+CNUM=?), ATX1, но главное что не работает отпрака СМС в PDU формате, после отправки PDU пакета модем не отвечает.
Ну и мне кажется что дела не в скетче а в SIM или модеме (
конкретно нет ответа на команды AT+CNUM (AT+CNUM=?)
не каждый оператор / SIM поддерживает работоспособность данной команды + зависит от конкретного места, настроек оператора, фазы луны и еще куча всего....
и зачем вообще скетчу знать свой номер? все равно же оператор/кто-то шлет команды устройству, тогда уж привязку железки рекомендую к IMEI делать
мне кажется что дела не в скетче
Откуда такая уверенность? разбираться в сотнях строк скопированного с интернета кода нет ни времени ни желания.
В качестве рекомендации - поставьте вывод информационных сообщений в Serial в разных местах и понять в каком месте конкретно зависает, с большой вероятностью не хватает памяти + проверить стабильность питания модема.
Так же советую разобраться самостоятельно в формате PDU, и соотвественно самим написать отправку, на форуме это уже было:
sim900 отправка больших СМС на русском в PDU формате | Аппаратная платформа Arduino
GSM A6 Mini смс в PDU формате | Аппаратная платформа Arduino
http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=1#comment-376729
вот еще нашел древний код для A6 модема (суть та же), что то типа температурной сигнализации, шлет SMS в PDU О времени работы и температуре
#include <EEPROM.h> // address 0 = count control users phone // address 1.... control users phones, first char - A - active D - deleted, last char = 0 #include "a6modem.h" #define max_time_without_response 14497537UL // ~ 4 hour #define max_time_read_sms 120000UL // 2min #define max_time_read_command 10000UL // 10sec #define startEEPROMmessages 128 // 0 and 1 position = word - current save posifion from 0 #define endEEPROMmessages 383 #define max_count_users_phone 6 #define max_len_sms 128 unsigned long last_time_get_response; unsigned long time_read_sms; unsigned long time_read_command; byte gsmmode, submode; char OPSname[] = "Russia00"; char OPSbalance[] = "*99999#"; char* UnitCommands[] = {"addphone", "delphone", "getuptime", "getbalance"}; char sender[24]; char smsmsg[max_len_sms]; char begstr[] = "~NEWsSMS~"; char endstr[] = "~SUCCSMS~"; void setup() { // put your setup code here, to run once: firststart(); } void loop() { // put your main code here, to run repeatedly: unsigned long current_millis = millis(); if (a6work() == 1) { last_time_get_response = current_millis; // clear watch dog timer domainmode(); } else { // watch dog timer for modem if ((current_millis - last_time_get_response) >= max_time_without_response) { a6resetmodem(); unsigned long delp = millis(); while ((millis() - delp) <= 20000); // boot modem firststart(); } else { // other action // read sms mode if ((current_millis - time_read_sms) >= max_time_read_sms) { if (gsmmode == 1) { if (a6sendcmd("AT+CMGL=4", "OK", "", "") == 1) { // read SMS, =0 unread, =4 all gsmmode = 2; submode = 0; // mode read sms time_read_sms = current_millis; // after sucess send command read sms } } } // end read sms mode // read sms from eeprom for execute comand if ((current_millis - time_read_command) >= max_time_read_command) { if (gsmmode == 1) { time_read_command = current_millis; readSMSforCommand(); } } // end read command } } } void domainmode() { if (a6getreturnedwork(0) == 2) { // timeout gsmmode = 1; submode = 0; // main loop a6clearrespbuf(); return; } switch (gsmmode) { case 0: { // init modem if (a6getreturnedwork(0) == 1) { switch (submode) { case 0: { // wait reponse first command AT if (a6sendcmd("ATE0", "OK", "", "") == 1) submode = 1; // no echo break; } case 1: { // wait reponse command ATE0 if (a6sendcmd("ATV1", "OK", "", "") == 1) submode = 2; // get text for error break; } case 2: { // wait reponse command ATV1 if (a6sendcmd("AT+CMEE=2", "OK", "", "") == 1) submode = 3; // get full text error break; } case 3: { // wait reponse command cmee if (a6sendcmd("AT+CLIP=1", "OK", "", "") == 1) submode = 4; // on aon break; } case 4: { // wait reponse command clip if (a6sendcmd("ATS0=3", "OK", "", "") == 1) submode = 5; // 3 ring break; } case 5: { // wait reponse command ats unsigned long delp = millis(); while ((millis() - delp) <= 30000); //delay for registration if (a6sendcmd("AT+CREG?", "+CREG: 1,1", "OK", "") == 1) submode = 6; // true registration //if (a6sendcmd("AT+CREG?", "OK", "", "") == 1) submode = 6; // registration break; } case 6: { // wait registration if (a6sendcmd("AT+CMGF=0", "OK", "", "") == 1) submode = 7; // mode SMS = PDU break; } case 7: { // wait mode sms if (a6sendcmd("AT+CMGD=1,4", "OK", "", "") == 1) submode = 8; // delete all sms break; } case 8: { // wait del sms if (a6sendcmd("AT+COPS?", "+COPS:", "OK", "") == 1) submode = 9; // load operator data break; } case 9: { // decode operator data a6getopsname(OPSname, OPSbalance); gsmmode = 1; submode = 0; // init ok digitalWrite(LED_BUILTIN, HIGH); a6clearrespbuf(); break; } } } else { a6clearrespbuf(); } break; } case 1: { // main loop if (a6getreturnedwork(2) == 1) { // ring // ring by admin } if ((a6getreturnedwork(1) == 1) || (a6getreturnedwork(3) == 1)) { // problem a6resetmodem(); unsigned long delp = millis(); while ((millis() - delp) <= 20000); // boot modem firststart(); return; } a6clearrespbuf(); break; } case 2: { // mode read sms if (a6getreturnedwork(0) == 1) { switch (submode) { case 0: { byte countsms = a6getcountsms(); if (countsms > 0) { while (countsms > 0) { // loop by sms a6readsms(countsms, sender, smsmsg); if ((getAllowCommandPhone(sender) == 1) || (getAllowCommandPhone(sender) == 2)) { // save sms to eeprom saveSMStoEEPROM(sender, smsmsg); } // - end loop sms --countsms; } // delete all sms if (a6sendcmd("AT+CMGD=1,4", "OK", "", "") == 1) submode = 1; } else { a6clearrespbuf(); gsmmode = 1; submode = 0; // no sms } break; } default: { a6clearrespbuf(); gsmmode = 1; submode = 0; } } } else { a6clearrespbuf(); } break; } case 3: { // mode send sms if (a6getreturnedwork(0) == 1) { switch (submode) { case 0: { if (a6sendcmd(smsmsg, ">", "+CMGS:", "OK") == 1) submode = 1; break; } default: { a6clearrespbuf(); gsmmode = 1; submode = 0; } } } else { a6clearrespbuf(); } break; } case 4: { // mode get balance if (a6getreturnedwork(0) == 1) { switch (submode) { case 0: { // decode USSD // send SMS text from USSD a6clearrespbuf(); gsmmode = 1; submode = 0; // temp text, seed submode = 1 break; } default: { a6clearrespbuf(); gsmmode = 1; submode = 0; } } } else { a6clearrespbuf(); } break; } default: { a6clearrespbuf(); } } } void firststart() { a6initmodem(9600, 1, 9600); // test init soft uart //a6initmodem(38400, 0, 0); // work - hard uart gsmmode = 0; submode = 0; // start last_time_get_response = millis(); time_read_sms = 0UL; time_read_command = 0UL; } void SerialPrintWin1251(char* textsms) { byte i = 0; while (textsms[i] != 0) { byte wb = textsms[i]; if (wb <= 128) { Serial.write(wb); } else { switch (wb) { case 168: { Serial.write(208); Serial.write(101); break; } case 184: { Serial.write(209); Serial.write(145); break; } default: { if (wb < 192) { Serial.write(wb); } else { if (wb < 240) { Serial.write(208); Serial.write(wb - 48); } else { Serial.write(209); Serial.write(wb - 112); } } } } } ++i; } } byte getAllowCommandPhone(char* sender) { if (strPos(sender, ADMIN_PHONE) >= 0) return 2; word rb = FindPhomeFromUsersList(sender); if ((rb > 1000) && (rb < 2000)) { return 1; } else { return 0; } } void saveSMStoEEPROM(char* sender, char* textsms) { byte l1 = strlen(sender); byte l2 = strlen(textsms); word lastpos = EEPROM.read(startEEPROMmessages); if ((lastpos == 0xFF) || ((lastpos + l1 + l2 + 12) >= (endEEPROMmessages - startEEPROMmessages))) lastpos = 0; lastpos += (startEEPROMmessages + 1); byte i = 0; while (begstr[i] != 0) { EEPROM.write(lastpos + i, begstr[i]); ++i; } EEPROM.write(lastpos + i, 0); lastpos += (i + 1); i = 0; while (sender[i] != 0) { EEPROM.write(lastpos + i, sender[i]); ++i; } EEPROM.write(lastpos + i, 0); lastpos += (i + 1); i = 0; while (textsms[i] != 0) { EEPROM.write(lastpos + i, textsms[i]); ++i; } EEPROM.write(lastpos + i, 0); lastpos += (i + 1); EEPROM.write(startEEPROMmessages, (lastpos - startEEPROMmessages - 1)); } void readSMSforCommand() { word lastpos = startEEPROMmessages + 1; word i, j, k; m3: i = 0; j = 0; k = 0; m1: byte eb = EEPROM.read(lastpos + i); if ((eb == begstr[i]) || (eb == endstr[i])) { if (eb == begstr[i]) ++j; if (eb == endstr[i]) ++k; if ((++i) >= 9) goto m2; goto m1; } else { return; } m2: if (k == 9) { // skip -> new sms lastpos += (k + 1); // find 0 and 0 i = 0; while (EEPROM.read(lastpos + i) != 0) ++i; lastpos += (i + 1); if (lastpos >= endEEPROMmessages) return; i = 0; while (EEPROM.read(lastpos + i) != 0) ++i; lastpos += (i + 1); if (lastpos >= endEEPROMmessages) return; goto m3; } if (j == 9) { // save to eeprom ~SUCCSMS~ i = 0; while ((endstr[i]) != 0) { EEPROM.write((lastpos + i), endstr[i]); ++i; } // new command lastpos += (j + 1); i = 0; while ((sender[i] = EEPROM.read(lastpos + i)) != 0) ++i; sender[i] = 0; lastpos += (i + 1); i = 0; while ((smsmsg[i] = EEPROM.read(lastpos + i)) != 0) ++i; smsmsg[i] = 0; lastpos += (i + 1); // find command j = 0; // num found command for (i = 0; i < 4; ++i) { // 4 commands if (strPos(smsmsg, UnitCommands[i]) >= 0) { j = i + 1; break; } } switch (j) { case 1: { if (getAllowCommandPhone(sender) != 2) return; // command for admin only if (CutPhoneFromText(smsmsg) != 1) return; // save phone to eeprom AddPhoneToUsersList(smsmsg); break; } case 2: { if (getAllowCommandPhone(sender) != 2) return; // command for admin only if (CutPhoneFromText(smsmsg) != 1) return; // delete phone from eeprom DelPhoneToUsersList(smsmsg); break; } case 3: { if (getAllowCommandPhone(sender) == 0) return; // command for any user // prepare send text i = 0; while ((smsmsg[i] = OPSname[i]) != 0 ) ++i; smsmsg[i] = ' '; ++i; i = addTextUptime(i); smsmsg[i] = 0; sendSMS(); break; } case 4: { if (getAllowCommandPhone(sender) == 0) return; // command for any user char strcmd[] = "AT+CUSD=1,"; i = 0; while ((sender[i] = strcmd[i]) != 0) ++i; j = 0; while ((sender[i] = OPSbalance[j]) != 0) { ++i; ++j; } sender[i] = ','; ++i; sender[i] = '1'; ++i; sender[i] = '5'; ++i; sender[i] = 0; a6sendcmd(sender, "OK", "+CUSD: 2,", ",72"); gsmmode = 4; submode = 0; break; } default: { // Serial.println(" no command"); } } } else { return; } } byte CutPhoneFromText(char* smstxt) { int pp = strPos(smstxt, "+79"); if (pp > 0) { byte cb = 0; for (byte i = 0; i < 12; ++i) { // +7 and 10 digit smstxt[cb] = smstxt[pp + cb]; ++cb; } smstxt[cb] = 0; if (cb == 12) return 1; } return 0; } void AddPhoneToUsersList(char* phoneNumber) { word rb = FindPhomeFromUsersList(phoneNumber); if (rb > 2000) { // set active number EEPROM.write((rb - 2000), 'A'); return; } if (rb > 1000) { return; } // add new number byte pc = EEPROM.read(0); if (pc >= max_count_users_phone) pc = 5; // last number; word startpos = 1 + (pc * 14); byte i = 0; EEPROM.write(startpos, 'A'); while (phoneNumber[i] != 0) { EEPROM.write((startpos + 1 + i), phoneNumber[i]); ++i; } EEPROM.write((startpos + 1 + i), 0); ++pc; EEPROM.write(0, pc); } void DelPhoneToUsersList(char* phoneNumber) { word rb = FindPhomeFromUsersList(phoneNumber); if (rb > 1000) { // set delete number EEPROM.write((rb - 1000), 'D'); return; } } word FindPhomeFromUsersList(char* phoneNumber) { byte pc = EEPROM.read(0); if (pc == 0xFF) pc = 0; if (pc == 0) { EEPROM.write(0, 0); return 0; } byte i; boolean fla = false; for (i = 0; ((i < pc) && (i < max_count_users_phone)); ++i) { boolean fle = true; word startpos = 1 + i * 14; if (EEPROM.read(startpos) == 'A') fla = true; else fla = false; byte j = 0; while (phoneNumber[j] != 0) { if (phoneNumber[j] != EEPROM.read(startpos + j + 1)) { fle = false; break; } ++j; } if (fle) { if (fla) { return (1000 + startpos); } else { return (2000 + startpos); } } } return 0; } byte addTextUptime(byte firstpos) { unsigned long cml = millis() / 1000UL; byte days = cml / 86400; byte hours = (cml % 86400) / 3600; byte mins = ((cml % 86400) % 3600) / 60; if (days > 9) { smsmsg[firstpos] = (days / 10) + '0'; ++firstpos; } smsmsg[firstpos] = (days % 10) + '0'; ++firstpos; smsmsg[firstpos] = 228; ++firstpos; smsmsg[firstpos] = 237; ++firstpos; smsmsg[firstpos] = '.'; ++firstpos; if (hours > 9) { smsmsg[firstpos] = (hours / 10) + '0'; ++firstpos; } smsmsg[firstpos] = (hours % 10) + '0'; ++firstpos; smsmsg[firstpos] = 247; ++firstpos; smsmsg[firstpos] = 224; ++firstpos; smsmsg[firstpos] = 241; ++firstpos; smsmsg[firstpos] = '.'; ++firstpos; if (mins > 9) { smsmsg[firstpos] = (mins / 10) + '0'; ++firstpos; } smsmsg[firstpos] = (mins % 10) + '0'; ++firstpos; smsmsg[firstpos] = 236; ++firstpos; smsmsg[firstpos] = 232; ++firstpos; smsmsg[firstpos] = 237; ++firstpos; smsmsg[firstpos] = '.'; ++firstpos; return firstpos; } void sendSMS() { // convert msg to pdu format byte lenTextByChar = strlen(smsmsg); // move text to end buf byte i, j; for (i = 0; i < lenTextByChar; ++i) { smsmsg[max_len_sms - lenTextByChar + i] = smsmsg[i]; } byte curr_pos_pdu = 0; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; // SCA field smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '1'; ++curr_pos_pdu; // PDU type smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; // MR byte lenSenderPhone = strlen(sender); if (lenSenderPhone != 12) return; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = 'B'; ++curr_pos_pdu; // DA-PL smsmsg[curr_pos_pdu] = '9'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '1'; ++curr_pos_pdu; // DA-PT // convert sender number for (i = 0; i < lenSenderPhone; ++i) { sender[i] = sender[i + 1]; } sender[lenSenderPhone - 1] = 'F'; sender[lenSenderPhone] = 0; for (i = 0; i < lenSenderPhone; i += 2) { j = sender[i + 1]; sender[i + 1] = sender[i]; sender[i] = j; } for (i = 0; i < lenSenderPhone; ++i) { // DA-RP smsmsg[curr_pos_pdu] = sender[i]; ++curr_pos_pdu; } smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; // PID field smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '8'; ++curr_pos_pdu; // DCS field lenTextByChar *= 2; // UDL byte bb = lenTextByChar / 16; if (bb < 10) { smsmsg[curr_pos_pdu] = (bb + '0'); ++curr_pos_pdu; } else { smsmsg[curr_pos_pdu] = (bb + '0' + 7); ++curr_pos_pdu; } bb = lenTextByChar % 16; if (bb < 10) { smsmsg[curr_pos_pdu] = (bb + '0'); ++curr_pos_pdu; } else { smsmsg[curr_pos_pdu] = (bb + '0' + 7); ++curr_pos_pdu; } // UD - text by UCS2 for (i = 0; i < (lenTextByChar / 2); ++i) { bb = smsmsg[max_len_sms - (lenTextByChar / 2) + i]; if (bb < 0x7F) { smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; // convert to hex j = bb / 16; if (j < 10) { smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu; } else { smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu; } j = bb % 16; if (j < 10) { smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu; } else { smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu; } } else { switch (bb) { case 168: { smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '4'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '1'; ++curr_pos_pdu; break; } case 184: { smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '4'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '5'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '1'; ++curr_pos_pdu; break; } default: { if (bb < 192) { smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; // convert to hex j = bb / 16; if (j < 10) { smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu; } else { smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu; } j = bb % 16; if (j < 10) { smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu; } else { smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu; } } else { smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '4'; ++curr_pos_pdu; // convert to hex j = (bb - 176) / 16; if (j < 10) { smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu; } else { smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu; } j = (bb - 176) % 16; if (j < 10) { smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu; } else { smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu; } } } } } } // - smsmsg[curr_pos_pdu] = 26; smsmsg[curr_pos_pdu + 1] = 0; char strcmd[] = "AT+CMGS="; i = 0; while ((sender[i] = strcmd[i]) != 0) ++i; sender[i] = ((curr_pos_pdu / 2 - 1) / 10) + '0'; ++i; sender[i] = ((curr_pos_pdu / 2 - 1) % 10) + '0'; ++i; sender[i] = 0; a6sendcmd(sender, ">", "", ""); gsmmode = 3; submode = 0; } // functions for a6 gsm modem #include "Arduino.h" #include <SoftwareSerial.h> #define _a6_uart_rx_pin 9 // soft uart // 9 - TX Arduino (RX SIM800L) #define _a6_uart_pin_tx 8 // soft uart // 8 - RX Arduino (TX SIM800L), #define _a6_power_pin 10 #define _a6_reset_pin 7 #define RESPONSE_BUF_SIZE 184 #define RESPONSE_DETECT_SIZE 16 #define RESPONSE_MAX_TIME 30000 #define RESPONSE_MSG_SIZE 16 #define RESPONSE_COUNT_MSG 3 #define ADMIN_PHONE "+79206319946" #define RING_ADMIN_PHONE "79206319946" void a6initmodem(word a6uartspeed, byte a6softuart, word serialspeed); byte a6sendcmd(char* txtcmd, char* resp1, char* resp2, char* resp3); byte a6work(); byte a6detectresp(char* resp1, char* resp2, char* resp3); char* LastPos(char *str1, char *str2); int strPos(char *str11, char *str22); void a6clearrespbuf(); void a6addmsgdetect(byte nummsg, char* resp1, char* resp2, char* resp3); byte a6getreturnedwork(byte returnpos); void a6resetmodem(); byte a6getcountsms(); byte a6readsms(byte indexsms, char* phonenumber, char* textsms); void a6decodepdusms(byte firstcharpdu, byte counttextpdu, byte lastcharpdu, char* senderphone, char* textsms); byte strHexTobyte(char p1, char p2); void a6decodetextpdu7bit(byte charcount, byte firstpos, char* textsms); void a6decodetextpduUCS2(byte bytecount, byte firstpos, char* textsms); void a6getopsname(char* opsname, char* opsbalance); // functions for a6 gsm modem #include "a6modem.h" #include "Arduino.h" #include <SoftwareSerial.h> byte _a6_soft_uart; byte _use_console; char _rsp_buf[RESPONSE_BUF_SIZE]; word _rsp_pos; char _resp_detect1[RESPONSE_DETECT_SIZE]; char _resp_detect2[RESPONSE_DETECT_SIZE]; char _resp_detect3[RESPONSE_DETECT_SIZE]; char _msg_detect1[RESPONSE_COUNT_MSG][RESPONSE_MSG_SIZE]; char _msg_detect2[RESPONSE_COUNT_MSG][RESPONSE_MSG_SIZE]; char _msg_detect3[RESPONSE_COUNT_MSG][RESPONSE_MSG_SIZE]; byte _a6_returned_work[RESPONSE_COUNT_MSG + 1]; // position 0 = response sent at command, other position - returned msg unsigned long cmd_started_time; boolean wait_response; char* OPSlist[] = {"TELE2RUS", "*105#", "25020", "Beeline", "*100#", "25099", "MegaFon", "*100#", "25002", "MTS", "*100#", "25001"}; char OPScode[] = "250000"; SoftwareSerial gsm(_a6_uart_pin_tx, _a6_uart_rx_pin); // a6 init modem // p1 - modem speed // p2 - 1=use Software Serial UART // p3 - Serial0 speed, use as console, =0 if dont use or modem use Serial0; void a6initmodem(word a6uartspeed, byte a6softuart, word serialspeed) { pinMode(_a6_reset_pin, OUTPUT); pinMode(_a6_power_pin, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); digitalWrite(_a6_reset_pin, LOW); digitalWrite(_a6_power_pin, HIGH); // power on unsigned long delp = millis(); while ((millis() - delp) <= 10000); if (a6softuart != 0) { _a6_soft_uart = 1; gsm.begin(a6uartspeed); if (serialspeed > 0) { Serial.begin(serialspeed); _use_console = 1; } else { _use_console = 0; } } else { _a6_soft_uart = 0; _use_console = 0; Serial.begin(a6uartspeed); } // adaptive speed a6 module unsigned long curr_millis = millis(); while ((millis() - curr_millis) <= 4000UL) { if (_a6_soft_uart == 1) gsm.println("AT"); else Serial.println("AT"); } curr_millis = millis(); while ((millis() - curr_millis) <= 5000UL) { if (_a6_soft_uart) { if (gsm.available()) while (gsm.available()) gsm.read(); } else { if (Serial.available()) while (Serial.available()) Serial.read(); } } // - wait_response = false; for (int i = 0; i < RESPONSE_COUNT_MSG; ++i) { _msg_detect1[i][0] = 0; _msg_detect2[i][0] = 0; _msg_detect3[i][0] = 0; } // init command a6addmsgdetect(0, "-VOLTAGE WARN", "", ""); // power problem a6addmsgdetect(1, "+CLIP:", RING_ADMIN_PHONE, "CONNECT"); // input ring a6addmsgdetect(2, "+CMTE: 1", "", ""); // temp problem a6sendcmd("AT", "OK", "", ""); // begin work } void a6resetmodem() { // reset modem digitalWrite(_a6_reset_pin, HIGH); unsigned long delp = millis(); while ((millis() - delp) <= 500); digitalWrite(_a6_reset_pin, LOW); } byte a6sendcmd(char* txtcmd, char* resp1, char* resp2, char* resp3) { if (wait_response) return 0; if (_a6_soft_uart) gsm.println(txtcmd); else Serial.println(txtcmd); cmd_started_time = millis(); a6clearrespbuf(); byte pp = 0; if (_use_console) Serial.println(txtcmd); if (resp1[0] == 0) { wait_response = false; _resp_detect1[0] = 0; return 1; } else { wait_response = true; pp = 0; while ((resp1[pp] != 0) && (pp < (RESPONSE_DETECT_SIZE - 1))) { _resp_detect1[pp] = resp1[pp]; ++pp; } _resp_detect1[pp] = 0; } pp = 0; while ((resp2[pp] != 0) && (pp < (RESPONSE_DETECT_SIZE - 1))) { _resp_detect2[pp] = resp2[pp]; ++pp; } _resp_detect2[pp] = 0; pp = 0; while ((resp3[pp] != 0) && (pp < (RESPONSE_DETECT_SIZE - 1))) { _resp_detect3[pp] = resp3[pp]; ++pp; } _resp_detect3[pp] = 0; return 1; } byte a6work() { boolean getdata = false; if (_a6_soft_uart) { if (gsm.available()) while (gsm.available()) if (_rsp_pos < (RESPONSE_BUF_SIZE - 1)) { _rsp_buf[_rsp_pos] = gsm.read(); ++_rsp_pos; getdata = true; } } else { if (Serial.available()) while (Serial.available()) if (_rsp_pos < (RESPONSE_BUF_SIZE - 1)) { _rsp_buf[_rsp_pos] = Serial.read(); ++_rsp_pos; getdata = true; } } if (getdata) { _rsp_buf[_rsp_pos] = 0; if (_use_console) { if (_rsp_pos > 0) { Serial.println(_rsp_buf); } } } byte result = 0; for (byte i = 0; i <= RESPONSE_COUNT_MSG; ++i) _a6_returned_work[i] = 0; // find msg for (byte i = 0; i < RESPONSE_COUNT_MSG; ++i) { if (a6detectresp(_msg_detect1[i], _msg_detect2[i], _msg_detect3[i])) { result = 1; _a6_returned_work[i + 1] = 1; } } // wait response for sent at command if (wait_response) { if ((millis() - cmd_started_time) >= RESPONSE_MAX_TIME) { wait_response = false; result = 1; _a6_returned_work[0] = 2; // timeout } else { if (a6detectresp(_resp_detect1, _resp_detect2, _resp_detect3)) { wait_response = false; result = 1; _a6_returned_work[0] = 1; // OK } } } return result; } void a6addmsgdetect(byte nummsg, char* resp1, char* resp2, char* resp3) { if (nummsg > (RESPONSE_COUNT_MSG - 1)) return; if (resp1[0] == 0) { _msg_detect1[nummsg][0] = 0; return; } byte pp = 0; while ((resp1[pp] != 0) && (pp < (RESPONSE_MSG_SIZE - 1))) { _msg_detect1[nummsg][pp] = resp1[pp]; ++pp; } _msg_detect1[nummsg][pp] = 0; if (resp2[0] == 0) return; pp = 0; while ((resp2[pp] != 0) && (pp < (RESPONSE_MSG_SIZE - 1))) { _msg_detect2[nummsg][pp] = resp2[pp]; ++pp; } _msg_detect2[nummsg][pp] = 0; if (resp3[0] == 0) return; pp = 0; while ((resp3[pp] != 0) && (pp < (RESPONSE_MSG_SIZE - 1))) { _msg_detect3[nummsg][pp] = resp3[pp]; ++pp; } _msg_detect3[nummsg][pp] = 0; } void a6clearrespbuf() { _rsp_pos = 0; _rsp_buf[_rsp_pos] = 0; } byte a6detectresp(char* resp1, char* resp2, char* resp3) { if (_rsp_pos > 0) { if (resp1[0] != 0) { if (strPos(_rsp_buf, resp1) >= 0) { if (resp2[0] == 0) { return 1; } else { if (strPos(_rsp_buf, resp2) >= 0) { if (resp3[0] == 0) { return 1; } else { if (strPos(_rsp_buf, resp3) >= 0) { return 1; } else { return 0; } } } else { return 0; } } } else { return 0; } } else { return 0; } } else { return 0; } } char* LastPos(char *str1, char *str2) { int L1 = strlen(str1); int L2 = strlen(str2); for (int i = L1 - L2; i >= 0; i--) { int j = 0; for (; j < L2; j++) if (str1[i + j] != str2[j]) break; if (j == L2) return str1 + i; } return 0; } int strPos(char *str11, char *str22) { char*p = LastPos(str11, str22); int n = p - str11; return n; } byte a6getreturnedwork(byte returnpos) { return _a6_returned_work[returnpos]; } byte a6getcountsms() { char findstr[] = "+CMGL:"; if (a6detectresp(findstr, "", "") == 0) return 0; byte result = 0; int L1 = strlen(_rsp_buf); int L2 = strlen(findstr); for (int i = L1 - L2; i >= 0; i--) { int j = 0; for (j = 0; j < L2; j++) if (_rsp_buf[i + j] != findstr[j]) break; if (j == L2) { ++result; } } return result; } byte a6readsms(byte indexsms, char* phonenumber, char* textsms) { phonenumber[0] = 0; textsms[0] = 0; byte numfirstchar; if (indexsms < 10) { char findstr[] = "+CMGL: 1"; findstr[7] = '0' + indexsms; numfirstchar = strPos(_rsp_buf, findstr); numfirstchar += (strlen(findstr) + 4); // first posifion = count byte of pdu message } else { char findstr[] = "+CMGL: 1 "; findstr[8] = '0' + (indexsms % 10); numfirstchar = strPos(_rsp_buf, findstr); numfirstchar += (strlen(findstr) + 4); // first posifion = count byte of pdu message } // get lenght pdu byte i = 0; byte countbytepdu = 0; while (isdigit(_rsp_buf[numfirstchar + i])) { if (i > 0) { countbytepdu = (countbytepdu * 10) + (_rsp_buf[numfirstchar + i] - '0'); } else { countbytepdu = _rsp_buf[numfirstchar + i] - '0'; } ++i; } numfirstchar += i; if ((_rsp_buf[numfirstchar] == '\r') && (_rsp_buf[numfirstchar + 1] == '\n')) { // find first CR LF numfirstchar += 2; } else { return; } i = 0; while (!((_rsp_buf[numfirstchar + i] == '\r') && (_rsp_buf[numfirstchar + 1 + i] == '\n') && (_rsp_buf[numfirstchar + i] != 0))) { // find last CR LF ++i; } byte numlastchar = numfirstchar + i - 1; a6decodepdusms(numfirstchar, countbytepdu, numlastchar, phonenumber, textsms); } void a6decodepdusms(byte firstcharpdu, byte counttextpdu, byte lastcharpdu, char* senderphone, char* textsms) { // firstcharpdu - pos TP-SCA + 1 byte size byte nf = strHexTobyte(_rsp_buf[firstcharpdu], _rsp_buf[firstcharpdu + 1]) + 1; // new pos = TP-MTI & Co ++nf; // new pos = TP-OA byte lf = strHexTobyte(_rsp_buf[firstcharpdu + (nf * 2)], _rsp_buf[firstcharpdu + (nf * 2) + 1]); // lenght sender phone number // check format number ++nf; if ((_rsp_buf[firstcharpdu + (nf * 2)] != '9') || (_rsp_buf[firstcharpdu + (nf * 2) + 1] != '1')) return; // not digit format ++nf; senderphone[0] = '+'; for (byte i = 0; i < lf; ++i) { senderphone[i + 1] = _rsp_buf[firstcharpdu + (nf * 2) + i + 1]; senderphone[i + 2] = _rsp_buf[firstcharpdu + (nf * 2) + i]; ++i; } nf *= 2; nf += lf; if (senderphone[lf] == 'F') senderphone[lf] = 0; else senderphone[lf + 1] = 0; ++nf; // next char - pos TP-PID nf += 2; // pos TP-DCS boolean flUCS2; if ((_rsp_buf[firstcharpdu + nf] == '0') && (_rsp_buf[firstcharpdu + nf + 1] == '0')) flUCS2 = false; else flUCS2 = true; nf += 2; // pos TP-SCTS nf += 14; // pos TP-UDL byte lenpdutext = strHexTobyte(_rsp_buf[firstcharpdu + nf], _rsp_buf[firstcharpdu + nf + 1]); nf += 2; // pos TP-UD if (flUCS2) { a6decodetextpduUCS2(lenpdutext, (firstcharpdu + nf), textsms); } else { a6decodetextpdu7bit(lenpdutext, (firstcharpdu + nf), textsms); } } byte strHexTobyte(char p1, char p2) { p1 -= '0'; if (p1 > 10) (p1 -= 7); p1 = p1 << 4; p2 -= '0'; if (p2 > 10) (p2 -= 7); return (p1 | p2); } void a6decodetextpdu7bit(byte charcount, byte firstpos, char* textsms) { for (byte i = 0; i < charcount; ++i) { byte begin7bytepart = i / 8; byte resultbyte = 0; byte numbyte = i % 8; byte b1 = firstpos + (begin7bytepart * 2 * 8) + (numbyte * 2) - (2 * (begin7bytepart + 1)); byte b2 = strHexTobyte(_rsp_buf[b1 + 2], _rsp_buf[b1 + 3]); b1 = strHexTobyte(_rsp_buf[b1], _rsp_buf[b1 + 1]); byte lowb; if (numbyte == 0) { lowb = b2; } else { if (numbyte < 7) (lowb = b2 << numbyte); else (lowb = 0); } byte hib; if (numbyte > 0) (hib = b1 >> (8 - numbyte)); else (hib = 0); resultbyte = hib | lowb; textsms[i] = resultbyte & 0x7F; } textsms[charcount] = 0; } void a6decodetextpduUCS2(byte bytecount, byte firstpos, char* textsms) { for (byte i = 0; i < bytecount; i += 2) { byte b1 = firstpos + (i * 2); byte b2 = strHexTobyte(_rsp_buf[b1 + 2], _rsp_buf[b1 + 3]); b1 = strHexTobyte(_rsp_buf[b1], _rsp_buf[b1 + 1]); if (b1 == 0) { textsms[i / 2] = b2; } else { byte rb; if (b1 == 0x04) { switch (b2) { case 0x01: { rb = 168; break; } case 0x51: { rb = 184; break; } default: { if ((b2 >= 0x10) && (b2 <= 0x4F)) { rb = b2 + 176; } else { rb = b2; } } } } else { rb = b2; } textsms[i / 2] = rb; } } textsms[bytecount / 2] = 0; } void a6getopsname(char* opsname, char* opsbalance) { boolean fl = false; byte i; for (i = 0; i < 12; ++i) { if (strPos(_rsp_buf, OPSlist[i]) >= 0) { fl = true; break; } } if (fl) { byte j = 0; while ((OPScode[j] = OPSlist[i][j]) != 0) ++j; OPScode[j] = 0; j = 0; while ((opsname[j] = OPSlist[i - 2][j]) != 0) ++j; opsname[j] = 0; j = 0; while ((opsbalance[j] = OPSlist[i - 1][j]) != 0) ++j; opsbalance[j] = 0; } }Update:
посмотрел свой древний код, по факту вам необходима только одна функция
voidsendSMS() {на вход подается char строка в Win1251 кодировке
не забудьте перевести модем в режим отправки сообщений в PDU формате
Спасибо большое за помощь. К вопросу зачем мене именно комманда AT+CNUM (AT+CNUM=?), да в сущности незачем, я просто птался проверить что SIM карта работает с модемом правильно и с нее можно считать информацию. Меня напрягает только тот факт, что весь код раньше работал правильно и я не знаю после чего он перестал рпботать.
Спасибо еще раз, позже посмотрю ваш код и напишу, наверное, как все прошло.
Для проверки работоспособности модема есть масса других команд, регистрация в сети, уровень сигнала, данные базовых станций.....