PCプラットフォームによる PCプラットフォームによる 産業用ソリューションプロバイダー 産業用ソリューションプロバイダー


採用情報


お問合せ

JapaneseEnglish

  • PP359

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対話を閉鎖して通信を終えます。
EhSetApiTimeout() EH APIの応答タイムアウトを設定します。
EhGetApiTimeout() EH APIの応答タイムアウトを取得します。
マスター制御  
EhRqState() マスターステートの変更要求を行います。
EhGetState() 現在要求中のマスターステートと現在のマスターステートを取得します。
EhWaitForCyclic() マスターサイクリック処理の開始を待機します。
EhCancelWaitForCyclic() EhWaitForCyclicで待機中のスレッドに対して待機を中断し、APIから返るようにします。
EhGetSystemInfo() マスターの情報を取得します。
イベント制御  
EhSetEventFilter() 診断イベントのフィルタを設定します。
EhGetEventFilter() 設定されている診断イベントのフィルタ情報を取得します。
EhWaitForEvent() 診断イベントを待機します。
スレーブ検索  
EhFindSlave() VendorID, ProductCode の指定でスレーブを検索し詳細情報を取得します。
EhFindSlaveByAlias() エイリアス番号の指定でスレーブを検索し詳細情報を取得します。
EhFindSlaveBySlaveNo() スレーブの接続順番号の指定でスレーブを検索し詳細情報を取得します。
スレーブ管理  
EhGetSlaveStatus() 対象スレーブのステータス情報を取得します。
EhGetSlaveCount() コンフィグレーション(XML)定義上のスレーブ数を取得します。
EhGetOnlineSlaveCount() 接続しているスレーブ数を取得します。
EhGetSlaveStatus() 対象スレーブのステータス状態を取得します。
EhGetALStatus() 対象スレーブのALステータスを取得します。
EhGetALStatusCode() 対象スレーブのALステータスコードを取得します。
EhGetDLStatus() 対象スレーブのDLステータスコードを取得します。
EhReadRegister() 対象スレーブのESCレジスタからデータを読み取ります。
EhWriteRegister() 対象スレーブのESCレジスタへデータを書き込みます。
EhReadEEPROM() 対象スレーブのEEPROMからデータを読み取ります。
EhWriteEEPROM() 対象スレーブのEEPROMへデータを書き込みます。
EhRecalcCheckSum() 対象スレーブのEEPROMのチェックサムを再計算し、チェックサムを更新します。
ProcessDataアクセス  
EhGetViosInAddress() Process Imageの入力メモリの先頭アドレスを取得します。
(以降、メモリアクセスでProcess Imageの入力値が読めます。)
EhGetViosOutAddress() Process Imageの出力メモリの先頭アドレスを取得します。
(以降、メモリアクセスでProcess Imageの出力メモリへ値が書き込めます。)
EhGetViosInOffset() 指定エイリアスのスレーブからProcess Imageの入力メモリオフセット値を取得します。
EhGetViosOutOffset() 指定エイリアスのスレーブからProcess Imageの出力メモリオフセット値を取得します。
EhReadByte() Process Imageの入力メモリから8ビットデータを読み取ります。
EhReadWord() Process Imageの入力メモリから16ビットデータを読み取ります。
EhReadDWord() Process Imageの入力メモリから32ビットデータを読み取ります。
EhWriteByte() Process Imageの出力メモリへ8ビットデータを書き込みます。
EhWriteWord() Process Imageの出力メモリへ16ビットデータを書き込みます。
EhWriteDWord() Process Imageの出力メモリへ32ビットデータを書き込みます。
EhReadbackByte() Process Imageの出力メモリから8ビットデータを読み取ります。
EhReadbackWord() Process Imageの出力メモリから16ビットデータを読み取ります。
EhReadbackDWord() Process Imageの出力メモリから32ビットデータを読み取ります。
Mailboxアクセス  
EhReadOD() 指定スレーブのオブジェクトディクショナリからデータを読み取ります。
EhWriteOD() 指定スレーブのオブジェクトディクショナリへデータを書き込みます。
EhReadODByAlias() 指定エイリアスのスレーブが持つオブジェクトディクショナリからデータを読み取ります。
EhWriteODByAlias() 指定エイリアスのスレーブが持つオブジェクトディクショナリへデータを書き込みます。
EhSetTimeoutForOD() EhReadOD, EhWriteOD, EhReadODByAlias, EhWriteODByAlias APIの応答タイムアウトを設定します。
EhGetTimeoutForOD() EhReadOD, EhWriteOD, EhReadODByAlias, EhWriteODByAlias APIの応答タイムアウトを取得します。

