注意 : この日本語版文書は参考資料としてご利用ください 最新情報は必ずオリジナルの英語版をご参照願います AN1108 Microchip 社の BSD ソケット API 対応 TCP/IP スタック Author: Abdul Rafiq Microchip Technology Inc. はじ

42 

Loading....

Loading....

Loading....

Loading....

Loading....

全文

(1)

AN1108

はじめに

Microchip 社の BSD ソケット API 対応 TCP/IP スタッ クはインターネット TCP/IP 通信用のソケット ライブ ラリを提供します (BSD: Berkley Socket Distribution)。 この汎用ソケット プログラミング インターフェイス は、カリフォルニア大学バークレー校によって開発さ れ ま し た。Microsoft® Windows®、UNIX®、Linux®

eCOS™ と多数の商用 TCP/IP スタックが BSD ソケッ ト API をサポートしています。共通のプログラミング インターフェイスを使うため、全く異なるプラット フォームにも簡単にアプリケーションを移植できま す。例えば、組み込みプラットフォームに BSD ライ ブラリ API を実装すれば、パーソナル コンピュータ環 境向けに書かれたネットワーク アプリケーションを 組み込み環境向けにコンパイルする事も可能です。 本書は、BSD ソケット API を備えた Microchip 社製 TCP/IP スタックについて説明します。本書は、ブログ ラム作成者のためのリファレンス ガイドとしてお使 い頂けます。本書は下記の内容を含みます。 • 組み込み環境におけるクライアント / サーバ アプリ ケーションの作成 • TCP/IP スタックの構成要素と設計 • スタックのビルド • API にインクルードされたソケット関数

前提条件

本書は Microchip MPLAB® IDE、MPLAB® REAL ICE™

インサーキット エミュレータ、C 言語、ソケット プ ログラミングに詳しい読者を対象としています。本書 では、これらの技術に関する専門用語を使いますが、 それらの概念について詳しく解説しません。より詳細 な情報が必要な読者は、関連する仕様書もお読みくだ さい。

機能

BSD ソケット API 対応 TCP/IP スタックの主な特長は 以下の通りです。 • 並行サーバをサポート • アプリケーションはサーバまたはクライアント ( ま たはその両方 ) として動作可能 • 組み込みアプリケーション向けに最適化 • 全二重通信 • ストリーム型とデータグラム型ソケットをサポート • IP アドレス解決をバックグラウンドで実行 • 必要に応じてカーネル /RTOS との併用が可能

制限事項

このスタックは PIC® MCU を使った組み込みプラット フォーム向けに設計されており、組み込み環境に特有 の制限があります。制限事項には下記を含みます。 • ソケット API は、オリジナルの BSD ソケットライ ブラリの全てではなく一部を実装する • API 関数の挙動はオリジナルの BSD ライブラリとは 異なる • 全ての API 関数はノンブロッキングである

システム ハードウェア

この BSD ソケット対応 TCP/IP スタックは、Microchip 社製 Explorer 16 プラットフォーム上で、Microchip 社 製ネットワーク チップ ENC28J60 (10 Mbps、MAC/ PHY Ethernet コントローラ内蔵 ) を使って開発されま した。このスタックは、他の PIC マイクロコントロー ラに容易に移植できます。このスタックは、Microchip 社製 PIC マイクロコントローラの新製品のリリースに 合わせて更新されます。 BSD ソケット API 対応 TCP/IP スタックのブロック図 を図 1 に示します。 図 1: MICROCHIP TCP/IP スタック ハードウェ アのブロック図

Author: Abdul Rafiq

Microchip Technology Inc.

MAGNETICS ENC28J60 Ethernet Controller SPI PIC® Microcontroller

(2)

PIC

®

のメモリリソース要件

最小限のアプリケーション プログラム ( 本書に付属す るデモ アプリケーション等 ) を使う場合、現在のス タックはフラッシュおよび RAM メモリを下記のよう に消費します。 フラッシュ : 23649 byte RAM: 2944 byte これらは、Microchip MPLAB® C32 C コンパイラ ( バー ジョン 1.0、コンパイラおよびリンカ設定は既定値 ) を 使った場合の値です。さらなる最適化については、 MPLAB C32 C コンパイラの関連文書を参照してくだ さい。

PIC

®

のハードウェア リソース要件

下表は、Microchip 社製 TCP/IP スタックと ENC28J60 Ethernet コントローラ間の接続に使う I/O ピンの一覧 です。これらのポートは eTCP.def 内で定義され、 ユーザによる変更が可能です。

表 1: TCP/IP と ENC28J60 の接続ピン

PIC® I/O ピン Ethernet コントローラピン

RD0 ( 出力 ) チップセレクト RE8 ( 入力 ) WOL ( 未使用 ) RE9 ( 入力 ) 割り込み RD15 ( 出力 ) リセット RF6 ( 出力 ) SCK RF7 ( 入力 ) SDO RF8 ( 出力 ) SDI

(3)

ソースファイルのインストール

Microchip 社のウェブサイトから、TCP/IP スタッ クの完全なソースコードをダウンロードできます (「ソースコード」、p. 40 参照 )。ソースコードは、 1 つ の Windows 用 イ ン ス ト ー ル フ ァ イ ル (pic32mx_bsd_tcp_ip_v1_00_00.zip) に収めら れています。 インストール手順は下記の通りです。 1. 圧縮ファイルを解凍します(その中にinstallation.exe ファイルが含まれます )。 2. installation.exe ファイルを実行します (Windows のインストール ウィザードに従ってインストー ルします )。 3. ソフトウェア使用許諾契約への同意が求められた ら、[ 同意する ] をクリックします。 4. インストールが完了すると、「Microchip」プログ ラム グループに「TCP/IP Stack with BSD Socket

API」が追加されます。全てのソースコードは、コ ン ピ ュ ー タ の ル ー ト ド ラ イ ブ 内 の 「pic32_solutions」ディレクトリにコピーされ ます。 5. version.log ファイルを開き、最新バージョン で変更または追加された機能と制限事項について 確認してください。 下表に、スタックのソースファイルとヘッダファイル の一覧を示します。 表 2: TCP/IP スタックのヘッダファイルとソースファイル ソースファイル ヘッダファイル ディレクトリ 内容

earp.c earp.h pic32_solutions\microchip\ bsd_tcp-ip\source

ARP パケットハンドラ関数 block_mgr.c block_mgr.h pic32_solutions\microchip\

bsd_tcp-ip\source メモリブロック マネージャ関数 ENC28J60.c ENC28J60.h MAC.h pic32_solutions\microchip\ bsd_tcp-ip\source Microchip Ethernet コントローラ向けドライバ ether.c ether.h pic32_solutions\microchip\

bsd_tcp-ip\source

Ethernet (MAC) 層ハンドラ gpfunc.c gpfunc.h pic32_solutions\microchip\

bsd_tcp-ip\source

ユーティリティ関数 eicmp.c — pic32_solutions\microchip\

bsd_tcp-ip\source

ICMP (Ping) メッセージ ハンドラ eip.c eip.h pic32_solutions\microchip\

bsd_tcp-ip\source

IP 層関数 etcp.c etcp.h pic32_solutions\microchip\

bsd_tcp-ip\source

TCP 層関数 eudp.c eudp.h pic32_solutions\microchip\

bsd_tcp-ip\source

UDP 層関数 pkt_queue.c pkt_queue.h pic32_solutions\microchip\

bsd_tcp-ip\source

一般的パケット FIFO キューの実装 route.c route.h pic32_solutions\microchip\

