スキップしてメイン コンテンツに移動

Nuttx: zoneinfo(time zone)を使用してみる

前回はNTPClientを実行してみましたが、デフォルトではzoneinfo/timezoneの設定は入っていないので、同期できるのはGMT/UTCのみです。当然といえば当然なのですが、ローカルタイムを設定できないかと思いコンフィグをしてみたのですが、少し込み入った結果になったので前回とは別稿で本稿を挙げてみることにしました。なお、ビルドは今回Debianではビルドできず(malloc erro)、ubuntu 2004 LTSでビルドしました。
まず、Configです。前回と今回のコンフィグのdiffは以下の通りです。
$diff -urN boards/arm/stm32/weact-f401ce/configs/rndis_ipv6_ntpc/defconfig \
boards/arm/stm32/weact-f401ce/configs/rndis_tz/defconfig

--- boards/arm/stm32/weact-f401ce/configs/rndis_ipv6_ntpc/defconfig     2021-03-28 03:34:21.000000000 +0900
+++ boards/arm/stm32/weact-f401ce/configs/rndis_tz/defconfig    2021-03-29 19:29:34.283539700 +0900
@@ -22,10 +22,17 @@
 CONFIG_BOARD_LOOPSPERMSEC=8499
 CONFIG_BUILTIN=y
 CONFIG_FS_PROCFS=y
+CONFIG_FS_ROMFS=y
 CONFIG_HAVE_CXX=y
 CONFIG_HAVE_CXXINITIALIZE=y
 CONFIG_HOST_WINDOWS=y
 CONFIG_INTELHEX_BINARY=y
+CONFIG_LIB_ZONEINFO=y
+CONFIG_LIB_ZONEINFO_ROMFS=y
+CONFIG_LIBC_LOCALTIME=y
+CONFIG_LIBC_TZDIR="/etc/zoneinfo"
+CONFIG_LIBC_TZ_MAX_TIMES=370
+CONFIG_LIBC_TZ_MAX_TYPES=20
 CONFIG_MAX_TASKS=16
 CONFIG_MAX_WDOGPARMS=2
 CONFIG_NFILE_DESCRIPTORS=8
つぎに追加のソースおよび変更点です。
# boards/arm/stm32/weact-f401ce/src/stm32_zoneinfo.c
/****************************************************************************
 * boards/arm/stm32/weact-f401ce/src/stm32_zoneinfo.c
 *
 *   Copyright (C) 2015-2016 Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <gnutt@nuttx.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name NuttX nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include <nuttx/drivers/ramdisk.h>
#include <nuttx/zoneinfo.h>

#ifdef CONFIG_LIB_ZONEINFO_ROMFS

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#ifndef CONFIG_LIBC_TZDIR
#  error CONFIG_LIBC_TZDIR is not defined
#endif

#ifdef CONFIG_DISABLE_MOUNTPOINT
#  error "Mountpoint support is disabled"
#endif

#if CONFIG_NFILE_DESCRIPTORS < 4
#  error "Not enough file descriptors"
#endif

#ifndef CONFIG_FS_ROMFS
#  error "ROMFS support not enabled"
#endif

#define SECTORSIZE  64
#define NSECTORS(b) (((b)+SECTORSIZE-1)/SECTORSIZE)

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: stm32_zoneinfo
 *
 * Description:
 *   Mount the TZ database.  The nuttx/zoneinfo directory contains
 *   logic to create a version of the TZ/Olson database.
 *   This database is required if localtime() support is selected via
 *   CONFIG_LIBC_LOCALTIME.  This logic in that directory does the following:
 *
 *   - It downloads the current TZ database from the IANA website
 *   - It downloads the current timezone tools from the same location
 *   - It builds the tools and constructs the binary TZ database
 *   - It will then, optionally, build a ROMFS filesystem image containing
 *     the data base.
 *
 *   The ROMFS filesystem image can that be mounted during the boot-up
 *   sequence so that it is available for the localtime logic.
 *   There are two steps to doing this:
 *
 *   - First, a ROM disk device must be created.  This is done by calling
 *     the function romdisk_register() as described in
 *     nuttx/include/nuttx/drivers/ramdisk.h.  This is an OS level operation
 *     and must be done in the board-level logic before your application
 *     starts.
 *
 *     romdisk_register() will create a block driver at /dev/ramN where N
 *     is the device minor number that was provided to romdisk_register.
 *
 *   - The second step is to mount the file system.  This step can be
 *     performed either in your board configuration logic or by your
 *     application using the mount() interface described in
 *     nuttx/include/sys/mount.h.
 *
 *     These steps, however, must be done very early in initialization,
 *     before there is any need for time-related services.
 *
 ****************************************************************************/

