/*
 * @history		2019_12_27  [SDK3.0] タスクをTA_FPU属性付で起動していない不具合を修正 (uC3版) (#2698)
 */
/*
 * This program was created by AXELL CORPORATION.
 * Copyright (C) 2017 AXELL CORPORATION, all rights reserved.
*/

/*****************************************************************************/
/*     include file                                                          */
/*****************************************************************************/
#include "kernel.h"
#include "uhs_configtop.h"
#include "hid/usb_hid_class_api.h"
#include "hid/usb_hid_api.h"
#include <stdint.h>
#include "vram/vrammgr.h"
#include "usb_sample.h"
#include "sample_util.h"
#include "sample_app_hid.h"


/*****************************************************************************/
/*     enum data                                                             */
/*****************************************************************************/
/* HIDデバイスタイプ */
typedef enum {
	HID_DEVICE_TYPE_MOUSE,									/* マウス		*/
	HID_DEVICE_TYPE_MOUSE12,								/* マウス(12bit)*/
	HID_DEVICE_TYPE_KEYBOARD,								/* キーボード	*/
} HID_DEVICE_TYPE;

/*****************************************************************************/
/*     typedef                                                               */
/*****************************************************************************/
/* タスク情報 */
typedef struct HidTaskInfo {
	ID					tskid;								/* タスクID							*/
	ID					mbxid;								/* メールボックスID					*/
	uhs_ubit8_t*		pNotifyBuff;						/* Notify用バッファアドレス			*/
	PHID_DESC_INFO		pHidDescInfo;						/* HIDディスクリプタ情報			*/
	PHID_DESC_INFO		pReportDescInfo;					/* レポートディスクリプタ情報		*/
	HID_DEVICE_TYPE		deviceType;							/* HIDデバイスタイプ				*/
	uhs_ubit8_t*		pLastReport;						/* 前回のレポート(キーボードのみ)	*/
	void				*pContext;							/* 接続されていなければNULL			*/
} HID_TASK_INFO;

/* 接続／切断メッセージ */
typedef struct HidConnMsgPkt {
	uhs_ubit32_t		msg;								/* メッセージ内容					*/
	void*				pContext;							/* 通知元デバイスのコンテキスト		*/
} HID_CONN_MSG_PKT;

/* アプリケーションタスクメッセージ */
typedef struct HidAppMsgPkt {
	uhs_ubit32_t		msg;								/* メッセージ内容					*/
	HID_NOTIFY_INFO		notify;								/* 通知情報							*/
	void*				pContext;							/* 通知元デバイスのコンテキスト		*/
} HID_APP_MSG_PKT;

/*****************************************************************************/
/*     define                                                                */
/*****************************************************************************/
/* バッファサイズ */
#define NOTIFY_BUFF_SIZE			(64)

/* HIDディスクリプタサイズ */
#define HID_DESC_SIZE				(9)

/* レポートディスクリプタ用バッファサイズ */
#define REPORT_DESC_SIZE			(200)

/* キーコード値（Modifier byte） */
#define HID_LEFT_CTRL				(0x01)
#define HID_LEFT_SHIFT				(0x02)
#define HID_LEFT_ALT				(0x04)
#define HID_LEFT_GUI				(0x08)
#define HID_RIGHT_CTRL				(0x10)
#define HID_RIGHT_SHIFT				(0x20)
#define HID_RIGHT_ALT				(0x40)
#define HID_RIGHT_GUI				(0x80)

/* キーコードを格納する配列のサイズ */
#define KEY_CODE_ARR_SIZE			(6)

/* マウスのレポートサイズ */
#define MOUSE_REPORT_SIZE			(4)

/* キーボードのレポートサイズ */
#define KEYBOARD_REPORT_SIZE		(8)


/*****************************************************************************/
/*     global variable                                                       */
/*****************************************************************************/
/* Notify用バッファ */
static uhs_ubit8_t	g_notifyBuff[USBH_MAX_CLS_HID_NUM][NOTIFY_BUFF_SIZE];

/* HIDディスクリプタ情報 */
static HID_DESC_INFO	g_hidDescInfo[USBH_MAX_CLS_HID_NUM];

/* レポートディスクリプタ情報 */
static HID_DESC_INFO	g_reportDescInfo[USBH_MAX_CLS_HID_NUM];

/* 前回レポート */
static uhs_ubit8_t		g_lastReport[USBH_MAX_CLS_HID_NUM][KEYBOARD_REPORT_SIZE];

/* タスク情報テーブル */
static HID_TASK_INFO g_HidTaskInfoTbl[USBH_MAX_CLS_HID_NUM];

/* 接続切断タスク用メールボックスID */
ER_ID				g_mbxid_hid_conn;

/* 接続切断タスク用タスクID */
ER_ID				g_tskid_hid_conn;

/* キーコードテーブル(シフトなし) */
static char		g_keyTable[] = {
/*	 		 0    1    2    3    4    5    6    7    8    9    a    b    c    d    e    f */
/* 00 */	 0 ,  0 ,  0 ,  0 , 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
/* 10 */	'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
/* 20 */	'3', '4', '5', '6', '7', '8', '9', '0',  0 ,  0 ,  0 ,'\t', ' ', '-', '^', '@',
/* 30 */	'[',  0 , ']', ';', ':',  0 , ',', '.', '/',  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 40 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 50 */	 0 ,  0 ,  0 ,  0 , '/', '*', '-', '+',  0 , '1', '2', '3', '4', '5', '6', '7',
/* 60 */	'8', '9', '0', '.',  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 70 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 80 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,'\\',  0 ,'\\',  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 90 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* a0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* b0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* c0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* d0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* e0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* f0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
};