bsd_tcp-ip\source MAC-IP 間マッピング関数 socket.c sockAPI.h socket.h pic32_solutions\microchip\ bsd_tcp-ip\source ソケット API 実装関数 StackMgr.c pic32_solutions\microchip\ bsd_tcp-ip\source コア スタックプロセス マネージャ Tick.c Tick.h pic32_solutions\microchip\

bsd_tcp-ip\source タイムアウト生成用 Timer Tick 関数 — Compiler.h pic32_solutions\microchip\ bsd_tcp-ip\source コンパイラ依存 typedefs — eTCPcfg.h pic32_solutions\microchip\ bsd_tcp-ip\source スタック幅の設定 ( ユーザ アプリケーション のカスタマイズ用 ) — NetPkt.h pic32_solutions\microchip\ bsd_tcp-ip\source スタックの TCP/IP パケット構造体

(4)

デモ アプリケーション

本書に付属するデモ アプリケーションは、ストリーム 型ソケットを使うクライアント / サーバ アプリケー ションのサンプルを提供します。このデモには、デー タグラム型ソケット向けのサンプルも含まれていま す。ターゲット ハードウェアの設定については「シス テム ハードウェア」、p. 1 を参照してください。デモ アプリケーションを実行するには、ターゲット プラッ トフォームに加えて、Microsoft Windows が動作する ホスト コンピュータが必要です。ホスト側のデモ ア プリケーションは、ターゲット ハードウェアとの通信 用に各種の API を使います。ホスト コンピュータと ターゲットボードは同一ネットワークに接続する必要 があります。アプリケーションを作成する前に、実際 のセットアップに合わせて eTCP.def コンフィグレー ション ファイル内の #defines を適切に変更する必要 があります (「スタックのコンフィグレーション」、p. 9 参照 )。ホスト コンピュータとターゲット ハードウェ ア 間 の 接 続 を 確 立 す る に は、少 な く と も DEFAULT_IP_ADDR を 変 更 す る 必 要 が あ り ま す。 DHCP を使う場合、DHCP サーバによって IP アドレ スが割り当てられます。 PIC® マイクロコントローラからホスト コンピュータ上 のサーバ アプリケーションに対してクライアント接続 を実行する場合、bsd_socket_demo\source\main.c ソースファイル内でコンピュータの IP アドレスも変更 する必要があります(#define PC_SERVER_IP_ADDRを、 ホスト側アプリケーション ソフトウェアを実行するコ ンピュータの IP アドレスに変更 )。コンピュータの IP アドレスは、コマンド プロンプトから「ipconfig」を 実行すると表示されます。

デモ ファームウェアのビルド

本書に付属するデモ アプリケーションは、MPLAB C32 C コンパイラを使ってビルドされています。デモ アプリケーションをビルドするための手順を以下で説 明します。この手順は MPLAB IDE の使用を前提とし ており、MPLAB IDE の使用に関する知識が必要です。 MPLAB IDE によるプロジェクトの作成、オープン、ビ ルドの方法を知らない読者は、MPLAB IDE のオンラ インヘルプを参照してください。 1. Microchip 社製スタックのソースファイルがイン ストール済みである事を確認します。インストー ル方法は「ソースファイルのインストール」、p. 3 を参照してください。 2. MPLAB IDE を起動し、プロジェクトファイル bsd_socket_demo\bsd_socket_demo.mcw を開きます。 3. eTCP.def を開き、使用するターゲットボードに 応じて SPI ポートとその他の定義を設定します。 ENC28J60 ボードを備えた Explorer 16 ボードを 使う場合、既定値設定を変更する必要はありませ ん。 4. eTSP.def 内で既定値のIP アドレス、IP マスク、 MAC アドレス、ゲートウェイ アドレスを設定し ます。これらの定義は、使用するネットワークの 設定に適合している必要があります。DHCP サー バを使う場合、これらの設定を変更する必要はあ りません。 5. MPLAB IDE のメニューコマンドを使ってプロ ジェクトをビルドします。 6. 正しくビルドされなかった場合、MPLAB IDE と MPLAB C32 C コンパイラのセットアップを確認 してください。 ソースファイルの一覧は「ソースファイルのインス トール」に記載しています。

(5)

デモ ファームウェアのプログラミングと実行

ターゲットボードにデモ アプリケーションをプログ ラミングするには、PIC マイクロコントローラにアク セスする必要があります。以下の手順では、MPLAB REAL ICE インサーキット エミュレータをプログラマ として使います。他のプログラマを使う場合は、それ らの使用説明書を参照してください。

1. MPLAB REAL ICE インサーキット エミュレータ を Explorer 16 ボード ( または他のターゲットボー ド ) に接続します。 2. ターゲットボードに電源を投入します。 3. MPLAB IDE を起動します。 4. 使用する PIC デバイスを選択します ( この手順は、 以前にビルドした HEX ファイルをインポートす る場合にのみ必要です )。

5. MPLAB REAL ICE インサーキット エミュレータ をプログラマとして有効にします。 6. 以前にビルドした HEX ファイルを使う場合、プ ロジェクト HEX ファイルをインポートします。 7. HEX ファイルをリビルドする場合、適切なデモ プ ロジェクト ファイルを開き、ビルド手順に従って アプリケーション HEX ファイルを作成します。 8. MPLAB REAL ICE インサーキット エミュレータ

のメニューから [Program] オプションを選択して ターゲットのプログラミングを開始します。 9. 数秒後に、「Programming successful」というメッ

セージが表示されます。このメッセージが表示さ れない場合、ボードと MPLAB REAL ICE の接続 を確認してください。 問題が解消しない場合、メ ニューバーの [Help] をクリックしてください。 10. ターゲットボードの電源を OFF にし、ボードから

MPLAB REAL ICE ケーブルを切り離します。 11. ボードに再度電源を投入します。DHCP サーバと ターゲットボードが同じ Ethernet ネットワークに 接続されていれば、デモ ファームウェアが動作を 開始して、ENC28J50 ドータボード上の黄 LED が 点滅します。

TCP/IP ネットワークの試験

「ping」ユーティリティを使うと、デモプログラムを実 行する前にホストとターゲットボード間の TCP/IP 通 信リンクをテストできます。ホスト コンピュータのコ マンドプロンプト ウィンドウで、下記のように「ping」 に続けてターゲットボードの IP アドレスを入力しま す。 C:\> ping 10.10.33.201 この場合、IP アドレス 10.10.33.201 のターゲットボー ドに対して ping 要求が送信されます。ネットワークが 正しく設定され、ターゲットがホスト コンピュータと 同じネットワークに接続されていれば、コマンドプロ ンプトに応答メッセージが表示されます。ターゲット ボードと通信できなかった場合、各 ping 要求に対して タイムアウト メッセージが表示されます。ping に対し て応答が返されない場合、ターゲットボードの LED が 「デモ ファームウェアのプログラミングと実行」に記 載したように動作している事を確認してください。ま た、ネットワーク設定 (IP アドレスとサブネットマス クを含む ) も確認してください。コンピュータとボー ドの間にルータが接続されている場合、ボードには ルータ ゲートウェイ アドレスを正しく設定する必要 があります。

デモ アプリケーションの実行

ホスト コンピュータ側のアプリケーションには下記 の 3 種類があり、ターゲットボード上のデモアプリ ケーションとの通信方法に応じて使い分けます。 • TCPClientAPP • TCPServerAPP • UDPApp ホスト ソフトウェア プログラムは、コンピュータの メイン インストール フォルダ内の「PCTestCode」 フォルダに保存されます。 これらを実行するには、プログラム実行ファイルを起 動します。 次のページで、各デモ アプリケーションについて詳し く説明します。

(6)