RSI-ECAT-Masterの高レベルAPI(RSI-ECAT HI API)

RSI-ECAT HI APIでは、基本的な EtherCAT通信制御を 5つの API(Init,Open,Close,Read,Write)で実現します。
特長として、EtherCAT回線利用までの初期処理が簡略化されており、Openコールによって、マスタステートの Operationalまでの遷移、及び、その間に考慮すべきリトライ処理が内部で自動的に実行されるため、Open コールに成功すれば、Read/Write APIによりVIOS領域を介してプロセスイメージへの値の読み書きが可能となります。また他のユーザーアプリケーションのオープン状態を把握しているため、Closeコールによって、他のユーザーアプリケーションへの影響はありません。
これらの機能により、基本的なEtherCATプログラミングをシンプルに作成することができます。また、EH API(低レベル API)を併用することで、より詳細な制御を行うことも可能です。
RSI-ECAT HI API Feature
初期化API  
Init() RSI-ECAT HI APIの初期化します。
Open() EtherCAT®回線をオープンし、マスタステートをOperationalへ遷移させます。
Close() Open()でオープンしたEtherCAT®回線をクローズし、確保していたリソースを解放します。
ProcessDataアクセス  
Read() 指定バイトサイズのデータを読み取ります。
Write() 指定バイトサイズのデータを書き込みます。
■ 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 + RSI-ECAT-Master
 * Data, Writer       :                                  2023/06/16 : 篠崎勝利
 \*****************************************************************************/
 #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(woStatus != ER_EHAPI_OK) {
                 printf("EhGetEhNodeStatus() Status = %04xH\n", woStatus);
                 printf("start check failed\n");
                 return ;
         }

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

         // Masterステートチェンジ要求 (RSI-ECAT API コール)
         // MST_OPERATIONAL : オペレーショナルへ遷移
         woStatus = EhRqState(hAPI, MST_OPERATIONAL);
         if(woStatus != ER_EHAPI_OK) {
                 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.dwVendorID    = 131;
         stSlave.dwProductCode = 50;
         stSlave.dwInstance    = 0;

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

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

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

         printf("program end.");
 }

高レベルAPIによるDIOスレーブ制御の事例

このサンプルはRSI-ECAT-Masterの高レベルAPIを使用し、OMRON Corporation社のディジタルI/Oスレーブ製品を制御するC言語INtime®アプリケーションです。コード中のオフセットアドレス、値などについては、メーカーの製品仕様に準じます。
高レベルAPIを用いた場合、EtherCAT通信を意識することなくプロセスデータへのアクセス処理を記述することができます。
/*****************************************************************************
 * Description        : DO プログラムサンプル
 * Software           : INtime 6.4 + RSI-ECAT 4.1.0
 * Data, Writer       :                                  2023/06/16 : okamoto
 \*****************************************************************************/
#include <stdio.h>
#include <rt.h>
#include <HiECAT.h>

/*****************************************************************************
 * Description : main 処理
 \*****************************************************************************/
int main(int argc, char* argv[])
{
	DWORD		dwRes;				// 処理結果
	IFHANDLE	hIF = NULL;			// インターフェースハンドル値
	RSIHANDLE	hRsi = NULL;		// 接続インスタンスハンドル値
	BYTE		byDoData = 0;		// スレーブへの書込み値

	// 初期化処理
	dwRes = Init(NULL, "NodeA", &hIF, 3000);
	if(dwRes != ER_HI_OK){
		printf("Fail to initialize API. Status = %08xH\n", dwRes);
		return ;
	}
	 
	// EtherCAT回線オープン、マスタステートをOperational状態へ遷移
	dwRes = Open(hIF, "", &hRsi, 30000);
	if(dwRes != ER_HI_OK){
		printf("Fail to open EtherCAT connection. Status = %08xH\n", dwRes);
		return ;
	}

    // 動作処理: ループ毎にON/OFF変換要求
    while(1)
	{
		// 周期生成
		RtSleepEx(1);

		// 読み取り
		Read(hRsi, HIECAT_CALC_VIOS_OUT(0), &byDoData, 1, sizeof(byDoData), 0);

		// 値更新
		if( byDoData != 0 ) { byDoData = 0x00; } 
		else                { byDoData = 0xFF; }

		// 書込み
		Write(hRsi, HIECAT_CALC_VIOS_OUT(0), &byDoData, 1, 0);
	}

	// EtherCAT回線のクローズ
	Close(hRsi);
	
	printf("program end.");
	return 0;
}

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