/* キーコードテーブル(シフトあり) */
static char		g_keyTableShift[] = {
/*	 		 0    1    2    3    4    5    6    7    8    9    a    b    c    d    e    f */
/* 00 */	 0 ,  0 ,  0 ,  0 , 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
/* 10 */	'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!','\"',
/* 20 */	'#', '$', '%', '&','\'', '(', ')',  0 ,  0 ,  0 ,  0 ,  0 , ' ', '=', '~', '`',
/* 30 */	'{',  0 , '}', '+', '*',  0 , '<', '>','\?',  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 40 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 50 */	 0 ,  0 ,  0 ,  0 , '/', '*', '-', '+',  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 60 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 70 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 80 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 , '_',  0 , '|',  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* 90 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* a0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* b0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* c0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* d0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* e0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
/* f0 */	 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
};

/*****************************************************************************/
/*     extern function                                                       */
/*****************************************************************************/
extern	int32_t AG903_VRAMMgrCreateMpl(AG903_VRAMMgrMplPrm* mplprm);
extern	int32_t AG903_VRAMMgrDeleteMpl(int32_t mplid);
extern	void* AG903_VRAMMgrMalloc(int32_t mplid, uint32_t blksz);
extern	int32_t AG903_VRAMMgrFree(int32_t mplid, void* blk);

/*****************************************************************************/
/*     function prototype                                                    */
/*****************************************************************************/
static void hid_notifyCallback(PHID_NOTIFY_INFO pNotifyInfo, uhs_status_t RetVal);
static int hid_registTaskInfo(void* pContext);
static int hid_unregistTaskInfo(void* pContext);
static ID hid_getMbxId(void* pContext);
static uhs_ubit8_t* hid_getNotifyBuff(void* pContext);
static PHID_DESC_INFO hid_getHidDescInfo(void* pContext);
static PHID_DESC_INFO hid_getReportDescInfo(void* pContext);
static void hid_setDeviceType(void* pContext, HID_DEVICE_TYPE type);
static uhs_ubit8_t* hid_getLastReport(void* pContext);
static int hid_getDeviceNum(void* pContext);
static void hid_conn_task(void* context);
static void hid_app_task(void* context);
static uhs_status_t hid_attachDeviceInit(void* pContext);
static void hid_procMouseEvent(uhs_ubit8_t* pReport, uhs_ubit32_t size , HID_DEVICE_TYPE mouse_type );
static void hid_procKeyboardEvent(uhs_ubit8_t* pLastReport, uhs_ubit8_t* pReport);
static void hid_printMouseEvent(uhs_ubit8_t* pReport , HID_DEVICE_TYPE mouse_type );
static void hid_printKeyName(uhs_ubit8_t* pReport, uhs_ubit8_t* pKeyCode);
static char hid_getOnKeyCode(uhs_ubit8_t* pLastReport, uhs_ubit8_t* pNewReport, uhs_ubit8_t* pKeyCode);
static int hid_isShiftOn(uhs_ubit8_t *pReport);
static int hid_convert8bitToSignedValue(unsigned char val);

static unsigned char hid_dstMouseSize( PHID_DESC_INFO pReportDescInfo);
static int hid_convert12bitToSignedValue(unsigned short val);


/******************************************************************************
   Function：  hid_appinit
   Argument：  なし
   Return  ：  なし
   Summary ：  HID初期化を行います
   Caution ：  なし
******************************************************************************/
void hid_appinit(void)
{
	T_CMBX					cmbx;							/* メールボックス生成パラメータ		*/
	T_CTSK					ctsk;							/* タスク生成パラメータ				*/
	uhs_ubit8_t				majorVersion, minorVersion;		/* バージョン						*/
	uhs_status_t			retval;
	int						i;


	/*----------------*/
	/* バージョン取得 */
	/*----------------*/
	retval = Usbh_Hid_GetVersion(&majorVersion, &minorVersion);
	if(retval == USBHID_API_SUCCESS) {
		SAMPLE_PRINT("HID Driver version : ");
		SAMPLE_PRINT_BYTE_HEX(majorVersion);
		SAMPLE_PRINT(".");
		SAMPLE_PRINT_BYTE_HEX(minorVersion);
		SAMPLE_PRINT("\r\n");
	}
	
	/*--------------------------*/
	/* タスク情報テーブル初期化 */
	/*--------------------------*/
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		g_HidTaskInfoTbl[i].tskid			= 0;
		g_HidTaskInfoTbl[i].mbxid			= 0;
		g_HidTaskInfoTbl[i].pNotifyBuff		= g_notifyBuff[i];
		g_HidTaskInfoTbl[i].pHidDescInfo	= &g_hidDescInfo[i];
		g_HidTaskInfoTbl[i].pReportDescInfo	= &g_reportDescInfo[i];
		g_HidTaskInfoTbl[i].deviceType		= HID_DEVICE_TYPE_MOUSE;
		g_HidTaskInfoTbl[i].pLastReport		= g_lastReport[i];
		g_HidTaskInfoTbl[i].pContext		= NULL;
	}
	
	/*--------------------*/
	/* メールボックス生成 */
	/*--------------------*/
	/* パラメータ設定 */
    cmbx.mbxatr		= TA_TFIFO | TA_MFIFO;
    cmbx.maxmpri	= 1;
    cmbx.mprihd		= NULL;

	/* 接続切断タスク用メールボックス生成 */
	g_mbxid_hid_conn = acre_mbx(&cmbx);
	if(g_mbxid_hid_conn < 0) {
		/* エラー */
		return;
	}

	/* アプリケーションタスク用メールボックス生成×２ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		g_HidTaskInfoTbl[i].mbxid = acre_mbx(&cmbx);
		if(g_HidTaskInfoTbl[i].mbxid < 0) {
			/* エラー */
			return;
		}
	}
	
	/*------------------------------------*/
	/* クラスディスクリプタ用バッファ取得 */
	/*------------------------------------*/
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		g_HidTaskInfoTbl[i].pHidDescInfo->pu8Buff    = AG903_VRAMMgrMalloc(g_mplid_app, HID_DESC_SIZE);
		g_HidTaskInfoTbl[i].pReportDescInfo->pu8Buff = AG903_VRAMMgrMalloc(g_mplid_app, REPORT_DESC_SIZE);
	}

	/*----------------------*/
	/* 接続／切断タスク生成 */
	/*----------------------*/
	/* パラメータ設定 */
	ctsk.tskatr		= TA_HLNG | TA_ACT | TA_FPU;
	ctsk.exinf		= (void *)NULL;							/* TASK起動時のパラメータ(無し)			*/
	ctsk.task		= (FP)hid_conn_task;					/* TASKの起動アドレス					*/
	ctsk.itskpri	= (PRI)TSK_PRI_SAMPLE;					/* TASKの優先度							*/
	ctsk.stksz		= (INT)TSK_STACK_SIZE_SAMPLE;			/* TASKのスタックSIZE					*/
	ctsk.stk		= NULL;									/* TASKのスタックアドレス=NULL(自動)	*/
	
	/* タスク生成 */
	g_tskid_hid_conn = acre_tsk(&ctsk);
	if(g_tskid_hid_conn < 0) {
		/* エラー */
		return;
	}

	/*----------------------------*/
	/* アプリケーションタスク生成 */
	/*----------------------------*/
	/* パラメータ設定 */
	ctsk.task		= (FP)hid_app_task;						/* TASKの起動アドレス					*/

	/* タスク生成 */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		ctsk.exinf = (void *)&g_HidTaskInfoTbl[i];			/* TASK起動時のパラメータ(テーブル)		*/
		g_HidTaskInfoTbl[i].tskid = acre_tsk(&ctsk);
		if(g_HidTaskInfoTbl[i].tskid < 0) {
			/* エラー */
			return;
		}
	}
}

