ntp сервер на ардуино накинул день

mrWang
Offline
Зарегистрирован: 19.03.2017

сегодня был озадачен такой проблемой, NTP сервер возвращает Timestamp на 70 лет больше 3855190435

что в переводе Sat, 01 Mar 2092 06:13:55 GMT

void processNTP() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    digitalWrite(ledLAN, HIGH);
    Udp.read(packetBuffer, NTP_PACKET_SIZE);
    IPAddress remote = Udp.remoteIP();
    int portNum = Udp.remotePort();
    //
    if (debugNTP == true) {
      Serial.println();
      Serial.print("From: ");

      for (int i = 0; i < 4; i++) {
        Serial.print(remote[i], DEC);
        if (i < 3) {
          Serial.print(".");
        }
      }
      Serial.print(" port ");
      Serial.print(portNum);
    }

    // Упаковываем данные в ответный пакет:
    packetBuffer[0] = 0b00100100;   // версия, режим
    packetBuffer[1] = 1;   // стратум
    packetBuffer[2] = 6;   // интервал опроса
    packetBuffer[3] = 0xFA; // точность
    packetBuffer[7] = 0; // задержка
    packetBuffer[8] = 0;
    packetBuffer[9] = 8;
    packetBuffer[10] = 0;
    packetBuffer[11] = 0; // дисперсия
    packetBuffer[12] = 0;
    packetBuffer[13] = 0xC;
    packetBuffer[14] = 0;

    //getRTCDateTime();
    tmElements_t tm;
    if (RTC.read(tm)) {
      //    Serial.print("Ok, Time = ");
      //    print2digits(tm.Hour);
      //    Serial.write(':');
      //    print2digits(tm.Minute);
      //    Serial.write(':');
      //    print2digits(tm.Second);
      //    Serial.print(", Date (D/M/Y) = ");
      //    Serial.print(tm.Day);
      //    Serial.write('/');
      //    Serial.print(tm.Month);
      //    Serial.write('/');
      //    Serial.print(tmYearToCalendar(tm.Year));
      //    Serial.println();
    }
    timestamp = numberOfSecondsSince1900Epoch(tmYearToCalendar(tm.Year), tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);

    if (debugNTP == true) {
      Serial.println(" Timestamp = " + (String)timestamp);
    }
    tempval = timestamp;
    packetBuffer[12] = 71; //"G";
    packetBuffer[13] = 80; //"P";
    packetBuffer[14] = 83; //"S";
    packetBuffer[15] = 0; //"0";

    // Относительное время
    packetBuffer[16] = (tempval >> 24) & 0xFF;
    tempval = timestamp;
    packetBuffer[17] = (tempval >> 16) & 0xFF;
    tempval = timestamp;
    packetBuffer[18] = (tempval >> 8) & 0xFF;
    tempval = timestamp;
    packetBuffer[19] = (tempval) & 0xFF;

    packetBuffer[20] = 0;
    packetBuffer[21] = 0;
    packetBuffer[22] = 0;
    packetBuffer[23] = 0;

    // Копируем метку времени клиента
    packetBuffer[24] = packetBuffer[40];
    packetBuffer[25] = packetBuffer[41];
    packetBuffer[26] = packetBuffer[42];
    packetBuffer[27] = packetBuffer[43];
    packetBuffer[28] = packetBuffer[44];
    packetBuffer[29] = packetBuffer[45];
    packetBuffer[30] = packetBuffer[46];
    packetBuffer[31] = packetBuffer[47];

    // Метка времени
    packetBuffer[32] = (tempval >> 24) & 0xFF;
    tempval = timestamp;
    packetBuffer[33] = (tempval >> 16) & 0xFF;
    tempval = timestamp;
    packetBuffer[34] = (tempval >> 8) & 0xFF;
    tempval = timestamp;
    packetBuffer[35] = (tempval) & 0xFF;

    packetBuffer[36] = 0;
    packetBuffer[37] = 0;
    packetBuffer[38] = 0;
    packetBuffer[39] = 0;

    // Записываем метку времени
    packetBuffer[40] = (tempval >> 24) & 0xFF;
    tempval = timestamp;
    packetBuffer[41] = (tempval >> 16) & 0xFF;
    tempval = timestamp;
    packetBuffer[42] = (tempval >> 8) & 0xFF;
    tempval = timestamp;
    packetBuffer[43] = (tempval) & 0xFF;

    packetBuffer[44] = 0;
    packetBuffer[45] = 0;
    packetBuffer[46] = 0;
    packetBuffer[47] = 0;

    // Отправляем NTP ответ
    Udp.beginPacket(remote, portNum);
    Udp.write(packetBuffer, NTP_PACKET_SIZE);
    Udp.endPacket();
    digitalWrite(ledLAN, LOW);
  }
}