TCPCLIENTAPP TCPClientAPP は Windows ベースの TCP クライアン ト アプリケーションです。このアプリケーションは、 ターゲットボード上で動作するデモ TCP サーバ アプ リケーションに対して接続を要求します。このプログ ラムを実行するには、コマンド プロンプト ウィンド ウを開き、下記のようにプログラム名に続けてター ゲットボードの IP アドレスを入力します。 C:\> TCPClientApp 10.10.33.201 このアプリケーションは、ターゲットボード上で動作 するデモ TCP サーバに対して接続を試みます。接続が 確立すると、このアプリケーションは 1 つの TCP ソ ケットを使って 50 個のメッセージを交換します。こ のプログラムの出力を図 2 に示します。 図 2: TCPCLIENTAPP プログラムの出力 TCPSERVERAPP TCPServerAPP は Windows ベースの TCP サーバ アプリ ケーションです。このアプリケーションは、ターゲット ボード上で動作するデモ クライアント アプリケーショ ンからの接続要求を承認します。このプログラムを実行 する前に、コンピュータの IP アドレスを demo.c ソー スファイルにコピーしておく必要があります。これを行

うには、demo.c 内の #define PC_SERVER_IP_ADDR 宣言をコンピュータの IP アドレスに設定します。コマ ンド プロンプトからこのサーバ アプリケーションを 起動すると、ターゲットボード上で動作するクライア ント アプリケーションがサーバへの接続を試み、接続 が確立するとデータを交換します。このプログラムの 出力を図 3 に示します。 図 3: TCPSERVERAPP プログラムの出力 UDPAPP

UDPApp は Windows ベース UDP アプリケーションで す。このアプリケーションは、データグラム型ソケッ トを介してターゲットボード上のデモ ファームウェア との間でメッセージを交換します。このアプリケー 図 4 に、このプログラムの動作例を示します。この例 の場合、ターゲットボードのIPアドレスは10.10.33.201 です。

(7)
(8)

アプリケーションへの組み込み

スタックをユーザ アプリケーションに組み込む方法 は 2 通りあります。本アプリケーション ノートに付属 する PIC32 デモ アプリケーション MPLAB プロジェク トをそのまま使えば、簡単にデモを始める事ができま す。別の方法として、main.c ファイルにお客様のア プリケーション コードを追加し、お客様が用意したそ の他の .c および .lib ファイルをプロジェクトにイ ンクルードできます。この方法が使えない場合、BSD スタックのファイルをお客様の既存プロジェクトにイ ンクルードする事もできます。 スタックの初期化と実行のために、main() 関数を下 記のように変更します。 #include <plib.h> #include "bsd_dhcp_client\dhcp.h" ... main() { ... SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit(); DHCPInit(); ... while(1) { StackMgrProcess(); DHCPTask(); ... ... } ... } 詳細は「スタックの使用」、p. 16 を参照してください。

(9)

スタックのコンフィグレーション

各種のコンフィグレーション オプションを設定する 事で、お客様のアプリケーションに合わせてスタック をカスタマイズできます。コンフィグレーション オプ ションは eTCP.def ファイル内で定義します。オプ ションを変更した場合、スタックをクリーンビルドす る必要があります。 スタックのカスタマイズには、以下のオプションが使 えます。

DEFAULT_IP_ADDR

目的 : 起動時にデバイスの IP アドレスを設定します。 前提条件 : なし 有効値 : ピリオドで区切った十進数の IP アドレスを引用符で囲んだ ASCII 文字列 例 : #define DEFAULT_IP_ADDR “10.10.33.201”

DEFAULT_MAC_ADDR

目的 : 起動時の MAC アドレス ( 既定値 ) を設定します。 前提条件 : なし 有効値 : ダッシュで区切った MAC アドレスを引用符で囲んだ ASCII 文字列 例 :

#define DEFAULT_MAC_ADDR “00-04-a3-00-00-00”

DEFAULT_IP_GATEWAY

目的 : ルータ / ゲートウェイの IP アドレスを設定します。 前提条件 : なし 有効値 : ピリオドで区切った十進数の IP アドレスを引用符で囲んだ ASCII 文字列 例 : #define DEFAULT_IP_GATEWAY “10.10.33.201”

DEFAULT_IP_MASK

目的 : 起動時にデバイスの IP アドレスマスクを設定します。 前提条件 : なし 有効値 : ピリオドで区切った十進数のマスク値を引用符で囲んだ ASCII 文字列 例 : #define DEFAULT_IP_ADDR “255.255.255.0”

CLOCK_FREQ

目的 : 周辺モジュール クロックの周波数を定義します。この値は、TMR0 および SPBRG 値を計算する ために Tick.c および Debug.c ファイルによって使われます。これは、お客様のアプリケー ションでも使えます。 前提条件 : なし 有効値 : PIC32 の周辺モジュール クロック仕様レンジ内の値 例 :

(10)

MAX_SOCKET

目的 : アプリケーションが開く事のできるソケットの最大数を設定します。各ソケットは最大で 80 byte のメモリを消費します。MAX_SOCKET を定義する際は、ソケット配列に必要なメモリ容量をシス テムが提供可能である事を確認する必要があります。 前提条件 : なし 有効値 : 1 ~ 65535 の整数値 例 : #define MAX_SOCKET 8

TICKS_PER_SECOND

目的 : 1 秒間のティック数を定義します。 前提条件 : なし 有効値 : 1 ~ 65535 の整数値 例 : #define TICKS_PER_SECOND 10

TX_COLLSION_TIMEOUT

目的 : ENC28J60 の B1 エラッタ向けに、送信コリジョン タイムアウトを設定する必要があります。こ れは、TICKS_PER_SECOND の 0.05 ~ 0.20 倍の範囲で設定する事を推奨します。このエラッタ の詳細は、ENC28J60 エラッタ文書を参照してください。 前提条件 : なし 有効値 : TICKS_PER_SECOND の0.05 ~ .20 倍 例 : #define TX_COLLSION_TIMEOUT((WORD)(TICKS_PER_SECOND * .15))

(11)

TCP_DEFAULT_TX_BFR_SZ

目的 : ストリーム型ソケットを使ってデータを送信する場合の既定値バッファサイズを定義します。こ の値は、setsocketopt API 関数を使って上書きできます。 前提条件 : なし 有効値 : 1 ~ 65535 の整数値 例 :

#define TCP_DEFAULT_TX_BFR_SZ 80 //Set the default Tx Buffer to 80 bytes.

NAGGLES_TX_BFR_TIMEOUT

目的 : スタックが送信バッファをホールドしている時のタイムアウト条件をティック数で定義します。 このタイムアウトが発生すると、スタックはデータパケットを送信します。スタックは、帯域幅 を最大限に使って、TX バッファに可能な限り書き込もうとします。このタイムアウト値は、ス タックが現在の TX パケットを送信用に転送する前の待機時間を定義します。 前提条件 : なし 有効値 : 1 ~ 65535 の整数値 例 : #define NAGGLES_TX_BFR_TIMEOUT(TICKS_PER_SECOND * 0.2)

ARP_TIMEOUT_TICKS

目的 : このタイムアウト値は、スタックがリモートノード MAC アドレスを要求する際に、リモートノー ドからの応答を待機する時間を設定します。通常、このタイムアウト値は数秒~ 20 または 30 秒 の範囲で設定します。この遅延を長くすると、リモートノードが応答しない場合にアプリケーショ ンの待機時間が長くなります。この遅延時間は ARP_TIMEOUT_TICKS / TICKS_PER_SECOND 秒です。 前提条件 : なし 有効値 : 1 以上かつユーザ定義タイムアウト値以下の整数値 例 : ティックが 1000/s に設定されている場合、50 を指定するとタイムアウトは 50 ms になります。 #define ARP_TIMEOUT_TICKS 50 // i.e. 50 Ticks / (1000Ticks/Sec) = .050sec

