• 2022/12/16
  • ルンバ

Roomba

④ルンバとのUART通信

RL-78の設定と初期化関数

UART設定と送受信割込み処理は、「RL-78のUART0操作例」を参照してください。ここでのルンバ通信にはUART0を利用するとします
以下で使うサンプルプログラムのリストは、ここからダウンロードできます

・サンプルファイルのダウンロード

UART0のTxD:ユニット0(m=0)、チャンネル0(n=0)
UART0のRxD:ユニット0(m=0)、チャンネル1(n=1)

以下は全体に関わる定義や初期化関数で、受信バッファ _gRcvBuf と送信バッファ _gSndBuf はリングバッファとして動作します

・RL-78の受信は、1バイト受信毎に割込み関数_ComRmb_IntRcvが起動され、受信データを_gRcvBuf にセットします。割込み内から割込み外処理へデータを渡すバッファです

・RL-78からの送信は、_gSndBuf にデータをセットすれば割込み関数_ComRmb_IntSndで自動的に送信処理をします。割込み外から割込み内処理にデータを渡すバッファです

・_gRcvBuf と _gSndBuf のどちらのバッファに対しても「バッファ書き込み時に書込みインデックスが読込みインデックスに追いついた場合はバッファオーバー」のエラーとする必要があります

#define M_RING_INC(a,b) (((b)<=(a+1)) ? (a=0):(a+=1))	// マクロ定義
#define C_SIZE_COM_FRAME       22						// 送受信フレームの最大長
#define C_SIZE_COM_BUF         40						// 割込内送受信バッファサイズ
#define	_C_CNT_RMB_RCV_MESSAGE 52						// 受信メッセージ数
#define _C_CNT_RMB_QUELY       27						// パケットクエリー数
#define _C_CMD_RMB_STREAM      19						// CmdStream(148)に対する応答

//*************************
//         UART
//     割込外送受信フレーム
//*************************
typedef struct
{
	uint16_t		Count;								// 送受信バイト数
	uint8_t			Data[ C_SIZE_COM_FRAME ];			// 送受信データ
} T_COM_FRAME;

//************************
//         UART
//    割込内送受信バッファ
//************************
typedef struct
{
	uint16_t		WriteIdx;							// 書込みインデックス
	uint16_t		ReadIdx;							// 読込みインデックス
	uint8_t			Buf[ C_SIZE_COM_BUF ];				// バッファ
} T_COM_BUFFER;

//*************************
//         UART
//       受信ステート
//*************************
typedef enum
{
	enComState_RcvStandby		= 0,					// 待機中
	enComState_RcvStx,									// STX受信済
	enComState_Rcv,										// データ受信中
	enComState_RmbHeader,								// ヘッダー待ち
	enComState_RmbCount,								// データ数待ち
	enComState_RmbPacketId,								// パケットID待ち
	enComState_RmbData,									// データ受信中
	enComState_RmbChecksum								// チェックサム待ち
} COM_RCV_STATE;

//*************************
//         UART
//       受信ステータス
//*************************
typedef enum
{
	enComStatus_RcvNon			= 0,					// 受信データなし
	enComStatus_RcvAck,									// ACK受信
	enComStatus_RcvNack,								// NAK受信
	enComStatus_RcvStx,									// STX受信
	enComStatus_RcvDat,									// データ受信中
	enComStatus_RcvEtx,									// フレーム受信完了
	enComStatus_RcvNotStx,								// 先頭がSTXでない無効データ受信
	enComStatus_RcvNotEtx,								// 最後がETXでない無効データ受信
	enComStatus_RcvErr,									// エラー発生
	enComStatus_RcvNotSupported,						// 未対応プロトコル
	enComStatus_RcvRmbCount,							// データ数待ち
	enComStatus_RcvRmbPacketId,							// パケットID待ち
	enComStatus_RcvRmbData,								// データ受信中
	enComStatus_RcvRmbChecksum,							// チェックサム待ち
	enComStatus_RcvRmbPacketEnd,						// 全パケット受信完了
	enComStatus_RcvRmbErr								// エラー発生
} COM_RCV_STATUS;

//*************************
//       RL通信エラー
//*************************
typedef enum
{
	enComErr_Non				= 0,					// エラーなし	
	enComErr_RcvIndexOver,								// 受信インデックス超え
	enComErr_RcvChecksum,								// 受信チェックサムエラー
	enComErr_RcvNotStx,									// 先頭がSTXでない無効データ受信
	enComErr_RcvNotEtx,									// 最後がETXでない無効データ受信
	enComErr_RcvNotSupported,							// 未対応プロトコル受信
	enComErr_RcvOverrun,								// 受信バッファオーバーラン
	enComErr_SndIndexOver,								// 送信インデックス超え
	enComErr_SndAck,									// ACK送信エラー
	enComErr_SndStx,									// STX送信エラー
	enComErr_SndFrame,									// データ送信エラー
	enComErr_SndChecksum,								// チェックサム送信エラー
	enComErr_SndEtx										// ETX送信エラー
} COM_ERROR;

//*************************
//         変数
//*************************
static COM_RCV_STATE         _gRcvState    = enComState_RmbHeader;// 割込外フレーム受信ステート
static T_COM_FRAME           _gRcvFrame    = { 0 };	// 割込外受信フレーム
static uint16_t              _gPacketCount = 0;		// 割込外受信パケット数

static volatile BOOL         _gSending     = FALSE;	// 割込内送信中フラグ
static volatile T_COM_BUFFER _gRcvBuf      = { 0 };	// 割込内受信バッファ
static volatile T_COM_BUFFER _gSndBuf      = { 0 };	// 割込内送信バッファ

T_RMB_DATA                   gRmbData      = { 0 };	// ルンバセンサデータ
volatile COM_ERROR           gRmbComError  = enComErr_Non;// 送受信エラー

//************************************************************************************************
//	機能概要:通信初期化、割込許可、管理変数の初期化
//	引数	:なし
//	戻り値	:なし
//	備考	:
//************************************************************************************************
void ComRmb_Init( void )
{
	_ComRmb_Stop();										// UART停止・割込み禁止

	_gRcvState        = enComState_RmbHeader;			// 割込外フレーム受信ステート
	_gRcvFrame.Count  = 0;								// 割込外受信フレーム
	_gPacketCount     = 0;								// 割込外受信パケット数
	_gSending         = FALSE;							// 割込内送信中フラグクリア
	_gRcvBuf.WriteIdx = 0;								// 割込内受信バッファ 書込みインデックスクリア
	_gRcvBuf.ReadIdx  = 0;								// 割込内受信バッファ 読込みインデックスクリア
	_gSndBuf.WriteIdx = 0;								// 割込内送信バッファ 書込みインデックスクリア
	_gSndBuf.ReadIdx  = 0;								// 割込内送信バッファ 読込みインデックスクリア
	gRmbComError      = enComErr_Non;					// 送受信エラー

	_ComRmb_Start();									// UART動作・割込み許可
}
//************************************************************************************************
//	機能概要:メインから呼ぶ ComRmb_RcvFrame 関数の初期化を行う。ルンバからのストリームデータの受信で
//			:同期がとれないケースのエラーに対し受信処理を初期化して同期をとる
//			:この対応は初期化後の受信開始時に起きる enComErr_RcvIndexOver エラーへの対応として追加
//	引数	:なし
//	戻り値	:なし
//	備考	:
//************************************************************************************************
void ComRmb_InitRcvFrame( void )
{
	_gRcvState       = enComState_RmbHeader;			// 割込外フレーム受信ステート
	_gRcvFrame.Count = 0;								// 割込外受信フレーム
}

送受信割込み関数

