EV3RTを使ってみる(2)

Toppers/EV3RTを使ってプログラムを作成したときの記事です。
この記事を書いた時のEV3RTのバージョンはβ3です。
目次はこちら

前回サンプルプログラムを動作させることができましたので、今回は自分で作ったプログラムを動かしていこうと思います。最初に作るプログラムといえばHelloですね。公式Wikiにも開発方法の説明がありますが、Wikiに書かれている方法とは少し違って、スクラッチから書いていく方法を試してみます 1

まずは、workspace(サンプルプログラムが入っている場所)に新しいディレクトリを作成します。適当にhelloというディレクトリを作成しました。

$ mkdir hello
$ ls
Makefile  gyroboy  helloev3      linetrace  test-cpp  trike
common    hello    hwbrickbench  loader     test-cyc

作成したディレクトリの中にプログラムを作っていくのですが、作成したプログラムをビルドするときに必要となるファイルが上のcommonディレクトリに入っていますので、最初にcommonディレクトリの中のファイルをhelloディレクトリにコピーします。あと、Makefile.incという名前のファイルも必要なので空ファイルを作っておきます。

$ cp common/* hello/
$ touch hello/Makefile.inc
$ ls hello
Makefile.app  Makefile.appmod  Makefine.inc  app_common.cfg

app_common.cfgというファイルまでコピーされていますが、このファイルは無くても問題ありません 2

次に、プログラムを書いていきます。必ずapp.cという名前のソースファイルが必要となるので、app.hとapp.cを作成して、メインの処理を行う関数main_taskを書いていきます 3

まず、app.hは関数の宣言を書くだけです 4

extern void main_task(intptr_t exinf);

次に、ソースファイルを作成していくのですが、単純にHelloと表示するだけでは寂しいので、0.1秒おきにバッテリ電圧とシステム時間を表示するプログラムにしてみました。ev3_*という関数はEV3を制御するためのAPIです。また、tslp_tskという関数はtoppersのAPIで、C言語のselectやJavaのwaitと同じような使い方ができそうです。

#include "ev3api.h"
#include "app.h"

void main_task(intptr_t unused) {
  int battery;
  ulong_t time;
  char battery_str[32];
  char time_str[32];

  while(1){
    battery = ev3_battery_voltage_mV();
    get_tim(&time);

    sprintf(battery_str, "Battery: %d", battery);
    sprintf(time_str, "Time: %ld", time);

    ev3_lcd_set_font(EV3_FONT_MEDIUM);
    ev3_lcd_draw_string("HELLO", 20, 20);
    ev3_lcd_draw_string(battery_str, 20, 40);
    ev3_lcd_draw_string(time_str, 20, 60);

    tslp_tsk(100);
  }
}

最後に、これらのファイルをビルドするための設定ファイルを用意します。この設定ファイルの名前もapp.cfgにしなくてはなりません。このファイルで関数main_taskをタスクに登録するため、main_taskの宣言をしているapp.hを読み込む必要があります。また、コンパイル後にできたオブジェクトファイルapp.oを組み込むように登録しておきます。CRE_TSKというのはToppersの静的APIというものだそうで、この部分で関数main_taskを実行するタスクを作成しています 5

INCLUDE("app_common.cfg");

#include "app.h"

DOMAIN(TDOM_APP) {
CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, TMIN_APP_TPRI + 1, STACK_SIZE, NULL });
}

ATT_MOD("app.o");

最終的に用意したファイルの一覧です。

$ ls hello
Makefile.app     Makefile.inc  app.cfg  app_common.cfg
Makefile.appmod  app.c         app.h

後はビルドしてEV3に転送すれば作成したプログラムが動作します。ビルドとEV3への転送方法は前回と同じ方法で行いました。

$ make mod=hello
rm -rf /opt/ev3rt/workspace/OBJ
configure: Generating Makefile.appmod from ../hello/Makefile.appmod.
...
  LD      app
$ lsz app > /dev/tty.MindstormsEV3 < /dev/tty.MindstormsEV3
Sending: app
Bytes Sent:  88383   BPS:3753                            

Transfer complete

実行すると、Helloという文字列とバッテリ電圧とシステム時間だけが表示されます。EV3のバッテリ電圧は安定しているみたいですね。
2015-03-04-1

Notes:

  1. 現在(2015年3月4日)のところは既存のサンプルプログラムを拡張する方法が書かれています。
  2. あっても問題ありません
  3. 後でこの関数名を登録するので、他の関数名にしても動かすことはできます。
  4. サンプルプログラムではTOPPERS_MACRO_ONLYという定義のチェックをしていますが、これはアセンブラからC言語のヘッダファイルを読み込むための定義のようですので、アプリケーションには不要、、、だと思います。
  5. このタスクを自動で実行するためにTA_ACTを指定しています。あとはタスクの優先度とスタックサイズを指定しています。