int stm32_zoneinfo(int minor)
{
  char devname[32];
  int  ret;

  /* Create a RAM disk for the test */

  ret = romdisk_register(minor, romfs_zoneinfo_img,
                         NSECTORS(romfs_zoneinfo_img_len), SECTORSIZE);
  if (ret < 0)
    {
      printf("ERROR: Failed to create RAM disk\n");
      return ret;
    }

  /* Use the minor number to create a name for the ROM disk block device */

  snprintf(devname, 32, "/dev/ram%d", minor);

  /* Mount the ROMFS file system */

  printf("Mounting ROMFS filesystem at target=%s with source=%s\n",
         CONFIG_LIBC_TZDIR, devname);

  ret = mount(devname, CONFIG_LIBC_TZDIR, "romfs", MS_RDONLY, NULL);
  if (ret < 0)
    {
      printf("ERROR: Mount failed: %d\n", errno);
      return ret;
    }

  printf("TZ database mounted at %s\n", CONFIG_LIBC_TZDIR);
  return OK;
}

#endif /* CONFIG_LIB_ZONEINFO_ROMFS */
# boards/arm/stm32/weact-f401ce/src/Make.defs
# 以下を追加

ifeq ($(CONFIG_LIB_ZONEINFO_ROMFS),y)
  CSRCS += stm32_zoneinfo.c
endif

#boards/arm/stm32/weact-f401ce/src/weact-f401ce.h
#以下を追加
/****************************************************************************
 *  * Name: stm32_zoneinfo
 *  *
 *  * Description:
 *  *   Mount the TZ database.  The nuttx/zoneinfo directory contains
 *  *   logic to create a version of the TZ/Olson database.
 *  *   This database is required if localtime() support is selected via
 *  *   CONFIG_LIBC_LOCALTIME.  This logic in that directory does the following:
 *  *
 *  *   - It downloads the current TZ database from the IANA website
 *  *   - It downloads the current timezone tools from the same location
 *  *   - It builds the tools and constructs the binary TZ database
 *  *   - It will then, optionally, build a ROMFS filesystem image containing
 *  *     the data base.
 *  *
 *  *   The ROMFS filesystem image can that be mounted during the boot-up
 *  *   sequence so that it is available for the localtime logic.
 *  *   There are two steps todoing this:
 *  *
 *  *   - First, a ROM disk device must be created.  This is done by calling
 *  *     the function romdisk_register() as described in
 *  *     nuttx/include/nuttx/drivers/ramdisk.h.  This is an OS level operation
 *  *     and must be done in the board-level logic before your application
 *  *     starts.
 *  *
 *  *     romdisk_register() will create a block driver at /dev/ramN where N
 *  *     is the device minor number that was provided to romdisk_register.
 *  *
 *  *   - The second step is to mount the file system.  This step can be
 *  *     performed either in your board configuration logic or by your
 *  *     application using the mount() interface described in
 *  *     nuttx/include/sys/mount.h.
 *  *
 *  *     These steps, however, must be done very early in initialization,
 *  *     before there is any need for time-related services.
 *  *
 *****************************************************************************/

#ifdef CONFIG_LIB_ZONEINFO_ROMFS
int stm32_zoneinfo(int minor);
#endif