/******************************************************************************
   Function：  hid_append
   Argument：  なし
   Return  ：  なし
   Summary ：  HID終了処理を行います
   Caution ：  なし
******************************************************************************/
void hid_append(void)
{
	int						i;

	del_mbx(g_mbxid_hid_conn);
	
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		del_mbx(g_HidTaskInfoTbl[i].mbxid);
	}

	ter_tsk(g_tskid_hid_conn);
	del_tsk(g_tskid_hid_conn);
	
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		ter_tsk(g_HidTaskInfoTbl[i].tskid);
		del_tsk(g_HidTaskInfoTbl[i].tskid);
	}

	return;
}

/******************************************************************************
   Function：  hid_appstop
   Argument：  なし
   Return  ：  AG903_ENONE	 正常終了
           ：  -AG903_EFAULT   異常終了
   Summary ：  HIDの転送停止を行います
   Caution ：  なし
******************************************************************************/
int32_t hid_appstop(void)
{
	int32_t			retval=AG903_ENONE;
	uint32_t		loop;
	uhs_status_t	ret;
	
	for( loop=0 ; loop<USBH_MAX_CLS_HID_NUM; loop++ ){
		if( NULL != g_HidTaskInfoTbl[loop].pContext ) {
			ret = Usbh_Hid_StopIntIN(g_HidTaskInfoTbl[loop].pContext);
			if( (USBHID_API_SUCCESS != ret) &&
				(USBHID_API_ALREADY_STOP_INTIN != ret) ) {
				retval=-AG903_EFAULT;
			}
		}
	}
	
	return retval;
}

/******************************************************************************
   Function：  hid_apprestart
   Argument：  なし
   Return  ：  AG903_ENONE	 正常終了
           ：  -AG903_EFAULT   異常終了
   Summary ：  HIDの転送再開を行います
   Caution ：  なし
******************************************************************************/
int32_t hid_apprestart(void)
{
	HID_IDLE		hidIdle;
	int32_t			retval=AG903_ENONE;
	uint32_t		loop;
	uhs_status_t	ret;
	
	for( loop=0 ; loop<USBH_MAX_CLS_HID_NUM; loop++ ){
		if( NULL != g_HidTaskInfoTbl[loop].pContext ) {
			ret = Usbh_Hid_RestartIntIN(g_HidTaskInfoTbl[loop].pContext);
			if( (USBHID_API_SUCCESS != ret) &&
				(USBHID_API_ALREADY_START_INTIN != ret) ) {
				retval=-AG903_EFAULT;
			}
			
			hidIdle.u8Id		= 0;
			hidIdle.u8Duration	= 0;
			ret = Usbh_Hid_SetIdle(g_HidTaskInfoTbl[loop].pContext , &hidIdle);
			if(USBHID_API_SUCCESS != ret) {
				retval=-AG903_EFAULT;
			}
			
		}
	}
	
	return retval;
}

/******************************************************************************
   Function：  hid_callback
   Argument：  callback_id : コールバック種別
               pContext    : コールバックcontext
   Return  ：  なし
   Summary ：  HIDクラスドライバからの接続／切断コールバック処理
   Caution ：  なし
******************************************************************************/
void hid_callback(int callback_id, void* pContext)
{
	HID_CONN_MSG_PKT*		pk_msg;							/* メッセージパケット				*/
	uhs_status_t			retval;
	ER						ercd;
	
	
	/* メッセージバッファ取得 */
	pk_msg = AG903_VRAMMgrMalloc(g_mplid_app, sizeof(HID_CONN_MSG_PKT));
	/* メッセージ内容 */
	pk_msg->msg = (uhs_ubit32_t)callback_id;
	/* コンテキスト */
	pk_msg->pContext = pContext;
	
	switch(callback_id){
		/*--------*/
		/* 接続   */
		/*--------*/
		case CBID_HID_DEVATTACH:

//			SAMPLE_PRINT("HID device attached\r\n");

			/* コンテキストを登録 */
			hid_registTaskInfo(pContext);

			/* コールバック登録 */
			retval = Usbh_Hid_RegistCallBack(pContext, hid_notifyCallback);
			if(retval != USBHID_API_SUCCESS){
				/* バッファ解放 */
				AG903_VRAMMgrFree(g_mplid_app, pk_msg);
				return;
			}

			/* メッセージ送信 */
			ercd = snd_mbx(g_mbxid_hid_conn, (T_MSG *)pk_msg);
			if(ercd != E_OK) {
				/* バッファ解放 */
				AG903_VRAMMgrFree(g_mplid_app, pk_msg);
				return;
			}
			break;
		
		/*--------*/
		/* 切断   */
		/*--------*/
		case CBID_HID_DEVDETACH:

//			SAMPLE_PRINT("HID device detached\r\n");
			
			/* コンテキストを削除 */
			hid_unregistTaskInfo(pContext);

			/* メッセージ送信 */
			ercd = snd_mbx(g_mbxid_hid_conn, (T_MSG *)pk_msg);
			if(ercd != E_OK) {
				/* バッファ解放 */
				AG903_VRAMMgrFree(g_mplid_app, pk_msg);
				return;
			}
			break;
		
		/*--------*/
		/* その他 */
		/*--------*/
		default:

//			SAMPLE_PRINT("HID callback other\r\n");
			/* バッファ解放 */
			AG903_VRAMMgrFree(g_mplid_app, pk_msg);
			break;
	}
}

