ntp по UDP

inspiritus
Offline
Зарегистрирован: 17.12.2012

Здравствуйте

пробую поиграться с получением времени от ntp серверов

примеры, присутствующие в сети, зависают на запросе к серверу ( то есть следующие за ним инструкции не выполняется).

  sendNTPpacket(timeServer);

так как пример в сети один и тот же,

ВОПРОС

у кого-нибудь получалось сделать ЭТО? способом из примера , или иным способом. 

 

 

Araris
Offline
Зарегистрирован: 09.11.2012

inspiritus пишет:

примеры, присутствующие в сети, зависают на запросе к серверу ( то есть следующие за ним инструкции не выполняется).

То есть условие if ( Udp.parsePacket() ) (строка 66 в примере) не выполняется ?

У меня пару лет работает скетч, где синхронизация времени сделана аналогично приведенному примеру, проблем с ним не было. Вот такая функция

void getNtpTime()
{
Udp_.begin(8888);
byte pb[48];
pb[0] = 0b11100011; pb[1] = 0; pb[2] = 6; pb[3] = 0xEC;
pb[12]  = 49; pb[13]  = 0x4E; pb[14]  = 49; pb[15]  = 52;
Udp_.beginPacket(timeServer, 123);
Udp_.write(pb,48);
Udp_.endPacket(); 
uint32_t beginWait = millis();
while (millis() - beginWait < 2000) 
 {
 int size = Udp_.parsePacket();
 if (size >= 48) 
  {
  #ifdef DEBUG
  Serial.print("Receive NTP Response ");
  #endif
  Udp_.read(pb, 48);
  unsigned long t1, t2, t3, t4;
  t1 = t2 = t3 = t4 = 0;
  for ( int i=0; i < 4; i++ )
   {
   t1 = t1 << 8 | pb[16+i];      
   t2 = t2 << 8 | pb[24+i];      
   t3 = t3 << 8 | pb[32+i];      
   t4 = t4 << 8 | pb[40+i];
   }
  float f1,f2,f3,f4;
  f1 = ((long)pb[20] * 256 + pb[21]) / 65536.0;      
  f2 = ((long)pb[28] * 256 + pb[29]) / 65536.0;      
  f3 = ((long)pb[36] * 256 + pb[37]) / 65536.0;      
  f4 = ((long)pb[44] * 256 + pb[45]) / 65536.0;
  const unsigned long seventyYears = 2208988800UL;
  t1 -= seventyYears;
  t2 -= seventyYears;
  t3 -= seventyYears;
  t4 -= seventyYears;
  t4 += (TimeZone * 3600L); // Adjust timezone
  t4 += 1;                  // adjust the delay(1000) at begin of loop!
  if (f4 > 0.4) t4++;       // adjust fractional part, see above
  t4 -= 946684800;    // bring to 2000 timestamp from 1970
  uint8_t ss = t4 % 60;
  t4 /= 60;
  uint8_t mm = t4 % 60;
  t4 /= 60;
  uint8_t hh = t4 % 24;
  rtc.setTime(hh, mm, ss);
  CurTime = rtc.getTime();
  CurTimeHour = CurTime.hour;
  CurTimeMin = CurTime.min;
  CurTimeSec = CurTime.sec;
  LastSyncHour = CurTimeHour;
  LastSyncMin = CurTimeMin;
  LastSyncSec = CurTimeSec;
  CurDay = CurTime.date;
  CurMonth = CurTime.mon;
  CurYear = CurTime.year;
  ntp_request_interval = NTP_INTERVAL;
  #ifdef DEBUG
  Serial.println("NTP SyncTime OK");
  #endif
  }
 }
Udp_.stop();
ntp_last_request_time = millis();
#ifdef DEBUG
Serial.print(CurTimeHour);
Serial.print(":");
Serial.print(CurTimeMin);
Serial.print(":");
Serial.print(CurTimeSec);
Serial.print(" ");
Serial.print(CurDay);
Serial.print(".");
Serial.print(CurMonth);
Serial.print(".");
Serial.print(CurYear); 
Serial.println();
#endif
}

как видите, по сути не отличается от http://wikihandbk.com/wiki/Arduino:Примеры/UdpNtpClient.

А Вы точно уверены, что у Вас отрабатывает

  1. Udp.beginPacket(address, 123); // NTP-запрос идет на порт 123
  2.   Udp.write(packetBuffer,NTP_PACKET_SIZE);
  3.   Udp.endPacket();

и пакет уходит на сервер, кстати, сервер живой, правильный ?

inspiritus
Offline
Зарегистрирован: 17.12.2012

