langEnglish

RSI-ECAT API一覧および開発手法


■ RSI-ECAT-masterのアプリケーションインターフェース
RSI-ECATはINtime® RTOSアプリケーション用に豊富なアプリケーションインターフェース関数(API)を提供しています

RSI-ECAT-masterの主要API一覧

RSI-ECAT API Feature
初期化API  
EhGetEhNodeStatus() マスターの動作状態を確認します。
EhOpen() API対話を開設して通信できる状態にします。
EhClose() API対話を閉鎖して通信を終えます。
マスター制御  
EhRqState() マスターステートの変更要求を行います。
EhGetState() 現在要求中のマスターステートと現在のマスターステートを取得します。
EhWaitForCyclic() マスターサイクリック処理の開始を待機します。
EhGetSystemInfo() マスターの情報を取得します。
イベント制御  
EhSetEventFilter() 診断イベントのフィルタを設定します。
EhGetEventFilter() 設定されている診断イベントのフィルタ情報を取得します。
EhWaitForEvent() 診断イベントを待機します。
スレーブ検索  
EhFindSlave() ID番号指定でスレーブを検索し詳細情報を取得します。
EhFindSlaveByAlias() エイリアス番号指定でスレーブを検索し詳細情報を取得します。
スレーブ管理  
EhGetSlaveStatus() 対象スレーブのステータス情報を取得します。
EhGetSlaveCount() コンフィグレーション(XML)定義上のスレーブ数を取得します。
EhGetOnlineSlaveCount() 接続しているスレーブ数を取得します。
ProcessDataアクセス  
EhGetViosInOffset() 指定エイリアスのスレーブからIN領域オフセット値を取得します。
EhGetViosOutOffset() 指定エイリアスのスレーブからOUT領域オフセット値を取得します。
EhReadByte() VIOS IN領域から8ビットデータを読み取ります。
EhReadWord() VIOS IN領域から16ビットデータを読み取ります。
EhReadDWord() VIOS IN領域から32ビットデータを読み取ります。
EhWriteByte() VIOS OUT領域へ8ビットデータを書き込みます。
EhWriteWord() VIOS OUT領域へ16ビットデータを書き込みます。
EhWriteDWord() VIOS OUT領域へ32ビットデータを書き込みます。
EhReadbackByte() VIOS OUT領域から8ビットデータを読み取ります。
EhReadbackWord() VIOS OUT領域から16ビットデータを読み取ります。
EhReadbackDWord() VIOS OUT領域から32ビットデータを読み取ります。
Mailboxアクセス  
EhReadOD() 指定スレーブの指定インデックスからデータを読み取ります。
EhWriteOD() 指定スレーブの指定インデックスへデータを書き込みます。
EhReadODByAlias() 指定エイリアスを持つスレーブの指定インデックスからデータを読み取ります。
EhWriteODByAlias() 指定エイリアスを持つスレーブの指定インデックスへデータを書き込みます。

RSI-ECAT-masterの入出力補助API一覧

すべてのスレーブは上記ProcessDataアクセスAPIで制御可能ですが、ディジタル入出力、アナログ入出力に関しては連続チャンネルとして再配置されたアドレス空間(カテゴリ)として、EtherCAT®に不慣れなお客様でも容易に扱えるように以下APIも準備されています。
RSI-ECAT API Feature
ディジタル入力  
EhDiRead() 指定のDIチャンネルから16ビットデータを読み込みます。
EhDiBlock() DIカテゴリの任意のオフセット位置から任意サイズ分のデータを読み込みます。
EhDiGetChNums() DIカテゴリのチャンネル数を取得します。
ディジタル出力  
EhDoWrite() 指定のDOチャンネルへ16ビットデータを書き出します。
EhDoRead() 指定のDOチャンネルから16ビットデータを読み込みます。
EhDoBlock() DOカテゴリの任意のオフセット位置から任意サイズ分のデータを書き込みます。
EhDoGetChNums() DOカテゴリのチャンネル数を取得します。
アナログ入力  
EhAiRead() 指定のAIチャンネルから32ビットデータを読み込みます。
EhAiBlock() AIカテゴリの任意のオフセット位置から任意サイズ分のデータを読み込みます。
EhAiSetRange() 指定のAIスレーブのレンジ設定を行います。
EhAiGetRange() 指定のAIスレーブのレンジを取得します。
EhAiGetChNums() AIカテゴリのチャンネル数を取得します。
アナログ出力  
EhAoWrite() 指定のAOチャンネルへ32ビットデータを書出します。
EhAoRead() 指定のAOチャンネルから32ビットデータを読み込みます。
EhAoBlock() AOカテゴリの任意のオフセット位置から任意サイズ分のデータを書き込みます。
EhAoSetRange() 指定のAOスレーブのレンジ設定を行います。
EhAoGetRange() 指定のAOスレーブのレンジを取得します。
EhAoGetChNums() AOカテゴリのチャンネル数を取得します。

■ EtherCAT®制御プログラミングの基礎知識

1. マスターの初期化

