/*
 *	clipmsgh.h
 *
 *	メッセージハンドシェイク
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Wed Mar 16 21:18:14 JST 2016 Naoyuki Sawa
 *	- 1st リリース。
 *	- RRSによって管理されている複数のジョブ間で、メッセージ通信を行うためのモジュールです。
 *	  特徴は、ST_MsgHsk構造体の中にバッファを設けず、送信者が作成したバッファのメモリを、受信者が直接参照する事です。
 *	  要するに、共有メモリを使ったジョブ間通信です。
 *	  当モジュールの役割は、受信側がデータ参照を終えるまで送信側をブロックする事と、デッドロックの検出を行う事です。
 *	- 当モジュールは、基本的には、二つのジョブ間での通信を想定しています。
 *	  RRSの中に三個以上のジョブが有っても構いませんが、一つのST_MsgHskを使って通信するジョブは二つに固定する方が安全です。
 *	  送受信タイミングが被らないように気を付ければ、一つのST_MsgHskで三つ以上のジョブ間通信を行う事も可能ではありますが、複雑になったり再現し辛いバグの原因になるので望ましくありません。
 *	  三つ以上のジョブ間で通信を行う場合は、二個のジョブの対ごとに、個別のST_MsgHskを作成する方が判り易いと思います。
 *	* Thu Mar 17 21:54:13 JST 2016 Naoyuki Sawa
 *	- 「使用例①　片方向通信の例」「使用例②　双方向通信の例」を書きました。
 *	* Mon Jul 25 21:36:27 JST 2016 Naoyuki Sawa
 *	- MsgHsk_Recv()を、MsgHsk_TryRecv()とMsgHsk_Recv()に分離しました。
 *	  具体的には、以下の通りです。
 *	- 変更前は、MsgHsk_Recv()のbBlocking引数によって、ブロッキングモードと非ブロッキングモードを選択していました。
 *	  変更後は、MsgHsk_Recv()はブロッキングモード専用の関数、MsgHsk_TryRecv()は非ブロッキングモード専用の関数としました。
 *	  それに伴い、MsgHsk_Recv()のbBlocking引数を廃止しました。
 *	  上記の変更を行った理由は、実際のアプリケーションではブロッキングモードで使用する事がほとんどであり、毎回(bBlocking=1)を指定するのは使い辛いと思ったからです。
 *	* Fri Sep 30 21:41:38 JST 2016 Naoyuki Sawa
 *	- MsgHsk_SendIdle(),MsgHsk_RecvIdle(),MsgHsk_WaitIdle()を追加しました。
 *	  これまで、MsgHsk_Send(),MsgHsk_Recv(),MsgHsk_Wait()内でブロックされている間は、アプリケーション定義の周期処理が呼び出せない問題が有りました。
 *	  その問題を解決するために、ブロックされている間に呼び出されるアプリケーション定義のアイドリング関数を指定出来るバージョンの関数を追加しました。
 */
#ifndef __CLIP_MSGH_H__
#define __CLIP_MSGH_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	
 ****************************************************************************/
typedef struct _ST_MsgHsk {
	ST_RRS*		pRRS;		//+ 0, 4
	short		iJobSend;	//+ 4, 2 送信完了待ち中のジョブ番号(0～)。(-1)ならば送信完了待ち中のジョブが無い事を示す。
	short		iJobRecv;	//+ 6, 2 受信完了待ち中のジョブ番号(0～)。(-1)ならば受信完了待ち中のジョブが無い事を示す。
	int		iMsgType;	//+ 8, 4 送信中のメッセージタイプ(-1以外)	┬(iJobSend!=-1)時のみ有効			■NOTE:メッセージタイプの解釈はアプリケーション定義であり任意です。例①メッセージタイプだけで完結するコマンド番号のような値としメッセージデータは無し(NULL)にする。例②メッセージデータの内容を識別する値(いわゆるメッセージタイプ)とし詳細はメッセージデータで伝える。例③メッセージタイプは意味の無い固定値(0など)としてメッセージデータだけで情報を伝える。例④メッセージデータのバイト数を示す値とする。	ちなみに例④の場合は、POSIXメッセージキューのmq_send/mq_receiveと似た使い方になります。
	void*		pMsgData;	//+12, 4 送信中のメッセージデータポインタ(任意)	┘
} ST_MsgHsk;				//=16
/****************************************************************************
 *	
 ****************************************************************************/
void MsgHsk_Init(ST_MsgHsk* pMsgHsk, ST_RRS* pRRS);
void MsgHsk_Send(ST_MsgHsk* pMsgHsk, int iMsgType/*(-1)以外*/, void* pMsgData/*NULL可*/);
void MsgHsk_SendIdle(ST_MsgHsk* pMsgHsk, int iMsgType/*(-1)以外*/, void* pMsgData/*NULL可*/, void (*idle/*NULL可*/)(void* arg), void* arg);	//{{2016/09/30追加:MsgHsk_SendIdle(),MsgHsk_RecvIdle(),MsgHsk_WaitIdle()を追加しました。}}
int MsgHsk_Recv(ST_MsgHsk* pMsgHsk, void** ppMsgData/*NULL可*/);
int MsgHsk_RecvIdle(ST_MsgHsk* pMsgHsk, void** ppMsgData/*NULL可*/, void (*idle/*NULL可*/)(void* arg), void* arg);				//{{2016/09/30追加:MsgHsk_SendIdle(),MsgHsk_RecvIdle(),MsgHsk_WaitIdle()を追加しました。}}
int MsgHsk_TryRecv(ST_MsgHsk* pMsgHsk, void** ppMsgData/*NULL可*/);
void MsgHsk_Wait(ST_MsgHsk* pMsgHsk, int iMsgType/*(-1)以外*/, void** ppMsgData/*NULL可*/);
void MsgHsk_WaitIdle(ST_MsgHsk* pMsgHsk, int iMsgType/*(-1)以外*/, void** ppMsgData/*NULL可*/, void (*idle/*NULL可*/)(void* arg), void* arg);	//{{2016/09/30追加:MsgHsk_SendIdle(),MsgHsk_RecvIdle(),MsgHsk_WaitIdle()を追加しました。}}
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__CLIP_MSGH_H__
