せっかくTINETを導入したので、 ネットワークを使ったアプリケーションを作ってみます。 まずは、第一歩ということでUDPを使ってパソコンに"HelloWorld"を 送信するプログラムを作ります。 また、ターゲットシステムは秋月のH8/3069fネットワーク対応ボードとします。 μITRONでは、ネットワークに関するAPIについても標準化されていますので、 比較的使いやすくなっているかと思います。
以下にアプリケーションに必要なファイルを示します。 main.h〜main.cfgまでは、ユーザーアプリケーションのプログラムで、 tinet_app_config.h〜tinet_main.cfgまでは、TINETに関するソースコードになります。 また、通常のアプリケーションの場合Makefileは、 configureを実行することで生成されますが、 TINETの場合はTINETのサンプルプログラムを参考に一部修正を加える必要があります。
アプリケーションはシリアルでHelloWorld.と同様に、 1秒周期の周期ハンドラからメッセージタスクを起動します。 メッセージタスクは、起動後UDPで"HelloWorld."を送信します。
| ファイル | 備考 |
|---|---|
| main.h | メインプログラムヘッダ |
| main.c | メインプログラム |
| main.cfg | アプリケーションのコンフィギュレーション |
| tinet_app_config.h | IPアドレス等、TINETコンフィギュレーション・パラメータの定義 |
| route_cfg.c | ルーティングテーブルの定義 |
| tinet_main.cfg | TINETコンフィギュレーションファイル |
| Makefile | アプリケーションのMakefile |
メインプログラムのコンフィギュレーションファイルを以下に示します。 コンフィギュレーションファイルには、電源投入後のエントリーポイントとなるメインタスク(MainTask)、 メッセージをUDP送信するタスク(MessageTask)、1秒周期の周期ハンドラ(cyclic_hander) が宣言されています。 また、TINETを使用するために../../tinet/tinet.cfgをインクルードします。
//------------------------------------------------------------------------------
// UDPでHelloWorld
//------------------------------------------------------------------------------
#define _MACRO_ONLY
#include "main.h"
INCLUDE("\"main.h\"");
CRE_TSK(MAIN_TASK, { TA_HLNG|TA_ACT, 0, MainTask, MAIN_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(MSG_TASK, { TA_HLNG, 0, MessageTask, MID_PRIORITY, STACK_SIZE, NULL });
CRE_CYC(CYCHDR1, { TA_HLNG, 0, cyclic_handler, 1000, 0 });
#include "../../systask/timer.cfg"
#include "../../systask/serial.cfg"
#include "../../tinet/tinet.cfg"
アプリケーションでTINETのAPIを利用するために、nettinet/in.h、 nettinet/in_itron.h、tinet_id.hをインクルードします。 また、送信先のアドレス情報を格納する変数(DestAddr)を用意しておきます。 アドレスを格納するT_IPV4EP型は"tinet/netinet/in.h"に定義されています。
#include <t_services.h> #include <serial.h> #include "kernel_id.h" #include "tinet_id.h" #include <netinet/in.h> #include <netinet/in_itron.h> #include "main.h" //送信先アドレス T_IPV4EP DestAddr;
/*
* ITRON TCP/IPv4 アドレス/ポート番号の定義
*/
typedef struct t_ipv4ep {
UW ipaddr; /* IPv4 アドレス */
UH portno; /* ポート番号 */
} T_IPV4EP;
周期ハンドラにより、1秒おきにcyclic_handlerが呼び出されます。 HelloWorldを送信するためにメッセージタスクを起動します。 なお、周期ハンドラによる呼び出しは非タスクコンテキストに分類されるので、 cyclic_handler内ではUDP送信コードを実行できません。 したがって、iact_tskによってメッセージタスクを起動しています (実際には、起動がキューイングされる)。
//1秒周期イベント
void cyclic_handler(VP_INT exinf)
{
iact_tsk(MSG_TASK);
}
//------------------------------------------------------------------------------
//UDPコールバック関数
ER callback_udp(ID cepid, FN fncd, VP p_parblk)
{
}
//------------------------------------------------------------------------------
UDPによりメッセージを送信するタスクおよび、 アプリケーションのエントリーポイントとなるメインタスクを作成します。 メッセージタスクは"HelloWorld."を送信後、休止状態に移行させます。
//メッセージ送信タスク
void MessageTask(VP_INT exinf)
{
udp_snd_dat(UDP_CEPID, &DestAddr, "HelloWorld.", 12, TMO_NBLK);
ext_tsk();
}
//------------------------------------------------------------------------------
//エントリーポイント
void MainTask(VP_INT exinf)
{
//周期ハンドラの開始
sta_cyc( CYCHDR1 );
//あて先の設定
DestAddr.ipaddr = MAKE_IPV4_ADDR(192,168,0,2);
DestAddr.portno = 12345;
//メインループ
while ( TRUE ) {
slp_tsk();
}
kernel_exit();
}
//------------------------------------------------------------------------------
TINETコンフィギュレーションファイルにて、UDP受付口を生成します。 UDP受付口には、適当なIPアドレスとポートを割り当て、 メインプログラムにおいてあるcallback_udp関数をコールバック関数として登録します。 また、後述しますがTINETでは、アプリケーション側で動的にIPアドレスを変更することも可能です。
//------------------------------------------------------------------------------
// TINET用コンフィグファイル
//------------------------------------------------------------------------------
INCLUDE("\"main.h\"");
#define _MACRO_ONLY
#include "main.h"
// UDP 受付口
UDP_CRE_CEP(UDP_CEPID, { 0, { IPV4_ADDR_LOCAL, 12345 }, (FP)callback_udp } );
ネットワークサンプルプログラム(sample1n)を参考にTINETのパラメータを定義します。 IPアドレス、サブネットマスク、デフォルトゲートウェイ、 ルーティングテーブル数を定義します。IPアドレスの生成には、 MAKE_IPV4_ADDRマクロを使用することができます。
#ifndef _TINET_APP_CONFIG_H_ #define _TINET_APP_CONFIG_H_ //------------------------------------------------------------------------------ // TCP/IP に関する定義 //------------------------------------------------------------------------------ #ifdef SUPPORT_INET4 #define IPV4_ADDR_LOCAL MAKE_IPV4_ADDR(192,168,0,150) #define IPV4_ADDR_LOCAL_MASK MAKE_IPV4_ADDR(255,255,255,0) #define IPV4_ADDR_DEFAULT_GW MAKE_IPV4_ADDR(192,168,0,1) #define NUM_STATIC_ROUTE_ENTRY 3 #define NUM_REDIRECT_ROUTE_ENTRY 1 #endif /* of #ifdef SUPPORT_INET4 */ #endif /* _TINET_APP_CONFIG_H_ */
パラメータ定義同様、 ネットワークサンプルプログラム(sample1n)を参考にルーティングテーブルを作成します。
/*
* ルーティング表
*/
#include <s_services.h>
#include <t_services.h>
#include <tinet_defs.h>
#include <tinet_config.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
//ルーティングテーブルの定義
T_IN4_RTENTRY routing_tbl[NUM_ROUTE_ENTRY] = {
// 異なる LAN、default gateway による間接配送
{ 0, 0, IPV4_ADDR_DEFAULT_GW },
// 同一 LAN 内、直接配送
{ IPV4_ADDR_LOCAL & IPV4_ADDR_LOCAL_MASK, IPV4_ADDR_LOCAL_MASK, 0 },
// 同一 LAN 内へのブロードキャスト、直接配送
{ 0xffffffff, 0xffffffff, 0 },
};
TINETアプリケーション用のMakefileを生成する方法には、 configureにより生成する方法と、 サンプルプログラムのMakefileから生成する方法の2つがあります。 今回は、configureにより生成する方法を用いました。
configureのCPU引数にTINETを指定してMakefileを生成する方法です。 TOPPERSのconfigureは、jsp/config/<CPU名>となるディレクトリが必要なので、 TINET用にダミーのディレクトリを作成します。
$cd jsp/config $mkdir tinet
次に、Makefileを展開する一時フォルダを作成し、 configureを実行してMakefileを生成します。 Makefile以外の生成されたファイルは不要なので削除します。 生成されたMakefileをアプリケーションディレクトリにコピーして修正を行います。
$cd jsp $mkdir napp $cd napp $../configure -C tinet
今回、使用しているシステムは秋月のH8/3069Fボードなので、 CPUにh8を、SYSにakih8_3069fを指定します。 また、カーネルのルートディレクトリへの相対パスをSRCDIRに、 アプリケーション名をUNAMEに指定します。
# ターゲット名の定義 # CPU = h8 SYS = akih8_3069f TOOL =
# ソースファイルのディレクトリの定義 # SRCDIR = ../..
# アプリケーションプログラムに関する定義 # UNAME = main
アプリケーションにあわせて、ネットワークインターフェイス、 デバイスドライバ、ネットワーク層、トランスポート層を指定します。 今回は、IPv4にてUDPを使うので該当項目を以下のように修正しました。
# ネットワークサービスの定義 # # ネットワークインタフェースの選択、何れか一つ選択する。 #NET_IF = loop #NET_IF = ppp NET_IF = ether # イーサネット・ディバイスドライバの選択 NET_DEV = if_ed #PPP_CFG_MODEM = true # PPP で、モデム接続の場合 # ネットワーク層の選択、何れか一つ選択する。 SUPPORT_INET4 = true #SUPPORT_INET6 = true # トランスポート層の選択 #SUPPORT_TCP = true SUPPORT_UDP = true
以上で必要なものがそろったので、makeしてアプリケーションを生成します。 アプリケーションのビルドが完了したら、jsp.srecを書き込んでH8側の準備は完了です。 以上のソースコードを置いておきます。
$make depend $make
TINETでは、いくつか独自APIが用意されています。 独自APIを用いることでユーザープログラム上で、 IPアドレスとルーティングテーブルの変更ができるようになります。
T_IN4_ADDR mask, local, gate; //設定するIPアドレス等 mask = MAKE_IPV4_ADDR(255, 255, 255, 0); local = MAKE_IPV4_ADDR(192, 168, 0, 100); gate = MAKE_IPV4_ADDR(192, 168, 0, 1); //IPアドレスの再設定 in4_add_ifaddr(local, mask); //ルーティングテーブルの再設定 in4_add_route(1, local & mask, mask, 0); in4_add_route(0, 0, 0, gate);