/******************************************************************************
   Function：  hid_notifyCallback
   Argument：  pNotifyInfo : 通知情報
               RetVal      : 処理結果
   Return  ：  なし
   Summary ：  HIDクラスドライバからのInterrupt転送Report受信コールバック処理
   Caution ：  なし
******************************************************************************/
static void hid_notifyCallback(PHID_NOTIFY_INFO pNotifyInfo, uhs_status_t RetVal)
{
	HID_APP_MSG_PKT*		pk_msg;							/* メッセージパケット				*/
	uhs_ubit8_t*			pBuff;							/* Notify用バッファアドレス			*/
	ER						ercd;
	uhs_ubit32_t			i;
	

	/* 処理結果確認 */
	if(RetVal != USBHID_API_SUCCESS) {
		return;
	}

	/* メッセージバッファ取得 */
	pk_msg = AG903_VRAMMgrMalloc(g_mplid_app, sizeof(HID_APP_MSG_PKT));
	/* メッセージ内容 */
	sample_memcpy((void *)&pk_msg->notify, (void *)pNotifyInfo, sizeof(HID_NOTIFY_INFO));
	/* コンテキスト */
	pk_msg->pContext = pNotifyInfo->pContext;

	/* Interrupt データあり */
	if(pNotifyInfo->u32Length > 0) {
		
		/* バッファ取得 */
		pBuff = hid_getNotifyBuff(pNotifyInfo->pContext);
		if(pBuff == NULL) {
			/* バッファ解放 */
			AG903_VRAMMgrFree(g_mplid_app, pk_msg);
			return;
		}
		
		sample_memset(pBuff, 0, pNotifyInfo->u32Length);
		
		/* データ引き取り */
		for(i = 0; i < pNotifyInfo->u32Length; i++) {
			pBuff[i] = pNotifyInfo->pu8Buff[i];
		};
		/* バッファ置き換え */
		pk_msg->notify.pu8Buff = pBuff;
		pk_msg->notify.u32Length = pNotifyInfo->u32Length;
	}

	/* メッセージ送信 */
	ercd = snd_mbx(hid_getMbxId(pNotifyInfo->pContext), (T_MSG *)pk_msg);
	if(ercd != E_OK) {
		/* バッファ解放 */
		AG903_VRAMMgrFree(g_mplid_app, pk_msg);
	}
}

/******************************************************************************
   Function：  hid_registTaskInfo
   Argument：  pContext     : コールバックcontext
   Return  ：  SAMPLE_TRUE  : 成功
               SAMPLE_FALSE : 失敗
   Summary ：  タスク情報にコンテキストを登録します
   Caution ：  なし
******************************************************************************/
static int hid_registTaskInfo(void* pContext)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* 未登録 */
		if(g_HidTaskInfoTbl[i].pContext == NULL) {
			/* コンテキストを登録 */
			g_HidTaskInfoTbl[i].pContext = pContext;
			return SAMPLE_TRUE;
		}
	}
	/* 空きなし */
	return SAMPLE_FALSE;
}

/******************************************************************************
   Function：  hid_unregistTaskInfo
   Argument：  pContext     : コールバックcontext
   Return  ：  SAMPLE_TRUE  : 成功
               SAMPLE_FALSE : 失敗
   Summary ：  タスク情報からコンテキストを削除します
   Caution ：  なし
******************************************************************************/
static int hid_unregistTaskInfo(void* pContext)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* コンテキストが一致 */
		if(g_HidTaskInfoTbl[i].pContext == pContext) {
			/* コンテキストを削除 */
			g_HidTaskInfoTbl[i].pContext = NULL;
			return SAMPLE_TRUE;
		}
	}
	/* コンテキストなし */
	return SAMPLE_FALSE;
}

/******************************************************************************
   Function：  hid_getMbxId
   Argument：  pContext    : コールバックcontext
   Return  ：  メールボックスID
   Summary ：  登録してあるコンテキストに紐付けられたメールボックスIDを取得します
   Caution ：  なし
******************************************************************************/
static ID hid_getMbxId(void* pContext)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* コンテキストが一致 */
		if(g_HidTaskInfoTbl[i].pContext == pContext) {
			/* メールボックスIDを返す */
			return g_HidTaskInfoTbl[i].mbxid;
		}
	}
	
	/* エラー */
	return 0;
}

/******************************************************************************
   Function：  hid_getNotifyBuff
   Argument：  pContext    : コールバックcontext
   Return  ：  Notify用バッファ
   Summary ：  登録してあるコンテキストに紐付けられたNotify用バッファを取得します
   Caution ：  なし
******************************************************************************/
static uhs_ubit8_t* hid_getNotifyBuff(void* pContext)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* コンテキストが一致 */
		if(g_HidTaskInfoTbl[i].pContext == pContext) {
			/* Notify用バッファを返す */
			return g_HidTaskInfoTbl[i].pNotifyBuff;
		}
	}
	
	/* エラー */
	return NULL;
}

/******************************************************************************
   Function：  hid_getHidDescInfo
   Argument：  pContext    : コールバックcontext
   Return  ：  HIDディスクリプタ情報アドレス
   Summary ：  登録してあるコンテキストに紐付けられたHIDディスクリプタ情報を取得
               します
   Caution ：  なし
******************************************************************************/
static PHID_DESC_INFO hid_getHidDescInfo(void* pContext)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* コンテキストが一致 */
		if(g_HidTaskInfoTbl[i].pContext == pContext) {
			/* HIDディスクリプタ情報アドレスを返す */
			return g_HidTaskInfoTbl[i].pHidDescInfo;
		}
	}
	
	/* エラー */
	return NULL;
}