# boards/arm/stm32/weact-f401ce/src/stm32_bringup.c に追加
int stm32_bringup(void)
{
#前略
#ifdef CONFIG_LIB_ZONEINFO_ROMFS
  /* Mount the TZ database */

  stm32_zoneinfo(3);
#endif
#後略
コンフィグの編集およびその他の編集が済んだら、tools/configure.shでコンフィグを流した後、すぐにコンパイルせずに、
make distclean
tools/configure.sh weact-f401ce/rndis_tz
make context
とした後で、zoneinfoに使用するタイムゾーンを入れます。
たとえば、以下の様にします。
bash
cd /usr/src/nuttx-9.1.0/nuttx/libs/libc/zoneinfo/tzbin/etc
mkdir zoneinfo
cd zoneinfo
cp -a ../localtime .
cp -a ../../usr/share/zoneinfo/GMT* .
cp -a ../../usr/share/zoneinfo/Japan .
cp -a ../../usr/share/zoneinfo/UTC .
cp -a ../../usr/share/zoneinfo/Etc .
mkdir Asia
cp -a ../../usr/share/zoneinfo/Asia/Tokyo Asia/
exit
zoneinfoに使用するタイムゾーンをいれたら、ここでビルドします。なお、タイムゾーンは容量を喰うので、ターゲットのFlash容量などを考慮してください。
ビルドが済んだら書き込みし、実行します。
Mounting ROMFS filesystem at target=/etc/zoneinfo with source=/dev/ram3
TZ database mounted at /etc/zoneinfo

NuttShell (NSH) NuttX-9.1.0
nsh> date
Mon, Mar 29 11:13:08 2021
ここで、環境変数TZをセットしてみますが、期待通りに動作しませんでした。
nsh> ls /etc/zoneinfo
/etc/zoneinfo:
 .
 GMT-0
 localtime
 Japan
 Etc/
 UTC
 Asia/
nsh> set TZ Etc/GMT-9
nsh> date
Mon, Mar 29 11:13:37 2021
さらに、手動で時刻をセットしてみます。(せっかくNTPClientを実行している意味がなくなるので、深い意図はありません。)しかしこれも期待通りに動作しませんでした。
nsh> date -s "Mar 29 11:13:55 2021"
nsh> date
Mon, Mar 29 02:13:58 2021
/etc/zoneinfo/localtimeがGMT0に設定されていて、TZがEtc/GMT-9(UTC+9, GMT+9)の状態でdateコマンドの実行結果は、GMT+9(Eec/GMT-9)ではなくGMT-9(Eec/GMT+9)になりました。なお、Etc/GMT-XはGMT+X(UTC+X)で、Etc/GMT+XはGMT-X(UTC-X)として取り扱われるのが正解です。
少なくともnuttx9.1.0ではどうやらtime zoneの取り扱いがこなれていないようです。そこで全く動作しないのかどうか調べるため、localtimeを呼び出しているアプリを実行してみることにしました。実行したのはBASというBASICのインタープリターです。コンフィグはmake menuconfigで以下を追加しました。
CONFIG_INTERPRETERS_BAS
CONFIG_LIBM
CONFIG_ARCH_FPU
実行結果は以下の様になりました。
Mounting ROMFS filesystem at target=/etc/zoneinfo with source=/dev/ram3
TZ database mounted at /etc/zoneinfo

NuttShell (NSH) NuttX-9.1.0
nsh> date
Mon, Mar 29 11:15:53 2021
nsh> set TZ Etc/GMT-9
nsh> date
Mon, Mar 29 11:16:07 2021
nsh> bas
bas 2.4
Copyright 1999-2014 Michael Haardt.
This is free software with ABSOLUTELY NO WARRANTY.
> print TIME$
20:16:17
> print DATE$
03-29-2021
basでの時刻/localtimeの取り扱いは期待通りに動作していますので、Nuttxのdateコマンドの時刻取り扱いの問題だろうという感じです。
今回は以上です。それでは。

コメント

このブログの人気の投稿

Hyper-V Server2019にワークグループ環境下でWindows10(1809)から接続

Hyper-V server 2019に、ワークグループ環境にてWindows10(1809)から接続してみました。Windows10にHyper-V管理ツールがインストールされていることと、Hyper-V Serverをインストール済であることが前提です。以下、Hyper-V serverは名前がHyperVSV、アドレスは192.168.1.110としています。 まず、Hyper-V server上で、powershellを起動し、以下のコマンドを入力します。 Enable-WSManCredSSP -Role Server -Force 続いて、クライアントのWindows10のpowershell で以下のコマンドを入力します。 winrm quickconfig -Force Enable-WSManCredSSP -Role Client -DelegateComputer * -Force さらに、クライアントマシンで、gpedit(グループポリシーエディタ)を起動し、以下の要領でポリシーを設定します。 a. [コンピューターの構成]->[管理テンプレート]->[システム]->[資格情報の委任]->[NTLMのみのサーバー認証で新しい資格情報の委任を許可する] を有効にし、サーバを一覧に追加[表示...]ボタンをクリックして、「WSMAN/*」を追加 b. [コンピューターの構成]->[管理テンプレート]->[システム]->[資格情報の委任]->[NTLM のみのサーバー認証で保存された資格情報の委任を許可する] を有効にし、サーバを一覧に追加[表示...]ボタンをクリックして、「*」を追加 また、名前解決できるように、(notepadを管理者権限で実行し)C:\Windows\System32\Drivers\etc\hostsにサーバ名とIPアドレスの対を追加。 192.168.1.110 HyperVSV 最後に、Hyper-Vマネージャーを起動し、Windows10からHyper-V サーバに接続します。手順は以下の通りです。 「サーバーに接続」->コンピュータの選択->別のコンピューターに[HyperVSV]と入力し、[別のユーザーとして接続する

wsdd を使ってSamba サーバをネットワークに表示

Windows 10のアップデートで、セキュリティー対応のため、smbv1がデフォルトではインストールされなくなり、Samba serverがエクスプローラーのネットワークに表示されなくなってしまいました。そこで、いくつか方法を調べたのですが、linuxでwsdの実装がないか探したところ、 https://github.com/christgau/wsdd が、見つかりましたので、さっそくインストールしてみました。まだパッケージにはないようですが、インストール自身は簡単です。wsdd自体は以下のように取得し、linkを張っておきます。 cd /usr/local/bin/ sudo wget https://raw.githubusercontent.com/christgau/wsdd/master/src/wsdd.py sudo chmod 755 wsdd.py sudo ln -sf wsdd.py wsdd こちらのsambaサーバはDebianなので、/etc/systemd/system/wsdd.serviceは以下のようにしました。 [Unit] Description=Web Services Dynamic Discovery host daemon Requires=network-online.target After=network.target network-online.target multi-user.target [Service] Type=simple ExecStart=/usr/local/bin/wsdd -d MYDOMAIN [Install] WantedBy=multi-user.target wsdd -d MYDOMAINのところを、環境にあわせて書き換えてください。 次に、systemdに登録・起動テストを行います。 systemctl enable wsdd systemctl start wsdd 起動に成功すると、エクスプローラーのネットワークに表示されます。  なおこのwsddはpython3が必要です。一度試してみてください。SMBv1/CIFSを停止していても、大丈夫です。 cで書かれたほかのwsddの実装もあるようなので、いずれパッケージになるかもしれませ

フレッツ光クロス:MAP-E ROUTER by Debian Box (iptables)

フレッツ光クロスがようやく開通したので、Debianにてrouterを構成し接続してみました。なお、プロバイダーを選ぶにあたっては、IPoE方式がそれぞれ異なるため検討したところ、IPoEでは、MAP-Eでもv6plusとocnバーチャルコネクトがあり、前者がポート数240なのに対し、後者は約4倍のポート数が使えるようなネットの情報をみて、OCNバーチャルコネクトを選択しました。(プロバイダーとしてはぷららです。なおDS-LiteはCE側でのNATではないので今回は見送りました。)そこで、OCN バーチャルコネクトをDebian(iptables)で実現するとどうなるかと思い、ネットの情報を頼りにしつつ、設定した次第です。 実際に試した結果、とりあえず通信できていますが、MAP-Eは本来マッピングルールをマップサーバから取得するはずなので、今回のやり方が正解とはいえませんし、仕様変更されると通信できなくなる可能性があります。あくまでも参考程度ですが、本稿をUPしてみました。 2023/03/16追記: こちら にゲームコンソールNAT越え(Nintendo Switch ナットタイプ A判定)対応版を投稿しました。 2023/03/28追記:※1の記述および3行無効化によりNAT越え(Nintendo Switch ナットタイプ B判定)できるようになりました。 構成は以下の通りです。 ルーターがDebianで回線がOCNバーチャルコネクトであること以外はなにも特別なところはない構成です。 さて、いきなり設定ですが、まず、割り当てられたプレフィックスを確認します。 確認は、 dhclient -6 -d -P enp2s0 とします。出力の中に 前略 RCV: | | X-- IAPREFIX 2400:4050:5c71:af00::/56 後略 このようにプレフィックスが表示されるので、その確認したプレフィックスを書き留めておきます。これを こちらで 入力します。すると、 CE: 2400:4050:5c71:af00:99:f171:c600:2f00 IPv4 アドレス: 153.241.113.198 ポート番号:(1776-1791 2800-2815 3824-3839) 4848-4863 5872-5887 6896-