EtherCAT®を制御するINtime®アプリケーションは、まずRSI-ECAT-masterとの接続を初期化します。
ノード名引数指定によって、異なるCPUコアに動作しているINtime®カーネルに接続することもできます。これは負荷分散の目的で有利です。
 WORD                    woStatus;
 EHHANDLE                hAPI;

 hAPI = EhOpen("NodeA", &woStatus);

2. マスターをOPERATIONAL状態に移行

EtherCAT®のサイクリック通信を開始します。
 woStatus = EhRqState(hAPI, MST_OPERATIONAL);

3. 制御対象スレーブの検索

EtherCAT®スレーブには不揮発なID(VendorId,ProductId)が書き込まれています。
これをキーにして制御対象のスレーブの存在と位置を取得できます。同じメーカーの同じ型式のスレーブが複数存在する場合はインスタンス番号deInstanceをインクリメントして特定します。
EtherCAT®スレーブが検出されると、構造体にはスレーブのビットオフセット位置などが格納されています。
 SLAVE_DETAIL    stSlave;

 stSlave.dwSize        = sizeof(stSlave);
 stSlave.dwVenderID    = 131;
 stSlave.dwProductCode = 50;
 stSlave.dwInstance    = 0;

 woStatus = EhFindSlave(hAPI, &stSlave);

4. マスターサイクル周期待ち

マスターサイクルを迎えるまで待機します。
 woStatus = EhWaitForCyclic(hAPI, WAIT_FOREVER);

5. 入出力

RSI-ECATによって、EtherCAT®スレーブ機器は連続する仮想のアドレス空間に再配置されています。
I/Oアドレス空間を扱うかのようにEtherCAT®スレーブ機器に対する入力、出力を制御できます。
 byData = EhReadByte(hAPI, stSlaveABC.dwViosInBaseOffset, &woStatus);
 EhWriteByte(hAPI, stSlaveXYZ.dwViosOutBaseOffset, byData);
■ コーディングサンプル

DIOスレーブ制御の事例

このサンプルはRSI-ECAT-Masterを使用し、OMRON Corporation社のディジタルI/Oスレーブ製品を制御するC言語INtime®アプリケーションです。コード中のオフセットアドレス、値などについては、メーカーの製品仕様に準じます。
 /*****************************************************************************
 * Description        : DO プログラムサンプル
 * Software           : INtime 4.2 + RSI-ECAT 2.1
 * Data, Writer       :                                  2012/06/05 : 篠崎勝利
 \*****************************************************************************/
 #include <stdio.h>
 #include <rt.h>
 #include <EhApi.h>

 /*****************************************************************************
 * Description : main 処理
 \*****************************************************************************/
 void    main(int argc, char* argv[])
 {
         WORD                    woStatus;
         WORD                    woReqState = 0;
         WORD                    woNowState = 0;
         EHHANDLE                hAPI;
         SLAVE_DETAIL    stSlave;

         // RSI-ECAT 起動状態チェック (RSI-ECAT API コール)
         woStatus = EhGetEhNodeStatus("NodeA", 100);
         if( 0 != woStatus ) {
                 printf("EhGetEhNodeStatus() Status = %04xH\n", woStatus);
                 printf("start check failed\n");
                 return ;
         }

         // RSI-ECAT API対話ハンドルOPEN (RSI-ECAT API コール)
         hAPI = EhOpen("NodeA", &woStatus);
         if( 0 != woStatus ) {
                 printf("EH Handle Open failed\n");
                 return ;
         }

         // Masterステートチェンジ要求 (RSI-ECAT API コール)
         // MST_OPERATIONAL : オペレーショナルへ遷移
         woStatus = EhRqState(hAPI, MST_OPERATIONAL);
         if( 0 != woStatus ) {
                 printf("EhRqState() failed. Status = %04xH\n", woStatus);
                 return ;
         }

         // オペレーショナルへ遷移したかどうかの確認処理
         while(1) {
                 // 現在の Masterステート状態取得 (RSI-ECAT API コール)
                 woStatus = EhGetState(hAPI, &woReqState, &woNowState);

                 // オペレーショナルへ遷移完了かをチェック
                 if( woNowState == MST_OPERATIONAL ) {
                         break; // 遷移完了の為ブレイク
                 }

                 // ステートチェンジ待機用スリープ
                 RtSleep(500);
         }


         // ここからスレーブへのアクセス処理

         // スレーブ検索
         stSlave.dwSize        = sizeof(stSlave);       // ■注意■ 必ず構造体サイズを指定する必要があります。
         stSlave.dwVenderID    = 131;
         stSlave.dwProductCode = 50;
         stSlave.dwInstance    = 0;

         woStatus = EhFindSlave(hAPI, &stSlave);
         if( 0 != woStatus ) {
                 printf("EhFindSlave() failed. Status = %04xH\n", woStatus);
                 return ;
         }

         // 動作処理
         while(1) {
                 // サイクリック処理待ち
                 woStatus = EhWaitForCyclic(hAPI, WAIT_FOREVER);
                 if( 0 != woStatus ) {
                         break;  // サイクリック処理が中断された為、終了
                 }

                 // ループ毎にON/OFF変換要求
                 if( 0 != EhReadbackByte(hAPI, stSlave.dwViosOutBaseOffset, &woStatus) ) {
                         EhWriteByte(hAPI, stSlave.dwViosOutBaseOffset, 0x00);
                 } else {
                         EhWriteByte(hAPI, stSlave.dwViosOutBaseOffset, 0xFF);
                 }
         }

         printf("program end.");
 }

