4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

オープンソースのRTOS実装・NuttX RTOSでNimのasync/awaitのデモを動かした話

Last updated at Posted at 2023-03-20

はじめに

今回NimとNuttXという選択で、なぜNim?なぜNuttX?そもそもどんな特徴があるの?という話を書く。

プログラミング言語 Nim

Nimはefficient,expressive,elegantを謳っている、静的型つきでコンパイル型のプログラミング言語である。

  • C++やRustにインスパイアされたメモリ管理機能
  • C言語,C++,JavaScriptなど複数のターゲットへコンパイルが可能
  • ASTの書き換えが可能な強力なマクロシステム
  • エレガントな構文

といった点を特徴としてあげている。
より詳細な特徴に関しては公式サイトをみてほしい。

Nimの特徴のひとつとして、言語設計としてhard-real time systems向けにデザインされている点がある。たとえばTLSFアルゴリズムのメモリアロケータ・ARC/ORCメモリモードによる参照カウントベースのメモリ管理・Goto-based exceptionsによる決定論的な例外処理などが実装されている。

さらにNimは現在develでFreeRTOS/Zehpyr/NuttXといった複数のRTOSをサポートしており、一部の標準ライブラリの機能を利用することができる。またNuttXに関しては日本人の開発者の方がポーティング作業を行っている。

今回はNuttX上でNimのサンプルプログラム(async/awaitの利用例)を動かすことに挑戦する。

NuttX

NuttXはオープンソースのRTOS実装である。

国内での利用事例として、ソニーのSpresenseに搭載ということで話題にもなったことがある。NuttXはPOSIX準拠・高機能といったあたりが主な特徴で、詳しくはやはり公式ドキュメントをみることをおすすめする。

個人的にはPOSIXやLinuxのインターフェースの実装で他のオープンソースのRTOSよりportingが充実している点に魅力を感じる。たとえば posix_spawnepoll なんかがわりとそのまま使えたりする。

やっていくぞ

Nimの入手

Nimの入手方法はいろいろ手段があるが、nightlyを使う必要があることを考えるとchoosenimを使うのが一番手っ取り早いだろう。

choosenimをダウンロードしたらdevel channel(実質的にnightly相当)を持ってくる。

$ choosenim devel

NuttXのダウンロード

NuttXのインストールの手順は https://nuttx.apache.org/docs/latest/quickstart/install.html をみればだいたいできるはず。
サンプルプログラムやアプリケーションは別レポジトリで管理されているため、そちらのレポジトリも用意することを忘れずに。

$ mkdir nuttxspace
$ cd nuttxspace
$ git clone https://github.com/apache/nuttx.git nuttx
$ git clone https://github.com/apache/nuttx-apps apps

依存ライブラリなどは各種環境によって違ってくるので、上記公式ドキュメントのgetting startedを読んで用意する。

hello nimを動かす

プログラムの内容

実際に動かしていく前に、少しだけプログラムをみていく。

import std/asyncdispatch
import std/strformat

proc task(id: int): Future[void] {.async.} =
  for loop in 0..2:
    echo &"Hello from task {id}! loops: {loop}"
    if loop < 2:
      await sleepAsync(1000)

proc launch() {.async.} =
  for id in 1..2:
    asyncCheck task(id)
    await sleepAsync(200)
  await task(3)

proc hello_nim() {.exportc, cdecl.} =
  waitFor launch()
  GC_runOrc()

このプログラムの特徴として:

  • async/awaitによる非同期処理で、taskがforループ内でsleepしている間に別のtaskが起動する
  • exportc, cdecl プラグマにより外部のCコードから参照できるように
  • GC_runOrc で明示的にcycle collectorを起動

などがある。

またビルド時にconfig.nimsをNimのスクリプト機能で実行してビルド時の設定を決定するようになっている。

その設定内容として一部を抜粋したものが以下である:

switch "os", "nuttx"
switch "mm", "orc"

switch "arm.nuttx.gcc.exe", "arm-none-eabi-gcc"
switch "arm64.nuttx.gcc.exe", "aarch64-none-elf-gcc"
switch "riscv32.nuttx.gcc.exe", "riscv64-unknown-elf-gcc"
switch "amd64.nuttx.gcc.exe", "x86_64-linux-gnu-gcc"