このサンプルは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 position 4 3 サーボモータ目標位置

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

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


// 制御で利用するオブジェクトのPDO Mapping情報
//------------------------------------------------------

// PI/IN:                  offset  (CoEIndex)
//------------------------+------+------------
//  Statusword               +02h  (6041h:00)

// PI/OUT:                  offset  (CoEIndex)
//------------------------+------+------------
//  Controlword              +00h  (6040h:00)
//  Modes of operation       +02h  (6060h:00)
//  Target potion            +03h  (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(woStatus != ER_EHAPI_OK) {
        printf("start check failed\n");
        return ;
    }

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

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

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

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

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

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

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

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

        dwTargetPos += 100;

        if(dwTargetPos > 1000000){
            break;
        }
    }

    printf("program end.");
 }

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

このサンプルはRSI-ECAT-Masterを使用し、日本パルスモーター社CiA402準拠モーション制御スレーブ EC-AD1241A4 (VendorId=0x00000B07,ProductId=0x000010001)をProfile position mode(プロファイルポジションモード)で制御するC言語INtime®アプリケーションです。
コード中のオフセットアドレス、値などについては、メーカーの製品仕様に準じます。

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

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

<output>
Name Size (byte) Offset (byte) 意味
Controlword 2 0 PDS状態確認
Target position 4 2 サーボモータ目標位置
Profile velocity 4 6 サーボモータ目標速度
Profile acceleration 4 10 サーボモータ目標加速度
Profile deceleration 4 14 サーボモータ目標減速度
Modes of operation 1 22 制御モードの変更

■ 使用したENIファイル:
RtEcHdrEC-AD1241A4.zip: EC-AD1241A4 1台構成のENIファイルです。

■ サンプルコード
 /*****************************************************************************
 * Description        : CiA402 モーションプログラムサンプル   プロファイルポジションモード
 * Software           : INtime 6.4 + RSI-ECAT 3.0.9
 * Data, Writer       :                                  2023/09/08 : okamoto
 \*****************************************************************************/
 #include 
 #include 
 #include 
 #include 

// 制御で利用するオブジェクトのPDO Mapping情報
//------------------------------------------------------

// PI/IN:                  offset  (CoEIndex)
//------------------------+------+------------
// Statusword               +00h  (6041h:00)