送受信割込み処理は、「RL-78のUART0操作例」を参照してください。関数名称の違いだけで同じ関数です

#pragma interrupt _ComRmb_IntRcv( vect = INTSR0  )
#pragma interrupt _ComRmb_IntSnd( vect = INTST0  )
#pragma interrupt _ComRmb_IntErr( vect = INTSRE0 )

//*************************
//         ビット
//*************************
#define BIT0 (0x00000001U)
#define BIT1 (0x00000002U)
#define BIT2 (0x00000004U)
#define BIT3 (0x00000008U)
#define BIT4 (0x00000010U)
#define BIT5 (0x00000020U)
#define BIT6 (0x00000040U)
#define BIT7 (0x00000080U)

//************************************************************************************************
//	機能概要	:UART動作・割込み許可
//	引数	:なし
//	戻り値	:なし
//	備考	:
//************************************************************************************************
static void _ComRmb_Start( void )
{
	SO0		|= BIT0;									// 出力Hiセット
	SOE0	|= BIT0;									// 出力許可
	SS0		|= ( BIT1 | BIT0 );							// 送受信開始
	STIF0	 = 0U; 										// 送信割込み要求フラグクリア
	SRIF0	 = 0U;										// 受信割込み要求フラグクリア
	SREIF0	 = 0U;										// 受信エラー割込み要求フラグクリア
	STMK0	 = 0U;										// 送信割込み許可
	SRMK0	 = 0U;										// 受信割込み許可
	SREMK0	 = 0U;										// 受信エラー割込み許可
}
//************************************************************************************************
//	機能概要	:UART停止・割込み禁止
//	引数	:なし
//	戻り値	:なし
//	備考	:
//************************************************************************************************
static void _ComRmb_Stop( void )
{
	STMK0	 = 1U;										// 送信割込みマスク
	SRMK0	 = 1U;										// 受信割込みマスク
	SREMK0	 = 1U;										// 受信エラー割込みマスク
	ST0		|= ( BIT1 | BIT0 );							// 送受信停止
	SOE0	&= ~(BIT0);									// 出力禁止
	STIF0	 = 0U;										// 送信割込み要求フラグクリア
	SRIF0	 = 0U;										// 受信割込み要求フラグクリア
	SREIF0	 = 0U;										// 受信エラー割込み要求フラグクリア
}
//************************************************************************************************
//	機能概要:エラー処理。既にエラーが発生している場合はスルー
//	引数	:Error エラーメッセージ
//	戻り値	:なし
//	備考	:
//************************************************************************************************
static void _ComRmb_Error( COM_ERROR Error )
{
	if(( gRmbComError != enComErr_Non ) || ( Error == enComErr_Non ))
	{
		return;
	}
	gRmbComError = Error;
}
//************************************************************************************************
//	機能概要	:受信割込みハンドラ
//	引数	:なし
//	戻り値	:なし
//	備考	:
//************************************************************************************************
static void __near _ComRmb_IntRcv( void )
{
	volatile uint8_t rx_data = RXD0;					// レジスタ読込み
	_gRcvBuf.Buf[ _gRcvBuf.WriteIdx ] = rx_data;		// データ格納
	M_RING_INC( _gRcvBuf.WriteIdx, C_SIZE_COM_BUF );	// 書込インデックス更新
	if( _gRcvBuf.WriteIdx == _gRcvBuf.ReadIdx )		// 書込が読込に追いついた
	{
		_ComRmb_Error( enComErr_RcvOverrun );			// 受信バッファオーバーラン
		return;
	}
}
//************************************************************************************************
//	機能概要	:送信割込みハンドラ
//	引数	:なし
//	戻り値	:なし
//	備考	:
//************************************************************************************************
static void __near _ComRmb_IntSnd( void )
{
	if( _gSndBuf.ReadIdx == _gSndBuf.WriteIdx )		// 読込みが書込みに追いついた場合
	{
		/* ---< 転送完了での割込み >--- */
		if(( SMR00 & 0x0001U ) == 0U )
		{
			_gSending = FALSE;							// 転送完了
		}
		/* ---< 転送前のバッファ空きでの割込み >--- */
		else
		{
			SMR00 &= ~(0x0001U);						// 転送完了割込みセット
		}
	}
	else
	{
		SMR00 |= 0x0001U;								// 転送前のバッファ空きでの割込み/
		TXD0   = _gSndBuf.Buf[ _gSndBuf.ReadIdx ];		// レジスタ書込み
		M_RING_INC(_gSndBuf.ReadIdx,C_SIZE_COM_BUF);	// 読込みインデックス更新
	}
}
//************************************************************************************************
//	機能概要:受信エラー割込
//	引数	:なし
//	戻り値	:なし
//	備考	:
//************************************************************************************************
static void __near _ComRmb_IntErr( void )
{
	volatile uint8_t err;
	volatile uint8_t rx = 0;
	
	rx   |= RXD0;										// ダミーリード
	err   = (uint8_t)( SSR01 & 0x0007U );				// エラー取得(フレーミング、パリティ、オーバーラン)
	SIR01 = (uint16_t)err;								// 同エラークリア
}

送受信プロトコル

ルンバへのコマンド指示は垂れ流しでコマンド(Opcode)を送信し、ルンバのセンサ情報取得はストリーム形式での送受信を行います。「ルンバとIFでの留意点・・・その1」を参照願います

コマンド(Opcode)の垂れ流しで、不明なコードが戻ることがたまにありますが無視します。RL-78からストリームコマンドを送信した場合、ルンバから不明なコードが送信されることはないので、受信はヘッダ(19)を常に監視して受信開始すれば大丈夫です

コマンド(Opcode)送信

ルンバへのコマンド(Opcode)を送信(センサコマンド除く)する関数群です

・送信は_ComRmb_Send関数に送信データの配列へのポインタと送信データ数を渡して送信します

・_ComRmb_Send関数では、_ComRmb_SetByte関数で送信データを送信バッファ_gSndBufにセットします

・_ComRmb_Send関数内で送信データをセットしたら、_ComRmb_SendStart関数で送信割込みを起動します

以下のコマンド関数群の中でリセットコマンドはルンバに無視され、Fullモードコマンドは未定義コマンドにセットされてしまうので実際には使用していません。SafeモードコマンドがFUllモードにセットされるので、Safeモードコマンドを使用しました
ストップコマンドは無視されているようですが、念のためレベルで停止時とか初期化時に使ってはいます

ルンバに対する初期化処理は、以下のコマンド送信で実行します

・スタートコマンド送信(ComRmb_CmdStart)

・Safeモードコマンド送信(ComRmb_CmdSafe)

・センサコマンド送信(ComRmb_CmdSensor)

