Синхронизация. Получить время от NTP сервера (GPRS, SIM900, UDP?)

VS_Viktor
Offline
Зарегистрирован: 27.02.2018
Добрый день,

прошу помочь с кодом для первоначальной установки часов и дальнейшей синхронизации Arduino Mega 2560 по GPRS.

SIM900 подключен через HWSerial к Mega. На шилде есть часы. Прошивка на SIM900 обновлена до последней (1137B06SIM900M64_ST_ENHANCE).

Пробовал два варианта:

1) расширенные команды от SIMCOM - "AT+CNTP" и "AT+CIPGSMLOC". первая с большой задежкой возвращает ошибку сети +CNTP:61 (хотя сначала отвечает OK), вторая ничего не возвращает кроме OK.

2) Подключиться к NTP серверу по UDP, отправить пакет и распарсить ответ. Также ничего не получилось, так как во всех примерах синхронизации по GPRS в и-нете все заканчивается отправкой пакета. А как его получить и распарсить нигде не нашел. То есть, в данном варианте у меня все заканчивается успешной отправкой пакета.

 

 

VS_Viktor
Offline
Зарегистрирован: 27.02.2018
sendATcommand("AT+GSN", "OK", "ERROR", 2000);
delay(1500);
sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"","OK","ERROR", 2000);
delay(1500);
sendATcommand("AT+SAPBR=3,1,\"APN\",\"internet.beeline.ru\"", "OK", "ERROR", 2000);
delay(1500);
sendATcommand("AT+SAPBR=1,1", "OK", "ERROR", 2000);
delay(1500);
sendATcommand("AT+SAPBR=2,1", "OK", "ERROR", 2000);
delay(1500);
sendATcommand("AT+CNTPCID=1", "OK", "ERROR", 2000);
delay(1500);
sendATcommand("AT+CNTP=\"88.147.254.230\",3,1,2", "OK", "ERROR", 2000);
delay(1500);
sendATcommand("AT+CNTP", "OK", "ERROR", 2000);
delay(1500);
sendATcommand("AT+CCLK?", "OK", "ERROR", 2000);
delay(1500);
sendATcommand("AT+SAPBR=0,1", "OK", "ERROR", 2000);
delay(1500);

коды первого варианта:

 

VS_Viktor
Offline
Зарегистрирован: 27.02.2018
//==============подключаемся по UDP=====================
                      
sendATcommand("AT+CREG?", "+CREG: 0,1","ERROR", 2000);                      // Делаем попытку регистрации в сети
delay(1500);
sendATcommand("AT+CGATT=1", "OK", "ERROR", 2000);                           // запускаем GPRS
delay(1500);
sendATcommand("AT+CIPRXGET=1", "OK", "ERROR", 2000);                        // включаем получение данных
delay(1500);
sendATcommand("AT+CIPMUX=1", "OK", "ERROR", 2000);                          // устанавливаем только одно единовременное подключение
delay(1500);
sendATcommand("AT+CSTT=\"APN\",\"internet.beeline.ru\"", "OK", "ERROR", 2000);         // указываем APN
delay(1500);
sendATcommand("AT+CIICR", "OK", "ERROR", 2000);                    // Делаем попытку установки GPRS-соединения
delay(1500);
sendATcommand("AT+CIFSR", "OK", "ERROR", 2000);                             // Запрашиваем IP-адрес, полученный модулем. Проверяем интернет-соединение
delay(1500);
sendATcommand("AT+CDNSCFG=\"8.8.4.4\"", "OK", "ERROR", 2000);           // указываем DNS-сервера                    
delay(1500);
sendATcommand("AT+CIPSTATUS", "+CIPSTATUS: 0,1", "ERROR", 2000);            // Делаем попыткe запроса статуса соединения
delay(1500);
sendATcommand("AT+CIPSTART=\"0\",\"UDP\",\"88.147.254.230\",\"123\"", "OK", "ERROR", 2000); // открываем соединение номер 0 с UDP-сервером
delay(1500);
sendATcommand("AT+CIPSEND=0,8", "OK", "ERROR", 2000); // Устанавливаем размер пакета передачи данных
delay(1500);
Serial.println("0001020304050607"); - "пустой пакет"