MAX_RETRY_COUNTS

目的 : パケットを破棄する前に実行する再送信の最大回数を定義します。再送信は、ピアノードがパケッ トに対して肯定応答 (ACK) を返さなかった場合に発生します (TCP ソケットの場合のみ )。 前提条件 : なし 有 効値 : 1 ~ 65535 の整数値 例 : #define MAX_RETRY_COUNTS 1

TCP_RETRY_TIMEOUT_VAL

目的 : 再送信から次の再送信までの時間をティック数で定義します。 前提条件 : なし 有 効値 : 1 ~ 65535 の整数値 例 :

#define TCP_RETRY_TIMEOUT_VAL (TICKS_PER_SECOND * 5) // 5 sec interval between resends.

(12)

MAX_TCP_TX_PKT_BFR

目的 : スタックは、ピアが肯定応答 (ACK) を返すまで、TCP 送信パケットをバッファリングします。こ のオプションは、バッファリング可能な最大パケット数を定義します。バッファリング中のパケッ ト数がこの値に達すると、後続の SEND AP の呼び出しはエラーコード SOCKET_TX_NOT_READY を返します。 前提条件 : なし 有 効値 : 1 ~ 65535 の整数値 例 : #define MAX_TCP_TX_PKT_BFR 2

TCP_WAIT_SOCKET_DEL

目的 : ピアによって正常に閉じられなかったソケットを削除する前の待機時間をティック数で定義しま す。これは、アプリケーションがそのソケットに対して既に closesocket API を呼び出し済み である場合にのみ適用されます。 前提条件 : なし 有 効値 : 1 ~ 65535 の整数値 例 :

#define TCP_WAIT_SOCKET_DEL (TICKS_PER_SECOND * 7) // Set timeout to 7 sec

STACK_MGR_RX_PKT_CNT

目的 : StackMgrProcess() API が呼び出された時に処理する受信パケットの最大数を定義します。大 量の受信パケットを処理する必要がある場合、Ethernet コントローラからのパケットを RAM に コピーするバッファが利用できるのであれば、この設定値を大きくできます。 前提条件 : なし 有効値 : 1 ~ 255 の整数値 例 : #define STACK_MGR_RX_PKT_CNT 3

ENABLE_HEAP_PKT_ALLOCATION

目的 : スタック ソフトウェアが静的メモリに加えてヒープ上にも送信および受信パケットバッファを 割り当てる事ができるようにします。 前提条件 : なし 有効値 : なし 例 : #define ENABLE_HEAP_PKT_ALLOCATION

MAX_HEAP_PKTS

目的 : ヒープに割り当て可能な最大パケット数を設定します。 前提条件 : ENABLE_HEAP_PKT_ALLOCATION も定義する必要があります。 有効値 : 1 以上かつターゲットメモリがサポート可能な最大パケット数以下の整数値 例 :

(13)

MGR_BLOCK_SIZE

目的 : TCP/IP パケットを保持するためのメモリブロックのサイズを定義します。メモリの総割り当て容 量は MGR_MAX_BLOCKS の MGR_BLOCK_SIZE 倍です。このメモリは静的に割り当てられます。 静的メモリ マネージャは、サイズ MGR_BLOCK_SIZE のメモリブロックのプールを作成します。 スタックは最初にこれらのブロック (1 つまたは複数 ) にパケットを割り当てようとします。これ が不可能な場合、ENABLE_HEAP_PKT_ALLOCATION 定義によってヒープの使用が可能になって いれば、スタックはパケットメモリの malloc を試みます。 前提条件 : なし 有効値 : 25 以上かつターゲットメモリがサポート可能な最大パケットサイズ以下の整数値。一般的に、パ ケットの大部分は 100 byte よりも小さいため、スタックはこれらのブロックをメモリプールの一 部として効率的に使ってメッセージ ストリームを処理します。 例 :

#define MGR_BLOCK_SIZE 50 //defines the size of memory block to be 50 bytes.

MGR_MAX_BLOCKS

目的 : パケットの静的メモリプールに割り当てるブロックの最大数を定義します。メモリの総割り当て量は MGR_MAX_BLOCKS の MGR_BLOCK_SIZE 倍です。静的メモリ マネージャは、サイズ MGR_BLOCK_SIZE のメモリブロックのプールを作成します。スタックは最初にこれらのブロック (1 つまたは複数 ) にパケットを割り当てようとします。これが不可能な場合、ENABLE_HEAP_PKT_ALLOCATION 定義によってヒープの使用が可能になっていれば、スタックはパケットメモリの malloc を試み ます。 前提条件 : なし 有効値 : 1 以上かつターゲットメモリがサポート可能な最大パケットサイズ以下の整数値 例 :

#define MGR_MAX_BLOCKS16 //defines max of 16 blocks for static packet allocation

mSetUpCSDirection

目的 : ENC28J60 のチップセレクト ポートピンを出力として設定します。 前提条件 : なし

有効値 : N/A 例 :

#define mSetUpCSDirection() { mPORTDSetPinsDigitalOut(BIT_14); } // RD14 as CS

mSetCSOn

目的 : ENC28J60 のチップセレクトをターンオン ( アサート ) します。 前提条件 : なし

有効値 : N/A 例 :

#define mSetCSOn() { mPORTDClearBits(BIT_14); }

mSetCSOff

目的 : ENC28J60 のチップセレクトをターンオフ ( ネゲート ) します。 前提条件 : なし

有効値 : N/A 例 :

(14)

mSetUpResetDirection

目的 : ENC28J60 のリセット ポートピンを設定します。 前提条件 : なし

有効値 : N/A 例 :

#define mSetUpResetDirection() { mPORTDSetPinsDigitalOut(BIT_15); } // RD15=Reset

mSetResetOn

目的 : ENC28J60 のリセット ポートピンをターンオン ( アサート ) します。 前提条件 : なし

有効値 : N/A 例 :

#define mSetResetOn() { mPORTDClearBits(BIT_15); }

mSetResetOff

目的 : ENC28J60 のリセット ポートピンをターンオフ ( ネゲート ) します。 前提条件 : なし

有効値 : N/A 例 :

#define mSetResetOff() { mPORTDClearBits(BIT_15); }

mSetUpWOLDirection

目的 : ENC28J60 の WOL (Wake-On-LAN) ポートピンを設定します。 前提条件 : なし

有効値 : N/A 例 :

#define mSetUpWOLDirection() { mPORTESetPinsDigitalIn(BIT_8); } // RE8=WOL

mSetUpINTDirection

目的 : ENC28J60 の割り込みポートピンを設定します。 前提条件 : なし

有効値 : なし 例 :

(15)

mSetSPILatch

目的 : Explorer16 ボード上の ENC28J60 への SPI 信号経路を設定します。 前提条件 : なし

有効値 : N/A 例 :

#define mSetSPILatch() { mPORTBSetPinsDigitalOut(BIT_12 | BIT_13); mPORTBSetBits(BIT_12 | BIT_13); }

(16)

スタックの使用

UDP アプリケーションの作成

UDP データグラム型通信を使うと、最も簡単にメッ セージを送受信できます。以下のコードセグメントは、 データの交換に必要な最小限のコードです。 #include <p32xxxx.h> #include <plib.h> ... main() { ... SOCKET s;

struct sockaddr_in addr;

int addrlen = sizeof(struct sockaddr_in); int len; ... SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit();

// create datagram socket //////////////////