Поставленная в 63 строку команда вывода в монитор чегонибудь не отрабатывает.

До 66 дело не доходит, сервер живой.

Udp.endPacket(); не отрабатывет, то есть вывод в монитор после него молчит, до него ок.

ну да Ваш код , по крайней мере запроса аналогичен.... Как говорится :" все как настоящее, только не работает :)

интересно, а порт 8888 принципиален и нужно ли по нему что-нибудь специально натить в роутере?

хмм пробросил нат снаружи внутрь по 8888 порту для udp, разрешил по адресу и этому порту входящие udp пакеты, не помогло. В любом случае счетчики не ловят по этому порту активности. Даже открывал полный сквозняк на файрволе, тоже ноль реакции.

Спасибо.

 

Araris
Offline
Зарегистрирован: 09.11.2012

Значит

  Udp.beginPacket(address, 123); // NTP-запрос идет на порт 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);

проходит,а на

Udp.endPacket();

тупо виснет ?

Хм.. Я бы, пожалуй, попробовал бы произвольный UDP-пакет послать себе на компьютер и там его поймать, например, вот этим: http://www.nsauditor.com/network_tools/udp-client-server.html. А потом туда же попробовать NTP-запрос послать.

На роутере специально ничего ни с какими портами я не делал.

inspiritus
Offline
Зарегистрирован: 17.12.2012

Точно так

По идее бегин-енд уже должны сформировать пакет с пустым содержимым...

Убрал между бегино-ендом запись содержимого буфера, по-прежнему енд не проходит...

программу попробую,

Также попробую прохождение пакета посмотреть на файрволе, у мну микротик, там можно тонко настраиваться.

хмм а для чего тогда нужен слушающий порт , это же клиент...

 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Araris пишет:

.......и пакет уходит на сервер, кстати, сервер живой, правильный ?

Сервер живой, правильный, я вчера виндой проверял.

И отвечал мгновенно, в отличии от микрософта

inspiritus
Offline
Зарегистрирован: 17.12.2012

нету ничего на выходе по udp протоколу, никто не ловит пакеты...

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

inspiritus пишет:
нету ничего на выходе по udp протоколу, никто не ловит пакеты...

По tcpdump - видно, что общаются, или "пакет-запрос ушел на сервер и тишина"? Год-полтора назад, помнится, крутили все ntp сервера на предмет запретов на определенные запросы. Вполне возможно, что Ваш запрос как раз под этот запрет и попадает...

 

inspiritus
Offline
Зарегистрирован: 17.12.2012

не общаются, любые манипуляции с udp заканчиваются на инструкции     Udp.endPacket();

насколько я понимаю именно ета инструкция обозначает для контроллера не только завершение засылки пакета в его буфер, но и указание на отсылку пакета.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

inspiritus пишет:

не общаются, любые манипуляции с udp заканчиваются на инструкции     Udp.endPacket();

Ну так распечатайте в 130-й строке пакет в консоль и попробуйте заслать его руками...

inspiritus
Offline
Зарегистрирован: 17.12.2012

как его заслать руками?

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

inspiritus
Offline
Зарегистрирован: 17.12.2012

продолжение плясок с бубном ...

раз уж с udp  не складывается, можно толкнуться по tcp и распарсить страничку, благо серверов много, например

http://www.direct-time.ru/

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

