source: asp3_tinet_ecnl_rx/trunk/ntshell/src/ntp_cli.c@ 374

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

mbed関連を更新
シリアルドライバをmbedのHALを使うよう変更
ファイルディスクリプタの処理を更新

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