sendATcommand("AT+CIPRXGET=2,0,48", "OK", "ERROR", 2000); // Даем команду на прием данных
delay(1500);
sendATcommand("AT+CIPCLOSE=0", "OK", "ERROR", 2000); // Закрываем соединение номер 0
delay(1500);

это второй вариант:

 

b707
Offline
Зарегистрирован: 26.05.2017

библиотеку для модема какую используете?

VS_Viktor
Offline
Зарегистрирован: 27.02.2018

Без библиотек. Управляю только AT-командами. Шилд пристегнут по HWserial на Serial2.

b707
Offline
Зарегистрирован: 26.05.2017

VS_Viktor пишет:

Без библиотек. Управляю только AT-командами. Шилд пристегнут по HWserial на Serial2.

функция sendATcommand() - ваша самописная?

Я не вижу в вашем коде - вы ответы на команды хоть где-то анализируете?

VS_Viktor
Offline
Зарегистрирован: 27.02.2018
byte sendATcommand(String ATcommand, String answer1, String answer2, unsigned int timeout){
   byte reply = 1;
   String content = "";
   char character;
   //Clean the modem input buffer
   while(Serial2.available()>0) Serial2.read();

   //Send the atcommand to the modem
   Serial2.println(ATcommand);
   delay(100);
   unsigned int timeprevious = millis();
   while((reply == 1) && ((millis() - timeprevious) < timeout)){
     while(Serial2.available()>0) {
       character = Serial2.read();
       content.concat(character);
       Serial.print(character);
       delay(10);
     }
     //Stop reading conditions
     if (content.indexOf(answer1) != -1){
       reply = 0;
     }else if(content.indexOf(answer2) != -1){
       reply = 2;
     }else{
       //Nothing to do...
     }
   }
   return reply;   
}

функцию позаимствовал. Оказалась очень удобной.

 

b707
Offline
Зарегистрирован: 26.05.2017

VS_Viktor пишет:

функцию позаимствовал. Оказалась очень удобной.

Ага, удобная. Только вы, похоже, даже не пытались разобраться, как с ней работать.

Эта функция имеет возвращаемое значение - при успехе возвращает ноль, а при ошибке или таймауте - ненулевой код ошибки. Вы его где-то проверяете? - имхо нет.

Во-вторых, в функцию уже встроен таймаут (последний параметр в скобках). Нафига ж вы еще delay() после каждого вызова этой функции навтыкали?

Для дальнейшего обсуждения ответьте на вопрос - каков ваш опыт программирования на Си? Например, исходный код функции sendATCommand()  - это китайская грамота или вы в нем что-то понимаете?

VS_Viktor
Offline
Зарегистрирован: 27.02.2018

уровень = "продвинутый новичок"

VS_Viktor
Offline
Зарегистрирован: 27.02.2018

Респонс на AT команды я проверял на отладку. По всем командам прилетали "0".

