а весь ваш взятый код с ресурса построен по принципу "отправил что то - жду команду" а в остальное время если что то надо сделать или придет другой ответ - "все пропало"
Вот тут я не поняла.
Незапрашиваемые уведомления обрабатываются же постоянно.
if (SIM800.available()) { // Если модем, что-то отправил...
_response = waitResponse(); // Получаем ответ от модема для анализа
_response.trim(); // Убираем лишние пробелы в начале и конце
Serial.println(_response); // Если нужно выводим в монитор порта
if (_response.indexOf("+CMTI:")>-1) { // Пришло сообщение об отправке SMS
lastUpdate = millis() - updatePeriod; // Теперь нет необходимости обрабатываеть SMS здесь, достаточно просто
// сбросить счетчик автопроверки и в следующем цикле все будет обработано
}
}
if (Serial.available()) { // Ожидаем команды по Serial...
SIM800.write(Serial.read()); // ...и отправляем полученную команду модему
};
}
Так статус смс не изхменится с "Непрочитанное" пока контроллер его не прочитает (после того как дождется ОК или перезагрузится после зависания). Так ведь?
Мне лично статьи понравились. Человек что то сделал, у него работает. Он не зажал скетч, не стал умничать на форуме, а выложил его на всеобщее обозрение, за что ему спасибо!
Выкладывание кода на всеобщее обозрение не делает его автоматически безупречным. Это типовой говнокод. Взять хотя бы сложение с millis с последующим сравнением, чел не понимает целочисленной арифметики, тупо закладывает в свой код баг, который бездумно тиражируется на этом ресурсе.
Votmax пишет:
Понятно, что проще критиковать, но если есть реальные основания так считать, то поделитесь со всеми. Что именно вам не понравилось?
Ардуино - это игрушка для школьников. Никто в здравом уме не станет использовать её для сколь нибудь серьезных решений. Её назначение поиграться и выкинуть. Индусский код тоже шлак, но здесь он рассматривается как эталон. Среда разработки - х#ня редкостная. Топология китайская - на отъ#$%ись. Что здесь вообще может понравится?
Votmax пишет:
Выложите свои примеры работы с модулем.
Вот предсерийный образец, для сухих отапливаемых помещений, не для авто. SIM800, стек USB, шифрование, закладки на радиоканал, SD карту и RTC. Код написан в кейле для STM, выкладывать здесь нет смысла. Страшно представить, что получится, если собрать это устройство из блоков для ардуино...
Irinka, где сброс SIM800 о котором ты спрашивала, где включение...?
.... Это типовой говнокод.... Ардуино - это игрушка для школьников. Индусский код тоже шлак, но здесь он рассматривается как эталон. Среда разработки - х#ня редкостная. Топология китайская - на отъ#$%ись. ....
Ахахахаха! Ответ на миллион!
Видно, что пишет профессионал)))). Хвастанул фоткой и материт все остальное. Мол, я гений, а вы тут все идиоты....
Ну давайте еще сравним промышленное серийное производство с поделками любителей.
Для многих любителей Ардуино - это хобби, где не нужно паять, тратить на это время. Минимум усилий и можно получить какую то никому не нужную, но ценную для самого себя игрушку. Таких людей никто не учит и скорее всего этому промыслу они и не учились. Для них любая информация, вроде той, которую вы поносите, ценна!
Не важно, что код работает с огрехами, главное понять принцип! А, уж, когда получилось, всегда есть возможность код исправить и переписать.
Нельзя говорить, что код плохой, если он работает. Нельзя плохо отзываться о человеке, который написал этот код, ведь он смог это сделать и при этом поделился со всеми.
Конечно, легко критиковать чужое, но не стоит, это низко.
Там описание модуля SIM900, но по работе с СМС подходит. Все вполне логично работает. А зная, какие приходят ответы, не сложно дальше развивать свой проект. Сейчас я только начал заниматься обработкой входящих смс, вроде ничего сложно, но нужно время. Как что то получится путное, сброшу.
P.S. Конечно, наш великий критик, Анди, скажет, что это ***код)))), куда нам до него...)))
Как мне кажется, моя проблема при пересечении границы области, как раз в этом и заключается, что оператор присылает сообщение типа: "Теле2 желает вам приятной поездки ........ и. .... т..... п....."
Для многих любителей Ардуино - это хобби, где не нужно паять, тратить на это время. Минимум усилий и можно получить какую то никому не нужную, но ценную для самого себя игрушку. Таких людей никто не учит и скорее всего этому промыслу они и не учились. Для них любая информация, вроде той, которую вы поносите, ценна!
Не следует путать информацию с дезинформацией.
Если сделано откровенно неправильно - в стиле "образец, как не нужно делать", а преподносится наоборот, как образец для\ подражания, то вред от такой "информации" существенно перекрывает возможную пользу.
Ваше утверждение эквивалентно следующему: любое сообщение ценно, вне зависимости от того, исинно оно или ложно.
Между ложью и истиной не может быть знака равенства.
Цитата:
Нельзя говорить, что код плохой, если он работает.
Если код плохой - он плохой вне зависимости от того, работает или нет.
Более того, от плохого, но работающего (естественно, ненадежно, и не всегда так, как хотел автор) кода вреда больше, чем от неработающего.
Если код плохой - он плохой вне зависимости от того, работает или нет.
О, еще один умник (философ) появился.
Программа работает по заложенному алгоритму. И если программисту нравится, как работает его код, значит он своей цели достиг, по крайней мере не в промышленных образцах, а в подделках любителей.
Можно с ума сходить добиваясь идеала, я так понимаю вы этим и страдаете, но часто это и не требуется.
Вы все ополчились на человека, который разобрался в работе с модулем, создал свой блог, написал статью и делится информацией с окружающими. Как только вы его, его код и ардуино не принижаете только!
Не нравится ардуино, не пользуйтесь и не сидите на этом форуме.
Еще раз повторюсь, проще критиковать, говорить, что код плохой и тд и тп, чем вы и занимаетесь. Мне тоже он не нравится, я работаю чисто с АТ командами, но тот код помог лично мне разобраться в каких то деталях и начать реализовывать свой проект, за что ему СПАСИБО!
А вы попробуйте вместо критики создать страничку в интернете, выложить свой код, сделать комментарии к нему, да еще и отвечать на вопросы в комментах. Тогда это будет по делу, это будет в пользу!
Но хочу вас предупредить, что как только вы сделаете это, найдется очередной Анди, который назовет ваш код, как он выражается - *****кодом ))), выложит какую то фотку и будет рассказывать, как он мега крут, а вы в программировании ничего не понимаете! А еще найдется философ, вроде вас, который начнет рассказывать про информацию и дезинформацию, про то , что истина это не ложь)))) И кстати, есть истина, есть ложь, а есть статистика, не забывайте про это!
Вот, что я хочу до вас донести! Все форумы в последнее время страдают этим и это печально.
Хвастанул фоткой и материт все остальное. Мол, я гений, а вы тут все идиоты....
Ты спросил, я ответил. Покажи своё говнотворчество...
Votmax пишет:
Ну давайте еще сравним промышленное серийное производство с поделками любителей.
Давай сравним результат твоих и моих усилий. Моя разработка с нуля до серийного производства. А что сделал ты? Соединил проводками чужие платы и написал несколько десятков строк говнокода... Всё. Я ничего не упустил?
Votmax пишет:
И если программисту нравится, как работает его код, значит он своей цели достиг
Между программистом и говнокодером огромная пропасть. Ты застрял на уровне школьного творчества, тебе до программиста, как до китая... Если твой код работает 5 минут, это еще не значит, что он будет работать круглый год, 24/7.
Andy, это ваша работа, не надо сравнивать проф разработку и устройство которое просто должно работать (кстати вполне возможно работать будет хорошо и круглогодично.
По поводу программтстов- лично для меня это слово ругательство, т к большинство это кодеры, которые видят только ТЗ а мозг включать не умеют и не видят всей задачи.
Поработав за последние 20 лет в разных областях и повидав десятки программ для ПС очень дорогих, понял что программистов единицы процентов, остальные просто уроды, которых хочется посадить за их произведения поработать, например заставить вбить клиента в базу за 3 минуты по нормативу, но это невозможно, поскольку отвратительный интерфейс и никакого удобства.
А что сделал ты? Соединил проводками чужие платы и написал несколько десятков строк говнокода...
Между программистом и говнокодером огромная пропасть. Ты застрял на уровне школьного творчества, тебе до программиста, как до китая... Если твой код работает 5 минут, это еще не значит, что он будет работать круглый год, 24/7.
По моему, дальнейшее обуждение чего либо с этим человеком бессмысленно. Подрасти для начала)))
Такими темпами arduino.ru превратится в forum.cxem.net где сидят старенькие дяденьки задроты (сугубо моё мнение), которым лень отвечать на вопросы новичков или, по их мнению, "элементарные" вопросы, и вместо этого начинают флуууудить да посылать читать литератуууууру (времен СССР).....воооооттт..... XD
На данном этапе меня интересует способность модуля принимать и совершать звонки. (наверное это выше нужно было указать) При любом входящем смс-сообщении все смски удаляются.
Если нет ответа OK от АТ команды - это однозначно перезагрузка модуля.
Вот я и спрашиваю, какой командой лучше проверять может ли модуль принять звонок или позвонить.
я пытался запустить sim800 на симке теле2, но не заработал, немного почитал и понял что симки и модуль не понимают друг друга из за чистоты(стандарта связи)
тут или я ошибся или у кого работает на теле2 с другого региона?
я пытался запустить sim800 на симке теле2, но не заработал, немного почитал и понял что симки и модуль не понимают друг друга из за чистоты(стандарта связи)
Да, кстати, у меня с Теле2 тоже не заработало. Использую МТС.
я пытался запустить sim800 на симке теле2, но не заработал, немного почитал и понял что симки и модуль не понимают друг друга из за чистоты(стандарта связи)
тут или я ошибся или у кого работает на теле2 с другого региона?
а вы в каком регионе? если я правильно помню, в МСК нет 2G сети (может быть не прав), соотвественно и sim800 с данной симкой работать не будет.
Кстати, может не по делу, когда столкнулся с проблемой с памятью, стал использовать F(), отбил у памяти 300 Бт )).
Вдруг пригодится.
я тоже так хотел, но то ли я криворукий, то ли есть ограничение на эту штуку, но это удобно если использовать например Serial.println(F"ATE0"), а у меня все команды формируются или динамически или из массива, короче ничего не получилось, скетч выше приведенный почти 90% памяти кушает, уже ничего не впихнешь.
сейчас с нуля начал новый, буду все делать по другому, более универсальный с возможностью не только смс но и dtmf и gprs, пока с работой только смс уже 43 % памяти, но это дело не быстрое....к лету может допишу.
Но всё же если сеть пропадет, модуль оповестит +CCALR: 0?
кого оповестит? и как? вам необходимо мониторить качество и наличие сети? наверное в даташите это есть, читать надо, выдерните симку во время работы и посмотрите что нибудь модем скажет или нет.
опять же смысл? ну заехали вы в мертвую зону, ну скажет МК что работать не буду - дальше что? полезете на березу с антеной как партизаны во время войны?
а весь ваш взятый код с ресурса построен по принципу "отправил что то - жду команду" а в остальное время если что то надо сделать или придет другой ответ - "все пропало"
Вот тут я не поняла.
Незапрашиваемые уведомления обрабатываются же постоянно.
if (SIM800.available()) { // Если модем, что-то отправил... _response = waitResponse(); // Получаем ответ от модема для анализа _response.trim(); // Убираем лишние пробелы в начале и конце Serial.println(_response); // Если нужно выводим в монитор порта if (_response.indexOf("+CMTI:")>-1) { // Пришло сообщение об отправке SMS lastUpdate = millis() - updatePeriod; // Теперь нет необходимости обрабатываеть SMS здесь, достаточно просто // сбросить счетчик автопроверки и в следующем цикле все будет обработано } } if (Serial.available()) { // Ожидаем команды по Serial... SIM800.write(Serial.read()); // ...и отправляем полученную команду модему }; }Пожалуйста ситуация - пришла смс, но МК ждал ок от отправки смс или тупо завис - команда потерялась.
Так статус смс не изхменится с "Непрочитанное" пока контроллер его не прочитает (после того как дождется ОК или перезагрузится после зависания). Так ведь?
Я не знаю как вам объяснить что ваш скетч кривой и устройство на нем будет работать не предсказуемо (
TELE2RUS 7дн.15час.36мин.R118.
Вот например ответ моего устройства - обратите внимание на аптайм, и то это мало - свет в квартире включали.
Т е свет выключали
Библиотекой Sim800l-master не пользовались?
Библиотекой Sim800l-master не пользовались?
Нет конечно, все ручками, at командами
Чтож...буду изучать...
Вот предсерийный образец, для сухих отапливаемых помещений, не для авто. SIM800, стек USB, шифрование, закладки на радиоканал, SD карту и RTC. Код написан в кейле для STM, выкладывать здесь нет смысла. Страшно представить, что получится, если собрать это устройство из блоков для ардуино...
Irinka, где сброс SIM800 о котором ты спрашивала, где включение...?
Кто сталкивался с проблемой плохого контакта сим карты? В машине часто теряется связь.
проблема 100% не в контакте который на симкарте....
40% - качественное и правильное питание !
40% - код ! может тупо "виснуть" из-за кода..
20% - проблема использования глупых плат от совсем дешевого ардуино..
поэтому рисую свои платы на сим800С ..
.... Это типовой говнокод.... Ардуино - это игрушка для школьников. Индусский код тоже шлак, но здесь он рассматривается как эталон. Среда разработки - х#ня редкостная. Топология китайская - на отъ#$%ись. ....
Ахахахаха! Ответ на миллион!
Видно, что пишет профессионал)))). Хвастанул фоткой и материт все остальное. Мол, я гений, а вы тут все идиоты....
Ну давайте еще сравним промышленное серийное производство с поделками любителей.
Для многих любителей Ардуино - это хобби, где не нужно паять, тратить на это время. Минимум усилий и можно получить какую то никому не нужную, но ценную для самого себя игрушку. Таких людей никто не учит и скорее всего этому промыслу они и не учились. Для них любая информация, вроде той, которую вы поносите, ценна!
Не важно, что код работает с огрехами, главное понять принцип! А, уж, когда получилось, всегда есть возможность код исправить и переписать.
Нельзя говорить, что код плохой, если он работает. Нельзя плохо отзываться о человеке, который написал этот код, ведь он смог это сделать и при этом поделился со всеми.
Конечно, легко критиковать чужое, но не стоит, это низко.
Irinka, где сброс SIM800 о котором ты спрашивала, где включение...?
Сброс происходит
Serial.println("Timeout..."); в этом месте кода
Serial.println ("Error answer"); и здесь
Ввиду большого количества заинтересованных лиц, давайте сделаем хороший, стабильный пример* работы с SIM800.
PS ввиду моих небольших познаний, с меня тестирование XD
Ввиду большого количества заинтересованных лиц, давайте сделаем хороший, стабильный пример* работы с SIM800.
PS ввиду моих небольших познаний, с меня тестирование XD
Я только ЗА!
Я делал так. Набросал такой код:
#include <SoftwareSerial.h> SoftwareSerial ss1(2, 3); void setup() { Serial.begin(9600); ss1.begin(9600); } void loop() { if (ss1.available()) Serial.write(ss1.read()); if (Serial.available()) ss1.write(Serial.read()); }И стал проверять АТ команды, посылая их на модуль, и анализируя ответы на них. Команды брал тут: http://www.2150692.ru/faq/47-at-komandy-a6
Там описание модуля SIM900, но по работе с СМС подходит. Все вполне логично работает. А зная, какие приходят ответы, не сложно дальше развивать свой проект. Сейчас я только начал заниматься обработкой входящих смс, вроде ничего сложно, но нужно время. Как что то получится путное, сброшу.
P.S. Конечно, наш великий критик, Анди, скажет, что это ***код)))), куда нам до него...)))
Я сделала вот так:
Читаю только последнее полученное смс и удаляю все.
Добавила проверку при запуске - если модуль не отвечает на AT - перезагрузка.
И раз в x времени проверку на готовность модуля совершать звонки (возможно нужно заменить на проверку уровня сигнала сети или что-то другое)
#define DEBUG //Если отладка не нужна, закомментировать #ifdef DEBUG #define DEBUG_PRINT(x) Serial.print (x) #define DEBUG_PRINTLN(x) Serial.println (x) #else #define DEBUG_PRINT(x) #define DEBUG_PRINTLN(x) #endif #include <avr/wdt.h> #include <SoftwareSerial.h> SoftwareSerial SIM800(6, 7);//RX, TX #define _pinreset A3//Пин ресета long vrstatusa = 0; String _buffer = ""; //Функция перезагрузки Nano и SIM800 void(* resetFunc) (void) = 0; void restart() { DEBUG_PRINTLN("Modul negotov. Reset"); digitalWrite(_pinreset, LOW); delay(1000); digitalWrite(_pinreset, HIGH); resetFunc(); } void setup() { wdt_disable(); Serial.begin(9600); SIM800.begin(9600); pinMode(_pinreset, OUTPUT); digitalWrite(_pinreset, HIGH); DEBUG_PRINTLN("Start!"); delay(5000); if (sendATCommand("AT", true).indexOf("OK") > -1) { DEBUG_PRINTLN("Modul gotov"); if (sendATCommand("AT+CLIP=1", true).indexOf("OK") > -1) DEBUG_PRINTLN("AON vcliuchen"); if (sendATCommand("AT+CMGF=1", true).indexOf("OK") > -1) DEBUG_PRINTLN("Tekstovy rezhim sms vcliuchen"); if (sendATCommand("AT+CMGDA=\"DEL ALL\"", true).indexOf("OK") > -1) DEBUG_PRINTLN("Sms udaleny"); DEBUG_PRINTLN("Rabotaem"); vrstatusa = millis(); }else{ restart(); } wdt_enable (WDTO_8S); } String sendATCommand(String cmd, bool waiting) { String _response = ""; //DEBUG_PRINTLN(cmd); SIM800.println(cmd); if (waiting) { _response = waitResponse(); if (_response.startsWith(cmd)) { _response = _response.substring(_response.indexOf("\r\n", cmd.length()) + 2); } //DEBUG_PRINTLN(_response); return _response; } return ""; } String waitResponse() { String _buffer; long _timeout = millis() + 10000; while (!SIM800.available() && millis() < _timeout) {}; if (SIM800.available()) { _buffer = SIM800.readString(); return _buffer; }else{ DEBUG_PRINTLN("Timeout..."); } return ""; } void getActionBySMS(String msg) { String msgheader = ""; String msgbody = ""; String msgphone = ""; msg = msg.substring(msg.indexOf("+CMGR: ")); msgheader = msg.substring(0, msg.indexOf("\r")); // Выдергиваем телефон msgbody = msg.substring(msgheader.length() + 2); msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK")); // Выдергиваем текст SMS msgbody.trim(); int firstIndex = msgheader.indexOf("\",\"") + 3; int secondIndex = msgheader.indexOf("\",\"", firstIndex); msgphone = msgheader.substring(firstIndex, secondIndex); Serial.println("Phone: " + msgphone); // Выводим номер телефона Serial.println("Message: " + msgbody); } void loop() { wdt_reset(); //Проверяем готовность модуля совершать звонки (если не может - перезагрузка) if (millis()-vrstatusa>60000 ){ _buffer = sendATCommand("AT+CCALR?", true); if (_buffer.indexOf("+CCALR: 1") > -1) { DEBUG_PRINTLN("Status-Ok"); vrstatusa = millis(); }else{ DEBUG_PRINTLN("Status-Error"); restart(); } } if (SIM800.available()){ wdt_reset(); String msg = waitResponse(); msg.trim(); DEBUG_PRINTLN(".. " + msg); //Сбрасываем все входящие вызовы if (msg.startsWith("RING")) { sendATCommand("ATH", true); DEBUG_PRINTLN("Vyzov sbroshen"); } //Если есть какая-то ошибка else if (msg.startsWith("ERROR")) { DEBUG_PRINTLN("Error"); } //Если пришло входящее сообщение else if (msg.startsWith("+CMTI:")) { _buffer = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);// Отправляем запрос чтения непрочитанных сообщений if (_buffer.indexOf("+CMGL: ") > -1) { //Если есть непрочитанное сообщение _buffer = sendATCommand("AT+CMGR=1,1", true); //Читаю последнее полученное сообщение _buffer.trim(); if (_buffer.endsWith("OK")) { getActionBySMS(_buffer); } } sendATCommand("AT+CMGDA=\"DEL ALL\"", true); } } }....на проверку уровня сигнала сети....)
Кстати, хорошая идея, нужно воспользоваться! Если нет сигнала, то и нет смысла отправлять смс!
Ввиду большого количества заинтересованных лиц, давайте сделаем хороший, стабильный пример* работы с SIM800.
PS ввиду моих небольших познаний, с меня тестирование XD
А для модема a6 нужен?
ЗЫ. Интересно как определить стабильность надёжность проекта (
А для модема a6 нужен?
ЗЫ. Интересно как определить стабильность надёжность проекта (
Что такое аб?
Стабильность определить, наверное, временем работы без косяков*
#include <avr/wdt.h> #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" #include <OneWire.h> #include <DallasTemperature.h> #include <RCSwitch.h> #define max_time_read_sms 120000UL // 2min #define max_time_read_command 10000UL // 10sec #define startEEPROMmessages 128 // 0 position = byte - current save posifion from 0 #define endEEPROMmessages 383 #define max_count_users_phone 6 #define max_len_sms 252 #define keypad_pin A0 #define min_time_period_key_press 1000 #define alarm_pin A1 #define rc_reciv_pin 2 #define ds18b20_pin 3 #define period_get_internal_temp 317947 // ~ 5 min #define pos_eeprom_relay1_mode 456 // 0 or FF - off 12 -on #define pos_eeprom_relay2_mode 458 // 0 or FF - off 21 -on #define pos_eeprom_count_reset_timeout 454 OneWire oneWire(ds18b20_pin); DallasTemperature sensors(&oneWire); RCSwitch mySwitch = RCSwitch(); unsigned long time_read_sms; unsigned long time_read_command; unsigned long time_unpress_key; byte gsmmode, submode; char OPSname[] = "Russia00"; char OPSbalance[] = "*99999#"; char* UnitCommands[] = {"addphone", "delphone", "getuptime", "getbalance", "gettemp", "resetmodem", "relay1on", "relay1off", "relay2on", "relay2off", "getrelay", "resetdevice"}; char sender[24]; char smsmsg[max_len_sms]; char begstr[] = "~NEWsSMS~"; char endstr[] = "~SUCCSMS~"; boolean sw_lcd_light; unsigned long time_sw_lcd_light; boolean req_temp; byte internal_temp; byte external_temp; unsigned long time_get_internal_temp; unsigned long time_req_internal_temp; word mas_str_temp[10]; byte med_str_pos = 0; byte med_str_cnt = 0; boolean minus_str_temp = false; void setup() { // put your setup code here, to run once: firststart(); } void loop() { // put your main code here, to run repeatedly: wdt_reset(); unsigned long current_millis = millis(); // lcd backlight control if (!sw_lcd_light) { word palm = analogRead(alarm_pin); if (palm < 500) { time_sw_lcd_light = current_millis; sw_lcd_light = true; digitalWrite(10, HIGH); } } else { if ((current_millis - time_sw_lcd_light) >= 30000) { // 30 sec - lcd light on sw_lcd_light = false; digitalWrite(10, LOW); } } // end lcd backlight control // get ext temp if (mySwitch.available()) { unsigned long receivedCode = mySwitch.getReceivedValue(); mySwitch.resetAvailable(); if ((receivedCode >= 11500UL) && (receivedCode <= 14750UL)) { receivedCode -= 11500; if (((receivedCode >= 2000UL) && (receivedCode <= 2600UL)) || ((receivedCode >= 0UL) && (receivedCode <= 400UL))) { if ((receivedCode <= 400UL)) { receivedCode = 2000UL - receivedCode; } // correct temp if (receivedCode <= 1900UL) { receivedCode -= 12UL; // 1.2 degree } else { if (receivedCode <= 1950UL) { receivedCode -= 8UL; // 0.8 degree } else { if (receivedCode <= 1999UL) { receivedCode -= 5UL; // 0.5 degree } } } // -- mas_str_temp[med_str_pos] = (word)(receivedCode); if ((++med_str_pos) >= 10) { med_str_pos = 0; } if ((++med_str_cnt) >= 10) { med_str_cnt = 10; } word sum_temp = 0; for (int i = 0; i < med_str_cnt; ++i) { sum_temp += mas_str_temp[i]; } sum_temp /= med_str_cnt; if (sum_temp < 2000) { minus_str_temp = true; sum_temp = 2000 - sum_temp; } else { minus_str_temp = false; sum_temp -= 2000; } sum_temp /= 10; external_temp = (byte)(sum_temp); } } } // end get ext temp byte result = a6work(); if ((result == 1) || (result == 2)) { if (result == 1) { domainmode(); } else { //timeout byte br = EEPROM.read(pos_eeprom_count_reset_timeout); if (br == 0xFF) br = 0; ++br; EEPROM.write(pos_eeprom_count_reset_timeout, br); wdt_disable(); 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", "", "", true) == 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 // read key pad if (gsmmode == 1) { if ((current_millis - time_unpress_key) >= min_time_period_key_press) { word kp = analogRead(keypad_pin); byte key_mode; if ((kp > 600) && (kp < 700)) { key_mode = 0; } else { if ((kp > 370) && (kp < 450)) { key_mode = 1; } else { if ((kp > 80) && (kp < 120)) { key_mode = 2; } else { if ((kp > 216) && (kp < 296)) { key_mode = 3; } else { if (kp < 20) { key_mode = 4; } else { key_mode = 5; // not press } } } } } if (key_mode < 5) { time_unpress_key = current_millis; switch (key_mode) { case 0: { char strtemp[4]; SendStrToLCD("Int="); strtemp[0] = '0' + internal_temp / 10; strtemp[1] = '0' + internal_temp % 10; strtemp[2] = 0; SendStrToLCD(strtemp); SendStrToLCD(" Ext="); if (minus_str_temp) strtemp[0] = '-'; else strtemp[0] = '+'; strtemp[1] = '0' + external_temp / 10; strtemp[2] = '0' + external_temp % 10; strtemp[3] = 0; SendStrToLCD(strtemp); SendStrToLCD(" "); break; } case 1: { if (a6sendcmd("AT+CREG?", "OK", "", "", true) == 1) { gsmmode = 3; submode = 1; } break; } case 2: { byte i = 0; while ((smsmsg[i] = OPSname[i]) != 0 ) ++i; smsmsg[i] = ' '; ++i; i = addTextUptime(i); smsmsg[i] = 0; SendStrToLCD(smsmsg); break; } case 3: { gsmmode = 100; // show phones from eeprom byte pc = EEPROM.read(0); if (pc == 0xFF) pc = 0; for (byte i = 0; ((i < pc) && (i < max_count_users_phone)); ++i) { byte possend = 0; boolean fle = true; word startpos = 1 + i * 14; if (EEPROM.read(startpos) == 'A') sender[possend] = 'A'; else sender[possend] = 'D'; ++possend; sender[possend] = ' '; ++possend; byte j = 0; while (EEPROM.read(startpos + j + 1) != 0) { sender[possend] = EEPROM.read(startpos + j + 1); ++j; ++possend; } sender[possend] = ' '; ++possend; sender[possend] = 0; SendStrToLCD(sender); unsigned long delp = millis(); while ((millis() - delp) <= 2000); wdt_reset(); } // end show phones resetModeAndClearRespBuf(); break; } case 4: { if (a6sendcmd("AT+CSQ", "OK", "", "", true) == 1) { gsmmode = 3; submode = 1; } break; } default: { } } } } } // end key pad // req temp if ((current_millis - time_req_internal_temp) >= period_get_internal_temp) { if ((gsmmode == 1) && (!req_temp)) { time_req_internal_temp = current_millis; sensors.requestTemperatures(); req_temp = true; time_get_internal_temp = current_millis; } } // end req temp -> get temp if ((current_millis - time_get_internal_temp) >= 1200) { if ((gsmmode == 1) && (req_temp)) { internal_temp = sensors.getTempCByIndex(0); req_temp = false; } } // end get internal temp } } void domainmode() { switch (gsmmode) { case 0: { // init modem switch (submode) { case 0: { // wait reponse first command AT if (a6sendcmd("ATE0", "OK", "", "", true) == 1) submode = 1; // no echo break; } case 1: { // wait reponse command ATE0 if (a6sendcmd("ATV1", "OK", "", "", true) == 1) submode = 2; // get text for error break; } case 2: { // wait reponse command ATV1 if (a6sendcmd("AT+CMEE=2", "OK", "", "", true) == 1) submode = 3; // get full text error break; } case 3: { // wait reponse command cmee if (a6sendcmd("AT+CLIP=1", "OK", "", "", true) == 1) submode = 4; // on aon break; } case 4: { // wait reponse command clip if (a6sendcmd("ATS0=3", "OK", "", "", true) == 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", "", true) == 1) submode = 6; // true registration //if (a6sendcmd("AT+CREG?", "OK", "", "", true) == 1) submode = 6; // registration break; } case 6: { // wait registration if (a6sendcmd("AT+CMGF=0", "OK", "", "", true) == 1) submode = 7; // mode SMS = PDU break; } case 7: { // wait mode sms if (a6sendcmd("AT+CMGD=1,4", "OK", "", "", true) == 1) submode = 8; // delete all sms break; } case 8: { // wait del sms if (a6sendcmd("AT+COPS?", "+COPS:", "OK", "", true) == 1) submode = 9; // load operator data break; } case 9: { // decode operator data a6getopsname(OPSname, OPSbalance); resetModeAndClearRespBuf(); // init ok digitalWrite(LED_BUILTIN, HIGH); SendByteToLCD(32, true); SendByteToLCD(223, false); SendByteToLCD(32, true); SendByteToLCD(226, false); SendByteToLCD(32, true); SendByteToLCD(241, false); SendByteToLCD(229, false); SendByteToLCD(242, false); SendByteToLCD(232, false); SendByteToLCD(32, true); SendByteToLCD('!', true); SendByteToLCD(32, true); wdt_enable(WDTO_8S); break; } } break; } case 1: { // main loop break; } case 2: { // mode read sms 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", "", "", true) == 1) submode = 1; } else { resetModeAndClearRespBuf(); // no sms } break; } default: { resetModeAndClearRespBuf(); } } break; } case 3: { // mode send sms and mode test commands switch (submode) { case 0: { if (a6sendcmd(smsmsg, "+CMGS:", "OK", "", false) == 1) submode = 1; break; } default: { resetModeAndClearRespBuf(); } } break; } case 4: { // mode get balance switch (submode) { case 0: { // decode USSD // send SMS text from USSD resetModeAndClearRespBuf(); // temp text, need submode = 1 break; } default: { resetModeAndClearRespBuf(); } } break; } default: { a6clearrespbuf(); } } } void firststart() { pinMode(A0, INPUT_PULLUP); pinMode(A1, INPUT_PULLUP); pinMode(10, OUTPUT); pinMode(rc_reciv_pin, INPUT); digitalWrite(10, LOW); // LCD backlight control sensors.begin(); time_req_internal_temp = 0; req_temp = false; sw_lcd_light = false; gsmmode = 0; submode = 0; // start time_read_sms = 0UL; time_read_command = 0UL; mySwitch.enableReceive(0); pinMode(A2, OUTPUT); // relay 1 pinMode(A3, OUTPUT); // relay 2 // on off relay if (EEPROM.read(pos_eeprom_relay1_mode) == 12) digitalWrite(A2, LOW); else digitalWrite(A2, HIGH); if (EEPROM.read(pos_eeprom_relay2_mode) == 21) digitalWrite(A3, LOW); else digitalWrite(A3, HIGH); // end on off relay pinMode(A4, OUTPUT); digitalWrite(A4, LOW); pinMode(A5, OUTPUT); digitalWrite(A5, LOW); a6initmodem(9600); // work - hard uart } 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 < 12; ++i) { // 12 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", true); gsmmode = 4; submode = 0; break; } case 5: { if (getAllowCommandPhone(sender) == 0) return; // command for any user // prepare send text char strtemp[] = "Int="; i = 0; while ((smsmsg[i] = strtemp[i]) != 0 ) ++i; strtemp[0] = '0' + internal_temp / 10; strtemp[1] = '0' + internal_temp % 10; strtemp[2] = 0; j = 0; while ((smsmsg[i] = strtemp[j]) != 0 ) { ++i; ++j; } smsmsg[i] = ','; ++i; strtemp[0] = 'E'; strtemp[1] = 'x'; strtemp[2] = 't'; strtemp[3] = '='; strtemp[4] = 0; j = 0; while ((smsmsg[i] = strtemp[j]) != 0 ) { ++i; ++j; } if (minus_str_temp) strtemp[0] = '-'; else strtemp[0] = '+'; strtemp[1] = '0' + external_temp / 10; strtemp[2] = '0' + external_temp % 10; strtemp[3] = 0; j = 0; while ((smsmsg[i] = strtemp[j]) != 0 ) { ++i; ++j; } smsmsg[i] = ','; ++i; i = addTextUptime(i); smsmsg[i] = 0; sendSMS(); break; } case 6: { if (getAllowCommandPhone(sender) == 0) return; // command for any user byte br = EEPROM.read(pos_eeprom_count_reset_timeout); if (br == 0xFF) br = 0; ++br; EEPROM.write(pos_eeprom_count_reset_timeout, br); wdt_disable(); a6resetmodem(); unsigned long delp = millis(); while ((millis() - delp) <= 20000); // boot modem firststart(); break; } case 7: { if (getAllowCommandPhone(sender) == 0) return; // command for any user // relay 1 ON EEPROM.write(pos_eeprom_relay1_mode, 12); digitalWrite(A2, LOW); unsigned long delp = millis(); while ((millis() - delp) <= 1000); // relay 2 ON EEPROM.write(pos_eeprom_relay2_mode, 21); digitalWrite(A3, LOW); break; } case 8: { if (getAllowCommandPhone(sender) == 0) return; // command for any user // relay 1 OFF EEPROM.write(pos_eeprom_relay1_mode, 00); digitalWrite(A2, HIGH); unsigned long delp = millis(); while ((millis() - delp) <= 1000); // relay 2 OFF EEPROM.write(pos_eeprom_relay2_mode, 00); digitalWrite(A3, HIGH); break; } case 9: { if (getAllowCommandPhone(sender) == 0) return; // command for any user // relay 2 ON EEPROM.write(pos_eeprom_relay2_mode, 21); digitalWrite(A3, LOW); unsigned long delp = millis(); while ((millis() - delp) <= 1000); // relay 1 ON EEPROM.write(pos_eeprom_relay1_mode, 12); digitalWrite(A2, LOW); break; } case 10: { if (getAllowCommandPhone(sender) == 0) return; // command for any user // relay 2 OFF EEPROM.write(pos_eeprom_relay2_mode, 00); digitalWrite(A3, HIGH); unsigned long delp = millis(); while ((millis() - delp) <= 1000); // relay 1 OFF EEPROM.write(pos_eeprom_relay1_mode, 00); digitalWrite(A2, HIGH); break; } case 11: { if (getAllowCommandPhone(sender) == 0) return; // command for any user // prepare send text char strtemp[] = "Rl1"; i = 0; while ((smsmsg[i] = strtemp[i]) != 0 ) ++i; if (EEPROM.read(pos_eeprom_relay1_mode) == 12) { strtemp[0] = 'o'; strtemp[1] = 'n'; strtemp[2] = 0; } else { strtemp[0] = 'o'; strtemp[1] = 'f'; strtemp[2] = 'f'; strtemp[3] = 0; } j = 0; while ((smsmsg[i] = strtemp[j]) != 0 ) { ++i; ++j; } smsmsg[i] = ','; ++i; strtemp[0] = 'R'; strtemp[1] = 'l'; strtemp[2] = '2'; strtemp[3] = 0; j = 0; while ((smsmsg[i] = strtemp[j]) != 0 ) { ++i; ++j; } if (EEPROM.read(pos_eeprom_relay2_mode) == 21) { strtemp[0] = 'o'; strtemp[1] = 'n'; strtemp[2] = 0; } else { strtemp[0] = 'o'; strtemp[1] = 'f'; strtemp[2] = 'f'; strtemp[3] = 0; } j = 0; while ((smsmsg[i] = strtemp[j]) != 0 ) { ++i; ++j; } smsmsg[i] = ','; ++i; i = addTextUptime(i); smsmsg[i] = 0; sendSMS(); break; } case 12: { if (getAllowCommandPhone(sender) != 2) return; // command for admin only // test WDT unsigned long delp = millis(); while ((millis() - delp) <= 20000); // reboot device after 8 sec break; } default: { } } } 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 == 0xFF) pc = 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) { 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; // add count timeout reset smsmsg[firstpos] = 'R'; ++firstpos; byte br = EEPROM.read(pos_eeprom_count_reset_timeout); smsmsg[firstpos] = '0' + (br / 100); ++firstpos; smsmsg[firstpos] = '0' + ((br % 100) / 10); ++firstpos; smsmsg[firstpos] = '0' + ((br % 100) % 10); ++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, ">", "", "", false); gsmmode = 3; submode = 0; } void resetMode() { gsmmode = 1; submode = 0; // main loop } void resetModeAndClearRespBuf() { resetMode(); a6clearrespbuf(); }// functions for a6 gsm modem #include "a6modem.h" #include "Arduino.h" #include <LiquidCrystal_1602_RUS.h> 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]; 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"; byte IdxLCD = 0; // 0..31 - char on LCD LiquidCrystal_1602_RUS LCD(8, 9, 4, 5, 6, 7 );//For LCD Keypad Shield // 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) { // init LCD LCD.begin(16, 2); LCD.clear(); LCD.setCursor(0, 0); IdxLCD = 0; SendByteToLCD(209, false); SendByteToLCD(242, false); SendByteToLCD(224, false); SendByteToLCD(240, false); SendByteToLCD(242, false); SendByteToLCD(32, true); SendStrToLCD("Start "); LCD.cursor(); LCD.blink(); // init modem 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); Serial.begin(a6uartspeed); // adaptive speed a6 module unsigned long curr_millis = millis(); while ((millis() - curr_millis) <= 4000UL) Serial.println("AT"); curr_millis = millis(); while ((millis() - curr_millis) <= 5000UL) if (Serial.available()) while (Serial.available()) Serial.read(); // - wait_response = false; a6sendcmd("AT", "OK", "", "", true); // 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, boolean show_cmd) { if (wait_response) return 0; Serial.println(txtcmd); if (show_cmd) SendStrToLCD(txtcmd); cmd_started_time = millis(); a6clearrespbuf(); byte pp = 0; 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 (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 (_rsp_pos > 0) { if (_rsp_pos <= 32) SendStrToLCD(_rsp_buf); } } // wait response for sent at command if (wait_response) { if ((millis() - cmd_started_time) >= RESPONSE_MAX_TIME) { wait_response = false; return 2; // timeout } else { if (a6detectresp(_resp_detect1, _resp_detect2, _resp_detect3)) { wait_response = false; return 1; // OK } } } return 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 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; } } // send win1251 byte to LCD void SendByteToLCD(byte inByte, boolean ET) { if (inByte == 13) { LCD.print(" "); } else { if (inByte < 0x20) return; if ((ET == true) && (inByte >= 0x7F)) return; if (ET == false) { if ((inByte == 168) || (inByte == 184) || ((inByte >= 192) && (inByte <= 255))) { LCD.print(LCD.asciiutf8(inByte)); } else { LCD.print(char(inByte)); } } else { LCD.print(char(inByte)); } } switch (IdxLCD) { case 15: { LCD.setCursor(0, 1); ++IdxLCD; break; } case 31: { LCD.setCursor(0, 0); IdxLCD = 0; break; } default : { ++IdxLCD; } } } void SendStrToLCD(char* latinStr) { byte i = 0; while (latinStr[i] != 0) { SendByteToLCD(latinStr[i], false); ++i; } }https://ru.aliexpress.com/item/mini-A6-GA6-GPRS-GSM-Kit-Wireless-Extensi...
Такая проблема:
При проверке баланса (Теле2 *105#) ардуина перезагружается либо не обрабатывает текст:
Код:
#define DEBUG //Если отладка не нужна, закомментировать #ifdef DEBUG #define DEBUG_PRINT(x) Serial.print (x) #define DEBUG_PRINTLN(x) Serial.println (x) #else #define DEBUG_PRINT(x) #define DEBUG_PRINTLN(x) #endif #include <avr/wdt.h> #include <SoftwareSerial.h> SoftwareSerial SIM800(6, 7);//RX, TX #define _pinreset A3//Пин ресета long vrstatusa = 0; String _buffer = ""; String phones = "+79601809765"; //Функция перезагрузки Nano и SIM800 void(* resetFunc) (void) = 0; void restart() { DEBUG_PRINTLN("Modul negotov. Reset"); digitalWrite(_pinreset, LOW); delay(1000); digitalWrite(_pinreset, HIGH); resetFunc(); } void setup() { wdt_disable(); Serial.begin(9600); SIM800.begin(9600); pinMode(_pinreset, OUTPUT); digitalWrite(_pinreset, HIGH); DEBUG_PRINTLN("Start!"); //delay(5000); //if (sendATCommand("AT", true).indexOf("OK") > -1) { _buffer = sendATCommand("AT", true); _buffer.trim(); if (_buffer.endsWith("OK")) { DEBUG_PRINTLN("Modul gotov"); if (sendATCommand("AT+CLIP=1", true).indexOf("OK") > -1) DEBUG_PRINTLN("AON vcliuchen"); if (sendATCommand("AT+CMGF=1", true).indexOf("OK") > -1) DEBUG_PRINTLN("Tekstovy rezhim sms vcliuchen"); if (sendATCommand("AT+CMGDA=\"DEL ALL\"", true).indexOf("OK") > -1) DEBUG_PRINTLN("Sms udaleny"); DEBUG_PRINTLN("Rabotaem"); vrstatusa = millis(); }else{ restart(); } wdt_enable (WDTO_8S); } //Обработка полученных AT команд String sendATCommand(String cmd, bool waiting) { wdt_reset(); String _response = ""; DEBUG_PRINTLN(cmd); SIM800.println(cmd); if (waiting) { _response = waitResponse(); if (_response.startsWith(cmd)) { _response = _response.substring(_response.indexOf("\r\n", cmd.length()) + 2); } DEBUG_PRINTLN(_response); return _response; } return ""; } String waitResponse() { long _timeout = millis() + 10000; while (!SIM800.available() && millis() < _timeout) {}; if (SIM800.available()) { _buffer = SIM800.readString(); return _buffer; }else{ DEBUG_PRINTLN("Timeout..."); } return ""; } //Получаем номер и текст сообщения void parsimSMS(String msg) { wdt_reset(); String msgheader = ""; String msgbody = ""; String msgphone = ""; msg = msg.substring(msg.indexOf("+CMGR: ")); msgheader = msg.substring(0, msg.indexOf("\r")); msgbody = msg.substring(msgheader.length() + 2); msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK")); msgbody.trim(); int firstIndex = msgheader.indexOf("\",\"") + 3; int secondIndex = msgheader.indexOf("\",\"", firstIndex); msgphone = msgheader.substring(firstIndex, secondIndex); DEBUG_PRINTLN("Phone: " + msgphone); DEBUG_PRINTLN("Message: " + msgbody); if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1) { if (msgbody.length() > 5 ) { if (msgbody=="StartOn"){ DEBUG_PRINTLN("Vcliucheno"); } else if (msgbody=="StartOff"){ DEBUG_PRINTLN("Vycliucheno"); } else if (msgbody=="Balans"){ sendATCommand("AT+CUSD=1,\"*105#\"", true); } } } } //Функция проверки готовности модуля void Sim800Stat() { wdt_reset(); _buffer = sendATCommand("AT", true); _buffer.trim(); if (_buffer.endsWith("OK")) { _buffer = sendATCommand("AT+CCALR?", true); _buffer.trim(); if (_buffer.indexOf("+CCALR: 1") > -1) { DEBUG_PRINTLN("Status-Ok"); vrstatusa = millis(); }else{ DEBUG_PRINTLN("Status-Error"); restart(); } }else{ DEBUG_PRINTLN("Modul ne otvechaet"); restart(); } } //Функция отправки смс void sendSMS(String message) { sendATCommand("AT+CMGS=\"" + phones + "\"", true); sendATCommand(message + "\r\n" + (String)((char)26), true); } void loop() { wdt_reset(); if (Serial.available()) { int val = Serial.read(); if (val == '2') sendATCommand("AT+CUSD=1,\"*105#\"", true); if (val == '3') sendATCommand("AT+CUSD=1,\"*120#\"", true); } //Раз в минуту проверяем готовность модуля //if (millis()-vrstatusa>10000 ){ //Sim800Stat(); //} if (SIM800.available()){ wdt_reset(); String msg = waitResponse(); msg.trim(); DEBUG_PRINTLN(".. " + msg); //Сбрасываем все входящие вызовы if (msg.startsWith("RING")) { sendATCommand("ATH", true); DEBUG_PRINTLN("Vyzov sbroshen"); } //Если есть какая-то ошибка else if (msg.startsWith("ERROR")) { DEBUG_PRINTLN("Error"); } // Пришло уведомление о USSD-ответе else if (msg.startsWith("+CUSD:")) { if (msg.indexOf("\"") > -1) { String msgBalance = msg.substring(msg.indexOf("\"") + 1); msgBalance = msgBalance.substring(0, msgBalance.indexOf("\"")); DEBUG_PRINTLN("USSD: " +msgBalance); } } //Если пришло входящее сообщение else if (msg.startsWith("+CMTI:")) { _buffer = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);// Отправляем запрос чтения непрочитанных сообщений if (_buffer.indexOf("+CMGL: ") > -1) { //Если есть непрочитанное сообщение _buffer = sendATCommand("AT+CMGR=1,1", true); //Читаю последнее полученное сообщение _buffer.trim(); if (_buffer.endsWith("OK")) { parsimSMS(_buffer); } } sendATCommand("AT+CMGDA=\"DEL ALL\"", true); } } }ставлю на то что памяти не хватает
Я тоже так думаю. Как это можно исправить?
Как мне кажется, моя проблема при пересечении границы области, как раз в этом и заключается, что оператор присылает сообщение типа: "Теле2 желает вам приятной поездки ........ и. .... т..... п....."
сначала определиться дело в памяти или как
если я правильно понял код - попробовать после 78 строки поставить условие что если длина буфера больше например 20 символов то не принимать ответ
соотвественно если после этого МК не зависнет, значит да, дело в памяти - избавляться от String, парсить ответ по частям.
Почему не образается переменная _buffer?
String waitResponse() { long _timeout = millis() + 10000; while (!SIM800.available() && millis() < _timeout) {}; if (SIM800.available()) { _buffer = SIM800.readString(); if (_buffer.length() > 20){ DEBUG_PRINTLN("Bufer perepolnen"); _buffer = _buffer.substring(0,20); } return _buffer; }else{ DEBUG_PRINTLN("Timeout..."); } return ""; }А здесь обрезается как надо:
if (SIM800.available()){ wdt_reset(); String msg = waitResponse(); msg.trim(); if (msg.length() > 20){ DEBUG_PRINTLN("Bufer perepolnen"); msg = msg.substring(0,20); } DEBUG_PRINTLN(".. " + msg);Вот так работает:
#define DEBUG //Если отладка не нужна, закомментировать #ifdef DEBUG #define DEBUG_PRINT(x) Serial.print (x) #define DEBUG_PRINTLN(x) Serial.println (x) #else #define DEBUG_PRINT(x) #define DEBUG_PRINTLN(x) #endif #include <avr/wdt.h> #include <SoftwareSerial.h> SoftwareSerial SIM800(6, 7);//RX, TX #define _pinreset A3//Пин ресета long vrstatusa = 0; String _buffer = ""; String phones = "+79601809765"; bool razmbuf=false; //Функция перезагрузки Nano и SIM800 void(* resetFunc) (void) = 0; void restart() { DEBUG_PRINTLN("Modul negotov. Reset"); digitalWrite(_pinreset, LOW); delay(1000); digitalWrite(_pinreset, HIGH); resetFunc(); } void setup() { wdt_disable(); Serial.begin(19200); SIM800.begin(19200); pinMode(_pinreset, OUTPUT); digitalWrite(_pinreset, HIGH); DEBUG_PRINTLN("Start!"); //delay(5000); _buffer = sendATCommand("AT", true); _buffer.trim(); if (_buffer.endsWith("OK")) { DEBUG_PRINTLN("Modul gotov"); if (sendATCommand("AT+CLIP=1", true).indexOf("OK") > -1) DEBUG_PRINTLN("AON vcliuchen"); if (sendATCommand("AT+CMGF=1", true).indexOf("OK") > -1) DEBUG_PRINTLN("Tekstovy rezhim sms vcliuchen"); if (sendATCommand("AT+CMGDA=\"DEL ALL\"", true).indexOf("OK") > -1) DEBUG_PRINTLN("Sms udaleny"); DEBUG_PRINTLN("Rabotaem"); vrstatusa = millis(); }else{ restart(); } wdt_enable (WDTO_8S); } 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); } 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); } //Обработка полученных AT команд String sendATCommand(String cmd, bool waiting) { wdt_reset(); String _response = ""; //DEBUG_PRINTLN(cmd); SIM800.println(cmd); if (waiting) { _response = waitResponse(); if (_response.startsWith(cmd)) { _response = _response.substring(_response.indexOf("\r\n", cmd.length()) + 2); } //DEBUG_PRINTLN(_response); return _response; } return ""; } String waitResponse() { long _timeout = millis() + 10000; while (!SIM800.available() && millis() < _timeout) {}; if (SIM800.available()) { _buffer = SIM800.readString(); return _buffer; }else{ DEBUG_PRINTLN("Timeout..."); } return ""; } //Получаем номер и текст сообщения void parsimSMS(String msg) { wdt_reset(); String msgheader = ""; String msgbody = ""; String msgphone = ""; msg = msg.substring(msg.indexOf("+CMGR: ")); msgheader = msg.substring(0, msg.indexOf("\r")); msgbody = msg.substring(msgheader.length() + 2); msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK")); msgbody.trim(); int firstIndex = msgheader.indexOf("\",\"") + 3; int secondIndex = msgheader.indexOf("\",\"", firstIndex); msgphone = msgheader.substring(firstIndex, secondIndex); DEBUG_PRINTLN("Phone: " + msgphone); DEBUG_PRINTLN("Message: " + msgbody); if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1) { if (msgbody.length() > 5 ) { if (msgbody=="StartOn"){ DEBUG_PRINTLN("Vcliucheno"); } else if (msgbody=="StartOff"){ DEBUG_PRINTLN("Vycliucheno"); } else if (msgbody=="Balans"){ sendATCommand("AT+CUSD=1,\"*105#\"", true); } } } } //Функция проверки готовности модуля void Sim800Stat() { wdt_reset(); _buffer = sendATCommand("AT+CCALR?", true); _buffer.trim(); if (_buffer.indexOf("+CCALR: 1") > -1) { DEBUG_PRINTLN("Status-Ok"); vrstatusa = millis(); }else{ DEBUG_PRINTLN("Status-Error"); restart(); } } //Функция отправки смс void sendSMS(String message) { sendATCommand("AT+CMGS=\"" + phones + "\"", true); sendATCommand(message + "\r\n" + (String)((char)26), true); } void loop() { wdt_reset(); if (Serial.available()) { int val = Serial.read(); if (val == '2') sendATCommand("AT+CUSD=1,\"*105#\"", true); if (val == '3') sendATCommand("AT+CUSD=1,\"*120#\"", true); } //Раз в минуту проверяем готовность модуля if (millis()-vrstatusa>60000 ){ Sim800Stat(); } if (SIM800.available()){ wdt_reset(); razmbuf=false; String msg = waitResponse(); msg.trim(); if (msg.length() > 50){ razmbuf=true; DEBUG_PRINTLN("Bufer perepolnen"); msg = msg.substring(0,80); } DEBUG_PRINTLN(".. " + msg); //Сбрасываем все входящие вызовы if (msg.startsWith("RING")) { sendATCommand("ATH", true); DEBUG_PRINTLN("Vyzov sbroshen"); } //Если есть какая-то ошибка else if (msg.startsWith("ERROR")) { DEBUG_PRINTLN("Error"); } // Пришло уведомление о USSD-ответе else if (msg.startsWith("+CUSD:")) { if (msg.indexOf("\"") > -1) { String msgBalance = msg.substring(msg.indexOf("\"") + 1); msgBalance = msgBalance.substring(0, msgBalance.indexOf("\"")); if (razmbuf){ DEBUG_PRINTLN("USSD: " + UCS2ToString(msgBalance)); }else{ DEBUG_PRINTLN("USSD: " + msgBalance); } } } //Если пришло входящее сообщение else if (msg.startsWith("+CMTI:")) { _buffer = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);// Отправляем запрос чтения непрочитанных сообщений if (_buffer.indexOf("+CMGL: ") > -1) { //Если есть непрочитанное сообщение _buffer = sendATCommand("AT+CMGR=1,1", true); //Читаю последнее полученное сообщение _buffer.trim(); if (_buffer.endsWith("OK")) { parsimSMS(_buffer); } } sendATCommand("AT+CMGDA=\"DEL ALL\"", true); } } }Это все костыли к сожалению.
Добиться таким образом работы проекта можно, но задела на будущее нет(
Простейший вариант вам: на ходу обрабатывать смс о балансе и откидываьь лишнее. Ну а если по уму делать - все переписывать надо.
ЗЫ. Впрочем терять свое время / жизнь ради красоты кода - тоже хрень. Если задача выполняется - оставляйте как есть.
Для многих любителей Ардуино - это хобби, где не нужно паять, тратить на это время. Минимум усилий и можно получить какую то никому не нужную, но ценную для самого себя игрушку. Таких людей никто не учит и скорее всего этому промыслу они и не учились. Для них любая информация, вроде той, которую вы поносите, ценна!
Не следует путать информацию с дезинформацией.
Если сделано откровенно неправильно - в стиле "образец, как не нужно делать", а преподносится наоборот, как образец для\ подражания, то вред от такой "информации" существенно перекрывает возможную пользу.
Ваше утверждение эквивалентно следующему: любое сообщение ценно, вне зависимости от того, исинно оно или ложно.
Между ложью и истиной не может быть знака равенства.
Нельзя говорить, что код плохой, если он работает.
Если код плохой - он плохой вне зависимости от того, работает или нет.
Более того, от плохого, но работающего (естественно, ненадежно, и не всегда так, как хотел автор) кода вреда больше, чем от неработающего.
Если код плохой - он плохой вне зависимости от того, работает или нет.
О, еще один умник (философ) появился.
Программа работает по заложенному алгоритму. И если программисту нравится, как работает его код, значит он своей цели достиг, по крайней мере не в промышленных образцах, а в подделках любителей.
Можно с ума сходить добиваясь идеала, я так понимаю вы этим и страдаете, но часто это и не требуется.
Вы все ополчились на человека, который разобрался в работе с модулем, создал свой блог, написал статью и делится информацией с окружающими. Как только вы его, его код и ардуино не принижаете только!
Не нравится ардуино, не пользуйтесь и не сидите на этом форуме.
Еще раз повторюсь, проще критиковать, говорить, что код плохой и тд и тп, чем вы и занимаетесь. Мне тоже он не нравится, я работаю чисто с АТ командами, но тот код помог лично мне разобраться в каких то деталях и начать реализовывать свой проект, за что ему СПАСИБО!
А вы попробуйте вместо критики создать страничку в интернете, выложить свой код, сделать комментарии к нему, да еще и отвечать на вопросы в комментах. Тогда это будет по делу, это будет в пользу!
Но хочу вас предупредить, что как только вы сделаете это, найдется очередной Анди, который назовет ваш код, как он выражается - *****кодом ))), выложит какую то фотку и будет рассказывать, как он мега крут, а вы в программировании ничего не понимаете! А еще найдется философ, вроде вас, который начнет рассказывать про информацию и дезинформацию, про то , что истина это не ложь)))) И кстати, есть истина, есть ложь, а есть статистика, не забывайте про это!
Вот, что я хочу до вас донести! Все форумы в последнее время страдают этим и это печально.
+100500
Покажи своё говнотворчество...
А что сделал ты? Соединил проводками чужие платы и написал несколько десятков строк говнокода...
Между программистом и говнокодером огромная пропасть. Ты застрял на уровне школьного творчества, тебе до программиста, как до китая... Если твой код работает 5 минут, это еще не значит, что он будет работать круглый год, 24/7.
По моему, дальнейшее обуждение чего либо с этим человеком бессмысленно. Подрасти для начала)))
Согласен!
Где модераторы? Друзья, мы отклонились от темы?)
Где модераторы? Друзья, мы отклонились от темы?)
а у вас был какой то вопрос :) ?
вроде все заработало? че бы не помусорить на форуме :) за удачное исполнение проекта :)
Добрый день (по крайней мере у нас во Владимире). Есть вопрос)
Для перезагрузки SIM800 я произвожу проверку на готовность модуля совершать звонки AT+CCALR?
Если вынуть сим карту (что я и делаю для проверки), то модуль естественно возвращает +CCALR: 0
0 — модуль не готов совершать звонки
Если в какой-то момент пропадет сеть (антенка надежно припаяна, не могу проверить это условие) модуль также вернет +CCALR: 0 или нет?
Правильно ли производить такую проверку или использовать другую команду, например:
AT+CREG? - тип регистрации в сети
и если модуль ответит
1 — зарегистрирован в домашней сети
5 — зарегистрирован, в роуминге
то все нормально, иначе - перезагрузка
Такими темпами arduino.ru превратится в forum.cxem.net где сидят старенькие дяденьки задроты (сугубо моё мнение), которым лень отвечать на вопросы новичков или, по их мнению, "элементарные" вопросы, и вместо этого начинают флуууудить да посылать читать литератуууууру (времен СССР).....воооооттт..... XD
я наверное не правильно понял....модем нужно перезагружать если он завис - правильно?
тогда при чем здесь регистрация в сети? у меня в деревне в принципе сети нет, но это не причина перезагрузки.
каждые две минуты проверяются входящие смс, если от АТ команды (любой) нет ответа в течении 30 секунд - перезагрузка.
На данном этапе меня интересует способность модуля принимать и совершать звонки. (наверное это выше нужно было указать) При любом входящем смс-сообщении все смски удаляются.
Если нет ответа OK от АТ команды - это однозначно перезагрузка модуля.
Вот я и спрашиваю, какой командой лучше проверять может ли модуль принять звонок или позвонить.
я AT+CREG? проверяю + уровень сигнала AT+CSQ, меньше 7 - связь на грани разрыва.
заглядываю в тему
и вижу что люди используют симки теле2...
я пытался запустить sim800 на симке теле2, но не заработал, немного почитал и понял что симки и модуль не понимают друг друга из за чистоты(стандарта связи)
тут или я ошибся или у кого работает на теле2 с другого региона?
Baks здравствуйте. У меня работает сим-карта ТЕЛЕ2 как Владимирской области, так и Нижегородской области.
andycat Спасибо.
Владимирская сим-карта при нахождении в Нижегородской области пишет +CREG: 0,1 зарегистрирован в домашней сети
я пытался запустить sim800 на симке теле2, но не заработал, немного почитал и понял что симки и модуль не понимают друг друга из за чистоты(стандарта связи)
Да, кстати, у меня с Теле2 тоже не заработало. Использую МТС.
заглядываю в тему
и вижу что люди используют симки теле2...
я пытался запустить sim800 на симке теле2, но не заработал, немного почитал и понял что симки и модуль не понимают друг друга из за чистоты(стандарта связи)
тут или я ошибся или у кого работает на теле2 с другого региона?
а вы в каком регионе? если я правильно помню, в МСК нет 2G сети (может быть не прав), соотвественно и sim800 с данной симкой работать не будет.
Кстати, может не по делу, когда столкнулся с проблемой с памятью, стал использовать F(), отбил у памяти 300 Бт )).
Вдруг пригодится.
Но всё же если сеть пропадет, модуль оповестит +CCALR: 0?
Кстати, может не по делу, когда столкнулся с проблемой с памятью, стал использовать F(), отбил у памяти 300 Бт )).
Вдруг пригодится.
я тоже так хотел, но то ли я криворукий, то ли есть ограничение на эту штуку, но это удобно если использовать например Serial.println(F"ATE0"), а у меня все команды формируются или динамически или из массива, короче ничего не получилось, скетч выше приведенный почти 90% памяти кушает, уже ничего не впихнешь.
сейчас с нуля начал новый, буду все делать по другому, более универсальный с возможностью не только смс но и dtmf и gprs, пока с работой только смс уже 43 % памяти, но это дело не быстрое....к лету может допишу.
Кстати, может не по делу, когда столкнулся с проблемой с памятью, стал использовать F(), отбил у памяти 300 Бт )).
Вдруг пригодится.
А я вот так сделала:
И в нужно месте пишем:
DEBUG_PRINTLN("Привет"); DEBUG_PRINT("Пока");Но всё же если сеть пропадет, модуль оповестит +CCALR: 0?
кого оповестит? и как? вам необходимо мониторить качество и наличие сети? наверное в даташите это есть, читать надо, выдерните симку во время работы и посмотрите что нибудь модем скажет или нет.
опять же смысл? ну заехали вы в мертвую зону, ну скажет МК что работать не буду - дальше что? полезете на березу с антеной как партизаны во время войны?