Перейти к содержанию
    

Как получить время по протоколу NTP

Растолкуйте по простому SUBJ на уровне

1 посылаешь по 123 порту xxxxx

2 получаешь хххххх где xx часы xx минуты

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гугл сломался?

Вот моя реализация клиента SNTP, может быть что-то полезное почерпнёте:

/**
* @file  sntp.c
* @brief SNTP client / clock
*/

#include "sntp.h"
#include "event.h"
#include "systime.h"
#include "mcf5223xif.h"
#include "lwip/udp.h"
#include "assert_static.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define SENDFAIL_TIMEOUT 5000          /* 5 seconds */
#define SENT_TIMEOUT     60000         /* 1 minute */
#define BADREPLY_TIMEOUT 60000         /* 1 minute */
#define VALID_TIMEOUT    (8 * 3600000) /* 8 hours */

#define SECSPERMIN      60L
#define MINSPERHOUR     60L
#define HOURSPERDAY     24L
#define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY      (SECSPERHOUR * HOURSPERDAY)
#define DAYSPERWEEK     7
#define MONSPERYEAR     12

#define YEAR_BASE       1900
#define EPOCH_WDAY      1
#define EPOCH_YEARS_SINCE_LEAP 2
#define EPOCH_YEARS_SINCE_CENTURY 70
#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370

#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)

enum sntp_state
{
       SNTP_INIT, SNTP_SENDFAIL, SNTP_SENT, SNTP_BADREPLY, SNTP_VALID
};

struct sntp_packet
{
       uint8_t status;
       uint8_t stratum;
       uint8_t ppoll;
       uint8_t precision;
       uint32_t distance;
       uint32_t dispersion;
       uint32_t refid;
       uint64_t reftime;
       uint64_t org;
       uint64_t rec;
       uint64_t xmt;
};

static bool time_valid = false;
static enum sntp_state state = SNTP_INIT;
static int32_t last_time, link_time;
static struct udp_pcb* upcb;
static struct ip_addr server;
static uint_fast16_t port = 123;
static uint64_t startup_time; /* timestamp in UTC */
static int_fast16_t tz;

static uint64_t
ms2ts(uint64_t ms)
{
       return ((ms / 1000) << 32) | (((ms % 1000) / 4) << 24);
}

static void recv(void *arg,
                struct udp_pcb *upcb,
                struct pbuf *p,
                struct ip_addr *addr,
                u16_t port)
{
       if (p->len == sizeof(struct sntp_packet))
       {
               int i;
               struct sntp_packet *ptr;
               assert(p->len == p->tot_len); /* don't accept chained pbuf */
               ptr = p->payload;
               i = (ptr->status >> 3) & 7;
               if ((i < 1) || (i > 4)) /* SNTP version 1..4 */
               {
                       goto out;
               }
               i = ptr->status & 7;
               if ((i != 4) && (i != 5)) /* mode 4 or 5: server or broadcast */
               {
                       goto out;
               }
               if (ptr->stratum == 0)
               {
                       goto out;
               }
               if (ptr->xmt == 0)
               {
                       goto out;
               }
               startup_time = ptr->xmt - ms2ts(systime_ms64());
               if (!time_valid)
               {
                       time_valid = true;
                       event_trigger(EVENT_SNTPSYNC);
               }
               state = SNTP_VALID;
               last_time = systime_ms32();
       }
out:
       pbuf_free(p);
}

void
sntp_enable(bool enable)
{
       assert_static(BYTE_ORDER == BIG_ENDIAN);
       if (enable)
       {
               if (upcb == 0)
               {
                       err_t ret;
                       upcb = udp_new();
                       assert(upcb != 0);
                       ret = udp_bind(upcb, IP_ADDR_ANY, port);
                       if (ret != ERR_OK)
                       {
                               udp_remove(upcb);
                               upcb = 0;
                       }
                       else
                       {
                               udp_recv(upcb, recv, 0);
                       }
                       state = SNTP_INIT;
               }
       }
       else if (upcb != 0)
       {
               udp_remove(upcb);
               upcb = 0;
       }
}

bool
sntp_isenabled(void)
{
       return upcb != 0;
}

void
sntp_setserveraddr(const struct ip_addr *addr)
{
       ip_addr_copy(server, *addr);
}

void
sntp_getserveraddr(struct ip_addr *addr)
{
       ip_addr_copy(*addr, server);
}

void
sntp_setserverport(uint_fast16_t port_arg)
{
       port = port_arg;
       if (sntp_isenabled())
       {
               sntp_enable(false);
               sntp_enable(true);
       }
}

uint_fast16_t
sntp_getserverport(void)
{
       return port;
}

void
sntp_settz(int_fast16_t tz_arg)
{
       tz = tz_arg;
}

int_fast16_t
sntp_gettz(void)
{
       return tz;
}