//************************************************************************************************
//	機能概要	:コマンド関数群
//	引数	:各関数参照
//	戻り値	:TRUE(成功)、FALSE(エラー)
//	備考	:
//************************************************************************************************
//*************************
//       スタートコマンド
//*************************
BOOL ComRmb_CmdStart( void )
{
	return _ComRmb_SendCmd( enOpCode_Start );
}
//*************************
//       リセットコマンド・・・ルンバに無視され使えない
//*************************
BOOL ComRmb_CmdReset( void )
{
	return _ComRmb_SendCmd( enOpCode_Reset );
}
//*************************
//      ストップコマンド・・・多分ルンバに無視され使えないが、念のため使ってはいる
//*************************
BOOL ComRmb_CmdStop( void )
{
	return _ComRmb_SendCmd( enOpCode_Stop );
}
//*************************
//     Safeモードコマンド・・・Fullモードになる
//*************************
BOOL ComRmb_CmdSafe( void )
{
	return _ComRmb_SendCmd( enOpCode_Safe );
}
//*************************
//     Fullモードコマンド・・・未定義モードになる
//*************************
BOOL ComRmb_CmdFull( void )
{
	return _ComRmb_SendCmd( enOpCode_Full );
}
//*************************
//       Dockコマンド
//*************************
BOOL ComRmb_CmdDock( void )
{
	return _ComRmb_SendCmd( enOpCode_Dock );
}
//*************************
//   パワーコマンド(電源オフ)
//*************************
BOOL ComRmb_CmdPowerOff( void )
{
	return _ComRmb_SendCmd( enOpCode_PowerOff );
}
//*************************
//     アクチュエータコマンド
//*************************
// SpeedL_MMPS:左タイヤ速度[mm/s]
// SpeedR_MMPS:右タイヤ速度[mm/s]
BOOL ComRmb_CmdDrive( int16_t SpeedL_MMPS, int16_t SpeedR_MMPS )
{
	uint8_t spdL[ 2 ];									// 送信バイト列 速度
	uint8_t spdR[ 2 ];									// 送信バイト列 速度
	uint8_t frame[ 5 ];									// 送信データ

	Utility_GetUint16ToBigByte( SpeedL_MMPS, spdL );	// ビッグエンディアン配列取得
	Utility_GetUint16ToBigByte( SpeedR_MMPS, spdR );

	frame[ 0 ] = enOpCode_DriveDirect;
	frame[ 1 ] = spdR[ 0 ];
	frame[ 2 ] = spdR[ 1 ];
	frame[ 3 ] = spdL[ 0 ];
	frame[ 4 ] = spdL[ 1 ];
	return _ComRmb_Send( frame, 5 );					// 送信
}
//************************************************************************************************
//	機能概要	:送信バッファへ1バイトセットして送信する
//	引数	:Data 送信データ
//	戻り値	:TRUE(成功)、FALSE(エラー)
//	備考	:
//************************************************************************************************
static BOOL _ComRmb_SendCmd( uint8_t Data )
{
	uint8_t data[ 1 ] = { Data };
	return _ComRmb_Send( data, 1 );
}
//************************************************************************************************
//	機能概要	:送信バッファへ指定バイトセットして送信する
//	引数	:Data  送信データ
//			:Count データ数
//	戻り値	:TRUE(成功)、FALSE(エラー)
//	備考	:
//************************************************************************************************
static BOOL _ComRmb_Send( uint8_t* Data, uint16_t Count )
{
	uint16_t index;

	for( index = 0; index < Count; index++ )			// メッセージ・データセット
	{
		if( FALSE == _ComRmb_SetByte( Data[ index ] ))
		{
			return FALSE;
		}
	}
	return _ComRmb_SendStart();							// 書込みインデックス更新と送信
}
//************************************************************************************************
//	機能概要	:送信バッファへ1バイトセットする
//	引数	:Data セットするデータ
//	戻り値	:TRUE(成功)、FALSE(エラー)
//	備考	:
//************************************************************************************************
static BOOL _ComRmb_SetByte( uint8_t Data )
{
	STMK0  = 1U;										// 送信割込みマスク

	/* ---< 送信バッファへセット >--- */
	_gSndBuf.Buf[ _gSndBuf.WriteIdx ] = Data;			// データ格納
	M_RING_INC( _gSndBuf.WriteIdx, C_SIZE_COM_BUF );	// 書込みインデックス更新
	if( _gSndBuf.ReadIdx == _gSndBuf.WriteIdx )		// 読込みインデックスに追いついた
	{
		_ComRmb_Error( enComErr_SndIndexOver );		// 範囲超え
		return FALSE;
	}

	STMK0 = 0U;											// 送信割込み許可
	return TRUE;
}
//************************************************************************************************
//	機能概要	:送信開始
//	引数	:なし
//	戻り値	:TRUE(成功)、FALSE(エラー)
//	備考	:送信割込動作中は自動で送信されるので起動の必要なし
//************************************************************************************************
static BOOL _ComRmb_SendStart( void )
{
	STMK0  = 1U;										// 送信割込みマスク

	/* ---< 送信データなしの場合 >--- */
	if( _gSending == FALSE )
	{
		_gSending = TRUE;
		SMR00    |= 0x0001U;							// 転送前のバッファ空きでの割込み
		TXD0      = _gSndBuf.Buf[ _gSndBuf.ReadIdx ];	// データをセット
		M_RING_INC( _gSndBuf.ReadIdx, C_SIZE_COM_BUF );// 読込みインデックス更新
	}
	/* ---< 送信データありの場合 >--- */
	else
	{
		;/* Do Nothing 割り込み処理内で書き込みインデックスまで勝手に送信する */
	}
	STMK0 = 0U;											// 送信割込み許可
	return TRUE;
}

ストリームコマンドによるセンサ要求送信

ストリーム形式での送受信を行います。ストリームコマンド(148)とパケットID数、センサデータを要求するパケットIDを並べて送信します
「148、パケット数、パケットID・・・」

送信するパケットIDを _gQuely 配列で定義します。実際に送信されるデータは、
「148、_C_CNT_RMB_QUELY、_gQuely配列内容」
となります

//*************************
// パケットクエリテーブル
//*************************
static const char _gQuely[ _C_CNT_RMB_QUELY ] =
{
	enPacket_EncoderLeft,								// 左タイヤエンコーダ累積値
	enPacket_EncoderRight,								// 右タイヤエンコーダ累積値
	enPacket_LightBumpLSig,								// 左ライトバンパー信号強度
	enPacket_LightBumpFLSig,							// 左前ライトバンパー信号強度
	enPacket_LightBumpCLSig,							// 左センターライトバンパー信号強度
	enPacket_LightBumpCRSig,							// 右センターライトバンパー信号強度
	enPacket_LightBumpFRSig,							// 右前ライトバンパー信号強度
	enPacket_LightBumpRSig,								// 右ライトバンパー信号強度

	enPacket_BumpsDrop,									// 乗り上げ、脱輪
	enPacket_CliffLeft,									// 左崖有無
	enPacket_CliffFLeft,								// 左前崖有無
	enPacket_CliffFRight,								// 右前崖有無
	enPacket_CliffRight,								// 右崖有無
	enPacket_CliffLeftSig,								// 左崖センサ信号強度
	enPacket_CliffFLeftSig,								// 左前崖センサ信号強度
	enPacket_CliffFRightSig,							// 右前崖センサ信号強度
	enPacket_CliffRightSig,								// 右崖センサ信号強度

	enPacket_BattChargingSrc,							// 充電のリソース
	enPacket_BattVoltage,								// バッテリ電圧[mV]
	enPacket_BattCurrent,								// バッテリー電流[mA]
	enPacket_BattTemperature,							// バッテリー温度[℃]
	enPacket_BattCharge,								// 現在のバッテリー充電量[mAh]
	enPacket_BattCapacity,								// 現在のバッテリー充電容量[mAh]

	enPacket_OiMode,									// 現在のモード
	enPacket_Buttons,									// ボタンの押下状態
	enPacket_IrLeft,									// 左赤外線通信
	enPacket_IrRight,									// 右赤外線通信
};