if( (s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP )) == SOCKET_ERROR ) return -1;

// bind to a unique local port addr.sin_port = 7000;

addr.sin_addr.S_un.S_addr = IP_ADDR_ANY;

if( bind( s, (struct sockaddr*)&addr, addrlen ) == SOCKET_ERROR ) return -1; ... ... while(1) { StackMgrProcess(); ... ...

addrlen = sizeof(struct sockaddr_in);

len = recvfrom( s, bfr, sizeof(bfr), 0, (struct sockaddr*)&addr, &addrlen); if( len > 0 )

{

// process the datagram received in bfr of size len.Sender address is in addr. ...

// send a datagram reply of size 25 bytes to the sender

sendto( s, bfr, 25, 0, (struct sockaddr*)&addr, addrlen ); //echo back } ... ... } ... }

(17)

TCP クライアント アプリケーションの作成

TCP 方式のアプリケーションは、1 つまたは複数のリ モートノードとデータを交換するために、コネクショ ン指向の高信頼性通信手段を提供します。全ての TCP アプリケーションは、サーバまたはクライアントのど ちらかとしてプログラミングされます。TCP クライア ント アプリケーション側が、リモートサーバへの接続 を開始します。接続が確立した後は、通常の送受信ルー チンを使ってデータを交換します。接続を試みる前に、 サーバIPアドレスとポート番号を設定しておく必要が あります。 #include <p32xxxx.h> #include <plib.h> ... main() { ... ... SOCKET Sock;

struct sockaddr_in addr;

int addrlen = sizeof(struct sockaddr_in); int len; ... SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit();

//create tcp client socket

if( (Sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) == SOCKET_ERROR ) return -1;

//bind to a unique local port

addr.sin_port = 0; // Let the stack pick a unique port for us addr.sin_addr.S_un.S_addr = IP_ADDR_ANY;

if( bind( Sock, (struct sockaddr*)&addr, addrlen ) == SOCKET_ERROR ) return -1;

//create the server address addr.sin_port = SERVER_PORT;

addr.sin_addr.S_un.S_addr = SERVER_IP; addrlen = sizeof(struct sockaddr); ClientConnected = FALSE;

while(1) {

// execute the stack process once every iteration of the main loop StackMgrProcess();

... ...

// The connect process requires multiple messages to be

// sent across the link, so we need to keep on trying until successful while( !ClientConnected )

if( connect( Sock, (struct sockaddr*)&addr, addrlen ) == 0 ) ClientConnected = TRUE;

// Generate data to send ...

(18)

TCP クライアント アプリケーションの作成

( 続き )

//send the data to server

while( (len = send( Sock, bfr, msg_len, 0 )) != msg_len ) {

if( len == SOCKET_ERROR ) { closesocket( Sock); return(len); } } ... ...

//Receive data from server

len = recv( Sock, bfr, sizeof(bfr), 0 ); if( len > 0 )

{

//process the data received in bfr ...

... }

else if( len < 0 ) //handle error condition { closesocket( Sock ); Sock = INVALID_SOCK; ClientConnected = FALSE; return(len); } ... ... } ... ... }

(19)

TCP サーバ アプリケーションの作成

TCP サーバ アプリケーションは、TCP クライアント アプリケーションからの接続要求を受け取り、それら を順番に承認します。接続が承認されて確立すると、 クライアントおよびサーバ アプリケーションは互い にデータを交換できます。Microchip 社製スタックは 並行サーバ接続をサポートするため、サーバ アプリ ケーションは複数クライアントからの要求を同時に処 理できます。 #include <p32xxxx.h> #include <plib.h> ... main() { ... SOCKET srvr, NewClientSock; struct sockaddr_in addr;

int addrlen = sizeof(struct sockaddr_in); int len; ... ... SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit();

// create tcp server socket

if( (srvr = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) == SOCKET_ERROR ) return -1;

// Bind to a unique known local port. addr.sin_port = 6653;

addr.sin_addr.S_un.S_addr = IP_ADDR_ANY;

if( bind( srvr, (struct sockaddr*)&addr, addrlen ) == SOCKET_ERROR ) return -1;

// Start Listening for connections on this socket.The max // connection queue size is 5 elements deep.

listen( srvr, 5 ); while(1)

{

// execute the stack process once every interation of the main loop StackMgrProcess();

.... ....

if( NewClientSock == INVALID_SOCK ) {

// Check if we have a new client connection waiting

NewClientSock = accept( srvr, (struct sockaddr*)&addr, &addrlen ); }

else {

//receive data from this client

len = recvfrom( NewClientSock, bfr, sizeof(bfr), 0, NULL, NULL ); if( len > 0 )

{

//process data receive in bfr ....

(20)

TCP サーバ アプリケーションの作成

( 続き )

//send the reply to client

send( NewClientSock, bfr, len, 0 ); ....

.... }

else if( len < 0 ) { closesocket( NewClientSock ); NewClientSock = SOCKET_ERROR; } } .... .... } .... .... }

(21)

スタック アーキテクチャ

Microchip社製BSD TCP/IPスタックのアーキテクチャ を図 5 に示します。 図 5: スタック アーキテクチャ 2. Stack Manager

ENC28J60 1. MAC Layer

ICMP / PING Handler Route Functions ARP Cache UDP Layer Functions SOCKET INCOMING PKT FIFO

Memory Block Pool

TCP Manager Get/Set Route Get/Query Route Apps

SOCKET API SOCKET API

MAC Tx FIFO

4. IP MANAGER 3. ARP Functions

FIFO – PENDING ARP REPLY

Al locat e Pa cke t Buf fe r

(22)

スタック モジュールとオブジェクト

スタックは下記のモジュールとオブジェクトによって 構成されます。 1. Ethernet コントローラ ドライバ /MAC 層 Ethernet ドライバは、Ethernet コントローラ チッ プ用の下位ハードウェア インターフェイスを実 装します。これは、コントローラに固有の細部仕 様を隠蔽し、上位層に向けて抽象化したインター フ ェ イ ス を 提 供 し ま す。こ の モ ジ ュ ー ル は Ethernet コントローラからメッセージを取得し、 上位層に渡すためにそれらをパッケージ化しま す。ドライバは MBM (Memory Block Manager) を 使ってパケットプールを管理します。標準的な ユーザ アプリケーションでは、MAC 層のサービ スを直接呼び出す ( 使用する ) 必要はありません。 2. スタック マネージャ このモジュールは、ステートマシンの実行と、ス タック内のメッセージ ストリームの処理を担当 します。このモジュールは MAC 層を介して受信 パケットを取得し、そのパケットを適切な上位プ ロトコル ハンドラに渡します。スタック マネー ジャを使う事で、スタックはアプリケーションに 依存せずに動作できます。現バージョンのスタッ ク マネージャは、協調的マルチタスク方式で実装 されます。スタックを「alive」に維持してスタッ ク関連ロジックを実行するには、メイン アプリ ケーションから周期的にStackMgrProcess関数 を呼び出す必要があります。メイン アプリケー シ ョ ン を 協 調 的 マ ル チ タ ス ク 方 式 で 実 装 し、 StackMgrProcess をコード内のメイン部( メイ ンループ等 ) のみから呼び出す事を推奨します。 3. APR (Address Resolution Protocol) ハンドラ

ARP ハンドラ関数は、ARP 向けにパケットを作 成および処理します。一般的に、ユーザ アプリ ケーションから ARP 層関数を呼び出す必要はあ りません。IP マネージャが自動的に ARP 関数を 呼び出して、アドレス解決プロセスを開始します。 4. IP マネージャ このモジュールはパケットの IP 層を制御します。 このモジュールはスタック マネージャから受信 パケット受け取り、IP チェックサムを検証 / 生成 します。全ての有効パケットは、適切な上位 IP プ ロトコル ハンドラに渡されます。現バージョンの スタックは、下記の 3 つの IP レベルプロトコルを サポートします。 a) UDP b) TCP c) ICMP IP マネージャは、送信パケット向けの ARP 要求も生 成します。デスティネーション ノードの MAC ID が取 得できない場合、IP マネージャは ARP 要求を生成し、 保留 ARP リレーキューでパケットを保持します。MAC ID を格納した ARP 応答を受け取ると、パケットは MAC 層へ渡されて即座に送信されます。 メモリ割り当てスキーム パケットバッファの割り当てを高速化するために、ス タックはメモリを静的に割り当てます。MBM は静的 メモリブロックのプールを作成します。送信および受 信パケットのバッファは、1 つのブロックまたは隣接 する複数のブロックを使って作成されます。ブロック が割り当てられると、それらは使用中としてマーキン グされます。パケットが送信または処理されると、使 用中であったブロックは、次のパケットの割り当て用 に解放されます。 例として、MGR_BLOCK_SIZE = 100、MAX_MGR_BLOCK = 16 とした場合、全部で 1600 byte の静的メモリが割り当 てられます。このメモリ容量は、最大サイズの Ethernet パケット 1 個に対して十分な大きさです。1600 byte は 16 個の 100 byte ブロックで構成されるため、100 byte 以下のパケットを 16 個までバッファリングできます。 MBM を使うと、バイト マネージャとは対照的に、さ まざまなサイズのパケットに対して非常に効率的に バッファを割り当てる事ができます。