CiA402モーションコントロールの事例

このサンプルはRSI-ECAT-Masterを使用し、Panasonic社CiA402準拠モーション制御スレーブMINASシリーズ製品(VendorId=0x0000066F,ProductId=0x515070A1)をCyclic synchronous position mode(サイクリック同期位置モード)で制御するC言語INtime®アプリケーションです。コード中のオフセットアドレス、値などについては、メーカーの製品仕様に準じます。

■ Process Image
メーカーがデフォルトで設定しているプロセスイメージ構成のうち、今回の制御に最低限必要なオブジェクトを以下にまとめます。
下記のオブジェクトに対して値を読み書きすることで、サーボモータを回転させることができます。

<input>
Name Size (byte) Offset (byte) 意味
Statusword 2 2 PDS状態確認

<output>
Name Size (byte) Offset (byte) 意味
Controlword 2 0 PDS状態確認
Modes of operation 1 2 制御モードの変更
Target potision 4 3 サーボモータ目標位置

■ 使用したENIファイル:
RtEcHdrMADHT1507BA1.zip: MINAS MADHT1507BA1 1台構成のENIファイルです。

■ サンプルコード
/*****************************************************************************
 * Description        : CiA402 モーションプログラムサンプル   サイクリック同期位置モード
 * Software           : INtime 6.3 + RSI-ECAT 3.00
 * Data, Writer       :                                  2019/03/15 : okamoto
 \*****************************************************************************/
 #include 
 #include 
 #include 
 #include 

