source: azure_iot_hub/trunk/ntshell/src/ntp_cli.c@ 388

Last change on this file since 388 was 388, checked in by coas-nagasima, 5 years ago

Azure IoT Hub Device C SDK を使ったサンプルの追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 15.4 KB
Line 
1/*
2 * TOPPERS ECHONET Lite Communication Middleware
3 *
4 * Copyright (C) 2018 Cores Co., Ltd. Japan
5 *
6 * 上記著作権者
7は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
8 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9 * 変・再é…
10å¸ƒï¼ˆä»¥ä¸‹ï¼Œåˆ©ç”¨ã¨å‘¼ã¶ï¼‰ã™ã‚‹ã“とを無償で許諾する.
11 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
12 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
13 * スコード中に含まれていること.
14 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
15 * 用できる形で再é…
16å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œå†é…
17å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨
18 * 者
19マニュアルなど)に,上記の著作権表示,この利用条件および下記
20 * の無保証規定を掲載すること.
21 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22 * 用できない形で再é…
23å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œæ¬¡ã®ã„ずれかの条件を満たすこ
24 * と.
25 * (a) 再é…
26å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨è€…
27マニュアルなど)に,上記の著
28 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
29 * (b) 再é…
30å¸ƒã®å½¢æ…
31‹ã‚’,別に定める方法によって,TOPPERSプロジェクトに
32 * 報告すること.
33 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
34 * 害からも,上記著作権者
35およびTOPPERSプロジェクトをå…
36è²¬ã™ã‚‹ã“と.
37 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
38 * 由に基づく請求からも,上記著作権者
39およびTOPPERSプロジェクトを
40 * å…
41è²¬ã™ã‚‹ã“と.
42 *
43 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者
44お
45 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
46 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
47 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
48 * の責任を負わない.
49 *
50 * @(#) $Id: ntp_cli.c 388 2019-05-22 11:25:18Z coas-nagasima $
51 */
52
53/*
54 * NTP クライアント
55 */
56
57#include <string.h>
58#include <string.h>
59#include <time.h>
60
61#if defined(TARGET_KERNEL_ASP)
62
63#include <kernel.h>
64#include <sil.h>
65#include <t_syslog.h>
66#include "kernel_cfg.h"
67#include <stdio.h>
68
69#endif /* of #if defined(TARGET_KERNEL_ASP) */
70
71#if defined(TARGET_KERNEL_JSP)
72
73#include <t_services.h>
74#include "kernel_id.h"
75#include "tinet_id.h"
76
77#endif /* of #if defined(TARGET_KERNEL_JSP) */
78
79#include <netinet/in.h>
80#include <netinet/in_itron.h>
81
82#include <netapp/netapp.h>
83#include <netapp/netapp_var.h>
84#include "ntp_cli.h"
85
86/* NTP サーバのポート番号 */
87
88#define NTP_SRV_PORTNO UINT_C(123)
89
90/* NTP サーバのURL */
91
92#define NTP_SRV_URL "ntp.nict.jp"
93
94/* 送信間隔 */
95
96#define SLP_ITV (60*SYSTIM_HZ)
97
98/* 関数 */
99
100void ntp_cli_update_time(T_NTP_CLI_CONTEXT *nc);
101ER ntp_cli_time_synchronization(T_NTP_CLI_CONTEXT *nc, ntp_mode_t mode);
102void ntp_cli_read_time(T_NTP_CLI_CONTEXT *nc, struct timespec *tp);
103void ntp_cli_write_time(T_NTP_CLI_CONTEXT *nc, struct timespec *tp);
104void ntp_cli_read_data(T_NTP_CLI_CONTEXT *nc);
105
106/*
107 * å…
108¨åŸŸå¤‰æ•°
109 */
110
111T_NTP_CLI_CONTEXT ntp_cli;
112
113/* UNIX:1970/1/1 - NTP:1900/1/1 */
114#define TIME_OFS (25567ll * 24 * 60 * 60)
115
116void set_systime_to_ntptime(struct timespec *tp, T_NTP_TIMESTAMP *timestamp)
117{
118 timestamp->integer = htonl((uint32_t)(tp->tv_sec + TIME_OFS));
119 timestamp->fraction = htonl((((unsigned long long)tp->tv_nsec) << 32) / 1000000000ll);
120}
121
122void set_ntptime_to_systime(struct timespec *tp, T_NTP_TIMESTAMP *timestamp)
123{
124 tp->tv_sec = ntohl(timestamp->integer) - TIME_OFS;
125 tp->tv_nsec = ((unsigned long long)(ntohl(timestamp->fraction) * 1000000000ll)) >> 32;
126}
127
128void add_timestamp(T_NTP_TIMESTAMP *dst, T_NTP_TIMESTAMP *a, T_NTP_TIMESTAMP *b)
129{
130 uint32_t ai = ntohl(a->integer);
131 uint32_t af = ntohl(a->fraction);
132 uint32_t bi = ntohl(b->integer);
133 uint32_t bf = ntohl(b->fraction);
134 uint32_t f = af + bf;
135 uint32_t o = ((f < af) || (f < bf)) ? 1u : 0;
136 uint32_t i = ai + bi + o;
137 dst->integer = htonl(i);
138 dst->fraction = htonl(f);
139}
140
141void sub_timestamp(T_NTP_TIMESTAMP *dst, T_NTP_TIMESTAMP *a, T_NTP_TIMESTAMP *b)
142{
143 uint32_t ai = ntohl(a->integer);
144 uint32_t af = ntohl(a->fraction);
145 uint32_t bi = ntohl(b->integer);
146 uint32_t bf = ntohl(b->fraction);
147 uint32_t o = (af < bf) ? 1u : 0u;
148 uint32_t f = af - bf;
149 uint32_t i = ai - bi - o;
150 dst->integer = htonl(i);
151 dst->fraction = htonl(f);
152}
153
154void div2_timestamp(T_NTP_TIMESTAMP *a)
155{
156 uint32_t ai = ntohl(a->integer);
157 uint32_t af = ntohl(a->fraction);
158
159 if ((ai & 1) != 0) {
160 ai >>= 1;
161 af >>= 1;
162 af |= 0x80000000u;
163 }
164 else {
165 ai >>= 1;
166 af >>= 1;
167 }
168
169 a->integer = htonl(ai);
170 a->fraction = htonl(af);
171}
172
173#define NTP_POLL_ASYNC 10 // 1024秒毎に時刻問い合わせ
174#define NTP_POLL_NORMAL 16 // 65536秒毎に時刻問い合わせ
175
176void ntp_cli_initialize(T_NTP_CLI_CONTEXT *nc, ID cepid)
177{
178 nc->cepid = cepid;
179 nc->state = NTP_CLI_STATE_ASYNC;
180 nc->timer = TMO_FEVR;
181 nc->snd_rmt.portno = NTP_SRV_PORTNO;
182 nc->snd_rmt.ipaddr = IPV4_ADDRANY;
183 nc->rcv_rmt.portno = 0;
184 nc->rcv_rmt.ipaddr = IPV4_ADDRANY;
185}
186
187void ntp_cli_execute()
188{
189 ntp_cli.exe_flag = 1;
190 syscall(wup_tsk(ntp_cli.tskid));
191}
192
193void ntp_cli_wakeup(T_NTP_CLI_CONTEXT *nc)
194{
195 int rcv_flag = nc->rcv_flag;
196 nc->rcv_flag = 0;
197
198 if (rcv_flag > 0) {
199 ntp_cli_read_data(nc);
200 return;
201 }
202
203 if (nc->exe_flag != 0) {
204 nc->exe_flag = 0;
205
206 nc->state = NTP_CLI_STATE_ASYNC;
207 nc->timer = 0;
208 }
209}
210
211void ntp_cli_read_data(T_NTP_CLI_CONTEXT *nc)
212{
213 struct timespec tp;
214 T_NTP_MSG *ntp = &nc->ntp_msg;
215
216 // NTP時刻応答の場合
217 if ((ntp->mode == NTP_MODE_SERVER) || (ntp->mode == NTP_MODE_BROADCAST)) {
218 switch (nc->state) {
219 case NTP_CLI_STATE_RESOLVE_ADDR:
220 case NTP_CLI_STATE_ASYNC:
221 break;
222 case NTP_CLI_STATE_REQUEST:
223 // サーバーからの応答時刻を取得
224 memcpy(&nc->receive_timestamp, &ntp->receive_timestamp, sizeof(nc->receive_timestamp));
225 memcpy(&nc->transmit_timestamp, &ntp->transmit_timestamp, sizeof(nc->transmit_timestamp));
226
227 // 現在時刻取得
228 ntp_cli_read_time(nc, &tp);
229
230 // NTP参ç…
231§æ™‚刻に現在時刻を設定
232 set_systime_to_ntptime(&tp, &nc->recv_resp_timestamp);
233
234 // 時刻を更新
235 ntp_cli_update_time(nc);
236
237 nc->state = NTP_CLI_STATE_SYNC;
238 nc->poll = NTP_POLL_NORMAL;
239 nc->timer = (1 << nc->poll) * 1000 * 1000;
240 break;
241 case NTP_CLI_STATE_SYNC:
242 break;
243 }
244 }
245 // NTP時刻要求の場合
246 else if (ntp->mode == NTP_MODE_CLIENT) {
247 // 現在時刻取得
248 ntp_cli_read_time(nc, &tp);
249
250 // NTP受信・送信時刻に現在時刻を設定
251 set_systime_to_ntptime(&tp, &nc->receive_timestamp);
252 set_systime_to_ntptime(&tp, &nc->transmit_timestamp);
253
254 // NTPパケット送信
255 ntp_cli_time_synchronization(nc, NTP_MODE_SERVER);
256 }
257}
258
259void ntp_cli_update_time(T_NTP_CLI_CONTEXT *nc)
260{
261 struct timespec tp;
262 T_NTP_TIMESTAMP dt1, dt2, ofs;
263
264 sub_timestamp(&dt1, &nc->receive_timestamp, &nc->originate_timestamp);
265 sub_timestamp(&dt2, &nc->recv_resp_timestamp, &nc->transmit_timestamp);
266 sub_timestamp(&ofs, &dt1, &dt2);
267 div2_timestamp(&ofs);
268
269 // 差が大きい場合はサーバーの送信時間を設定
270 if (ntohl(ofs.integer) > 2) {
271 memcpy(&nc->reference_timestamp, &nc->transmit_timestamp, sizeof(nc->transmit_timestamp));
272 }
273 else {
274 add_timestamp(&nc->reference_timestamp, &nc->recv_resp_timestamp, &ofs);
275 }
276
277 set_ntptime_to_systime(&tp, &nc->reference_timestamp);
278
279 ntp_cli_write_time(nc, &tp);
280
281 nc->buf[0] = '\0';
282#ifdef __NEED_struct_timespec
283 if (ctime_r(&tp.tv_sec, nc->buf) != NULL)
284#else
285 if (ctime_s(nc->buf, sizeof(nc->buf), &tp.tv_sec) == 0)
286#endif
287 {
288 /* 改行コードの削除 */
289 int len = strnlen(nc->buf, sizeof(nc->buf) - 1);
290 nc->buf[len - 1] = '\0';
291 }
292 else {
293 nc->buf[0] = '\0';
294 }
295
296 syslog(LOG_NOTICE, "[NTP CLI,%d] recv time: %s .%09u",
297 nc->cepid, nc->buf, tp.tv_nsec);
298}
299
300int ntp_cli_get_timer(T_NTP_CLI_CONTEXT *nc)
301{
302 return nc->timer;
303}
304
305void ntp_cli_progress(T_NTP_CLI_CONTEXT *nc, TMO elapse)
306{
307 if (nc->timer <= 0)
308 return;
309
310 nc->timer -= elapse;
311 if (nc->timer < 0)
312 nc->timer = 0;
313}
314
315void ntp_cli_timeout(T_NTP_CLI_CONTEXT *nc)
316{
317 struct timespec tp;
318 char *line;
319
320 if (nc->timer != 0)
321 return;
322
323 switch (nc->state) {
324 case NTP_CLI_STATE_ASYNC:
325#if defined(SUPPORT_INET6) && defined(SUPPORT_INET4)
326 line = lookup_ipaddr(&nc->ipaddr6, NTP_SRV_URL, API_PROTO_IPV4);
327 if (line == NULL || !in6_is_addr_ipv4mapped(&nc->ipaddr6)) {
328 syslog(LOG_NOTICE, "[NTP CLI,%d] sleep %d.%03u[s], unknown host.",
329 nc->cepid, SLP_ITV / SYSTIM_HZ, SLP_ITV % SYSTIM_HZ);
330 nc->timer = SLP_ITV;
331 break;
332 }
333 nc->snd_rmt.ipaddr = ntohl(nc->ipaddr6.s6_addr32[3]);
334#else /* of #if defined(SUPPORT_INET6) && defined(SUPPORT_INET4) */
335 if ((line = lookup_ipaddr(&nc->snd_rmt.ipaddr, NTP_SRV_URL, DEFAULT_API_PROTO)) == NULL) {
336 syslog(LOG_NOTICE, "[NTP CLI,%d] sleep %d.%03u[s], unknown host.",
337 nc->cepid, SLP_ITV / SYSTIM_HZ, SLP_ITV % SYSTIM_HZ);
338 nc->timer = SLP_ITV;
339 break;
340 }
341#endif /* of #if defined(SUPPORT_INET6) && defined(SUPPORT_INET4) */
342 nc->state = NTP_CLI_STATE_RESOLVE_ADDR;
343 nc->timer = 1000;
344 /* through */
345 case NTP_CLI_STATE_RESOLVE_ADDR:
346 // 現在時刻取得
347 ntp_cli_read_time(nc, &tp);
348
349 // NTP開始時刻に現在時刻を設定
350 set_systime_to_ntptime(&tp, &nc->originate_timestamp);
351 memset(&nc->receive_timestamp, 0, sizeof(nc->receive_timestamp));
352 memset(&nc->transmit_timestamp, 0, sizeof(nc->transmit_timestamp));
353
354 // NTPパケット送信
355 ntp_cli_time_synchronization(nc, NTP_MODE_CLIENT);
356
357 // NTP応答待
358ちに遷移、500msでリトライ
359 nc->retry = 0;
360 nc->state = NTP_CLI_STATE_REQUEST;
361 nc->timer = 500 * 1000;
362 break;
363 case NTP_CLI_STATE_REQUEST:
364 nc->retry++;
365 if (nc->retry > 3) {
366 nc->state = NTP_CLI_STATE_ASYNC;
367 nc->poll = NTP_POLL_ASYNC;
368 nc->timer = (1 << nc->poll) * 1000 * 1000; // 1024秒後に時刻同期
369 break;
370 }
371 // 現在時刻取得
372 ntp_cli_read_time(nc, &tp);
373
374 // NTP開始時刻に現在時刻を設定
375 set_systime_to_ntptime(&tp, &nc->originate_timestamp);
376 memset(&nc->receive_timestamp, 0, sizeof(nc->receive_timestamp));
377 memset(&nc->transmit_timestamp, 0, sizeof(nc->transmit_timestamp));
378
379 // NTPパケット送信
380 ntp_cli_time_synchronization(nc, NTP_MODE_CLIENT);
381
382 // NTP応答待
383ちに遷移、500msでリトライ
384 nc->state = NTP_CLI_STATE_REQUEST;
385 nc->timer = 500 * 1000;
386 break;
387 case NTP_CLI_STATE_SYNC:
388 // 現在時刻取得
389 ntp_cli_read_time(nc, &tp);
390
391 // NTP開始時刻に現在時刻を設定
392 set_systime_to_ntptime(&tp, &nc->originate_timestamp);
393 memset(&nc->receive_timestamp, 0, sizeof(nc->receive_timestamp));
394 memset(&nc->transmit_timestamp, 0, sizeof(nc->transmit_timestamp));
395
396 // NTPパケット送信
397 ntp_cli_time_synchronization(nc, NTP_MODE_CLIENT);
398
399 // NTP応答待
400ちに遷移、500msでリトライ
401 nc->state = NTP_CLI_STATE_REQUEST;
402 nc->timer = 500 * 1000;
403 break;
404 }
405}
406
407ER ntp_cli_time_synchronization(T_NTP_CLI_CONTEXT *nc, ntp_mode_t mode)
408{
409 ER_UINT len = sizeof(nc->ntp_msg);
410 T_NTP_MSG *ntp = &nc->ntp_msg;
411 ER error;
412
413 memset(ntp, 0, len);
414
415 ntp->leap_indicator = 0;
416 ntp->version_number = 4;
417 ntp->mode = mode;
418 ntp->stratum = (mode == NTP_MODE_CLIENT) ? 2 : 1;
419 ntp->poll = nc->poll;
420 ntp->precision = 0xfa; // 精度は10^-6(1μs)
421 ntp->root_delay = htonl(0);
422 ntp->root_dispersion = htonl(0);
423 // 同期のための外部的な手段のないサブネット
424 ntp->reference_identifier[0] = 'L';
425 ntp->reference_identifier[1] = 'O';
426 ntp->reference_identifier[2] = 'C';
427 ntp->reference_identifier[3] = 'L';
428 // 参ç…
429§ã‚¿ã‚¤ãƒ ã‚¹ã‚¿ãƒ³ãƒ—
430 memcpy(&ntp->reference_timestamp, &nc->reference_timestamp, sizeof(ntp->reference_timestamp));
431 // 開始タイムスタンプ
432 memcpy(&ntp->originate_timestamp, &nc->originate_timestamp, sizeof(ntp->originate_timestamp));
433 // 受信タイムスタンプ
434 memcpy(&ntp->receive_timestamp, &nc->receive_timestamp, sizeof(ntp->receive_timestamp));
435 // 送信タイムスタンプ
436 memcpy(&ntp->transmit_timestamp, &nc->transmit_timestamp, sizeof(ntp->transmit_timestamp));
437 // 鍵識別子
438 ntp->key_identifier[0] = 0x08;
439 ntp->key_identifier[1] = 0x18;
440 ntp->key_identifier[2] = 0x00;
441 ntp->key_identifier[3] = 0x00;
442
443 if ((error = udp_snd_dat(nc->cepid, &nc->snd_rmt, ntp, len, TMO_NBLK)) != E_WBLK) {
444 syslog(LOG_NOTICE, "[NTP CLI,%d] udp_snd_dat error: %s",
445 nc->cepid, itron_strerror(error));
446 return error;
447 }
448 else
449 syslog(LOG_DEBUG, "[NTP CLI,%d] udp_snd_dat: to: %s.%d",
450 nc->cepid, ip2str(NULL, &nc->snd_rmt.ipaddr), nc->snd_rmt.portno);
451
452 return E_OK;
453}
454
455void ntp_cli_read_time(T_NTP_CLI_CONTEXT *nc, struct timespec *tp)
456{
457 SYSTIM time;
458 ER ret;
459
460 ret = get_tim(&time);
461 if (ret != E_OK) {
462 syslog(LOG_NOTICE, "[NTP CLI,%d] get_tim error: %s",
463 nc->cepid, itron_strerror(ret));
464 tp->tv_sec = 0;
465 tp->tv_nsec = 0;
466 return;
467 }
468
469 tp->tv_sec = time / 1000000ll;
470 tp->tv_nsec = (time % 1000000ll) * 1000ll;
471}
472
473void ntp_cli_write_time(T_NTP_CLI_CONTEXT *nc, struct timespec *tp)
474{
475 SYSTIM time;
476 ER ret;
477
478 time = (tp->tv_sec * 1000000ll) + (tp->tv_nsec / 1000ll);
479
480 ret = set_tim(time);
481 if (ret != E_OK) {
482 syslog(LOG_NOTICE, "[NTP CLI,%d] set_tim error: %s",
483 nc->cepid, itron_strerror(ret));
484 }
485}
486
487/*
488 * ノンブロッキングコールのコールバック関数
489 */
490
491ER
492callback_nblk_ntp_cli (ID cepid, FN fncd, void *p_parblk)
493{
494 T_NTP_CLI_CONTEXT *nc = &ntp_cli;
495 ER_UINT len;
496
497 len = *(ER_UINT*)p_parblk;
498 if (len < 0 && len != E_RLWAI) {
499 /* E_RLWAI 以外で、0 以下の場合は、エラーを意味している。*/
500 syslog(LOG_NOTICE, "[NTP CLI,%d] callback error: %s, fncd: %s", nc->cepid,
501 itron_strerror(len), in_strtfn(fncd));
502 }
503 else {
504 if (fncd == TEV_UDP_RCV_DAT) {
505 if ((len = udp_rcv_dat(nc->cepid, &nc->rcv_rmt, &nc->ntp_msg, len, TMO_POL)) < 0)
506 {
507 syslog(LOG_NOTICE, "[NTP CLI,%d] udp_rcv_dat error: %s", nc->cepid,
508 itron_strerror(len));
509 }
510 else
511 syslog(LOG_DEBUG, "[NTP CLI,%d] udp_rcv_dat len: %d", nc->cepid, len);
512
513 if (len >= sizeof(nc->ntp_msg))
514 nc->rcv_flag = len;
515 else
516 nc->rcv_flag = 0;
517 }
518 syscall(wup_tsk(nc->tskid));
519 }
520
521 return E_OK;
522}
523
524#ifdef NTP_CLI_TASK
525
526/*
527 * NTP クライアント送信タスク
528 */
529
530void
531ntp_cli_task (intptr_t exinf)
532{
533 T_NTP_CLI_CONTEXT *nc = &ntp_cli;
534 ER error, ret;
535 SYSTIM prev, time;
536 int timer;
537
538 get_tid(&nc->tskid);
539 syslog(LOG_NOTICE, "[NTP CLI:%d,%d] started.", nc->tskid, (ID)exinf);
540
541 /* 初期化 */
542 ntp_cli_initialize(nc, (ID)exinf);
543
544 ret = get_tim(&time);
545 if (ret != E_OK) {
546 syslog(LOG_NOTICE, "[NTP CLI,%d] get_tim error: %7lu,%s",
547 nc->cepid, time / SYSTIM_HZ, itron_strerror(ret));
548 return;
549 }
550
551 while (true) {
552 prev = time;
553
554 /* タイマー取得 */
555 timer = ntp_cli_get_timer(nc);
556
557 /* 待
558ち */
559 error = tslp_tsk(timer);
560 if ((error != E_OK) && (error != E_TMOUT)) {
561 syslog(LOG_NOTICE, "[NTP CLI,%d] tslp_tsk error: %s %d",
562 nc->cepid, itron_strerror(error), timer);
563 break;
564 }
565
566 ret = get_tim(&time);
567 if (ret != E_OK) {
568 syslog(LOG_NOTICE, "[NTP CLI,%d] get_tim error: %s",
569 nc->cepid, itron_strerror(ret));
570 break;
571 }
572
573 /* 時間経過 */
574 ntp_cli_progress(nc, time - prev);
575
576 /* 起こされた場合 */
577 if (error == E_OK) {
578 ntp_cli_wakeup(nc);
579 }
580
581 /* タイムアウト処理 */
582 ntp_cli_timeout(nc);
583 }
584}
585
586#endif
Note: See TracBrowser for help on using the repository browser.