// PI/OUT                  offset  (CoEIndex)
//------------------------+------+------------
// Controlword              +00h  (6040h:00)
// Target position          +02h  (607Ah:00)
// Profile velocty          +06h  (6081h:00)
// Profile acceleration     +0Ah  (6083h:00)
// Profile deceleration     +0Eh  (6084h:00)
// Modes of operation       +16h  (6060h: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 : CiA402 サーボドライバ状態遷移処理(初期状態へ戻す)
 \*****************************************************************************/
  WORD   fnChgMotionInitState(WORD woStWd, WORD *pCrWd)
 {
    switch( (0x6F & woStWd) ) {
    case    0:                                    break; // 未初期化状態   (初期状態)
    case 0x40:                                    break; // 初期化完了状態 (初期状態)
    case 0x60:                                    break; // 初期化完了状態 (初期状態)
    case 0x21: *pCrWd = (0xFF70 & *pCrWd) | 0x00; break; // 主回路電源OFF状態  -> 初期化完了状態
    case 0x23: *pCrWd = (0xFF70 & *pCrWd) | 0x06; break; // サーボレディ状態   -> 主回路電源OFF状態
    case 0x27: *pCrWd = (0xFF70 & *pCrWd) | 0x07; break; // サーボON状態       -> サーボレディ要求
    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			woStatusWord;	
    WORD			woControlWord;
    SLAVE_DETAIL    stSlave;
	

	// <<<< EtherCAT回線のOPEN >>>>
	//------------------------------------------------------
    // RSI-ECAT 起動状態チェック (RSI-ECAT API コール)
    woStatus = EhGetEhNodeStatus("NodeA", 100);
    if( (woStatus != ER_EHAPI_OK) && (woStatus != ER_EHAPI_OPENED) ) {
        printf("start check failed\n");
        return ;
    }
    // RSI-ECAT API対話ハンドルOPEN (RSI-ECAT API コール)
    hAPI = EhOpen("NodeA", &woStatus);
    if(woStatus != ER_EHAPI_OK) {
        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    = 0x0B07;				//  ここで操作するスレーブ用のVendorIDとProductCodeを入れること
    stSlave.dwProductCode = 0x1001;				//  VendorIDとProductCodeは、RSI-ECAT-StudioかENIファイルから確認できます。
    stSlave.dwInstance    = 0;
    woStatus = EhFindSlave(hAPI, &stSlave);
    if(woStatus != ER_EHAPI_OK) {
        printf("EhFindSlave() failed. Status = %04xH\n", woStatus);
        return ;
    }

    // CiA402 動作モードの変更
    // 1 : プロファイルポジションモード へ変更要求
    byModeVal = 1;
    woStatus = EhWriteByte(hAPI, stSlave.dwViosOutBaseOffset + 0x16, byModeVal);	// write to Modes of operation
    if(woStatus != ER_EHAPI_OK) {
        printf("EhWriteODByAlias() failed. Status = %04xH\n", woStatus);
        return ;
    }


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

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

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

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

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

    // サーボON後 100msec待機する(各メーカー仕様に合わせて設定)
	RtSleep(100);


	// <<<< 位置決め制御の実行 >>>>
	//------------------------------------------------------
	// 位置決め制御の登録  ※お使いのサーボモータの分解能に応じて値を設定してください。
	woStatus = 0;
	woStatus |= EhWriteDword(hAPI, stSlave.dwViosOutBaseOffset + 0x02, 10000);	//  目標位置のセット write to Target position		
	woStatus |= EhWriteDword(hAPI, stSlave.dwViosOutBaseOffset + 0x06, 10000);	//  目標速度のセット write to Profile velocty		
	woStatus |= EhWriteDword(hAPI, stSlave.dwViosOutBaseOffset + 0x0A, 100000);	//  加速度のセット   write to Profile acceleration
	woStatus |= EhWriteDword(hAPI, stSlave.dwViosOutBaseOffset + 0x0E, 100000);	//  減速度のセット   write to Profile deceleration
    if(woStatus != ER_EHAPI_OK) {
        printf("EhWriteDword() failed. Status = %04xH\n", woStatus);
        return ;
	}
    // Controlwordへの設定値を演算
	woControlWord = EhReadbackWord(hAPI, stSlave.dwViosOutBaseOffset + 0x00, &woStatus); // 現在値の読み込み read from ControlWord
    if(woStatus != ER_EHAPI_OK) {
        printf("EhWriteDword() failed. Status = %04xH\n", woStatus);
        return ;
	}
	woControlWord |= 0x0010;	// bit4:New Set-PointをONする
	woControlWord |= 0x0040;	// bit6:RelativeをONする

	// 位置決め制御(相対座標系)の開始 
	woStatus = EhWriteWord(hAPI, stSlave.dwViosOutBaseOffset + 0x00, woControlWord);	//  write to ControlWord
    if(woStatus != ER_EHAPI_OK) {
        printf("EhWriteWord() failed. Status = %04xH\n", woStatus);
        return ;
	}

	// スレーブ側で指令受け取ったかの確認
    while(1) 
	{
        // サイクリック処理待ち
        woStatus = EhWaitForCyclic(hAPI, WAIT_FOREVER);
        if(woStatus != ER_EHAPI_OK) {
            break;  // サイクリック処理が中断された為、終了
        }

		// 現在値の読み込み
		woStatusWord = EhReadWord(hAPI, stSlave.dwViosInBaseOffset + 0x00, &woStatus);	// read from StatusWord
		// 到達したか確認
		if((woStatusWord & 0x1000) == 0x1000)	// bit12:Set-Point AcknowledgeがONであるか確認
		{
			// [到達]
			break;
		}
    }


	// <<<< 目標位置到達の待機 >>>>
	//------------------------------------------------------
    while(1) 
	{
        // サイクリック処理待ち
        woStatus = EhWaitForCyclic(hAPI, WAIT_FOREVER);
        if(woStatus != ER_EHAPI_OK) {
            break;  // サイクリック処理が中断された為、終了
        }

		// 現在値の読み込み
		woStatusWord = EhReadWord(hAPI, stSlave.dwViosInBaseOffset + 0x00, &woStatus);	// read from StatusWord

		// 到達したか確認
		if((woStatusWord & 0x0400) == 0x0400)	// bit10:Target reachedがONであるか確認
		{
			// [到達]
			break;
		}
    }
	
	
	// <<<< 目標位置到達の待機 >>>>
	//------------------------------------------------------
	// Controlword: New Set-PointをOFFする
	woControlWord &= (~0x0010); // bit4:New Set-PointをOFFする
	woStatus = EhWriteWord(hAPI, stSlave.dwViosOutBaseOffset + 0x00, woControlWord);	//  write to ControlWord
    if(woStatus != ER_EHAPI_OK) {
        printf("EhWriteWord() failed. Status = %04xH\n", woStatus);
        return ;
	}

	
	// <<<< サーボOFF状態へ遷移 >>>>
	//------------------------------------------------------
	// CiA402 サーボドライバ状態を、初期状態に戻す
    while(1) {
        woControlWord = 0;

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

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

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

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


	// <<<< EtherCAT回線のCLOSE >>>>
	//------------------------------------------------------
	EhClose(hAPI);
    printf("program end.");
 }

RS232C通信対応スレーブの例

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

fileECES000SIOsample.zip ... VisualStudio 2008 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( (woSt != ER_EHAPI_OK) && (woSt != ER_EHAPI_OPENED) ) {	// 失敗
        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<woRSize; i++){

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

            // スレーブの受信Writeポインタを取得
            woWpos = EhReadWord( mhHandle, mstSlaveDetail.dwViosInBaseOffset + (26 + (4 * nID)), &woSt );
            if( ER_EHAPI_OK != woSt ){
                IFPe printf_("E$ miniRSI_Ec[%04d] RS_IntThread(%d) EhReadWord() Err[%04xh] \n", __LINE__, nID, woSt);
                break;
            }

            // 読み込み位置と書き込み位置が一致した場合、読み込むデータがなくなったと判断し処理を抜ける
            if( woRpos == woWpos ){
                break;
            }

            // 受信バッファから受信データを取得
            byCode = EhReadByte( mhHandle, mstSlaveDetail.dwViosInBaseOffset + (40 + (32 * nID)) + woRpos, &woSt );
            if( ER_EHAPI_OK != woSt ){
                IFPe printf_("E$ miniRSI_Ec[%04d] RS_IntThread(%d) EhReadByte() Err[%04xh] \n", __LINE__, nID, woSt);
                break;
            }

            // 受信データキューの空きがあれば格納
            if( GetRxQueSize(nID) < (sizeof(rxbuf[nID])-1) ){
                rxbuf[nID][rxidx1[nID]] = byCode;
                rxidx1[nID] = UpRxIdx1(nID);        // カウントを1つ更新(サイクリック)
            }

            // マスタの受信Readポインタを1つ更新
            woData = (BYTE)(woRpos + 1);
            if( woData >= 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<size ;lp1++ ) {
            *((BYTE*)buf+lp1) = rxbuf[nID][rxidx2[nID]];
            rxidx2[nID] = UpRxIdx2(nID);        // カウントを1つ更新(サイクリック)
        }
    }
    else{
        // 受信イベント通知用セマフォを空読み(前回の通知イベントが残っている場合があるので)
        WaitForRtSemaphore( semRsRx[nID], 1, NO_WAIT );

        // 受信要求と受信待ち
        rxrqe[nID]  = size;
        if( WaitForRtSemaphore( semRsRx[nID] ,1 ,timeout ) == WAIT_FAILED ) {
            IFPe printf_("E$ miniRSI_Ec[%04d] RSrecv(ID=%d, SIZE=%d): TimeOut \n", __LINE__, nID, size );
            return( -4 );
        }

        // 受信データキューからの取り出し
        for( lp1=0 ;lp1<size ;lp1++ ) {
            *((BYTE*)buf+lp1) = rxbuf[nID][rxidx2[nID]];
            rxidx2[nID] = UpRxIdx2(nID);        // カウントを1つ更新(サイクリック)
        }
    }

    return( size );
 }

 // ----------------------------------------------------------------------------
 // 機 能:    受信クリア関数
 // 入 力:    int         nID         (i)ch番号(0~3)
 // 出 力:    実行結果(0:正常、0以外:エラー)
 // ----------------------------------------------------------------------------
 int Tiny_RSclear(int nID)
 {
    IFPm printf_("I$ miniRSI_Ec[%04d] RSclear(%d) CALL!! \n", __LINE__, nID);

    // 指定されたchの範囲チェック
    if( (nID < 0) || (nID >= 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 );
 }