//*************************
//       センサコマンド
//*************************
// 15ms間隔で自動的にパケット応答がくるコマンド
// 予め決めた配列から指定したパケット要求を出す
BOOL ComRmb_CmdSensor( void )
{
	uint8_t index;
	uint8_t frame[ _C_CNT_RMB_QUELY + 2 ] = { 0 };		// コマンド+パケット要求数の2バイト加算

	/* ---< コマンドセット >--- */
	frame[ 0 ] = enOpCode_Stream;
	/* ---< 指定パケット抽出 >--- */
	_gPacketCount = 0;
	for( index = 0; index < _C_CNT_RMB_QUELY; index++ )
	{
		frame[ _gPacketCount + 2 ] = _gQuely[index];	// 送信用フレームバッファへパケットIDセット
		_gPacketCount++;
	}
	/* ---< パケット要求数セット >--- */
	frame[ 1 ] = _gPacketCount;

	/* ---< 指定パケットのクエリ送信 >--- */
	return _ComRmb_Send( frame, _gPacketCount + 2 );
}

センサデータのストリーム受信

受信データを詳細に書くと次のようになります
[19][N-bytes][Packet ID 1][Packet 1 Data…][Packet ID 2][Packet 2 Data…]・・・[Packet ID N][Packet N data…][Checksum]

・[19] ストリーム応答のヘッダ

・[N-bytes] Packet ID、Packet Data・・・Packet ID、Packet Data・・・のパケットにかかるデータバイト数

・[Packet ID] パケットID

・[Packet Data] パケットIDのデータ(データサイズはパケットIDに従う)

・[Checksum] Checksum を含めて、全通信データを合計すると0となる値が Checksum として通知される


main 関数の while 文から ComRmb_RcvFrame 関数をコールし続けて、受信エラーの場合の対処を main 関数内で行います

void main( void )
{
	ComRmb_InitCom();
	while( 1 )
	{
		if( enComStatus_RcvRmbErr == ComRmb_RcvFrame())
		{
			// ここにエラー処理を入れる
		}
	}
}

ComRmb_RcvFrame 関数を分割して説明します。関数全体は分割説明の次に添付します
ComRmb_RcvFrame 関数がmain 関数からコールされた時点で受信データなしなら戻ります。バッファへの書込み位置 WriteIdx と読込み位置 ReadIdx が同じ位置をさしていれば、処理すべき受信データはありません

受信データは、1バイト送信される毎に割込み関数 _ComRmb_IntRcv が起動され、その1バイト受信データは _gRcvBuf の Buf[] 内に格納されます。ComRmb_IntRcv 関数で1バイト受信すると WriteIdx は +1されます。リングバッファなので、バッファの最後に達したら WriteIdx は0になります。少なくとも格納された時点で WriteIdx != ReadIdx の関係(受信データあり)になります