const uint8_t daysInMonth [] PROGMEM = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // число дней в месяцах
const unsigned long seventyYears = 2208988800UL; // перевод времени unix в эпоху


// Формирует метку времени от момента 01.01.1900
static unsigned long int numberOfSecondsSince1900Epoch(uint16_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t mm, uint8_t s) {
  if (y >= 1970) {
    y -= 1970;
  }
  uint16_t days = d;
  for (uint8_t i = 1; i < m; ++i) {
    days += pgm_read_byte(daysInMonth + i - 1);
  }
  if (m > 2 && y % 4 == 0) {
    ++days;
  }
  days += 365 * y + (y + 3) / 4 - 1;
  return days * 24L * 3600L + h * 3600L + mm * 60L + s + seventyYears;
}

 

 

при этом функция

  tmElements_t tm;
  if (RTC.read(tm)) {
    Serial.print("Time RTC UTC+0:  ");
    Serial.print ((String)char (27) + "[30;43m");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print(" ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();

выводит правильное значение времени

mrWang
Offline
Зарегистрирован: 19.03.2017

может кто сталкивался с таким поведением или сможет помочь

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mrWang пишет:

может кто сталкивался с таким поведением или сможет помочь

А чего тут помогать.

Вы считаете (не знаю, кто Вам сказал), что NTP возвращает время в секундах с 1900 года и используете функцию numberOfSecondsSince1900Epoch, а он на самом деле, возвращает с 1970. Вот и Ваши 70 лет. Просто смещайте на константу.

А вообще, лучше бы Вам не использовать самогонных функций. Есть же системная библиотека времени - она всё делает, если надо и время восхода и заката посчитает. Там, кстати, есть и готовая константа для пересчёта секунд от 1900 в секунды от 1970. Вернее, две

#define UNIX_OFFSET 946684800

#define NTP_OFFSET 3155673600

Разница между ними и есть нужное Вам смещение.

mrWang
Offline
Зарегистрирован: 19.03.2017

посмотрел https://wikihandbk.com/wiki/Arduino:%D0%91%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8/Time

описание библиотеки и не нашел как вернуть с помощью нее время в unix формате.

или же речь идет про другую библиотеку?

 

или же тут речь идет что время возвращается в - now()

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mrWang пишет:

посмотрел https://wikihandbk.com/wiki/Arduino:%D0%91%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8/Time

описание библиотеки и не нашел как вернуть с помощью нее время в unix формате.

Я вообще не понял о чём Вы? Я о системной библиотеке time, которая описана в стандарте языка и есть абсолютно во всех реализациях С и С++, а вовсе не о самогоне, от которого я Вам как раз советовал воздерживаться. Вы же опять какой-то самогон нашли.

Вот здесь есть описание библиотеки, а вот здесь я приводил примеры для Ардуино с NTP (в стартовом посте) и (пониже) со временем восхода и заката.

Ещё раз, она системная, её не нужно ниоткуда скачивать и ставить, она есть везде.

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

mrWang пишет:

посмотрел описание библиотеки и не нашел как вернуть с помощью нее время в unix формате.

читать не умеете? цитата:

Функция now() считывает время, прошедшее с 1 января 1970 года (в секундах).

Вас смутило слово "считывает" ? - это кривой перевод с английского. тут правильно будет "возвращает"

polecat77
Offline
Зарегистрирован: 18.05.2022

Вроде еще не некротема.

Ковыряю этот же код (лежащий в открытом доступе), вдруг автор топика еще не разобрался.

Цитата:

Метки времени

Изначально NTP использовал 64-битные метки времени, состоявшие из 32-битной части для секунд и 32-битной части для долей секунды, что давало временную шкалу, которая прокручивалась бы каждые 232 секунды (136 лет) и давало теоретическое разрешение 2-32 секунды (233 пикосекунды). Отсчет времени начинался с 1 января 1900 года, поэтому первая эпоха закончилась бы 7 февраля 2036 года.

Последняя версия протокола NTPv4 вводит 128-битный формат представления времени: 64 бита для секунд и 64 бита для долей секунды, что дает временную шкалу более 584 млрд лет и разрешение в 0,05 аттосекунд. Дополнительно было введено 32-битное поле номера эры, которое устранило даже ставшей теоретической проблему окончания каждой эпохи.