(23)

API 関数の説明

この後の各ページでは、スタックが実装する各 API 関数について説明します。このスタックは、BSD の一部の API 関 数を実装します。全ての BSD API 関数を記載した一覧は、http://en.wikipedia.org/wiki/Berkeley_sockets でご覧になれ ます。

(24)

API - socket

socket は通信エンドポイントを作成します。このエンドポイントをソケットと呼びます。このAPI は、作成され たソケットの記述子を返します。返されたソケット記述子は、後続の全ての API の呼び出しで使われます。 現在、Microchip 社の BSD ソケット API は、UDP および TCP プロトコルのみをサポートします。

構文

SOCKET socket( int af, int type, int protocol )

パラメータ af - アドレスファミリ。現在、AF_INET のみをサポートしています。 type - 通信のタイプを定義します。現在、下記のタイプをサポートしています。 SOCK_STREAM 信頼性が高い全二重方式のコネクション指向データストリームを提供します。 SOCK_DGRAM データグラム型をサポートします。この通信はコネクションレス型であり、信頼性が 低く、メッセージの最大長は固定されます。 protocol - ソケットの型に応じて適切なインターネット プロトコルを指定する必要があります。 ストリーム型ソケットに対しては、IPPROTO_TCP を指定する必要があります。 データグラム型ソケットに対しては、IPPROTO_UDP を指定する必要があります。 戻り値 この関数は、実行に成功すると 0 から始まるソケット記述子を返します。エラーが発生すると、SOCKET_ERROR が返されます。 前提条件 InitStackMgr() の呼び出し 副次的影響 なし 例 SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit(); SOCKET sdesc;

(25)

API - bind

bind は、無名のソケットに名前を割り当てます。この名前は、通信エンドポイントのローカルアドレスを表しま す。SOCK_STREAM 型ソケットの場合、connect または accept 関数が実行された時に、リモート エンドポイ ントの名前が割り当てられます。

構文

int bind( SOCKET s, const struct sockaddr * name, int namelen )

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 name - ソケットのローカルアドレスを格納する sockaddr 構造体を指すポインタ namelen - sockaddr 構造体の長さ 戻り値 bind に成功すると、値 0 が返されます。SOCKET_ERROR の戻り値はエラーを示します。 前提条件 socket の呼び出しによるソケットの作成 副次的影響 なし 例 SOCKET sdesc;

struct sockaddr_in addr;

int addrlen = sizeof(struct sockaddr_in); SetupDefault_IP_MAC();

MSTimerInit(36000000); InitStackMgr();

TickInit();

sdesc = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

addr.sin_port = 7300; // Assign a unique known port number.

addr.sin_addr.S_un.S_addr = IP_ADDR_ANY; // accept packets from any MAC interface if( bind( sdesc, (struct sockaddr*)&addr, addrlen ) == SOCKET_ERROR )

(26)

API - listen

listen は、指定されたソケットを listen モードに設定します。listen 関数を呼び出す事で、アプリケーショ ンの準備が完了した事 (SOCK_STREAM 型ソケットに届いた接続要求を受け入れ可能である事 ) を示します。接続 要求は、accept 関数によって承認されるまで、キューに保存されます ( 可能な場合 )。

backlog パラメータは、キューに保存して保留できる接続要求の最大数を定義します。

構文

int listen( SOCKET s, int backlog )

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 backlog - キューに保存可能な接続要求の最大数 戻り値 listen に成功すると、値 0 が返されます。SOCKET_ERROR の戻り値はエラーを示します。 前提条件 bind() API の呼び出し 副次的影響 なし 例 SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit();

// create tcp server socket

if( (srvr = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) == SOCKET_ERROR ) return -1;

// Bind to a unique known local port. addr.sin_port = 6653;

addr.sin_addr.S_un.S_addr = IP_ADDR_ANY;

if( bind( srvr, (struct sockaddr*)&addr, addrlen ) == SOCKET_ERROR ) return -1;

// Start Listening for connections on this socket.The max // connection queue size is 5 elements deep.

if( listen( srvr, 5 ) < 0 ) .... handle error condition

(27)

API - accept

accept は、リスニング中ソケットに対して保留されている接続要求を承認するために使います。1 つの接続要求 が保留中である場合、accept はその接続要求をキューから取り出し、接続用に新しいソケットを作成します。 元のリスニング中ソケットは開いたまま、後続の接続要求をキューに保存し続けます。s は SOCK_STREAM 型ソ ケットである事が必要です。 構文

SOCKET accept( SOCKET s, struct sockaddr * addr, int * addrlen )

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子。ローカル名が付けられ、リスニングモード中 である事が必要 name - 接続中ノードの IP アドレスとポート番号を受け取る sockaddr 構造体を指すポインタ namelen - 結果を格納するパラメータ。初期値として name が指すメモリ空間の容量を格納し、戻り値として返さ れた名前の実際の長さ ( バイト数 ) を格納します。 戻り値 accept() 関数は、実行に成功すると、承認されたソケットの記述子である非負整数を返します。失敗した場合、 SOCKET_ERROR 値が返されます。 前提条件 ソケットに対する listen API の呼び出し 副次的影響 なし 例 SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit();

// create tcp server socket

if( (srvr = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) == SOCKET_ERROR ) return -1;

// Bind to a unique known local port. addr.sin_port = 6653;

addr.sin_addr.S_un.S_addr = IP_ADDR_ANY;

if( bind( srvr, (struct sockaddr*)&addr, addrlen ) == SOCKET_ERROR ) return -1;

// Start Listening for connections on this socket.The max // connection queue size is 5 elements deep.

listen( srvr, 5 ); while(1)