//Proccess Image mapping
//---------------------------------------------------
// PI/IN:
//	+02:Statusword			(6041h:00)
// PI/OUT:
//	+00:Controlword			(6040h:00)
//	+02:Modes of operation		(6060h:00)
//	+03:Target potion			(607Ah:00)
//

 /*****************************************************************************
 * Description : CiA402 サーボドライバ状態遷移処理
 \*****************************************************************************/
 WORD   fnChgMotionGoState(WORD woStWd, WORD *pCrWd)
 {
    switch( (0x6F & woStWd) ) {
    case    0: *pCrWd = (0xFF70 & *pCrWd) | 0;    break; // 未初期化状態      -> 初期化要求
    case 0x40: *pCrWd =                     0x06; break; // 初期化完了状態    -> 主回路電源OFF要求
    case 0x60: *pCrWd = (0xFF70 & *pCrWd) | 0x06; break; // 初期化完了状態    -> 主回路電源OFF要求
    case 0x21: *pCrWd = (0xFF70 & *pCrWd) | 0x07; break; // 主回路電源OFF状態  -> サーボレディ要求
    case 0x23: *pCrWd = (0xFF70 & *pCrWd) | 0x0F; break; // サーボレディ状態     -> サーボON要求
    case 0x27:                                    break; // サーボON状態 (運転開始OK状態)
    case 0x2F:                                    break; // 異常処理動作中状態
    case 0x28: *pCrWd = (0xFF70 & *pCrWd) | 0x80; break; // 異常状態           -> 初期化要求
    }
    return (0x6F & woStWd);
 }

 /*****************************************************************************
 * Description : main 処理
 \*****************************************************************************/
 void   main(int argc, char* argv[])
 {
    WORD			woStatus;
    WORD			woReqState = 0;
    WORD			woNowState = 0;
    EHHANDLE		hAPI;
    BYTE			byModeVal;
    WORD			woStatasWord;
    WORD			woControlWord;
    DWORD			dwTargetPos = 0;
    SLAVE_DETAIL    stSlave;

    // RSI-ECAT 起動状態チェック (RSI-ECAT API コール)
    woStatus = EhGetEhNodeStatus("NodeA", 100);
    printf("EhGetEhNodeStatus() Status = %04xH\n", woStatus);
    if( 0 != woStatus ) {
        printf("start check failed\n");
        return ;
    }

    // RSI-ECAT API対話ハンドルOPEN (RSI-ECAT API コール)
    hAPI = EhOpen("NodeA", &woStatus);
    if( 0 != woStatus ) {
        printf("EH Handle Open failed\n");
        return ;
    }

    // Masterステートチェンジ要求 (RSI-ECAT API コール)
    // MST_OPERATIONAL : オペレーショナルへ遷移
    woStatus = EhRqState(hAPI, MST_OPERATIONAL);
    if( 0 != woStatus ) {
		printf("EhRqState() failed. Status = %04xH\n", woStatus);
		return ;
    }

    // オペレーショナルへ遷移したかどうかの確認処理
    while(1) {
		// 現在の Masterステート状態取得 (RSI-ECAT API コール)
		woStatus = EhGetState(hAPI, &woReqState, &woNowState);

		// オペレーショナルへ遷移完了かをチェック
		if( woNowState == MST_OPERATIONAL ) {
			break; // 遷移完了の為ブレイク
		}

		// ステートチェンジ待機用スリープ
		RtSleep(500);
    }

    // スレーブ検索
    memset(&stSlave, 0, sizeof(stSlave));
    stSlave.dwSize        = sizeof(stSlave);	// ■注意■ 必ず構造体サイズを指定する必要があります。
    stSlave.dwVendorID    = 0x066F;		// ここで操作するスレーブ用のVendorIDとProductCodeを入れること
    stSlave.dwProductCode = 0x515070A1;	// VendorIDとProductCodeは、RSI-ECAT-StudioかENIファイルから確認できます。
    stSlave.dwInstance    = 0;
    woStatus = EhFindSlave(hAPI, &stSlave);
    if( 0 != woStatus ) {
        printf("EhFindSlave() failed. Status = %04xH\n", woStatus);
        return ;
    }

    // CiA402 動作モードの変更
    // 8 : サイクリック同期位置モード へ変更要求
    byModeVal = 8;
    woStatus = EhWriteByte(hAPI, stSlave.dwViosOutBaseOffset + 2, byModeVal); // write to [Modes of operation]
    if( 0 != woStatus ) {
        printf("EhWriteODByAlias() failed. Status = %04xH\n", woStatus);
        return ;
    }

    // CiA402 サーボドライバ状態を、サーボONに遷移
    while(1) {
        woControlWord = 0;

        // サイクリック処理待ち
        woStatus = EhWaitForCyclic(hAPI, WAIT_FOREVER);
        if( 0 != woStatus ) {
            break;  // サイクリック処理が中断された為、終了
        }

        // 現在のサーボドライバ状態取得 (RSI-ECAT API コール)
        woStatasWord = EhReadWord(hAPI, stSlave.dwViosInBaseOffset + 2, &woStatus);	// read from [StatusWord]
        if( 0 != woStatus ) {
            printf("EhReadWord() failed. Status = %04xH\n", woStatus);
            return ;
        }

        // 現在のサーボドライバ状態から、次のサーボドライバ状態へ遷移させる関数コール
        woStatus = fnChgMotionGoState(woStatasWord, &woControlWord);
        if( woStatus == 0x27 ) {
            break;
        }

        // 次のサーボドライバ遷移値を書き込み (RSI-ECAT API コール)
        woStatus = EhWriteWord(hAPI, stSlave.dwViosOutBaseOffset, woControlWord);	// write to [ControlWord]
        if( 0 != woStatus ) {
            printf("EhWriteWord() failed. Status = %04xH\n", woStatus);
            return ;
        }
    }

    // サーボON後 100msec待機する(メーカー仕様)
	RtSleep(100);

    // モーター動作処理
    while(1)
	{
        // サイクリック処理待ち
        woStatus = EhWaitForCyclic(hAPI, WAIT_FOREVER);
        if( 0 != woStatus ) {
            break;  // サイクリック処理が中断された為、終了
        }

        // ループ毎に1000分移動要求
        EhWriteDword(hAPI, stSlave.dwViosOutBaseOffset + 3, dwTargetPos);	// write to [Target position]

        dwTargetPos += 100;

        if(dwTargetPos > 1000000){
            break;
        }
    }

    printf("program end.");
 }

RS232C通信対応スレーブの例

アルゴシステム製SIOゲートウェイECES000-01台を使用したRS-232C通信処理のサンプルプログラムです。

fileECES000SIOsample.zip ... VisualStudio2008 Project

fileECES000SIOsampleENI.zip ... ECES000-01台構成のENIファイル