/******************************************************************************
   Function：  hid_getReportDescInfo
   Argument：  pContext    : コールバックcontext
   Return  ：  レポートディスクリプタ情報アドレス
   Summary ：  登録してあるコンテキストに紐付けられたレポートディスクリプタ情報を
               取得します
   Caution ：  なし
******************************************************************************/
static PHID_DESC_INFO hid_getReportDescInfo(void* pContext)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* コンテキストが一致 */
		if(g_HidTaskInfoTbl[i].pContext == pContext) {
			/* HIDディスクリプタ情報アドレスを返す */
			return g_HidTaskInfoTbl[i].pReportDescInfo;
		}
	}
	
	/* エラー */
	return NULL;
}

/******************************************************************************
   Function：  hid_setDeviceType
   Argument：  pContext    : コールバックcontext
               type        : HIDデバイスタイプ
   Return  ：  なし
   Summary ：  登録してあるコンテキストが示すHIDデバイスタイプを設定します
   Caution ：  なし
******************************************************************************/
static void hid_setDeviceType(void* pContext, HID_DEVICE_TYPE type)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* コンテキストが一致 */
		if(g_HidTaskInfoTbl[i].pContext == pContext) {
			/* HIDデバイスタイプを設定 */
			g_HidTaskInfoTbl[i].deviceType = type;
		}
	}
}

/******************************************************************************
   Function：  hid_getLastReport
   Argument：  pContext    : コールバックcontext
   Return  ：  前回レポート格納用バッファ
   Summary ：  登録してあるコンテキストに紐付けられた前回レポート格納用バッファを
               取得します
   Caution ：  なし
******************************************************************************/
static uhs_ubit8_t* hid_getLastReport(void* pContext)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* コンテキストが一致 */
		if(g_HidTaskInfoTbl[i].pContext == pContext) {
			/* 前回レポート格納用バッファを返す */
			return g_HidTaskInfoTbl[i].pLastReport;
		}
	}
	
	/* エラー */
	return NULL;
}

/******************************************************************************
   Function：  hid_getDeviceNum			 
   Argument：  pContext    : コールバックcontext
   Return  ：  デバイス番号
   Summary ：  登録してあるコンテキストに紐付けられたデバイス番号を取得します。
               デバイス番号は0〜1。
   Caution ：  なし
******************************************************************************/
static int hid_getDeviceNum(void* pContext)
{
	int						i;


	/* テーブルをサーチ */
	for(i = 0; i < USBH_MAX_CLS_HID_NUM; i++) {
		/* コンテキストが一致 */
		if(g_HidTaskInfoTbl[i].pContext == pContext) {
			/* テーブルの添字がデバイス番号とする */
			return i;
		}
	}
	
	/* エラー */
	return -1;
}

/******************************************************************************
   Function：  hid_conn_task
   Argument：  context     : NULL
   Return  ：  なし
   Summary ：  HID接続／切断検知タスク
   Caution ：  HIDデバイス共通
******************************************************************************/
static void hid_conn_task(void* context)
{
	HID_CONN_MSG_PKT*		pk_msg;							/* メッセージパケット				*/
	uhs_ubit32_t			msg;							/* メッセージ内容					*/
	void*					pContext;						/* コンテキスト						*/

	((void)context);

	while(1) {
		/* 接続／切断メッセージ待ち */
		rcv_mbx(g_mbxid_hid_conn, (T_MSG **)&pk_msg);
			
		/* 接続／されたデバイスのコンテキスト取得 */
		pContext = pk_msg->pContext;
		/* 取得失敗 */
		if(pContext == NULL) {
			/* バッファ解放 */
			AG903_VRAMMgrFree(g_mplid_app, pk_msg);
			continue;
		}

		SAMPLE_PRINT("  context : 0x");
		SAMPLE_PRINT_LONG_HEX((unsigned long)pContext);
		SAMPLE_PRINT("\r\n");

		/* メッセージ内容保存 */
		msg = pk_msg->msg;

		/* バッファ解放 */
		AG903_VRAMMgrFree(g_mplid_app, pk_msg);
		
		/*------*/
		/* 接続 */
		/*------*/
		if(msg == CBID_HID_DEVATTACH) {

			/* リクエスト発行 */
			hid_attachDeviceInit(pContext);
		}
		
		/*------*/
		/* 切断 */
		/*------*/
		else {
			/* 処理なし */
		}
	}
}

/******************************************************************************
   Function：  hid_app_task
   Argument：  context     : タスク起動パラメータ(タスク情報)
   Return  ：  なし
   Summary ：  HIDアプリケーションタスク
   Caution ：  デバイス単位で使用
******************************************************************************/
static void hid_app_task(void* context)
{
	HID_TASK_INFO*			pHidTaskInfo;					/* タスク情報						*/
	HID_APP_MSG_PKT*		pk_msg;							/* メッセージパケット				*/

	((void)context);

	/* タスク情報取得 */
	pHidTaskInfo = (HID_TASK_INFO *)context;

	while(1) {
		/*--------------------*/
		/* 通知メッセージ待ち */
		/*--------------------*/
		rcv_mbx(pHidTaskInfo->mbxid, (T_MSG **)&pk_msg);
		
		SAMPLE_PRINT("  Device No.[");
		SAMPLE_PRINT_NUM(hid_getDeviceNum(pHidTaskInfo->pContext));
		SAMPLE_PRINT("]");
		
		/* HIDデバイスタイプ判定 */
		switch(pHidTaskInfo->deviceType) {
			
			/*--------*/
			/* マウス */
			/*--------*/
			case (HID_DEVICE_TYPE_MOUSE):
			case (HID_DEVICE_TYPE_MOUSE12):
				/* マウスイベント処理 */
				hid_procMouseEvent(pk_msg->notify.pu8Buff, pk_msg->notify.u32Length , pHidTaskInfo->deviceType);
				break;
			
			/*------------*/
			/* キーボード */
			/*------------*/
			case (HID_DEVICE_TYPE_KEYBOARD):
				/* キーボードイベント処理 */
				hid_procKeyboardEvent(pHidTaskInfo->pLastReport, pk_msg->notify.pu8Buff);
				break;
			
			/* その他 */
			default:
				SAMPLE_PRINT("\r\n");
				/* Do Nothing */
				break;
		}
		/* バッファ解放 */
		AG903_VRAMMgrFree(g_mplid_app, pk_msg);
	}
}