{

// execute the stack process once every interation of the main loop StackMgrProcess();

.... ....

if( NewClientSock == INVALID_SOCK ) {

// Check if we have a new client connection waiting

NewClientSock = accept( srvr, (struct sockaddr*)&addr, &addrlen ); }

} else {

(28)

API - accept

( 続き )

SOCKET NewSock;

NewSock = accept( srvr, (struct sockaddr*)&addr, &addrlen ); if( NewSock != INVALID_SOCK )

{

//new socket connected, send some data to this client send( NewSocket, ...); } ... ... closesocket( NewSock ); ...

(29)

API - connect

connect は、ピア通信エンドポイントのアドレスを割り当てます。stream 型ソケットの場合、エンドポイント 間で通信が確立されます。datagram 型ソケットの場合、後続の connect() 関数によって変更されるまで、エ ンドポイント間でアドレスフィルタが確立されます。

構文

int connect( SOCKET s, struct sockaddr * name, int namelen );

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 name - ソケットのローカルアドレスを格納する sockaddr 構造体を指すポインタ namelen - sockaddr 構造体の長さ 戻り値 connect() 関数は、実行に成功すると 0 を返します。失敗すると、エラー条件を示す SOCKET_ERROR 値が返され ます。stream 型ソケットの場合、接続がまだ確立されていなければ、connect は SOCKET_CNXN_IN_PROGRESS を返します。 前提条件 socket API の呼び出しによるソケット s の作成 bind() の呼び出し(stream 型ソケットの場合 ) 副次的影響 なし 例 SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit();

//create tcp client socket

if( (Sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) == SOCKET_ERROR ) return -1;

//bind to a unique local port

addr.sin_port = 0; // Let the stack pick a unique port for us addr.sin_addr.S_un.S_addr = IP_ADDR_ANY;

if( bind( Sock, (struct sockaddr*)&addr, addrlen ) == SOCKET_ERROR ) return -1;

//create the server address addr.sin_port = SERVER_PORT;

addr.sin_addr.S_un.S_addr = SERVER_IP; addrlen = sizeof(struct sockaddr); ClientConnected = FALSE;

while(1) {

// execute the stack process once every iteration of the main loop StackMgrProcess();

...

// The connect process requires multiple messages to be sent across the link, // so we need to keep on checking until successful

while( !ClientConnected )

if( connect( Sock, (struct sockaddr*)&addr, addrlen ) == 0 ) ClientConnected = TRUE;

... }

(30)

API - sendto

sendto は、datagram 型ソケットでデータを送信するために使います。デスティネーション アドレスは to と tolenで指定します。データグラムの作成に利用可能なメモリブロックが存在しない場合、この関数はエラーコー ドを返します。

構文

int sendto( SOCKET s, const char * buf, int len, int flags, const struct sockaddr * to, int tolen )

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 buf - 送信データを格納するアプリケーション データバッファ len - データ長 ( バイト数 ) flags - メッセージフラグ。現在このフィールドはサポートしておらず、0 に設定する必要があります。 to - デスティネーション アドレスを格納する sockaddr 構造体を指すポインタ tolen - sockaddr 構造体の長さ 戻り値 sendto は、実行に成功すると送信バイト数を返します。失敗した場合、下記のいずれかの値が返されます。 SOCKET_BFR_ALLOC_ERROR パケットバッファに割り当て可能なメモリが存在しない SOCKET_ERROR 一般エラーコード。このエラーが返された場合、アドレス構造体の フォーマットとソケット記述子が正しいかどうか確認してください。 前提条件 socket API 呼び出しによるソケット s の作成 接続の確立 (stream 型ソケットの場合 ) 副次的影響 なし 例

sendto( s, bfr, strlen(bfr)+1, 0, (struct sockaddr*)&addr, addrlen ); 詳細な例は、「UDP アプリケーションの作成」に記載しています。

(31)

API - send

send は、接続済みソケットでデータを送信するために使います。通常、この関数は SOCK_STREAM 型ソケットで 順序付けられデータバイトのストリームを高い信頼性で送信するために使いますが、SOCK_DGRAM 型ソケットで データグラムの送信用にも使えます。

構文

int send( SOCKET s, const char* buf, int len, int flags );

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 buf - 送信データを格納するアプリケーション データバッファ len - データ長 ( バイト数 ) flags - メッセージフラグ。現在このフィールドはサポートしておらず、常に 0 に設定する必要があります。 戻り値 send は、実行に成功すると送信バイト数を返します。失敗した場合、下記のいずれかの値が返されます。 SOCKET_BFR_ALLOC_ERROR パケットバッファに割り当て可能なメモリが存在しない SOCKET_ERROR 一般エラーコード。このエラーが返された場合、アドレス構造体の フォーマットとソケット記述子が正しいかどうか確認してください。 SOCKET_TX_NOT_READY リモートノードによって送信されたパケットに対してリモートノー ドが肯定応答 (ACK) を送信した時に、TCP 送信機能が一時的に無効 になった

SOCKET_MAX_LEN_ERROR データバッファの長さが MTU 値 (Ethernet の場合、1500 byte) を超 えた 前提条件 socket API 呼び出しによるソケット s の作成 接続の確立 (stream ソケットの場合 ) 副次的影響 なし 例

if( send( StreamSock, bfr, len, 0 ) < 0 )

... handle error condition and close socket

(32)

API - recvfrom

recvfrom()は、ソケットで保留されていた受信データを受け取るために使います。通常、この関数はdatagrams 型ソケットでメッセージを受信するために使いますが、 SOCK_STREAM 型の接続済みソケットで順序付けられた データバイト ストリームを高い信頼性で受信する場合にも使えます。

from がNULL ではない場合、データグラムのソースアドレスが書き込まれます。fromlen は結果を格納するパラ メータであり、 from が指すバッファのサイズに初期化され、戻り値はそこに保存されているアドレスの実際のサ イズを示します。この機能は、SOCK_DGRAM 型ソケットに対してのみ有効です。 提供されたバッファ buf よりもデータグラムが長い場合、SOCK_DGRAM 型ソケットでは、バッファに収まらな いバイトは破棄されます。SOCK_STREAM 型の場合、データは内部でバッファリングされるため、アプリケーショ ンは recvfrom を複数回呼び出す事で、全てのデータを取得できます。 ソケットにデータが存在しない場合、recvfrom() は 0 を返します。 構文

int recvfrom( SOCKET s, char * buf, int len, int flags, struct sockaddr * from, int * fromlen) パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 buf - アプリケーション データ受信バッファ len - バッファ長 ( バイト数 ) flags - メッセージフラグ。現在このフィールドはサポートしておらず、常に 0 に設定する必要があります。 from - デスティネーション アドレスが書き込まれる sockaddr 構造体を指すポインタ fromlen - from が指すバッファのサイズ 戻り値 recvfrom の実行に成功すると、アプリケーション バッファ buf にコピーされたバイトの数が返されます。 値 0 は、データが存在しない事を意味します。SOCKET_ERROR の戻り値は、エラー条件を示します。 前提条件 接続の確立 (stream 型ソケットの場合 ) 副次的影響 なし 例

if( (len = recvfrom( s, bfr, sizeof(bfr), 0, (struct sockaddr*)&addr, &addrlen )) >= 0 )

... process data received

(33)

API - recv

recvfrom() は、ソケットで保留されていた受信データを受け取るために使います。 この関数は、datagram お よび stream 型ソケットで使えます。 提供されたアプリケーション バッファ buf よりもデータの方が長い場合、SOCK_DGRAM 型ソケットでは、バッ ファに収まらないバイトは破棄されます。SOCK_STREAM 型の場合、データは内部でバッファリングされるため、 アプリケーションは recv を複数回呼び出す事で、全てのデータを取得できます。 ソケットにデータが存在しない場合、recv() は 0 を返します。 構文

int recv( SOCKET s, char * buf, int len, int flags )

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 buf - アプリケーション データ受信バッファ len - バッファ長 ( バイト数 ) flags - メッセージフラグ。現在このフィールドはサポートしておらず、常に 0 に設定する必要があります。 戻り値 recv の実行に成功すると、アプリケーション バッファ buf にコピーされたバイトの数が返されます。値 0 は、 データが存在しない事を意味します。SOCKET_ERROR (-1) の戻り値は、エラー条件を示します。 前提条件 接続の確立 (stream ソケットの場合 ) 副次的影響 なし 例

if( (len = recv( s, bfr, sizeof(bfr), 0 ) >= 0 ) .... process data received.

(34)

API - closesocket

closesocket は、既存のソケットを閉じます。この関数は、ソケット記述子 s を解放します。その後の s への参 照は失敗し、SOCKET_ERROR コードが返されます。ソケットでバッファリングされていた全てのデータは破棄さ れます。ソケット s をその後使わない場合、s に関連付けられている全てのリソースを解放するために、 closesocket() を呼び出す必要があります。 構文

int closesocket( SOCKET s )

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 戻り値 closesocket の実行に成功すると、値 0 が返されます。SOCKET_ERROR (-1) の戻り値は、エラーを示します。 前提条件 なし 副次的影響 なし 例

len = recvfrom( clSock, bfr, sizeof(bfr), 0, NULL, NULL ); ...

...

closesocket( clSock );

(35)

API - MPSocketConnected

MPSocketConnectedはstream型ソケットの接続状態を返します。このAPI関数はオリジナルのBSDには含まれ ないカスタム関数です。stream 型ソケットの場合、接続が確立されていれば、この関数は 0 を返します。接続 確立プロセスが未完了の場合、この関数は SOCKET_CNXN_IN_PROGRESS を返します。アプリケーションは、 MpSocketConnected を使う事で、パケットをアセンブルする前に接続の状態を確認できます。BSD にも同様の 機能はありますが、それらはパケット形成後にのみ接続状態を返すため、多くのアプリケーションにとって遅す ぎます。 構文

int MPSocketConnected( SOCKET s )

パラメータ s - ソケットに対する前回の呼び出しから返されたソケット記述子 戻り値 stream 型ソケットの場合、この関数は接続が確立されていれば 0 を返し、接続の確立プロセスが未完了であれば SOCKET_CNXN_IN_PROGRESS を返します。その他の条件では、この関数は SOCKET_ERROR を返します。 前提条件 なし 副次的影響 なし 例

if( MPSocketConnected(s) == 0 ) //socket is connected send( s, bfr, len, 0 );

(36)

API - InitStackMgr

InitStackMgr は、eTCPIP スタック内の全てのモジュールを初期化します。アプリケーションは、他のどのAPI 呼び出しよりも先に、この関数を呼び出す必要があります。 構文 void InitStackMgr() パラメータ なし 戻り値 なし 前提条件 なし 副次的影響 なし 例 : SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit();

(37)

API - StackMgrProcess

StackMgrProcess() は、スタック内の全てのモジュールタスクを実行します。スタックは協調的マルチタスク 機構を使って複数のタスクを実行します。アプリケーションは、メインループの繰り返しのたびに、この関数を 呼び出す必要があります。この関数の呼び出しが遅れると、ローカル NIC が受信したネットワーク パケットを失 う可能性があります。 構文 void StackMgrProcess() パラメータ なし 戻り値 なし 前提条件 なし 副次的影響 なし 例 main() { ... SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit(); DHCPInit(); .. while(1) { StackMgrProcess(); DHCPTask(); ... ... } ... }

(38)

API - setsockopt

setsockopt を使うと、実行中にスタックのオプションを設定できます。この関数は SO_SNDBUF および TCP_NODELAY オプションをサポートします。

構文

int setsockopt( SOCKET s, int level, int optname,char * optval, int optlen );

パラメータ

s - ソケットに対する前回の呼び出しから返されたソケット記述子 level - SOL_SOCKET 専用

optname - 設定するオプション 選択可能なオプション

SO_SNDBUF tcp ソケットに対して send API で使う送信バッファのサイズを設定します。 TCP_NODELAY ソケットの Naggles アルゴリズムを有効または無効にします。既定値では、Naggles

アルゴリズムは有効です。これを無効にするには、optval データに非ゼロ値を使い ます。 optval - オプションデータへのポインタ optlen - オプションデータの長さ 戻り値 setsockopt の実行に成功すると、値0が返されます。SOCKET_ERROR (-1)の戻り値は、エラー条件を示します。 前提条件 なし 副次的影響 None Example ... // SetupDefault_IP_MAC(); MSTimerInit(36000000); InitStackMgr(); TickInit();

//create tcp client socket

if( (Sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) == SOCKET_ERROR ) return -1;

int len = 1;

setsockopt( Sock, SOL_SOCKET, TCP_NODELAY, (char*)&len, sizeof(int) ); ...

(39)

よく寄せられる質問 (FAQ)

Q: このスタックは全ての BSD ソケット API 関数を 実装していますか。 A: いいえ。このスタックは BSD API の一部だけを 実装しています。 Q: UDP とストリーム ソケットを同時に開く事は できますか。 A: MAX_SOCKET を超えない限り、型に関係なく複 数個のソケットを開く事ができます。 Q: このスタックは RTOS と一緒に使えますか。 A: RTOS またはカーネルと一緒に使えます。この スタックは単一スレッドとして実装されるた め、スタック API は単一スレッドから呼び出す 必要があります。API はスレッドセーフではな いため、複数のスレッドが API 関数を呼び出す 必要がある場合は、1 つのクリティカル セク ション内で呼び出す必要があります。

まとめ

このスタックは、PIC マイクロコントローラを使った 組み込みアプリケーションに、高機能な通信 API セッ トを提供します。BSD API との互換性が維持されるた め、アプリケーションをインターネットやローカル ネットワークに非常に柔軟に組み込む事ができます。 BSD API は、バイトレベルではなくバッファレベルで 動作するため、特に 16 および 32 ビット PIC マイクロ コントローラを使うシステムでは、性能が大幅に向上 します。

参考資料

Jeremy Bentham, “TCP/IP LEAN:Web Servers for

Embedded Systems”, (Second Edition).

Manhasset.NY:CMP Books, 2002

W. Richard Stevens, “TCP/IP Illustrated”.Indianapolis, IN:Addison-Wesley Professional, 1996.

N. Rajbharti, AN833, “The Microchip TCP/IP Stack” (DS00833).Microchip Technology Inc., 2002. Socket API Manual Pages:Richard Verhoeven, enhanced by Michael Hamilton, “VH-Man2html”, Computer Science @ Vassar College,

(40)

Software License Agreement

The software supplied herewith by Microchip Technology Incorporated (the “Company”) is intended and supplied to you, the Company’s customer, for use solely and exclusively with products manufactured by the Company.

The software is owned by the Company and/or its supplier, and is protected under applicable copyright laws. All rights are reserved. Any use in violation of the foregoing restrictions may subject the user to criminal sanctions under applicable laws, as well as to civil liability for the breach of the terms and conditions of this license.

THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.

補遺 A: ソースコード

デモ アプリケーションとサポートファイルを含む Microchip 社製 BSD Socket API 対応 TCP/IP スタック の完全なソースコードは、無償ライセンス契約の下に お使い頂けます。全ての内容を収めたアーカイブ ファ イルは、Microchip 社ウェブサイトからダウンロード できます : www.microchip.com ダウンロード後に、必ず version.log ファイルを開 いて、最新のリビジョンレベルとソフトウェアの変更 履歴を確認してください。

改訂履歴

リビジョン A (2007 年 10 月 )

本書は初版です。

Updating...

関連した話題 :