VS_Viktor
Offline
Зарегистрирован: 27.02.2018
 byte NTP_time_request (){
   byte reply = 1;
   int i = 0;
   while (i < 10 && reply == 1){ //Try 10 times...
     reply = sendATcommand("AT+CREG?","+CREG: 0,1","ERROR", 1000);
     i++;
     delay(1000);
   }
   if (reply == 0){
     reply = sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"","OK","ERROR", 1000);
     if (reply == 0){
       reply = sendATcommand("AT+SAPBR=3,1,\"APN\",\"internet.beeline.ru\"", "OK", "ERROR", 1000);
       if (reply == 0){
         reply = sendATcommand("AT+SAPBR=3,1,\"USER\",\"beeline\"", "OK", "ERROR", 1000);
         if (reply == 0){
           reply = sendATcommand("AT+SAPBR=3,1,\"PWD\",\"beeline\"", "OK", "ERROR", 1000);
           if (reply == 0){
             reply = 2;
             i = 0;
             while (i < 3 && reply == 2){ //Try 3 times...
               reply = sendATcommand("AT+SAPBR=1,1", "OK", "ERROR", 10000);
               if (reply == 2){
                 sendATcommand("AT+SAPBR=0,1", "OK", "ERROR", 10000);
               }
               i++;
             }
             if (reply == 0){
               reply = sendATcommand("AT+SAPBR=2,1", "OK", "ERROR", 1000);
              if (reply == 0){
                reply = sendATcommand("AT+CNTPCID=1", "OK", "ERROR", 2000);
                    Serial.println(reply);
                     if (reply == 0){
                          reply = sendATcommand("AT+CNTP=\"88.147.254.230\",3,1,2", "OK", "ERROR", 2000);
                             Serial.println(reply);
                              if (reply == 0){
                                reply = sendATcommand("AT+CNTP", "OK", "ERROR", 2000);
                                   Serial.println(reply);
                                     if (reply == 0){
                                        reply = sendATcommand("AT+CCLK?", "OK", "ERROR", 2000);
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                }
            }
         }
   return reply;         
 }

Переписал первую конструкцию с командами AT+CNTP. Ответы с нулями, но синхронизации по прежнему нет.

 

b707
Offline
Зарегистрирован: 26.05.2017

VS_Viktor пишет:

Переписал первую конструкцию с командами AT+CNTP. Ответы с нулями, но синхронизации по прежнему нет.

По первому варианту ничего не подскажу - не знаю. А во втором вам нужно не только передать запрос, но и принять ответ. В вашем скетче нет даже намека на это. Модем сам не умеет принимать ответ от NTP сервера. Вам нужно сделать жто вручную и распарсить принятый пакет. Как распарсить NTP-пакет - я не разбирался. а пример приема данных от GPRS вы можете найти в любом скетче, получающем данные с HTTP-сервера.

VS_Viktor
Offline
Зарегистрирован: 27.02.2018

В примерах (в основном это Ethernet-шилды) используют библиотеки и механизм парсинга не виден. я пробовал разобраться, но моих мозгов не хватает.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

когда поймаете нужный ответ/пакет - тогда уже думайте как парсить / разбирать данные.

А так конечно delay и вообще логика никуда не годиться, впрочем мой первый проект с gsm был чем то подобным.

VS_Viktor
Offline
Зарегистрирован: 27.02.2018

Для того, чтобы что-то поймать в ответ, нужно что-то послать... а я не понимаю что нужно посылать на NTP. Многие пишут, что достаточно послать пустой пакет и сервер ответит. Пакет, судя по ответам модема, я посылаю удачно. Но что делать дальше не знаю.

Поэтому и прошу помочь.

b707
Offline
Зарегистрирован: 26.05.2017

VS_Viktor пишет:

Для того, чтобы что-то поймать в ответ, нужно что-то послать... а я не понимаю что нужно посылать на NTP. Многие пишут, что достаточно послать пустой пакет и сервер ответит. Пакет, судя по ответам модема, я посылаю удачно.

По-моему, вы ничего не посылаете вообще.

Послать NTP серверу "пустой пакет"  - это не значит послать в сеть пакет нулевых байт или вообще ничего. Это должен быть UDP пакет, длиной, если не изменяет память - 48 байт, сформированный по формату NNTP. с правильным заголовком, но не содержащий текущего времени.

В вашем коде вы явно никакого "пустого пакета" не формируете и я даже не вижу, где бы вы его передавали.

Вообще, формат общения по NTP подробно описан в соответсвующий документах (RFC), в библиотеке Time.h и во многих местах в инете. Вопрос это довольно специфический и я не думаю. что у нас на форуме тут куча народу может вот так прямо выдать вам подробную инстукцию. Я с год назад разбирался с этим - но столкнулся с тем, что на используемом мной модеме (А6) оказалось. нет поддержки UDP. - поэтому готовых кодов у меня нет. ИМХО, вы значительно быстрее добьетесь успеха, если начнете копать инет сами.

 

VS_Viktor
Offline
Зарегистрирован: 27.02.2018

решил вопрос парсингом любой входящей смс.

b707
Offline
Зарегистрирован: 26.05.2017

VS_Viktor пишет:

решил вопрос парсингом любой входящей смс.

Не слишком надежно. Входящую СМС можно несколько дней ждать.

Как я уже писал - когда я делал похожий проект, столкнулся с тем, что на модеме А6 отсутсвует поддержка UDP. Поэтому я не смог сделать запрос времени по NTP. Зато практически на любом веб-сервере в заголовке ответа есть локальное время. Для синхронизации достаточно послать серверу запрос HTTP HEAD и распарсить его.

но на вашем месте я б NTP домучил....

VS_Viktor
Offline
Зарегистрирован: 27.02.2018

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

С другой стороны, освоив пасинг СМС, ответ от сервера, надеюсь, обработаю. Спасибо вам за отзыв и советы.