/******************************************************************************
   Function：  hid_attachDeviceInit
   Argument：  pContext    : 接続時のcontext
   Return  ：  なし
   Summary ：  HIDデバイス接続時のクラスリクエスト発行、HIDデバイスタイプ判定
   Caution ：  取得したバッファは、切断時に解放。
******************************************************************************/
static uhs_status_t hid_attachDeviceInit(void* pContext)
{
	HID_IDLE				hidIdle;						/* レポート頻度情報					*/
	PHID_DESC_INFO			pHidDescInfo;					/* HIDディスクリプタ情報アドレス	*/
	PHID_DESC_INFO			pReportDescInfo;				/* レポートディスクリプタ情報アドレス*/
	uhs_ubit8_t*			pLastReport;					/* 前回レポートバッファアドレス		*/
	uhs_status_t			retval;


	/*----------------------*/
	/* クラスリクエスト発行 */
	/*----------------------*/
	/* SetIdle */
	hidIdle.u8Id		= 0;
	hidIdle.u8Duration	= 0;
	retval = Usbh_Hid_SetIdle(pContext, &hidIdle);
	if(retval != USBHID_API_SUCCESS){
		/* Do Nothing */
	}

	/* HIDディスクリプタ情報アドレス取得 */
	pHidDescInfo = hid_getHidDescInfo(pContext);
	/* 切断時は取得出来ないため、終了 */
	if(pHidDescInfo == NULL) {
		return -1;
	}
	pHidDescInfo->u16Length = HID_DESC_SIZE;
	pHidDescInfo->u16Length = HID_DESC_SIZE;
	/* HIDディスクリプタ取得 */
	retval = Usbh_Hid_GetHIDDescriptor(pContext, pHidDescInfo);
	if(retval != USBHID_API_SUCCESS){
		return retval;
	}

	/* レポートディスクリプタ情報アドレス取得 */
	pReportDescInfo = hid_getReportDescInfo(pContext);
	/* 切断時は取得出来ないため、終了 */
	if(pReportDescInfo == NULL) {
		return -1;
	}
	pHidDescInfo->u16Length = HID_DESC_SIZE;
	pReportDescInfo->u16Length = (pHidDescInfo->pu8Buff[7] + (pHidDescInfo->pu8Buff[8] << 8));
	/* レポートディスクリプタ取得 */
	retval = Usbh_Hid_GetReportDescriptor(pContext, pReportDescInfo);
	if(retval != USBHID_API_SUCCESS){
		return retval;
	}
	
	/*-----------------------*/
	/* HIDデバイスタイプ判定 */
	/*-----------------------*/
	/* マウス */
	if((pReportDescInfo->pu8Buff[2] == 0x09) && 
	   (pReportDescInfo->pu8Buff[3] == 0x02)) {
		hid_setDeviceType(pContext, HID_DEVICE_TYPE_MOUSE);
		/* マウスの座標軸のサイズを判別 */
		if(hid_dstMouseSize( pReportDescInfo) == 2){
			hid_setDeviceType(pContext, HID_DEVICE_TYPE_MOUSE12);
			SAMPLE_PRINT("  -- mouse12\r\n");
		}else{
			SAMPLE_PRINT("  -- mouse8\r\n");
		}
	}
	/* キーボード */
	else if((pReportDescInfo->pu8Buff[2] == 0x09) && 
	        (pReportDescInfo->pu8Buff[3] == 0x06)) {
		hid_setDeviceType(pContext, HID_DEVICE_TYPE_KEYBOARD);
		SAMPLE_PRINT("  -- keyboard\r\n");

		/* 前回レポートをクリア */
		pLastReport = hid_getLastReport(pContext);
		sample_memset(pLastReport, 0, KEYBOARD_REPORT_SIZE);
	}
	/* 上記以外（本ケースはない） */
	else {
		SAMPLE_PRINT("  -- other device : ");
		SAMPLE_PRINT("0x");
		SAMPLE_PRINT_BYTE_HEX(pReportDescInfo->pu8Buff[2]);
		SAMPLE_PRINT(", 0x");
		SAMPLE_PRINT_BYTE_HEX(pReportDescInfo->pu8Buff[3]);
		SAMPLE_PRINT("\r\n");
	}
	return retval;
}

/******************************************************************************
   Function：  hid_procMouseEvent
   Argument：  pReport     : 通知されたレポート
               size        : 通知されたレポートのサイズ
               mouse_type  : マウス種別
   Return  ：  なし
   Summary ：  マウスイベント処理を行います。
   Caution ：  なし
******************************************************************************/
static void hid_procMouseEvent(uhs_ubit8_t* pReport, uhs_ubit32_t size , HID_DEVICE_TYPE mouse_type)
{
	uhs_ubit32_t			i;


	/* レポートをHEX値で出力 */
	SAMPLE_PRINT("  Report ");
	for(i = 0; i < size; i++) {
		SAMPLE_PRINT_BYTE_HEX(pReport[i]);
		SAMPLE_PRINT(" ");
	}

	/* イベント内容を表示 */
	hid_printMouseEvent(pReport , mouse_type);
		
	SAMPLE_PRINT("\r\n");
}