static void
send_request(void)
{
       struct sntp_packet packet;
       struct pbuf* psend;
       memset(&packet, 0, sizeof(packet));
       packet.status = (3 << 3)  /* SNTP vesion 3 */
                     | (3 << 0); /* Mode: client */
       psend = pbuf_alloc(PBUF_RAW, sizeof(packet), PBUF_REF);
       if (psend != 0)
       {
               psend->payload = &packet;
               state = (udp_sendto(upcb, psend, &server, port) == ERR_OK)
                       ? SNTP_SENT : SNTP_SENDFAIL;
               pbuf_free(psend);
       }
       last_time = systime_ms32();
}

void
sntp_poll(void)
{
       if (mcf5223xif_link() == false)
       {
               link_time = systime_ms32();
       }
       else if (upcb != 0)
       {
               int32_t now, timeout;
               now = systime_ms32();
               if (abs(now - link_time) > 2000)
               {
                       switch (state)
                       {
                       case SNTP_INIT:     send_request(); return;
                       case SNTP_SENDFAIL: timeout = SENDFAIL_TIMEOUT; break;
                       case SNTP_SENT:     timeout = SENT_TIMEOUT;     break;
                       case SNTP_BADREPLY: timeout = BADREPLY_TIMEOUT; break;
                       case SNTP_VALID:    timeout = VALID_TIMEOUT;    break;
                       }
                       if (now - last_time > timeout)
                       {
                               send_request();
                       }
               }
       }
}

bool
sntp_valid(void)
{
       return time_valid;
}

uint32_t
sntp_timestamp(void)
{
       return time_valid ? (startup_time + ms2ts(systime_ms64())) >> 32 : 0;
}

static const uint8_t mon_lengths[2][MONSPERYEAR] =
{
       {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
       {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
} ;

static const int year_lengths[2] = { 365, 366 } ;

void
sntp_seconds2tm(uint32_t sec32, struct tm* res)
{
       long days, rem;
       int y;
       int yleap;
       const uint8_t *ip;
       uint64_t sec;

       sec = sec32 + 60 * tz;
       if (((sec32 & 0x80000000UL) == 0) && (sec32 != 0))
       {
               sec += ((uint64_t)1 << 32);
       }
       days = sec / SECSPERDAY;
       rem = sec % SECSPERDAY;

       /* compute hour, min, and sec */
       res->tm_hour = (int) (rem / SECSPERHOUR);
       rem %= SECSPERHOUR;
       res->tm_min = (int) (rem / SECSPERMIN);
       res->tm_sec = (int) (rem % SECSPERMIN);

       /* compute day of week */
       if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
       {
               res->tm_wday += DAYSPERWEEK;
       }

       /* compute year & day of year */
       y = YEAR_BASE;
       if (days >= 40542) /* days in years 1900..2010 inclusive */
       {
               days -= 40542;
               y += 111;
       }
       if (days >= 0)
       {
               for (;;)
               {
                       yleap = isleap(y);
                       if (days < year_lengths[yleap])
                       {
                               break;
                       }
                       y++;
                       days -= year_lengths[yleap];
               }
       }
       else
       {
               do
               {
                       --y;
                       yleap = isleap(y);
                       days += year_lengths[yleap];
               }
               while (days < 0);
       }

       res->tm_year = y - YEAR_BASE;
       res->tm_yday = days;
       ip = mon_lengths[yleap];
       for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
       {
               days -= ip[res->tm_mon];
       }
       res->tm_mday = days + 1;
}

void
sntp_gettimestr(uint32_t timestamp, char *str)
{
       if (timestamp != 0)
       {
               struct tm time;
               sntp_seconds2tm(timestamp, &time);
               sprintf(str, "%02d.%02d.%d %02d:%02d:%02d",
                       time.tm_mday,
                       time.tm_mon + 1,
                       time.tm_year + 1900,
                       time.tm_hour,
                       time.tm_min,
                       time.tm_sec);
       }
       else
       {
               strcpy(str, "00.00.0000 00:00:00");
       }
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

спасибо за пример просветление в мозгах подступает:).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гугл сломался?

Еще один "велосипед". Не очень понятно, почему вы вместо функции strftime() стандартной библиотеки time.h пишете свою, делающую то же самое. Или не знали о её существовании? Какой смысл? И за 4 года никто не спросил и не поправил. В предыдущем посте кто-то даже просветлился. :biggrin: А что еще написать на такую портянку, когда сразу не въехал.

time_t rawtime = 1480685759; // Fri, 02 Dec 2016 13:35:59 GMT
struct tm * timeinfo;
timeinfo = (struct tm*)localtime(&rawtime);
char buffer [80];
strftime (buffer,80,"%d.%m.%Y %X",timeinfo);
puts (buffer); // 02.12.2016 13:35:59

 

Ладно бы вы использовали какой-нибудь R32C Renesas и их компилятор NC100 в котором стандартная библиотека time.h вообще не реализована, но вы же отвечаете в теме по ARM, а в ARMCC хорошая библиотека.

 

PS: И UnixTime в структуру руками не нужно переписывать (у вас 70 строк кода???):

void sntp_seconds2tm(uint32_t sec32, struct tm* res)...

Из NTP timestamp вычитаем разницу в секундах между 1970-1900 годами и используем стандартную функцию.

 

PPS: Дальше черпать неохота, т.к. почерпнуть нечего.

Изменено пользователем IgorKossak
бездумное цитирование

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...