/*
  Web client

 This sketch connects to a website (http://www.google.com)
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13

 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe, based on work by Adrian McEwen

 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xFD }; //physical mac address
byte ip[] = { 192, 168, 88, 237 }; // fixed IP addr in LAN
byte gateway[] = { 192, 168, 88, 254 }; // internet access via router
byte subnet[] = { 255, 255, 248, 0 }; //subnet mask
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(192,168,88,254);  // numeric IP for Google (no DNS)
//char server[] = "www.direct-time.ru";    // name address for Google (using DNS)
char server[] = "www.google.com";    // name address for Google (using DNS)

// Set the static IP address to use if the DHCP fails to assign

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  // start the Ethernet connection:
  Ethernet.begin(mac, ip, gateway, subnet);
   
  // give the Ethernet shield a second to initialize:
  delay(3000);
  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("GET /search?q=arduino HTTP/1.1");
    client.println("Host: www.google.com");
    client.println("Connection: close");
    client.println();
  }
  else {
    // kf you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop()
{
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}

.... ФИГВАМ ... коннекта не происходит, причем оно отшивает моментально, хотя должна быть какая то задержка на коннект.

Плата инициализирована, с роутера пингуется. На роутере стоят ловушки на пакеты по всем протоколам с IP платы и на IP платы. Ловушки ничего не фиксируют.

Прямо фантастика, причем, как сервер все работает изюмительно.

Может ли быть аппаратная проблема в железе ?

Похоже она самая,,, у меня роутер-шлюз микротик, у него веб-морда. Зарядил я ее адрес для обращения клиента. Откомпилировал и вгрузил. Выключил питание. Включил... И вдруг получил код страницы в клиенте. Попробовал еще раз - фиг. Короче одна из десяти-пятнадцати попыток успешна, или успешна частично. Похоже w5100 глючная. Кто-нибудь сталкивался ?

inspiritus
Offline
Зарегистрирован: 17.12.2012

странная весчь...

если 2560 и навернутый на нее W5100 выдернуть питание, потом, удерживая ресет, воткнуть питание , дождаться кваканья обнаружения USB-устройства (чтобы сериал монитор работал) и отпустить ресет....\

то коннект случается в 100 случаях из 100 попыток.

Принимается 1034 символа и все нахрен виснет.

что за срань с W5100 ? кто-нибудь сталкивался с подобным ?

inspiritus
Offline
Зарегистрирован: 17.12.2012

короче со странным поведением в связи с ресетом все выяснилось : страрые грабли. Если SD не используется, необходимо ее CS принудительно глушить на 1.

странное поведение клиента.

Все инициализируется, обращаюсь к веб-морде роутера (локальная сеть-локальный адрес) - получаю html страницы полностью и безукоризненно.

Все то-же-самоэ, только IP внешний, НИЧЕГО не происходит, на роутере даже пакеты не видны. 

mask,gate мк не отличаются от остальных участников локалки, ip естественно другой. вся локалка в инет ходит, мк нет. сетевые правила для мк пакетов не видят, специально созданный персональный маскарад для мк пакетов не получает.

чудеса да и только. видимо все мои проблемы с udp и ntp-серверами растут оттуда же.

такое ощущение, что , пока пакеты идут в локалке (без участия понятия gateway) все ок, как только за пределы локалки, чип должен отсылать пакеты на gateway, а он этого не делает. При работе сервером пакеты получаются из-под nat с srs ip роутера, находящегося в локалке, и отсылаются пакетв "в ответ" на адрес в локалке, потому все работает.

надо будет  мк уташшить к соседу, попробовать через его роутер толкануться.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

inspiritus пишет:
такое ощущение, что , пока пакеты идут в локалке (без участия понятия gateway) все ок, как только за пределы локалки, чип должен отсылать пакеты на gateway, а он этого не делает. При работе сервером пакеты получаются из-под nat с srs ip роутера, находящегося в локалке, и отсылаются пакетв "в ответ" на адрес в локалке, потому все работает.

Маска сети - правильная (/24) или какая-то другая?

Попробуйте принудительный проброс пакетов с мыльницы наружу (куда надо)...

inspiritus
Offline
Зарегистрирован: 17.12.2012

Маска правильная, пакеты вообще в сети отсутствуют, такое ощущение, что на gateway не отсылаются.

то есть Вы предлагаете гнать пакеты по локальному адресу роутера ( ака шлюза), например на порт 9090, а на роутере пробрасывать их наружу на целевой IP, на 80 порт .... ? 

Только вот вопрос , позволит ли это сделать. Destination nat ? 

Попробую конечно такой выверт, только ведь костыль, оно ведь само должно на указанный gateway. Отправлять , если destination ip не в диапазоне адресов локальной маски.

получается , что в контроллере w5100  засада порыдась ?

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

inspiritus пишет:
получается , что в контроллере w5100  засада порыдась ?

Или в библиотеке, обрабатывающей src ip пакета и формирующей ответ... Оно совершенно спокойно может брать последний октет, и отправлять пакеты на адрес, берущийся из первых трех октетов своего ip + последний октет из src ip. :)

inspiritus
Offline
Зарегистрирован: 17.12.2012

Да, но ведь это официальная библиотека и ее типовой пример. Ардуинцы наверно уж проверили работоспособность всего этаго. А то совсем все криво получается, и ntp и http клиенты косячат. Я склоняюсь к мысли, что пооблема все таки в железе. Вот приедет через неделю другую еще одна w5100 тогда отпишусь по результатам...

Araris
Offline
Зарегистрирован: 09.11.2012

inspiritus пишет:

Я склоняюсь к мысли, что проблема все таки в железе.

Поддерживаю.

inspiritus
Offline
Зарегистрирован: 17.12.2012

Угу ... Чудес не бывает, ...ня случается.

inspiritus
Offline
Зарегистрирован: 17.12.2012

Пришла новая плата w5100. Проблема осталась.

попутно вылезло неполучение IP по DHCP. 

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

после перезагрузки роутера адрес по DHCP  стал получаться без проблем. С полученным от DHCP адресом обращение к внешним серверам стало работать. С указанными явно параметрами инициализации шильда по-прежнему не работает.

Копаю дальше.

inspiritus
Offline
Зарегистрирован: 17.12.2012

Вопрос к уважаемому Araris-у.

В посте от Ср, 30/09/2015 - 21:16 Вы написали, что пару лет у Вас все работает по ntp. Там показан гравный цикл.

А как происходит инициализация. IP выделяется явно, как указывается gateway? 

Или по DHCP? Что будет, если указать параметры инициялизации явно ?

типа этого 


#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xFD }; //physical mac address
byte ip[] = { 192, 168, 88, 237 }; // fixed IP addr in LAN
byte gateway[] = { 192, 168, 88, 254 }; // internet access via router
byte subnet[] = { 255, 255, 248, 0 }; //subnet mask

//IPAddress server(192,168,88,254);  // numeric local  IP 
//char server[] = "www.direct-time.ru";    // name address for time server (using DNS)
//char server[] = "www.google.com";    // name address for Google (using DNS)
 
EthernetClient client;

void setup() {

  Serial.begin(9600);
  // start the Ethernet connection:

  Ethernet.begin(mac, ip, gateway, subnet);
  // give the Ethernet shield a second to initialize:
  delay(1000);

 

Araris
Offline
Зарегистрирован: 09.11.2012

Я слежу за этой темой, отвечаю - все указываю явно.

Прописываю всякие-разные переменные:

//////////////////// FOR ETHERNET
byte mac[] = { 0xDE, 0xAD, 0xBF, 0xEF, 0xFE, 0xED };
byte ip[] = {192,168,0,190};
byte dnServer[] = {192,168,0,1};
byte gateway[] = {192,168,0,1};
byte subnet[] = {255,255,255,0};
EthernetServer server(80); 
EthernetClient client;
EthernetUDP Udp_;
...
// For NTP
byte timeServer[] = {193,204,114,232};
int TimeZone = 2;
 
Потом вызываю функцию resetLAN()
 
void resetLAN()
{
lcd.setCursor(0,1);
lcd.print("LAN"); 
digitalWrite(W5100_RESET_PIN, LOW);
delay(100);
digitalWrite(W5100_RESET_PIN, HIGH);
delay(1000);
Ethernet.begin(mac,ip,dnServer,gateway,subnet);
server.begin();
delay(500);
W5100WatchdogTimer = millis();
#ifdef DEBUG
Serial.print("Reset LAN. IP=");
Serial.println(Ethernet.localIP());
#endif
}

 

 
 
inspiritus
Offline
Зарегистрирован: 17.12.2012
Вот же ЁКАРНЫЙ БАБАЙ... писал писал, а форумный движок взял и закрыл доступ к странице, и все написанное пропало.
 
Переменные у меня так же прописаны.
 
RESET я аппаратно не дергаю. Хотя видимо надо, тк после подачи питания шильд не заводится без нажатия на ресет (любой, что на плате, что на шильде).  А что у Вас на ресетпин приходит. У шильда ведь все ресеты бантиком завязаны на ресет основной платы, если просто заводить на ресетпин, то сбрасываться будет всё. Вы видимо гдетто дорожку резали, или у Вас старая редакция шильда ?
 
W5100WatchdogTimer = millis(); также заинтересовало. Что это догадываюсь, как используется?
 
Одновременная инициализация объектов
EthernetServer server(80); 
EthernetClient client;
EthernetUDP Udp_;
...наталкивает на мысль возможности одновременной работы и с сервером и с клиентами. Тогда вопрос: необходимо ли перед командой Udp_.begin(); говорить server.stop();, если до того был server.begin(); и Вы его использовали ?
 
Ethernet.localIP(); показывает IP шильда, можно ли увидеть остальные попавшие в него атрибуты (gateway, subnet, dnServer)?
 
Спасибо.
Araris
Offline
Зарегистрирован: 09.11.2012

Функция resetLAN(), как Вы правильно поняли, вызывается не только из setup(). Если RESET_PIN программно не дергаю, то толку мало. У меня W5100 не шилдом исполнен, а "отдельностоящая" платка, поэтому резать ничего не пришлось.

W5100WatchdogTimer срабатывает, если долго не было обмена данными через W5100, поскольку это скетч центрального контроллера квартиры, обмен есть постоянно.

server.stop(); в моем скетче отсутствует, server.begin только один раз в этой самой resetLAN(). (Скетч 129кБ, там ооочень много понаверчено, по прошествии времени самому уже нелегко разобраться.)

Заглянув в библиотекин ethernet.h, найдем там, помимо localIP(), функции subnetMask(), gatewayIP() и dnsServerIP().

Ответил кратко, занят сейчас. Если что, доспрашивайте ))

inspiritus
Offline
Зарегистрирован: 17.12.2012

Спасибо, в общем понятно.

Так и не получается явно инициализировать, видимо надо хард_ресет шильда добавить, как у Вас...

Добавил синхронизацию RTC по ntp. Получилось.

Одновременно стартованные у меня два сервера и один Udp - клиент, полет нормальный.

 W5100WatchdogTimer ... не поделитесь ли кодом :)

результат изысканий

Спасибо.

Araris
Offline
Зарегистрирован: 09.11.2012

inspiritus пишет:

 W5100WatchdogTimer ... не поделитесь ли кодом :)

Дык, там и кода-то особого не надо.

Получили данные - отмечаем "время"

W5100WatchdogTimer = millis();

В loop() ставим проверку

if ( (millis() - W5100WatchdogTimer) > MAXW5100WATCHDOGDELAY ) { resetLAN(); W5100WatchdogTimer = millis(); }

Значение MAXW5100WATCHDOGDELAY - какое пожелаете.

Естественно, это имеет смысл только если данные приходят постоянно и регулярно.

inspiritus
Offline
Зарегистрирован: 17.12.2012

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

.... или сделать пингующего клиента на что-нибудь никогда-не-падающее и внутри него сбрасывать миллис.

Вообще мне не нравится  с миллис работать, более явным , почти мультизадачным выглядит SimpleTimer, на котором я все и построил.

Работает устойчиво,  севера и мат.модель в loop() живут, а запись лога, коррекция ntp  и опрос датчиков периодически исполняются по таймеру... 

Araris
Offline
Зарегистрирован: 09.11.2012

inspiritus пишет:

.... или сделать пингующего клиента на что-нибудь никогда-не-падающее и внутри него сбрасывать миллис.

Я об этом тоже думал, но не стал делать, так как отсутствие пинга может означать также и отсутствие Интернета в данный момент. [А может просто поленился..]

inspiritus
Offline
Зарегистрирован: 17.12.2012

Добавил хардресет на шильд w5100.

Так как шильд старой ревизии, на нем кнопка ресета связана с пином ресет на боковой колодке и на SPI. Долго искал в инете схему на него и разводку, не нашел. Плюнул и взялся за кусачки. Откусил длинный пин на ресете боковой колодки под корешок и выкусил  миллиметр разрыва на шестом пине разъема SPI. Вызвонил на кнопке ресет шильда ноги на gnd остальные две звонились на ресет. Накинул на них провод с пумпочкой и воткнул пумпочку в боковую колодку на пин 5, который и объявил W5100_RESET_PIN. Инициализацию провел аналогично сделанному у Araris. 

Проверил работу клиентов tcp и udp. Все работает.  К ремот-серверам стучится, с ntp получает время, работают все стандартные примеры нативной библиотеки.

Получается, что отказ DHCP был вызван особенностями работы роутера микротик.

Отказ работы шильда с gateway связан с ошибкой инициализации из-за кривого ресета шильда старой ревизии.

И конечно, пока не используется SD, cs-sdшный держим в единице, иначе получаем сбой SPI и работы езернета.

Вот и сказочке конец , кто читал, тот молодец. 

Уважаемому Araris большое человеческое СПАСИБО. 

 

Araris
Offline
Зарегистрирован: 09.11.2012

Люблю хэппиэнды !

ctacb
Offline
Зарегистрирован: 03.01.2017

Чувствую мне надо менять ENC28 на W5100.... как я с ним напарился :) у меня хардресет не работает, вернее сам ресет работает, а вот переинициализации уже нет :(

Araris
Offline
Зарегистрирован: 09.11.2012

Это крик души был. Я Вас понимаю, свой ENC28J60 после серии садо-мазо экзерсисов я уложил в коробочку с утраченными надеждами и разочарованиями.

MurzzZ
Offline
Зарегистрирован: 21.04.2017

добрый день.

попробовал сделать по аналогии с Вашим примером 

if ( (millis() - W5100WatchdogTimer) > MAXW5100WATCHDOGDELAY ) { resetLAN(); W5100WatchdogTimer = millis(); }

проверку поставил в функции ожидания клиента, MAXW5100WATCHDOGDELAY = 10сек. в итоге 4 раза, нормально срабатывает resetLAN, а на 5 перезагружается ардуина. пробовал на Mege и на Uno. и там и там презагружается на 5 resetLAN. В чем может быть проблема?