/******************************************************************************
   Function：  hid_procKeyboardEvent
   Argument：  pReport     : 通知されたレポート
   Return  ：  なし
   Summary ：  キーボードイベント処理を行います。
   Caution ：  なし
******************************************************************************/
static void hid_procKeyboardEvent(uhs_ubit8_t* pLastReport, uhs_ubit8_t* pReport)
{
	uhs_ubit8_t				onKeyCode[KEY_CODE_ARR_SIZE];
	int						i;


	/* レポートをHEX値で出力 */
	SAMPLE_PRINT("  Report ");
	for(i = 0; i < KEYBOARD_REPORT_SIZE; i++) {
		SAMPLE_PRINT_BYTE_HEX(pReport[i]);
		SAMPLE_PRINT(" ");
	}
	
	/* 押下されたキーコード取得 */
	hid_getOnKeyCode(pLastReport, pReport, onKeyCode);
	
	/* 押下されたキーを表示 */
	hid_printKeyName(pReport, onKeyCode);
	
	SAMPLE_PRINT("\r\n");
	
	/* レポート保存 */
	sample_memcpy(pLastReport, pReport, KEYBOARD_REPORT_SIZE);
}

/******************************************************************************
   Function：  hid_printMouseEvent
   Argument：  pReport     : 通知されたレポート
           ：  mouse_type  : マウスの種別
   Return  ：  SAMPLE_TRUE  : シフトキーON状態
               SAMPLE_FALSE : シフトキーOFF状態
   Summary ：  マウス動作を表示します。
   Caution ：  なし
******************************************************************************/
static void hid_printMouseEvent(uhs_ubit8_t* pReport , HID_DEVICE_TYPE mouse_type )
{
	int					report;							/* レポート値						*/
	unsigned short		coordinates;

	SAMPLE_PRINT(" : ");
	
	SAMPLE_PRINT("Buttons[0x");
	SAMPLE_PRINT_BYTE_HEX(pReport[0]);
	SAMPLE_PRINT("], ");
	
	if( mouse_type == HID_DEVICE_TYPE_MOUSE){
		/* 座標軸 8bit */
		report = hid_convert8bitToSignedValue(pReport[1]);
		SAMPLE_PRINT("XMove[");
		SAMPLE_PRINT_NUM(report);
		SAMPLE_PRINT("], ");
		
		report = hid_convert8bitToSignedValue(pReport[2]);
		SAMPLE_PRINT("YMove[");
		SAMPLE_PRINT_NUM(report);
		SAMPLE_PRINT("], ");
		
		report = hid_convert8bitToSignedValue(pReport[3]);
		SAMPLE_PRINT("Wheel[");
		SAMPLE_PRINT_NUM(report);
		SAMPLE_PRINT("]");
	}else{
		/* 座標軸 12bit */
		coordinates = (unsigned short)pReport[1] | ((unsigned short)(pReport[2] & 0x0f) << 8);
		report = hid_convert12bitToSignedValue( coordinates);
		SAMPLE_PRINT("XMove[");
		SAMPLE_PRINT_NUM(report);
		SAMPLE_PRINT("], ");

		coordinates = ((unsigned short)(((pReport[3] & 0x0f) << 4) | (pReport[2] & 0xf0) >> 4)) | (((unsigned short)pReport[3] << 4) & 0x0f00);
		report = hid_convert12bitToSignedValue( coordinates);
		SAMPLE_PRINT("YMove[");
		SAMPLE_PRINT_NUM(report);
		SAMPLE_PRINT("], ");

		report = hid_convert8bitToSignedValue(pReport[4]);
		SAMPLE_PRINT("Wheel[");
		SAMPLE_PRINT_NUM(report);
		SAMPLE_PRINT("], ");

		report = hid_convert8bitToSignedValue(pReport[5]);
		SAMPLE_PRINT("Other[");
		SAMPLE_PRINT_NUM(report);
		SAMPLE_PRINT("]");
	}
}

/******************************************************************************
   Function：  hid_printKeyName
   Argument：  pReport     : 通知されたレポート
               pKeyCode    : 今回ONとなったキーコード配列
   Return  ：  なし
   Summary ：  今回ONされたキーコードに対応するキーの名称を表示します。
   Caution ：  なし
******************************************************************************/
static void hid_printKeyName(uhs_ubit8_t* pReport, uhs_ubit8_t* pKeyCode)
{
	char					name[2] = {0};					/* キーコード						*/
	int						i;


	/* 押下されたキーなし */
	if(pKeyCode[0] == 0) {
		/* 何も表示しない */
		return;
	}

	SAMPLE_PRINT(" : ");

	/* シフトON */
	if(hid_isShiftOn(pReport) == SAMPLE_TRUE) {
		for(i = 0; i < KEY_CODE_ARR_SIZE; i++) {
			/* もうキーコードは格納されていない */
			if(pKeyCode[i] == 0) {
				break;
			}
			
			/* キー名称取得 */
			name[0] = g_keyTableShift[pKeyCode[i]];
			/* 名称あり */
			if(name[0] != 0) {
				SAMPLE_PRINT(name);
				SAMPLE_PRINT(" ");
			}
		}
	}
	/* シフトOFF */
	else {
		for(i = 0; i < KEY_CODE_ARR_SIZE; i++) {
			/* もうキーコードは格納されていない */
			if(pKeyCode[i] == 0) {
				break;
			}
			
			/* キー名称取得 */
			name[0] = g_keyTable[pKeyCode[i]];
			/* 名称あり */
			if(name[0] != 0) {
				SAMPLE_PRINT(name);
				SAMPLE_PRINT(" ");
			}
		}
	}
}