COM_RCV_STATUS ComRmb_RcvFrame( void )
{
	static uint16_t  dataCount;							// 1パケットのデータ数
	static uint16_t  packetCount;						// 受信パケット数
	static uint8_t   checkSum;							// チェックサム
	uint8_t          rcvData;							// 1バイト受信データ
	const T_MES_TBL* table;								// 送受信定義テーブル

	/* ---< 受信データなし >--- */
	if( _gRcvBuf.ReadIdx == _gRcvBuf.WriteIdx )
	{
		return enComStatus_RcvNon;
	}

受信データを割込み内受信バッファ _gRcvBuf から読込みます。同時に読込みインデックスを更新します。1バイト読みだしたので ReadIdx は +1、バッファの最後に達したら ReadIdx は0になります

	//*************************
	//   受信データ読み込み
	//*************************
	if( _gRcvFrame.Count >= C_SIZE_COM_FRAME )
	{
		_ComRmb_Error( enComErr_RcvIndexOver );		// 範囲超え
		return enComStatus_RcvErr;
	}

	rcvData = _gRcvBuf.Buf[ _gRcvBuf.ReadIdx ];		// データ取得
	M_RING_INC( _gRcvBuf.ReadIdx, C_SIZE_COM_BUF );	// 読込インデックス更新

①ヘッダー待ち処理

・受信ステート _gRcvState は初期状態でヘッダー待ち enComState_RmbHeader です。受信データがヘッダ _C_CMD_RMB_STREAM(19) でなければエラーで戻し、ヘッダならチェックサムをセットして受信処理が開始されます

・次回ステートをパケット数待ちとし戻ります

	//*************************
	//     受信データ解析
	//*************************
	switch( _gRcvState )
	{
		case enComState_RmbHeader:						// ヘッダー待ち
			if( rcvData != _C_CMD_RMB_STREAM )
			{
				return enComStatus_RcvRmbErr;
			}
			packetCount = 0;							// 受信(処理済)パケット数クリア
			checkSum    = (uint8_t)_C_CMD_RMB_STREAM;	// チェックサムセット
			_gRcvState  = enComState_RmbCount;			// データ数待ちへ
			return enComStatus_RcvRmbCount;

②パケット数待ち処理

・受信データをチェックサムに加算します。パケット数は _gPacketCount とローカル変数 packetCount で管理し、この受信データは使っていません

・次回ステートをパケットID待ちとし戻ります

		case enComState_RmbCount:						// データ数待ち(ヘッダー,カウント,チェックサム除くデータ)
			checkSum  += (uint8_t)rcvData;				// チェックサム更新
			_gRcvState = enComState_RmbPacketId;		// パケットID待ちへ
			return enComStatus_RcvRmbPacketId;

③パケットID待ち処理

・受信テーブル_gRcvTableから受信したパケットIDにあたるテーブルを取得してます。後述の「受信データ長取得関数Utility_GetTable」参照

・割込外受信フレームをクリアし、以降の受信データをここに格納していきます

・割込外受信フレームにパケットIDを格納します

・受信データをチェックサムに加算します

・次に受信するデータ長をテーブルから取得します

・次回ステートをデータ受信中とし戻ります

		case enComState_RmbPacketId:					// パケットID待ち
			table = Utility_GetTable( rcvData, _gRcvTable, _C_CNT_RMB_PACKET_ID );	// 受信コマンドに対応したテーブル取得
			if( table == NULL )
			{
				return enComStatus_RcvRmbErr;
			}
			_gRcvFrame.Count  = 0;						// 割込外受信フレーム
			_gRcvFrame.Data[ _gRcvFrame.Count++ ] = rcvData;// パケットID
			checkSum  += (uint8_t)rcvData;				// チェックサム更新
			dataCount  = table->RcvMessageLen - 1;		// 1パケットのデータ数(ヘッダー受信済なので-1)
			_gRcvState = enComState_RmbData;			// データ受信中
			return enComStatus_RcvRmbData;

④データ受信処理

・割込外受信フレームに受信データを格納します

・受信データをチェックサムに加算します

・受信データ長を減算します

・受信データが無ければ以降を処理し、受信データがあれば戻ります

・受信したパケットデータを後述の「受信データ解析関数_ComRmb_AnalizePacket」で解析し、ルンバデータgRmbDataにセットします

・受信パケット数を加算します

・受信予定パケット数_gPacketCountを全て受信したら、次回ステートをチェックサム待ちとし戻ります

・まだ受信するパケットがあれば、次回ステートをパケットID待ちとし戻ります

		case enComState_RmbData:						// データ受信中
			_gRcvFrame.Data[_gRcvFrame.Count++]=rcvData;// データ
			checkSum += (uint8_t)rcvData;				// チェックサム更新
			dataCount--;
			if( dataCount == 0 )						// 1パケット受信完了
			{
				/* ---< 1パケットの解析とデータセット >--- */
				if( !_ComRmb_AnalizePacket( _gRcvFrame.Data[ 0 ], (uint8_t*)( _gRcvFrame.Data + 1 )))
				{
					return enComStatus_RcvRmbErr;
				}
				packetCount++;							// 受信(処理済)パケット数
				if( packetCount >= _gPacketCount )		// 全パケット受信済の場合、チェックサム待ちへ
				{
					_gRcvState=enComState_RmbChecksum;	// チェックサム待ちへ
					return enComStatus_RcvRmbChecksum;
				}
				else
				{
					_gRcvState=enComState_RmbPacketId;	// パケットID待ちへ
					return enComStatus_RcvRmbPacketId;
				}
			}
			return enComStatus_RcvRmbData;

⑤チェックサム待ち処理

・受信データをチェックサムに加算します

・チェックサムが0でなければエラーとして戻ります

・チェックサムが正常なら、処理完了で次回の受信に備え変数を初期化し戻ります

		case enComState_RmbChecksum:					// チェックサム待ち
			checkSum += (uint8_t)rcvData;				// チェックサム更新
			if( checkSum != 0 )							// checkSum + チェックサム = 0 が正解
			{
				return enComStatus_RcvRmbErr;
			}
			/* ---< ストリーム受信完了 >--- */
			packetCount = 0;							// 受信(処理済)パケット数クリア
			_gRcvState  = enComState_RmbHeader;			// ヘッダー受信待ちへ

			return enComStatus_RcvRmbPacketEnd;			// 全パケット受信完了

ComRmb_RcvFrame関数

//************************************************************************************************
//	機能概要:割込内の受信バッファから受信データを取り出しパケット解析する
//			:複数パケットを連続受信するので、受信予定のパケット数は _gPacketCount に格納されており
//			:全パケット受信・解析完了で enComStatus_RcvRmbPacketEnd を戻す
//	引数	:なし
//	戻り値	:受信状態 全パケット受信・解析完了で enComStatus_RcvRmbPacketEnd
//	備考	:
//************************************************************************************************
COM_RCV_STATUS ComRmb_RcvFrame( void )
{
	static uint16_t  dataCount;							// 1パケットのデータ数
	static uint16_t  packetCount;						// 受信パケット数
	static uint8_t   checkSum;							// チェックサム
	uint8_t          rcvData;							// 1バイト受信データ
	const T_MES_TBL* table;								// 送受信定義テーブル

	/* ---< 受信データなし >--- */
	if( _gRcvBuf.ReadIdx == _gRcvBuf.WriteIdx )
	{
		return enComStatus_RcvNon;
	}

	//*************************
	//   受信データ読み込み
	//*************************
	if( _gRcvFrame.Count >= C_SIZE_COM_FRAME )
	{
		_ComRmb_Error( enComErr_RcvIndexOver );		// 範囲超え
		return enComStatus_RcvErr;
	}

	rcvData = _gRcvBuf.Buf[ _gRcvBuf.ReadIdx ];		// データ取得
	M_RING_INC( _gRcvBuf.ReadIdx, C_SIZE_COM_BUF );	// 読込インデックス更新
	//*************************
	//     受信データ解析
	//*************************
	switch( _gRcvState )
	{
		case enComState_RmbHeader:						// ヘッダー待ち
			if( rcvData != _C_CMD_RMB_STREAM )
			{
				return enComStatus_RcvRmbErr;
			}
			packetCount = 0;							// 受信(処理済)パケット数クリア
			checkSum    = (uint8_t)_C_CMD_RMB_STREAM;	// チェックサムセット
			_gRcvState  = enComState_RmbCount;			// データ数待ちへ
			return enComStatus_RcvRmbCount;
		case enComState_RmbCount:						// データ数待ち(ヘッダー,カウント,チェックサム除くデータ)
			checkSum  += (uint8_t)rcvData;				// チェックサム更新
			_gRcvState = enComState_RmbPacketId;		// パケットID待ちへ
			return enComStatus_RcvRmbPacketId;
		case enComState_RmbPacketId:					// パケットID待ち
			table = Utility_GetTable( rcvData, _gRcvTable, _C_CNT_RMB_PACKET_ID );	// 受信コマンドに対応したテーブル取得
			if( table == NULL )
			{
				return enComStatus_RcvRmbErr;
			}
			_gRcvFrame.Count  = 0;						// 割込外受信フレーム
			_gRcvFrame.Data[_gRcvFrame.Count++]=rcvData;// パケットID
			checkSum  += (uint8_t)rcvData;				// チェックサム更新
			dataCount  = table->RcvMessageLen - 1;		// 1パケットのデータ数(ヘッダー受信済なので-1)
			_gRcvState = enComState_RmbData;			// データ受信中
			return enComStatus_RcvRmbData;
		case enComState_RmbData:						// データ受信中
			_gRcvFrame.Data[_gRcvFrame.Count++]=rcvData;// データ
			checkSum += (uint8_t)rcvData;				// チェックサム更新
			dataCount--;
			if( dataCount == 0 )						// 1パケット受信完了
			{
				/* ---< 1パケットの解析とデータセット >--- */
				if( !_ComRmb_AnalizePacket( _gRcvFrame.Data[ 0 ], (uint8_t*)( _gRcvFrame.Data + 1 )))
				{
					return enComStatus_RcvRmbErr;
				}
				packetCount++;							// 受信(処理済)パケット数
				if( packetCount >= _gPacketCount )		// 全パケット受信済の場合、チェックサム待ちへ
				{
					_gRcvState=enComState_RmbChecksum;	// チェックサム待ちへ
					return enComStatus_RcvRmbChecksum;
				}
				else
				{
					_gRcvState=enComState_RmbPacketId;	// パケットID待ちへ
					return enComStatus_RcvRmbPacketId;
				}
			}
			return enComStatus_RcvRmbData;
		case enComState_RmbChecksum:					// チェックサム待ち
			checkSum += (uint8_t)rcvData;				// チェックサム更新
			if( checkSum != 0 )							// checkSum + チェックサム = 0 が正解
			{
				return enComStatus_RcvRmbErr;
			}
			/* ---< ストリーム受信完了 >--- */
			packetCount = 0;							// 受信(処理済)パケット数クリア
			_gRcvState  = enComState_RmbHeader;			// ヘッダー受信待ちへ

			return enComStatus_RcvRmbPacketEnd;			// 全パケット受信完了
		default:
			return enComStatus_RcvRmbErr;
	}
}

OpcodeとPacketID定義

RL-78から送信するコマンド(Opcode)を以下に示します。ここでのコメントは、iRobot® Create® 2 Open Interfaceから抜粋したものですが、実際にはコメント通りの動作をしないものもあります。「692で使用できなかったコマンド」参照

//*************************
//     RL-78送信コマンド
//   Opcode(オペレーションコード)
//*************************
typedef enum
{
	/* 基本コマンドメッセージ */
	enOpCode_Start				= 128,					// スタートコマンド
	enOpCode_Reset				= 7,					// リセットコマンド
	enOpCode_Stop				= 173,					// ストップコマンド
	enOpCode_Baud				= 129,					// ボーレートコマンド
	enOpCode_Safe				= 131,					// Safeモードコマンド
	enOpCode_Full				= 132,					// Fullモードコマンド

	/* クリーニングコマンドメッセージ */
	enOpCode_Clean				= 135,					// クリーンコマンド
	enOpCode_Max				= 136,					// マックスコマンド
	enOpCode_Spot				= 134,					// スポットコマンド
	enOpCode_Dock				= 143,					// ドックコマンド
	enOpCode_PowerOff			= 133,					// パワーコマンド
	enOpCode_Schedule			= 167,					// スケジュールコマンド
	enOpCode_Clock				= 168,					// 時刻セットコマンド

	/* アクチュエータコマンドメッセージ */
	enOpCode_Drive				= 137,					// ドライブコマンド
	enOpCode_DriveDirect		= 145,					// ドライブダイレクトコマンド
	enOpCode_DrivePWM			= 146,					// ドライブPWMコマンド
	enOpCode_Mot				= 138, 					// モータコマンド
	enOpCode_MotPWM				= 144,					// PWMモータコマンド
	enOpCode_Led				= 139,					// LEDコマンド
	enOpCode_LedScheduling		= 162,					// LEDスケジューリングLEDコマンド
	enOpCode_LedDigit			= 163,					// LEDデジットコマンド
	enOpCode_LedButton			= 165,					// LEDボタンコマンド
	enOpCode_LedAscii			= 164,					// LEDアスキーコマンド
	enOpCode_Song				= 140,					// ソングコマンド
	enOpCode_Play				= 141,					// プレイコマンド

	/* インプットコマンドメッセージ */
	enOpCode_Sensor				= 142,					// センサーコマンド
	enOpCode_Quely				= 149,					// クエリーリストコマンド
	enOpCode_Stream				= 148,					// ストリームコマント
	enOpCode_PauseResume		= 150,					// Pause/Resumeストリームコマンド
} RMB_OP_CODE;
//*************************
//      RL-78センサ要求
//    PacketID(パケットID)
//*************************
typedef enum
{
	enPacket_BumpsDrop			= 7,					// Bumps and Wheel Drops
	enPacket_Wall				= 8,					// Wall
	enPacket_CliffLeft			= 9,					// Cliff Left
	enPacket_CliffFLeft			= 10,					// Cliff Front Left
	enPacket_CliffFRight		= 11,					// Cliff Front Right
	enPacket_CliffRight			= 12,					// Cliff Right
	enPacket_VirtualWall		= 13,					// Virtual Wall
	enPacket_WheelOverCur		= 14,					// Wheel Overcurrents
	enPacket_DirtDetect			= 15,					// Dirt Detect
	enPacket_UnusedByte			= 16,					// Unused Byte
	enPacket_InfraredOmni		= 17,					// Infrared Character Omni
	enPacket_InfraredLeft		= 52,					// Infrared Character Left
	enPacket_InfraredRight		= 53,					// Infrared Character Right
	enPacket_Buttons			= 18,					// Buttons
	enPacket_Distance			= 19,					// Distance
	enPacket_Angle				= 20,					// Angle
	enPacket_BattCharging		= 21,					// Charging State
	enPacket_BattVoltage		= 22,					// Battery Voltage
	enPacket_BattCurrent		= 23,					// Battery Current
	enPacket_BattTemperature	= 24,					// Battery Temperature
	enPacket_BattCharge			= 25,					// Battery Charge
	enPacket_BattCapacity		= 26,					// Battery Capacity
	enPacket_WallSig			= 27,					// Wall Signal
	enPacket_CliffLeftSig		= 28,					// Cliff Left Signal
	enPacket_CliffFLeftSig		= 29,					// Cliff Front Left Signal
	enPacket_CliffFRightSig		= 30,					// Cliff Front Right Signal
	enPacket_CliffRightSig		= 31,					// Cliff Right Signal
	enPacket_BattChargingSrc	= 34,					// Charging Sources Available
	enPacket_OiMode				= 35,					// OI Mode
	enPacket_SongNumber			= 36,					// Song Number
	enPacket_SongPlaying		= 37,					// Song Playing
	enPacket_StreamPcks			= 38,					// Number of Stream Packets
	enPacket_ReqVelocity		= 39,					// Requested Velocity
	enPacket_ReqRadius			= 40,					// Requested Radius
	enPacket_ReqRVelocity		= 41,					// Requested Right Velocity
	enPacket_ReqLVelocity		= 42,					// Requested Left Velocity
	enPacket_EncoderLeft		= 43,					// Left Encoder Counts
	enPacket_EncoderRight		= 44,					// Right Encoder Counts
	enPacket_LightBumper		= 45,					// Light Bumper
	enPacket_LightBumpLSig		= 46,					// Light Bump Left Signal
	enPacket_LightBumpFLSig		= 47,					// Light Bump Front Left Signal
	enPacket_LightBumpCLSig		= 48,					// Light Bump Center Left Signal
	enPacket_LightBumpCRSig		= 49,					// Light Bump Center Right Signal
	enPacket_LightBumpFRSig		= 50,					// Light Bump Front Right Signal
	enPacket_LightBumpRSig		= 51,					// Light Bump Right Signal
	enPacket_IrLeft				= 52,					// Infrared Character Left
	enPacket_IrRight			= 53,					// Infrared Character Right
	enPacket_MotCurLeft			= 54,					// Left Motor Current
	enPacket_MotCurRight		= 55,					// Right Motor Current
	enPacket_MotCurMain			= 56,					// Main Brush Motor Current
	enPacket_MotCurSide			= 57,					// Side Brush Motor Current
	enPacket_Stasis				= 58					// Stasis
} RMB_PACKET_ID;

ルンバのセンサ型定義

大きく「走行制御項目」「走行安全項目」「電気的安全項目」「その他項目」の分類で型定義(T_RMB_DATA)しています。その中の詳細の項目は、iRobot® Create® 2 Open Interface に従います

//*************************
//      ルンバのセンサ型
//*************************
typedef enum
{
	enRmbOff				= 0,						// オフモード
	enRmbPassive,										// パッシブモード
	enRmbSafe,											// セーフモード
	enRmbFull											// フルモード
} RMBMODE;
typedef union BumpsDrop
{
	uint8_t		Data;
	struct
	{
		uint8_t	BumpR		: 1;						// 右バンパー衝突
		uint8_t	BumpL		: 1;						// 左バンパー衝突
		uint8_t	DropR		: 1;						// 右脱輪
		uint8_t	DropL		: 1;						// 左脱輪
		uint8_t	b4			: 1;
		uint8_t	b5			: 1;
		uint8_t	b6			: 1;
		uint8_t	b7			: 1;
	} BIT;
} BIT_BUMPDROP;
typedef union WheelOverCur								// 過電流 1:過電流あり 0:なし
{
	uint8_t		Data;
	struct
	{
		uint8_t	SideB		: 1;						// サイドブラシ
		uint8_t	b1			: 1;
		uint8_t	MainB		: 1;						// メインブラシ
		uint8_t	WheelR		: 1;						// 右タイヤ
		uint8_t	WheelL		: 1;						// 左タイヤ
		uint8_t	b5			: 1;
		uint8_t	b6			: 1;
		uint8_t	b7			: 1;
	} BIT;
} BIT_WHEELOVERCUR;
typedef union Buttons									// ボタンの押下状態 1:押下あり 0:なし
{
	uint8_t		Data;
	struct
	{
		uint8_t	Clean		: 1;						// Clean
		uint8_t	Spot		: 1;						// Spot
		uint8_t	Dock		: 1;						// Dock
		uint8_t	Minitue		: 1;						// Minitue
		uint8_t	Hour		: 1;						// Hour
		uint8_t	Day			: 1;						// Day
		uint8_t	Schedule	: 1;						// Schedule
		uint8_t	Clock		: 1;						// Clock
	} BIT;
} BIT_BUTTONS;
typedef union ChargingSrc								// 充電のリソース 1:ソースあり & 充電中 0:以外
{
	uint8_t		Data;
	struct
	{
		uint8_t	Inner		: 1;						// 内部充電器充電
		uint8_t	Home		: 1;						// ドック充電器充電
		uint8_t	b2			: 1;
		uint8_t	b3			: 1;
		uint8_t	b4			: 1;
		uint8_t	b5			: 1;
		uint8_t	b6			: 1;
		uint8_t	b7			: 1;
	} BIT;
} BIT_CHARGESRC;
typedef union LightBump									// ライトバンパー検出
{
	uint8_t		Data;
	struct
	{
		uint8_t	LightBumpL	: 1;						// 左ライトバンパー
		uint8_t	LightBumpFL	: 1;						// 左前ライトバンパー
		uint8_t	LightBumpCL	: 1;						// 左センターライトバンパー
		uint8_t	LightBumpCR	: 1;						// 右センターライトバンパー
		uint8_t	LightBumpFR	: 1;						// 右前ライトバンパー
		uint8_t	LightBumpR	: 1;						// 右ライトバンパー
		uint8_t	b6			: 1;
		uint8_t	b7			: 1;
	} BIT;
} BIT_LIGHTBUMP;
typedef struct
{
	int16_t				EncoderLeft;					// 左タイヤエンコーダ累積値
	int16_t				EncoderRight;					// 右タイヤエンコーダ累積値
	int16_t				LightBumpLSig;					// 左ライトバンパー信号強度
	int16_t				LightBumpFLSig;					// 左前ライトバンパー信号強度
	int16_t				LightBumpCLSig;					// 左センターライトバンパー信号強度
	int16_t				LightBumpCRSig;					// 右センターライトバンパー信号強度
	int16_t				LightBumpFRSig;					// 右前ライトバンパー信号強度
	int16_t				LightBumpRSig;					// 右ライトバンパー信号強度
	BIT_LIGHTBUMP		LightBumper;					// ライトバンパー検出
} T_MOVE_CNTL;
typedef struct
{
	int16_t				CliffLeftSig;					// 左崖センサ信号強度
	int16_t				CliffFLeftSig;					// 左前崖センサ信号強度
	int16_t				CliffFRightSig;					// 右前崖センサ信号強度
	int16_t				CliffRightSig;					// 右崖センサ信号強度
	BOOL				CliffLeft;						// 左崖有無
	BOOL				CliffFLeft;						// 左前崖有無
	BOOL				CliffFRight;					// 右前崖有無
	BOOL				CliffRight;						// 右崖有無
	BIT_BUMPDROP		BumpDrop;						// 乗り上げ、脱輪
} T_MOVE_SAFTY;
typedef struct
{
	int16_t				BattVoltage;					// バッテリ電圧[mV]
	int16_t				BattCurrent;					// バッテリー電流[mA]
	int16_t				BattTemperature;				// バッテリー温度[℃]
	int16_t				BattCharge;						// 現在のバッテリー充電量[mAh]
	int16_t				BattCapacity;					// 現在のバッテリー充電容量[mAh]
	uint8_t				BattCharging;					// 充電状態
	BIT_CHARGESRC		BattChargingSrc;				// 充電のリソース
	BIT_WHEELOVERCUR	WheelOverCur;					// 過電流
} T_ELEC_SAFTY;
typedef struct
{
	RMBMODE				OiMode;							// 現在のモード
	BIT_BUTTONS			Buttons;						// ボタンの押下状態
	uint8_t				IrLeft;							// 左赤外線通信
	uint8_t				IrRight;						// 右赤外線通信
} T_RMB_OTHERS;
typedef struct
{
	T_MOVE_CNTL			MoveCntl;						// 走行制御項目のセンサ情報
	T_MOVE_SAFTY		MoveSafty;						// 走行安全項目のセンサ情報
	T_ELEC_SAFTY		ElecSafty;						// 電気的安全項目のセンサ情報
	T_RMB_OTHERS		Others;							// その他項目のセンサ情報
} T_RMB_DATA;

受信データ長取得関数

//************************************************************************************************
//	機能概要	:受信定義テーブルから検索メッセージのテーブルを探して戻す
//	引数	:Message     検索メッセージ
//			:Table       受信定義テーブル
//			:TableLength 受信定義テーブル長
// 戻り値	:検索した受信定義テーブル
//	備考	:
//************************************************************************************************
const T_MES_TBL* Utility_GetTable( uint8_t Message, const T_MES_TBL* Table, uint16_t TableLength )
{
	int index;
	
	/* ---< 検索メッセージのテーブル取得し戻す >--- */
	for( index = 0; index < TableLength; index++ )
	{
		if( Table[ index ].Message == Message )
		{
			return &( Table[ index ] );
		}
	}
	return NULL;
}
//*************************
// UART
// シリアル受信長
//*************************
typedef struct
{
	uint8_t			Message;							// 送受信メッセージ
	int16_t			RcvMessageLen;						// 受信メッセージ長
} T_MES_TBL;

static const T_MES_TBL _gRcvTable[ _C_CNT_RMB_PACKET_ID ] =
{
	// パケットID					メッセージ長(パケットID長 + データ長)
	{ enPacket_BumpsDrop,		( 1 + 1 )	},			// Bumps and Wheel Drops
	{ enPacket_Wall,			( 1 + 1 )	},			// Wall(非推奨)
	{ enPacket_CliffLeft,		( 1 + 1 )	},			// Cliff Left
	{ enPacket_CliffFLeft,		( 1 + 1 )	},			// Cliff Front Left
	{ enPacket_CliffFRight,		( 1 + 1 )	},			// Cliff Front Right
	{ enPacket_CliffRight,		( 1 + 1 )	},			// Cliff Right
	{ enPacket_VirtualWall,		( 1 + 1 )	},			// Virtual Wall
	{ enPacket_WheelOverCur,	( 1 + 1 )	},			// Wheel Overcurrents
	{ enPacket_DirtDetect,		( 1 + 1 )	},			// Dirt Detect
	{ enPacket_UnusedByte,		( 1 + 1 )	},			// Unused Byte
	{ enPacket_InfraredOmni,	( 1 + 1 )	},			// Infrared Character Omni
	{ enPacket_InfraredLeft,	( 1 + 1 )	},			// Infrared Character Left
	{ enPacket_InfraredRight,	( 1 + 1 )	},			// Infrared Character Right
	{ enPacket_Buttons,			( 1 + 1 )	},			// Buttons
	{ enPacket_Distance,		( 1 + 2 )	},			// Distance(要バージョン確認)
	{ enPacket_Angle,			( 1 + 2 )	},			// Angle(要バージョン確認)
	{ enPacket_BattCharging,	( 1 + 1 )	},			// Charging State
	{ enPacket_BattVoltage,		( 1 + 2 )	},			// Battery Voltage
	{ enPacket_BattCurrent,		( 1 + 2 )	},			// Battery Current
	{ enPacket_BattTemperature,	( 1 + 1 )	},			// Battery Temperature
	{ enPacket_BattCharge,		( 1 + 2 )	},			// Battery Charge
	{ enPacket_BattCapacity,	( 1 + 2 )	},			// Battery Capacity
	{ enPacket_WallSig,			( 1 + 2 )	},			// Wall Signal(非推奨)
	{ enPacket_CliffLeftSig,	( 1 + 2 )	},			// Cliff Left Signal
	{ enPacket_CliffFLeftSig,	( 1 + 2 )	},			// Cliff Front Left Signal
	{ enPacket_CliffFRightSig,	( 1 + 2 )	},			// Cliff Front Right Signal
	{ enPacket_CliffRightSig,	( 1 + 2 )	},			// Cliff Right Signal
	{ enPacket_BattChargingSrc,	( 1 + 1 )	},			// Charging Sources Available
	{ enPacket_IrLeft,			( 1 + 1 )	},			// Infrared Character Left
	{ enPacket_IrRight,			( 1 + 1 )	},			// Infrared Character Right
	{ enPacket_OiMode,			( 1 + 1 )	},			// OI Mode
	{ enPacket_SongNumber,		( 1 + 1 )	},			// Song Number
	{ enPacket_SongPlaying,		( 1 + 1 )	},			// Song Playing
	{ enPacket_StreamPcks,		( 1 + 1 )	},			// Number of Stream Packets
	{ enPacket_ReqVelocity,		( 1 + 2 )	},			// Requested Velocity
	{ enPacket_ReqRadius,		( 1 + 2 )	},			// Requested Radius
	{ enPacket_ReqRVelocity,	( 1 + 2 )	},			// Requested Right Velocity
	{ enPacket_ReqLVelocity,	( 1 + 2 )	},			// Requested Left Velocity
	{ enPacket_EncoderLeft,		( 1 + 2 )	},			// Left Encoder Counts
	{ enPacket_EncoderRight,	( 1 + 2 )	},			// Right Encoder Counts
	{ enPacket_LightBumper,		( 1 + 1 )	},			// Light Bumper
	{ enPacket_LightBumpLSig,	( 1 + 2 )	},			// Light Bump Left Signal
	{ enPacket_LightBumpFLSig,	( 1 + 2 )	},			// Light Bump Front Left Signal
	{ enPacket_LightBumpCLSig,	( 1 + 2 )	},			// Light Bump Center Left Signal
	{ enPacket_LightBumpCRSig,	( 1 + 2 )	},			// Light Bump Center Right Signal
	{ enPacket_LightBumpFRSig,	( 1 + 2 )	},			// Light Bump Front Right Signal
	{ enPacket_LightBumpRSig,	( 1 + 2 )	},			// Light Bump Right Signal
	{ enPacket_MotCurLeft,		( 1 + 2 )	},			// Left Motor Current
	{ enPacket_MotCurRight,		( 1 + 2 )	},			// Right Motor Current
	{ enPacket_MotCurMain,		( 1 + 2 )	},			// Main Brush Motor Current
	{ enPacket_MotCurSide,		( 1 + 2 )	},			// Side Brush Motor Current
	{ enPacket_Stasis,			( 1 + 1 )	}			// Stasis
};

受信データ解析関数

static BOOL _ComRmb_AnalizePacket( uint8_t PacketId, uint8_t* Data )
{
	switch( PacketId )
	{
		case enPacket_BumpsDrop:						// 乗り上げ、脱輪
			gRmbData.MoveSafty.BumpDrop.Data = Data[ 0 ];
			break;
		case enPacket_Wall:								// 非対応
			return FALSE;
		case enPacket_CliffLeft:						// 左崖有無
			gRmbData.MoveSafty.CliffLeft = Data[ 0 ] == 0 ? FALSE : TRUE;
			break;
		case enPacket_CliffFLeft:						// 左前崖有無
			gRmbData.MoveSafty.CliffFLeft = Data[ 0 ] == 0 ? FALSE : TRUE;
			break;
		case enPacket_CliffFRight:						// 右前崖有無
			gRmbData.MoveSafty.CliffFRight = Data[ 0 ] == 0 ? FALSE : TRUE;
			break;
		case enPacket_CliffRight:						// 右崖有無
			gRmbData.MoveSafty.CliffRight = Data[ 0 ] == 0 ? FALSE : TRUE;
			break;
		case enPacket_WheelOverCur:						// 過電流
			gRmbData.ElecSafty.WheelOverCur.Data = Data[ 0 ];
			break;
		case enPacket_UnusedByte:						// ダミーデータ 要求されたパケットが0、1、または6の場合、汚れ検出バイトの後に1つの未使用バイトが送信される
			break;
		case enPacket_Buttons:							// ボタンの押下状態
			gRmbData.Others.Buttons.Data = Data[ 0 ];
			break;
		case enPacket_BattCharging:						//  充電状態
			gRmbData.ElecSafty.BattCharging = Data[ 0 ];
			break;
		case enPacket_BattVoltage:						// バッテリ電圧
			gRmbData.ElecSafty.BattVoltage = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_BattCurrent:						// バッテリー電流
			gRmbData.ElecSafty.BattCurrent = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_BattTemperature:					// バッテリー温度
			gRmbData.ElecSafty.BattTemperature = (int16_t)Data[ 0 ];
			break;
		case enPacket_BattCharge:						// 現在のバッテリー充電量
			gRmbData.ElecSafty.BattCharge = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_BattCapacity:						// 現在の推定バッテリー充電容量
			gRmbData.ElecSafty.BattCapacity = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_WallSig:							// 非対応
			return FALSE;
		case enPacket_CliffLeftSig:						// 左崖センサ信号強度
			gRmbData.MoveSafty.CliffLeftSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_CliffFLeftSig:					// 左前崖センサ信号強度
			gRmbData.MoveSafty.CliffFLeftSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_CliffFRightSig:					// 右前崖センサ信号強度
			gRmbData.MoveSafty.CliffFRightSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_CliffRightSig:					// 右崖センサ信号強度
			gRmbData.MoveSafty.CliffRightSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_BattChargingSrc:					// 充電のリソース
			gRmbData.ElecSafty.BattChargingSrc.Data = Data[ 0 ];
			break;
		case enPacket_OiMode:							// 現在のモード
			gRmbData.Others.OiMode = (RMBMODE)Data[ 0 ];
			break;
		case enPacket_EncoderLeft:						// 左タイヤエンコーダ累積値
			gRmbData.MoveCntl.EncoderLeft = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_EncoderRight:						// 右タイヤエンコーダ累積値
			gRmbData.MoveCntl.EncoderRight = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_LightBumper:						// ライトバンパー検出
			gRmbData.MoveCntl.LightBumper.Data = Data[ 0 ];
			break;
		case enPacket_LightBumpLSig:					// 左ライトバンパー信号強度
			gRmbData.MoveCntl.LightBumpLSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_LightBumpFLSig:					// 左前ライトバンパー信号強度
			gRmbData.MoveCntl.LightBumpFLSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_LightBumpCLSig:					// 左センターライトバンパー信号強度
			gRmbData.MoveCntl.LightBumpCLSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_LightBumpCRSig:					// 右センターライトバンパー信号強度
			gRmbData.MoveCntl.LightBumpCRSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_LightBumpFRSig:					// 右前ライトバンパー信号強度
			gRmbData.MoveCntl.LightBumpFRSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_LightBumpRSig:					// 右ライトバンパー信号強度
			gRmbData.MoveCntl.LightBumpRSig = (int16_t)Utility_GetBigByteToUint16( Data );
			break;
		case enPacket_Stasis:							// 非対応
			return FALSE;
		case enPacket_IrLeft:							// 左赤外線通信
			gRmbData.Others.IrLeft = Data[ 0 ];
			break;
		case enPacket_IrRight:							// 右赤外線通信
			gRmbData.Others.IrRight = Data[ 0 ];
			break;
		default:
			return FALSE;
	}
	return TRUE;
}

その他の関数

//************************************************************************************************
//	機能概要	:16ビット符号なし整数からビッグエンディアンバイト列取得
//	引数	:Data16 16ビット符号なし整数
//			:Data   ビッグエンディアンバイト配列
//	戻り値	:なし
//	備考	:
//************************************************************************************************
void Utility_GetUint16ToBigByte( uint16_t Data16, uint8_t* Data )
{
	UINT16_UNION dat;
	dat.Uint16Data = Data16;
	Data[ 0 ] = dat.Data[ 1 ];
	Data[ 1 ] = dat.Data[ 0 ];
}
//************************************************************************************************
//	機能概要	:ビッグエンディアンバイト列から16ビット符号なし整数取得
//	引数	:Data ビッグエンディアンバイト配列
//	戻り値	:16ビット符号なし整数
//	備考	:
//************************************************************************************************
uint16_t Utility_GetBigByteToUint16( uint8_t* Data )
{
	UINT16_UNION dat;
	dat.Data[ 1 ] = Data[ 0 ];
	dat.Data[ 0 ] = Data[ 1 ];
	
	return dat.Uint16Data;
}