switch "nimcache", ".nimcache"
switch "d", "useStdLib"
switch "d", "useMalloc"
switch "d", "nimAllocPagesViaMalloc"
switch "d", "noSignalHandler"
switch "threads", "off"
switch "noMain", "on"
switch "compileOnly", "on"
switch "noLinking", "on"
  • os:nuttxを指定
  • mm:orcを指定
  • クロスコンパイル時に利用するコンパイラをswitchで指定
  • NuttXはデフォルトでmmapがないので、useMalloc/nimAllocPagesViaMallocを指定
  • NuttXはデフォルトでシグナル処理をしないのでnoSignalHandlerを指定
  • noMainでNimのメイン関数を利用しないように指定(NimMainの呼び出しなどはC言語のエントリポイントから呼んでいる)
  • 最終的なリンク作業などはNuttX側に任せるので、compileOnly/noLinkingの設定を有効に

などの設定が行われている。

またその他nimPageSizenimMemAlignTinyの設定などいろいろやっているが、マニュアルと照らし合わせながら実際に目で確認することをおすすめする。

今回は指定されていないが、配列の境界チェックなどの機能を使いたい場合はpanics:onフラグをつけることでsysFatal関数が例外を投げようとせずにpanicするようになるので、より大きなプログラムを書く際にデバッグ時に利用するとよいだろう。

NuttX: 設定初期化

次にnuttxの下に移動して設定の初期化を行っていく。

今回は simulator を使うことにするので、以下のようにスクリプトを実行してまず環境の初期化を行う。

$ cd nuttx
$ tools/configure.sh -l sim:nsh # Linuxなので-lにしているが、macOSなら-mにする必要がある

次にTUIベースの設定画面でシステム設定の初期化を行う。

$ make menuconfig

nuttx-appsのhello_nimプログラムを動かすためには一部ネットワークまわりの設定を有効にする必要がある。具体的には以下の設定が有効になっている必要がある。(詳しくは https://github.com/apache/nuttx-apps/pull/1597#issue-1599857833 を参照)

CONFIG_SCHED_CHILD_STATUS=y
CONFIG_NET=y
CONFIG_NET_SOCKOPTS=y

CONFIG_SCHED_CHILD_STATUSは初期状態で有効になっているため、menuconfigで以下の設定を有効にすればよい。

設定を有効にするには、フォーカスが当たっている状態でスペースキーを押して [*] のような表示になっていることを確認できればよい。

Networking Support --->
  [*] Networking Supprt
    Socket Supprt --->
      [*] Socket options
    TCP/IP Networking --->
      [*] TCP/IP Networking

また今回はhello_nimのサンプルプログラムを利用することが目的であるため、このプログラムもビルド対象に含める必要がある。

こちらのプログラムは以下の設定を有効にすることでビルド対象に含めることができる。

Application Configuration --->
  Examples --->
    [*] "Hello, World!" example (Nim)

NuttXはデフォルトの設定では毎度コンソールログインを要求されるので自分はNsh Libraryの設定でConsole Loginを切っているが、
このあたりはお好みで。

ここまでで準備が終わったら、あとはビルドして実行するだけとなる。

$ make

実行結果は以下の通りになるはず。

ループカウントよりも先にタスクのIDがインクリメントしていることを確認してほしい。

$ ./nuttx

NuttShell (NSH) NuttX-12.0.0
nsh> hello_nim
Hello from task 1! loops: 0
Hello from task 2! loops: 0
Hello from task 3! loops: 0
Hello from task 1! loops: 1
Hello from task 2! loops: 1
Hello from task 3! loops: 1
Hello from task 1! loops: 2
Hello from task 2! loops: 2
Hello from task 3! loops: 2
nsh> poweroff

まとめ

オープンソースのRTOSであるNuttX上でNimのサンプルプログラムを動かすことができた。

このサンプルプログラムはasync/awaitといった言語機能や標準ライブラリの機能が使われており、RTOSでそういった機能がすんなり動くというのはわかっていてもやはり驚きがある。

まだポーティング作業も完璧というわけではないが、Nim+NuttXは組み込み向けでRTOSを使う際の有力な選択肢の一つとなりえるポテンシャルを秘めているのではないかと期待している。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?