/******************************************************************************
   Function：  hid_getOnKeyCode
   Argument：  pLastReport : 前回のレポート
               pNewReport  : 今回のレポート
               pKeyCode    : ONされたキーコードを格納する配列アドレス
   Return  ：  SAMPLE_TRUE  : ONキーあり
               SAMPLE_FALSE : ONキーなし
   Summary ：  押下されたキーのキーコードを取得します。
   Caution ：  Modifier byteは除く。
******************************************************************************/
static char hid_getOnKeyCode(uhs_ubit8_t* pLastReport, uhs_ubit8_t* pNewReport, uhs_ubit8_t* pKeyCode)
{
	int						pos = 0;						/* キーコード格納位置				*/
	int						retval = SAMPLE_FALSE;
	int						i, j;


	/* パラメータチェック */
	if((pLastReport == NULL) || (pNewReport == NULL)) {
		return SAMPLE_FALSE;
	}
	
	/* キーコード配列初期化 */
	sample_memset(pKeyCode, 0, KEY_CODE_ARR_SIZE);
	
	/* 今回のレポートのキーコードを調べる */
	for(i = 2; i < KEYBOARD_REPORT_SIZE; i++) {
		/* 0の場合はONのキーなし */
		if(pNewReport[i] == 0) {
			continue;
		}
		
		/* 前回のレポートに含まれていない＝新たにONされたかどうか */
		for(j = 2; j < KEYBOARD_REPORT_SIZE; j++) {
			/* 一致＝前回もONであった */
			if(pLastReport[j] == pNewReport[i]) {
				break;
			}
		}
		if(j == KEYBOARD_REPORT_SIZE) {
			pKeyCode[pos] = pNewReport[i];
			pos++;
			retval = SAMPLE_TRUE;
		}
	}

	return retval;
}

/******************************************************************************
   Function：  hid_isShiftOn
   Argument：  pReport     : 通知されたレポート
   Return  ：  SAMPLE_TRUE  : シフトキーON状態
               SAMPLE_FALSE : シフトキーOFF状態
   Summary ：  シフトキーのON／OFFを判定します。
   Caution ：  なし
******************************************************************************/
static int hid_isShiftOn(uhs_ubit8_t* pReport)
{
	/* パラメータチェック */
	if(pReport == NULL) {
		return SAMPLE_FALSE;
	}
	
	/* シフトキーON */
	if(pReport[0] & (HID_LEFT_SHIFT | HID_RIGHT_SHIFT)) {
		return SAMPLE_TRUE;
	}

	return SAMPLE_FALSE;
}

/******************************************************************************
   Function：  hid_convert8bitToSignedValue
   Argument：  val         : 変換対象値
   Return  ：  変換値
   Summary ：  符号なし8ビット値を符号ありint値に変換します。
   Caution ：  なし
******************************************************************************/
static int hid_convert8bitToSignedValue(unsigned char val)
{
	int						ret = val;						/* 戻り値							*/


	/* マイナス値 */
	if(val & 0x80) {
		ret = (0 - (unsigned char)(~val) - 1);
	}
	return ret;
}



/******************************************************************************
   Function：  hid_dstMouseSize
   Argument：  pReportDescInfo   : レポートディスクリプタ情報アドレス
   Return  ：  マウスの座標軸のbit幅
                      1:座標軸  8bitマウス
                      2:座標軸 12bitマウス
   Summary ：  レポートディスクリプタから、マウスの座標軸の幅を判別する
   Caution ：  レポートディスクリプタサイズは、255Byte以下のものに対応
               判断は以下
                 ・Report Descriptor内 2つめの"Generic Desktop Controls"が存在
                 ・その後にある"Logical Maximum"のデータサイズを確認
                     - 1Byte： 8bitマウス
                     - 2Byte：12bitマウス
                   ※ この条件に合致しないものは8bitマウスとする。
               とする。
******************************************************************************/
static unsigned char hid_dstMouseSize( PHID_DESC_INFO pReportDescInfo)
{
	unsigned char	i;
	unsigned char	ret = 1;
	unsigned char	detect_flg = 0;
	unsigned char	size = (unsigned char)pReportDescInfo->u16Length;

	/* レポートディスクリプタ内 "Usage X"を検索  */
	for( i= 0; i < size; i++){
		switch((pReportDescInfo->pu8Buff[i]) & 0x03){	/* Short Item Datasize */
			case	0:	/* size = 0 */
				/* Do Nothing */
				break;
			case	1:	/* size = 1 */
				if(((unsigned short)pReportDescInfo->pu8Buff[i] | ((unsigned short)pReportDescInfo->pu8Buff[i+1] << 8)) == 0x0105){	/* Usage Page"Generic Desktop Controls"? */
					detect_flg++;
				}
				i++;
				break;
			case	2:	/* size = 2 */
				i += 2;
				break;
			case	3:	/* size = 4 */
				i += 4;
				break;
			default:
				SAMPLE_PRINT("\r\n");
				/* Do Nothing */
				;
				break;
		}
		if(detect_flg == 2){
			break;
		}
	}

	/* 次に来る "Logical Maximum"を検索し、そのサイズが 1Byte:8bit / 2Byte:12bitと判断 */
	if( detect_flg == 2){
        i++;    /* Short Itemに場所調整 */
		for( ; i < size; i++){
			if(((pReportDescInfo->pu8Buff[i]) & 0xfc) == 0x14){	/* "Logical Maximum"? */
				if(((pReportDescInfo->pu8Buff[i]) & 0x03) == 0x02){	/* DataSize = 2? */
					ret	= 2;
				}else{
					/* Do Nothing */
					;
				}
				break;
			}
			switch((pReportDescInfo->pu8Buff[i]) & 0x03){	/* Short Item Datasize */
				case	0:	/* size = 0 */
					/* Do Nothing */
					break;
				case	1:	/* size = 1 */
					i++;
					break;
				case	2:	/* size = 2 */
					i += 2;
					break;
				case	3:	/* size = 4 */
					i += 4;
					break;
				default:
					SAMPLE_PRINT("\r\n");
					/* Do Nothing */
					;
					break;
			}
		}
	}else{
		/* "Usage X"後に"Logical Maximum"が来なかった場合は、8bitマウスとして動作させる */
		/* Do Nothing */
		;
	}

	return	ret;
}



/******************************************************************************
   Function：  hid_convert12bitToSignedValue
   Argument：  val         : 変換対象値
   Return  ：  変換値
   Summary ：  12ビット値を符号ありint値に変換します。
   Caution ：  なし
******************************************************************************/
static int hid_convert12bitToSignedValue(unsigned short val)
{
	int						ret = val;						/* 戻り値							*/


	/* マイナス値 */
	if(val & 0x0800) {
		ret = (0 - (unsigned char)(~val) - 1);
	}
	return ret;
}