■主要コードの一部抜粋
//*****************************************************************************
 // FILE NAME:   miniRSI_Ec.c
 // DESCRIPTION:  EtherCAT シリアル通信関数
 //*****************************************************************************

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <rt.h>
 #include <EhApi.h>

 #include "EtherCAT_RSI.h"
 #include "miniRSI_Ec.h"

 WORD   woMiniRsiEcDebugFlag = 0x1000;                  // DEBUG表示切替フラグ
 #define IFPm   if((woMiniRsiEcDebugFlag&0x0001)!=0)    // API起動表示
 #define IFPi   if((woMiniRsiEcDebugFlag&0x0010)!=0)    // API詳細表示
 #define IFPw   if((woMiniRsiEcDebugFlag&0x0100)!=0)    // 受信スレッド詳細表示
 #define IFPe   if((woMiniRsiEcDebugFlag&0x1000)!=0)    // エラー表示


 #define    EC_NODE_NAME        "NodeA"                 // ノード名
 #define    EC_ALIAS_NO         255                     // エイリアス番号
 #define EC_MAX_CH          4                       // シリアルCH MAX数
 #define    MAXCNT              0x01FF                  // バッファ最大数-1(Bit0から連続にビットをON)
 #define EC_RECV_CYC_TIME   100                     // 受信サイクリックタイム(msec単位)
 #define EC_PRI_INTTASK     140                     // 受信スレッドのプライオリティ


 char   ctkminiRSIC[EC_MAX_CH][16] = {"tkminiRSIC0", "tkminiRSIC1", "tkminiRSIC2", "tkminiRSIC3"};      // スレッドカタログ名

 EHHANDLE       mhHandle = 0;                       // EtherCAT API対話ハンドル
 SLAVE_DETAIL   mstSlaveDetail;                     // スレーブ詳細情報
 RTHANDLE       semRsRx[EC_MAX_CH];                 // 受信イベント通知用セマフォのハンドル
 static RTHANDLE        thRsInt[EC_MAX_CH];             // 受信バッファ監視スレッドのハンドル
 static BYTE            rxbuf[EC_MAX_CH][MAXCNT+1];     // 受信バッファ
 static WORD            rxrqe[EC_MAX_CH] ;              // 受信したいサイズ
 static WORD            rxidx1[EC_MAX_CH];              // 受信済みインデックス
 static WORD            rxidx2[EC_MAX_CH];              // 読み込みインデックス
 static DWORD       mdwEcStartFlg = 0;              // EtherCATオープン完了フラグ(0:未オープン、1:オープン完了)

 /* 未受信データサイズの取得 */
 #define    GetRxQueSize(x) ((MAXCNT)&(rxidx1[x]-rxidx2[x]))
 #define    UpRxIdx1(x) ((MAXCNT)&(1+rxidx1[x]))
 #define    UpRxIdx2(x) ((MAXCNT)&(1+rxidx2[x]))

 // ボーレートテーブル
 static struct tagBaudTable{
     DWORD      dwRate;                         // ボーレート
    BYTE        byWData;                        // シリアルポートに出力するデータ値
 }BAUDTable[] = {
     {   1200, 0x00 },
     {   2400, 0x01 },
     {   4800, 0x02 },
     {   9600, 0x03 },
     {  19200, 0x04 },
     {  38400, 0x05 },
     {  57600, 0x06 },
     { 115200, 0x07 },
     {      0, 0x00 }
 };


 // 仮printf
 void printf_(const char *fmt, ...)
 {
    int     n = 0;
    va_list ap;
    char    buf[1024];

    va_start(ap, fmt);
    n = vsprintf( buf, fmt, ap );
    va_end(ap);

    printf("%s", buf);
 }

 void Tiny_RSdebug_info()
 {
    printf_("I$ miniRSI_Ec[%04d] Tiny_RSdebug_info() CALL!! \n", __LINE__);
    printf_(" req size    [%04d][%04d][%04d][%04d] \n", rxrqe[0], rxrqe[1], rxrqe[2], rxrqe[3]);
    printf_(" write point [%04d][%04d][%04d][%04d] \n", rxidx1[0], rxidx1[1], rxidx1[2], rxidx1[3]);
    printf_(" read point  [%04d][%04d][%04d][%04d] \n", rxidx2[0], rxidx2[1], rxidx2[2], rxidx2[3]);
    printf_(" in offset   [%08xh] \n", mstSlaveDetail.dwViosInBaseOffset);
    printf_(" out offset  [%08xh] \n", mstSlaveDetail.dwViosOutBaseOffset);
 }

 // ----------------------------------------------------------------------------
 // 機 能:    EtherCAT通信を開始し、API対話を開設
 // 入 力:    なし
 // 出 力:    実行結果(0:正常、0以外:エラー)
 // ----------------------------------------------------------------------------
 int    Tiny_RSEhOpen()
 {
    WORD        woSt;

    IFPm printf_("I$ miniRSI_Ec[%04d] RSEhOpen() CALL!! \n", __LINE__);

    // すでにAPI対話が開設済みの場合、なにもせずに処理を抜ける
    if( mhHandle != 0 ){
        return( 0 );
    }

    // EtherCAT通信を開始し、API対話を開設
    mhHandle = EhOpen(EC_NODE_NAME, &woSt);
    if( mhHandle == 0 ){        // 失敗
        IFPe printf_("E$ miniRSI_Ec[%04d] EhOpen() Err[%04xh] \n", __LINE__, woSt);
        return( -1 );
    }

    return( 0 );
 }

 // ----------------------------------------------------------------------------
 // 機 能:    EtherCAT通信を終了し、API対話を閉鎖
 // 入 力:    なし
 // 出 力:    実行結果(0:正常、0以外:エラー)
 // ----------------------------------------------------------------------------
 int    Tiny_RSEhClose()
 {
    WORD        woSt;

    IFPm printf_("I$ miniRSI_Ec[%04d] RSEhClose() CALL!! \n", __LINE__);

    // すでにAPI対話が閉鎖済みの場合、なにもせずに処理を抜ける
    if( mhHandle == 0 ){
        return( 0 );
    }

    // EtherCAT通信を終了し、API対話を閉鎖
    woSt = EhClose( mhHandle );
    if( woSt != ER_EHAPI_OK ){      // 失敗
        IFPe printf_("E$ miniRSI_Ec[%04d] EhClose() Err[%04xh] \n", __LINE__, woSt);
        return( -1 );
    }
    mhHandle = 0;

    return( 0 );
 }

 // ----------------------------------------------------------------------------
 // 機 能:    マスターステートの変更要求
 // 入 力:    WORD        woState         (i)変更したいマスターステートを指定
 // 出 力:    実行結果(0:正常、0以外:エラー)
 // ----------------------------------------------------------------------------
 int    Tyny_RSEhRqState( WORD woState )
 {
    WORD        woSt;

    IFPm printf_("I$ miniRSI_Ec[%04d] RSEhRqState() CALL!! \n", __LINE__);

    // API対話が開設されていない場合、エラー
    if( mhHandle == 0 ){
        return( -1 );
    }

    // マスターステートの変更要求
    woSt = EhRqState( mhHandle, woState );
    if( woSt != ER_EHAPI_OK ){      // 失敗
        IFPe printf_("E$ miniRSI_Ec[%04d] EhRqState() Err[%04xh] \n", __LINE__, woSt);
        return( -2 );
    }

    return( 0 );
 }



 // ----------------------------------------------------------------------------
 // 機 能:    受信バッファ監視スレッド
 // 入 力:    int*        pID         (i)ch番号(0~3)
 // ----------------------------------------------------------------------------
 void far Tiny_RS_IntThread( int* pID )
 {
    WORD        woRSize;        // 受信バッファデータサイズ
    WORD        woSt;
    DWORD       i;
    WORD        woRpos;         // マスタの受信Readポインタ
    WORD        woWpos;         // スレーブの受信Writeポインタ
    BYTE        byCode;         // 受信バッファから取得したデータ
    WORD        woData;         // 出力データ
    int         nID;

    nID = *pID;

    // スレッドカタログ、ただし失敗は無視
    Catalog(NULL_RTHANDLE, GetRtThreadHandles(THIS_THREAD), ctkminiRSIC[nID]);

    while( 1 ){
        // 受信バッファ監視周期分スリープ
        RtSleepEx(EC_RECV_CYC_TIME);

        // 受信バッファデータサイズを取得
        woRSize = EhReadWord( mhHandle, mstSlaveDetail.dwViosInBaseOffset + (4 + (6 * nID)), &woSt );
        if( ER_EHAPI_OK != woSt ){
            IFPe printf_("E$ miniRSI_Ec[%04d] RS_IntThread(%d) EhReadWord() Err[%04xh] \n", __LINE__, nID, woSt);
            continue;
        }

        // 受信バッファにデータがたまっていないならループに戻る
        if( woRSize == 0 ){
            continue;
        }

        // -----------------------------------------------------------------------------------------------------
        // 受信バッファにたまっているデータ分ループ
        for(i=0; i= 32 ){     // 終点まできたら先頭位置に戻す
                woData = 0;
            }

            // マスタの受信Readポインタを更新
            woSt  = EhWriteWord( mhHandle, mstSlaveDetail.dwViosOutBaseOffset + (2 + (4 * nID)), woData );
            if( ER_EHAPI_OK != woSt ){
                IFPe printf_("E$ miniRSI_Ec[%04d] RS_IntThread(%d) EhWriteWord() Err[%04xh] \n", __LINE__, nID, woSt);
                break;
            }

        }
        // -----------------------------------------------------------------------------------------------------

        /* 受信可能になったらイベントする */
        if( (GetRxQueSize(nID) >= rxrqe[nID] ) && ( rxrqe[nID] != 0 )){
            IFPw printf_("I$ miniRSI_Ec[%04d] RS_IntThread() ID[%d] %d=(rxidx1-rxidx2) rxrqe=%d rxidx2=%d rxidx1=%d \n", __LINE__,
                        nID, GetRxQueSize(nID), rxrqe[nID], rxidx2[nID], rxidx1[nID]);

            rxrqe[nID]  = 0;
            ReleaseRtSemaphore( semRsRx[nID] ,1 );
        }else {
            IFPw printf_("I$ miniRSI_Ec[%04d] RS_IntThread() ID[%d] %d=(rxidx1-rxidx2) rxrqe=%d rxidx2=%d rxidx1=%d \n", __LINE__,
                        nID, GetRxQueSize(nID), rxrqe[nID], rxidx2[nID], rxidx1[nID]);
        }

    }

 }

 // ----------------------------------------------------------------------------
 // 機 能:    初期化関数
 // 入 力:    int         nID         (i)ch番号(0~3)
 //         int         nBaudRate   (i)ボーレートを指定(1200,2400,4800,9600,…,115200)
 //         BYTE        cCommFlags  (i)データ長、ストップビット、パリティをビットで指定
 //                                     パリティなし        0x00
 //                                     パリティ偶数        0x18
 //                                     パリティ奇数        0x08
 //                                     ストップビット1bit  0x00
 //                                     ストップビット2bit  0x04
 //                                     データ長7bit        0x02
 //                                     データ長8bit        0x03
 // 出 力:    実行結果(0:正常、0以外:エラー)
 // ----------------------------------------------------------------------------
 int Tiny_RSinit(int nID, int nBaudRate, BYTE cCommFlags)
 {
    WORD        woSt;
    BYTE        byData;
    WORD        woData;
    WORD        woBaudIndex;

    IFPm printf_("I$ miniRSI_Ec[%04d] RSinit(%d) CALL!! BaudRate[%d] CommFlags[%02xh] \n", __LINE__, nID, nBaudRate, cCommFlags);

    // API対話が開設されていない場合、エラー
    if( mhHandle == 0 ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EherCAT API Handle nothing \n", __LINE__, nID);
        return( -1 );
    }

    // スレーブ詳細情報を取得していない場合
    if( mdwEcStartFlg == 0 ){
        mstSlaveDetail.woAlias = EC_ALIAS_NO;                       // 取得するスレーブのエイリアス番号をセット
        woSt = EhFindSlaveByAlias( mhHandle, &mstSlaveDetail );     // スレーブ詳細情報を取得します。
        if( ER_EHAPI_OK != woSt ){
            IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhFindSlaveByAlias() Err[%04xh] \n", __LINE__, nID, woSt);
            return( -2 );
        }

        mdwEcStartFlg = 1;
    }

    // 指定されたchの範囲チェック
    if( (nID < 0) || (nID >= EC_MAX_CH) ){
        // 範囲外の場合、エラー
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) ID range error \n", __LINE__, nID);
        return( -3 );
    }

    // 指定されたボーレートが有効かどうか判定
    woBaudIndex = 0;
    while(TRUE) {
        // ボーレートテーブルの最後まで検索し、一致するボーレートがなかった場合、エラー
        if (BAUDTable[woBaudIndex].dwRate == 0) {
            IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) BaudRate(%d) nothing \n", __LINE__, nBaudRate);
            return( -4 );
        }

        // ボーレートテーブル内から該当するボーレートが見つかった場合、有効と判定
        if (BAUDTable[woBaudIndex].dwRate == (DWORD)nBaudRate) {
            break;
        }

        woBaudIndex ++;
    }

    // 通信タイプの設定
    byData = 0;         // 通信タイプ(0:RS232C or RS422、1:RS485)
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x01, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -5 );
    }

    // ボーレートの設定
    byData = BAUDTable[woBaudIndex].byWData;
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x03, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -6 );
    }

    // データ長の設定
    if( (cCommFlags & DATABIT_EIGHT) == DATABIT_EIGHT ){
        byData = 1;     // データ長 8bit
    }else {
        byData = 0;     // データ長 7bit
    }

    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x04, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -7 );
    }

    // ストップビットの設定
    if( (cCommFlags & STOPBIT_TWO) == STOPBIT_TWO ){
        byData = 1;     // ストップビット 2bit
    }else {
        byData = 0;     // ストップビット 1bit
    }

    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x05, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -8 );
    }

    // パリティの設定
    if( (cCommFlags & PARITY_EVEN) == PARITY_EVEN ){
        byData = 1;     // パリティ 偶数
    }else if( (cCommFlags & PARITY_ODD) == PARITY_ODD ){
        byData = 2;     // パリティ 奇数
    }else {
        byData = 0;     // パリティ なし
    }

    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x06, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -9 );
    }

    // CTSフロー制御の設定
    byData = 0;         // CTSフロー制御(0:OFF、1:ON)
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x07, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -10 );
    }

    // RTSフロー制御の設定
    byData = 0;         // RTSフロー制御(0:Disable、1:Enable、2:HandShake)
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x08, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -11 );
    }

    // Xon/Xoff 出力フロー制御の設定
    byData = 0;         // Xon/Xoff 出力フロー制御(0:OFF、1:ON)
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x09, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -12 );
    }

    // Xon/Xoff 入力フロー制御の設定
    byData = 0;         // Xon/Xoff 入力フロー制御(0:OFF、1:ON)
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x0A, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -13 );
    }

    // コントロールパラメータに通信設定を出力
    woData = 0x0001;    // コマンド(0x0001:通信設定)
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8100 + nID, 0x01, &woData, 2);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -14 );
    }

    // ポートオープン
    byData = 1;         // オープンフラグ(0:OFF、1:ON)
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x02, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -15 );
    }

    // 受信データキューの初期化
    rxrqe[nID]  = 0 ;
    rxidx1[nID] = rxidx2[nID] = 0;

    // 受信イベント通知用セマフォの生成
    semRsRx[nID] = CreateRtSemaphore( 0, 1, FIFO_QUEUING );
    if( semRsRx[nID] == BAD_RTHANDLE ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) CreateRtSemaphore() Err[%04xh] \n", __LINE__, nID, GetLastRtError());
        return( -16 );
    }

    // 受信スレッドを生成
    thRsInt[nID] = CreateRtThread(EC_PRI_INTTASK, Tiny_RS_IntThread, 1024, &nID);
    if( thRsInt[nID] == BAD_RTHANDLE ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSinit(%d) CreateRtThread() Err[%04xh] \n", __LINE__, nID, GetLastRtError());
        return( -17 );
    }

    return( 0 );
 }

 // ----------------------------------------------------------------------------
 // 機 能:    クローズ関数
 // 入 力:    int         nID         (i)ch番号(0~3)
 // 出 力:    実行結果(0:正常、0以外:エラー)
 // ----------------------------------------------------------------------------
 int Tiny_RSterm(int nID)
 {
    WORD        woSt;
    BYTE        byData;

    IFPm printf_("I$ miniRSI_Ec[%04d] RSterm(%d) CALL!! \n", __LINE__, nID);

    // API対話が開設されていない場合、エラー
    if( mhHandle == 0 ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSterm(%d) EherCAT API Handle nothing \n", __LINE__, nID);
        return( -1 );
    }

    // 指定されたchの範囲チェック
    if( (nID < 0) || (nID >= EC_MAX_CH) ){
        // 範囲外の場合、エラー
        IFPe printf_("E$ miniRSI_Ec[%04d] RSterm(%d) ID range error \n", __LINE__, nID);
        return( -2 );
    }

    // ポートクローズ
    byData = 0;         // オープンフラグ(0:OFF、1:ON)
    woSt = EhWriteOD( mhHandle, (WORD)mstSlaveDetail.dwSlaveNo, 0x8000 + nID, 0x02, &byData, 1);
    if( ER_EHAPI_OK != woSt ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSterm(%d) EhWriteOD() Err[%04xh] \n", __LINE__, nID, woSt);
        return( -3 );
    }

    // 受信スレッドの削除
    if( FALSE == DeleteRtThread( thRsInt[nID] ) ){
        return( -4 );       // スレッドの削除に失敗
    }

    // 受信イベント通知用セマフォの削除
    if( FALSE == DeleteRtSemaphore( semRsRx[nID] ) ){
        return( -5 );       // セマフォの削除に失敗
    }

    return( 0 );
 }

 // ----------------------------------------------------------------------------
 // 機 能:    送信関数
 // 入 力:    int         nID         (i)ch番号(0~3)
 //         void*       buf         (i)送信バッファのポインタ
 //         size_t      size        (i)送信サイズを指定
 // 出 力:    送信サイズ(0未満:エラー)
 // 備 考:    送信関数は未作成
 // ----------------------------------------------------------------------------
 int Tiny_RSsend( int nID, void* buf, size_t size )
 {
    IFPm printf_("I$ miniRSI_Ec[%04d] RSsend(%d) CALL!! \n", __LINE__, nID);

    // 送信関数は未作成、とりあえず指定された送信サイズをそのまま返却
    return( size );
 }

 // ----------------------------------------------------------------------------
 // 機 能:    受信関数
 // 入 力:    int         nID         (i)ch番号(0~3)
 //         void*       buf         (o)受信バッファのポインタ
 //         size_t      size        (i)受信サイズを指定
 //         DWORD       timeout     (i)受信タイムアウトを指定(単位:msec)
 //         BYTE        *lpSts      未使用
 // 出 力:    受信サイズ(0未満:エラー)
 // ----------------------------------------------------------------------------
 int Tiny_RSrecv( int nID, void* buf, size_t size, DWORD timeout, BYTE *lpSts )
 {
    WORD    lp1;

    IFPm printf_("I$ miniRSI_Ec[%04d] RSrecv(%d) CALL!! \n", __LINE__, nID);

    // 指定されたchの範囲チェック
    if( (nID < 0) || (nID >= EC_MAX_CH) ){
        // 範囲外の場合、エラー
        IFPe printf_("E$ miniRSI_Ec[%04d] RSrecv(%d) ID range error \n", __LINE__, nID);
        return( -1 );
    }

    // 受信バッファのポインタが指定されていない場合、エラー
    if( buf == NULL ){
        IFPe printf_("E$ miniRSI_Ec[%04d] RSrecv(%d) *buf null error \n", __LINE__, nID);
        return( -2 );
    }

    // 指定された受信サイズの範囲チェック
    if(( size >= sizeof(rxbuf[nID]) ) || ( size == 0 )) {
        IFPe printf_("E$ miniRSI_Ec[%04d] RSrecv(ID=%d, SIZE=%d) \n", __LINE__, nID, size );
        return( -3 );
    }

    if( GetRxQueSize(nID) >= (WORD)size ){
        // 受信データキューに溜まっているので取り出しのみ
        for( lp1=0 ;lp1= EC_MAX_CH) ){
        // 範囲外の場合、エラー
        IFPe printf_("E$ miniRSI_Ec[%04d] RSclear(%d) ID range error \n", __LINE__, nID);
        return( -1 );
    }

    // 受信データキューを取り出し済みに設定
    rxidx2[nID] = rxidx1[nID];

    return ( 0 );
 }

※TenAsys®, INtime®, eVM® and iRMX® are registered trademarks in USA of the TenAsys Corporation.
※EtherCAT® は、Beckhoff Automation GmbH, Germanyの登録商標です。