このサンプルは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.");
}
アルゴシステム製SIOゲートウェイECES000-01台を使用したRS-232C通信処理のサンプルプログラムです。
ECES000SIOsample.zip ... VisualStudio 2008 Project
ECES000SIOsampleENI.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 );
}