THB2/bthome_phy6222/SDK/components/profiles/HID/hiddev.c
2024-01-11 18:33:53 +03:00

1467 lines
41 KiB
C

/*************
hiddev.c
SDK_LICENSE
***************/
/*********************************************************************
INCLUDES
*/
#include "OSAL.h"
#include "gatt.h"
#include "hci.h"
#include "gapgattserver.h"
#include "gattservapp.h"
#include "gatt_uuid.h"
#include "gatt_profile_uuid.h"
#include "linkdb.h"
#include "peripheral.h"
#include "gapbondmgr.h"
#include "devinfoservice.h"
#include "battservice.h"
#include "scanparamservice.h"
#include "hiddev.h"
#include "hidkbd.h"
#include "global_config.h"
#include "ll_def.h"
#include "hidkbdservice.h"
//#include "touch_key.h"
#include "log.h"
/*********************************************************************
MACROS
*/
// Battery measurement period in ms
#define DEFAULT_BATT_PERIOD 15000
// TRUE to run scan parameters refresh notify test
#define DEFAULT_SCAN_PARAM_NOTIFY_TEST TRUE
// Advertising intervals (units of 625us, 160=100ms)
#define HID_INITIAL_ADV_INT_MIN 48
#define HID_INITIAL_ADV_INT_MAX 80
#define HID_HIGH_ADV_INT_MIN 32
#define HID_HIGH_ADV_INT_MAX 48
#define HID_LOW_ADV_INT_MIN 32//1600
#define HID_LOW_ADV_INT_MAX 48//1600
// Advertising timeouts in sec
#define HID_INITIAL_ADV_TIMEOUT 60
#define HID_HIGH_ADV_TIMEOUT 5
#define HID_LOW_ADV_TIMEOUT 0
// Heart Rate Task Events
#define START_DEVICE_EVT 0x0001
#define BATT_PERIODIC_EVT 0x0002
#define HID_IDLE_EVT 0x0004
#define HID_SEND_REPORT_EVT 0x0008
#define HID_UPPARAM_EVT 0X0010
#define HID_TEST_EVT 0x0100
#define reportQEmpty() ( firstQIdx == lastQIdx )
#define CCD_CHECK_EN_FLAG 0
/*********************************************************************
CONSTANTS
*/
#define HID_DEV_DATA_LEN 8
#ifdef HID_DEV_RPT_QUEUE_LEN
#define HID_DEV_REPORT_Q_SIZE (HID_DEV_RPT_QUEUE_LEN+1)
#else
#define HID_DEV_REPORT_Q_SIZE (10+1)
#endif
/*********************************************************************
TYPEDEFS
*/
typedef struct
{
uint8 id;
uint8 type;
uint8 len;
uint8 data[HID_DEV_DATA_LEN];
} hidDevReport_t;
/*********************************************************************
GLOBAL VARIABLES
*/
// Task ID
uint8 hidDevTaskId;
/*********************************************************************
EXTERNAL VARIABLES
*/
/*********************************************************************
EXTERNAL FUNCTIONS
*/
// HID report mapping table
extern hidRptMap_t hidRptMap[];
/*********************************************************************
LOCAL VARIABLES
*/
// GAP State
gaprole_States_t hidDevGapState = GAPROLE_INIT;
// TRUE if connection is secure
static uint8 hidDevConnSecure = FALSE;
// GAP connection handle
uint16 gapConnHandle;
// TRUE if pairing in progress
static uint8 hidDevPairingStarted = FALSE;
// Status of last pairing
static uint8 pairingStatus = SUCCESS;
static hidRptMap_t* pHidDevRptTbl;
static uint8 hidDevRptTblLen;
static hidDevCB_t* pHidDevCB;
static hidDevCfg_t* pHidDevCfg;
// Whether to change to the preferred connection parameters
static uint8 updateConnParams = TRUE;
// Pending reports
static uint8 firstQIdx = 0;
static uint8 lastQIdx = 0;
static hidDevReport_t hidDevReportQ[HID_DEV_REPORT_Q_SIZE];
// Last report sent out
static attHandleValueNoti_t lastNoti = { 0 };
/*********************************************************************
LOCAL FUNCTIONS
*/
static void hidDev_ProcessOSALMsg( osal_event_hdr_t* pMsg );
static void hidDevProcessGattMsg( gattMsgEvent_t* pMsg );
static void hidDevDisconnected( void );
static void hidDevGapStateCB( gaprole_States_t newState );
static void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status );
static void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle,
uint8 uiInputs, uint8 uiOutputs );
void hidDevBattCB( uint8 event );
void hidDevScanParamCB( uint8 event );
static void hidDevBattPeriodicTask( void );
static hidRptMap_t* hidDevRptByHandle( uint16 handle );
static hidRptMap_t* hidDevRptById( uint8 id, uint8 type );
static hidRptMap_t* hidDevRptByCccdHandle( uint16 handle );
static void hidDevEnqueueReport( uint8 id, uint8 type, uint8 len, uint8* pData );
static hidDevReport_t* hidDevDequeueReport( void );
static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8* pData );
static void hidDevHighAdvertising( void );
static void hidDevLowAdvertising( void );
static void hidDevInitialAdvertising( void );
static uint8 hidDevBondCount( void );
static void hidDevStartIdleTimer( void );
static void hidDevStopIdleTimer( void );
static void HidDev_scanParamCB(uint8_t event);
/*********************************************************************
PROFILE CALLBACKS
*/
// GAP Role Callbacks
static gapRolesCBs_t hidDev_PeripheralCBs =
{
hidDevGapStateCB, // Profile State Change Callbacks
NULL // When a valid RSSI is read from controller
};
// Bond Manager Callbacks
static const gapBondCBs_t hidDevBondCB =
{
hidDevPasscodeCB,
hidDevPairStateCB
};
/*********************************************************************
PUBLIC FUNCTIONS
*/
/*********************************************************************
@fn HidDev_Init
@brief Initialization function for the Hid Dev Task.
This is called during initialization and should contain
any application specific initialization (ie. hardware
initialization/setup, table initialization, power up
notificaiton ... ).
@param task_id - the ID assigned by OSAL. This ID should be
used to send messages and set timers.
@return none
*/
void HidDev_Init( uint8 task_id )
{
hidDevTaskId = task_id;
// Setup the GAP Bond Manager
{
uint8 syncWL = TRUE;
// If a bond is created, the HID Device should write the address of the
// HID Host in the HID Device controller's white list and set the HID
// Device controller's advertising filter policy to 'process scan and
// connection requests only from devices in the White List'.
VOID GAPBondMgr_SetParameter( GAPBOND_AUTO_SYNC_WL, sizeof( uint8 ), &syncWL );
}
// Set up services
GGS_AddService( GATT_ALL_SERVICES ); // GAP
GATTServApp_AddService( GATT_ALL_SERVICES ); // GATT attributes
DevInfo_AddService( );
Batt_AddService();
ScanParam_AddService();
Batt_Register(NULL);
// Register for Scan Parameters service callback.
ScanParam_Register(HidDev_scanParamCB);
//touch_init(on_key);
// Setup a delayed profile startup
osal_set_event( hidDevTaskId, START_DEVICE_EVT );
}
/*********************************************************************
@fn HidDev_ProcessEvent
@brief Hid Dev Task event processor. This function
is called to process all events for the task. Events
include timers, messages and any other user defined events.
@param task_id - The OSAL assigned task ID.
@param events - events to process. This is a bit map and can
contain more than one event.
@return events not processed
*/
uint16 HidDev_ProcessEvent( uint8 task_id, uint16 events )
{
VOID task_id; // OSAL required parameter that isn't used in this function
LOG("%s\n",__FUNCTION__);
if ( events & SYS_EVENT_MSG )
{
uint8* pMsg;
if ( (pMsg = osal_msg_receive( hidDevTaskId )) != NULL )
{
hidDev_ProcessOSALMsg( (osal_event_hdr_t*)pMsg );
// Release the OSAL message
VOID osal_msg_deallocate( pMsg );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
if ( events & START_DEVICE_EVT )
{
// Start the Device
VOID GAPRole_StartDevice( &hidDev_PeripheralCBs );
// Register with bond manager after starting device
GAPBondMgr_Register( (gapBondCBs_t*) &hidDevBondCB );
// GAPBondMgr_SetParameter(GAPBOND_ERASE_ALLBONDS,0,NULL);
LOG("start Device EVT\n\r");
return ( events ^ START_DEVICE_EVT );
}
if ( events & HID_IDLE_EVT )
{
if ( hidDevGapState == GAPROLE_CONNECTED )
{
// if pairing in progress then restart timer
if ( hidDevPairingStarted )
{
hidDevStartIdleTimer();
LOG("hidDevStartIdleTimer \n\r");
}
// else disconnect
else
{
//GAPRole_TerminateConnection();
LOG("hidDevStartIdleTimer disconnect \n\r");
}
}
return ( events ^ HID_IDLE_EVT );
}
if ( events & BATT_PERIODIC_EVT )
{
// Perform periodic battery task
hidDevBattPeriodicTask();
return ( events ^ BATT_PERIODIC_EVT );
}
if ( events & HID_SEND_REPORT_EVT )
{
// if connection is secure
if ( hidDevConnSecure )
{
LOG("Send Hid Report\n\r");
hidDevReport_t* pReport = hidDevDequeueReport();
if ( pReport != NULL )
{
// Send report
hidDevSendReport( pReport->id, pReport->type, pReport->len, pReport->data );
}
return ( reportQEmpty() ? events^ HID_SEND_REPORT_EVT : events );
}
return ( events ^ HID_SEND_REPORT_EVT );
}
if( events & HID_UPPARAM_EVT)
{
uint8 bleupdateConnParams = TRUE;
uint8 enable_update_request= TRUE;
if(hidDevGapState == GAPROLE_CONNECTED)
{
GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &enable_update_request );
GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_REQ, sizeof( uint8 ), &bleupdateConnParams );
LOG("device updata connected parament");
}
return ( events ^ HID_UPPARAM_EVT );
}
return 0;
}
/*********************************************************************
@fn HidDev_Register
@brief Register a callback function with HID Dev.
@param pCfg - Parameter configuration.
@param pfnServiceCB - Callback function.
@return None.
*/
void HidDev_Register( hidDevCfg_t* pCfg, hidDevCB_t* pCBs )
{
pHidDevCB = pCBs;
pHidDevCfg = pCfg;
}
/*********************************************************************
@fn HidDev_RegisterReports
@brief Register the report table with HID Dev.
@param numReports - Length of report table.
@param pRpt - Report table.
@return None.
*/
void HidDev_RegisterReports( uint8 numReports, hidRptMap_t* pRpt )
{
pHidDevRptTbl = pRpt;
hidDevRptTblLen = numReports;
}
/*********************************************************************
@fn HidDev_Report
@brief Send a HID report.
@param id - HID report ID.
@param type - HID report type.
@param len - Length of report.
@param pData - Report data.
@return None.
*/
void HidDev_Report( uint8 id, uint8 type, uint8 len, uint8* pData )
{
// if connected
if ( hidDevGapState == GAPROLE_CONNECTED )
{
// if connection is secure
if ( hidDevConnSecure )
{
// Make sure there're no pending reports
if ( reportQEmpty() )
{
// send report
hidDevSendReport( id, type, len, pData );
LOG("send key action\n\r");
return; // we're done
}
}
}
// else if not already advertising
else if ( hidDevGapState != GAPROLE_ADVERTISING )
{
// if bonded
if ( hidDevBondCount() > 0 )
{
// start high duty cycle advertising
hidDevHighAdvertising();
}
// else not bonded
else
{
// start initial advertising
hidDevInitialAdvertising();
}
}
// hidDev task will send report when secure connection is established
hidDevEnqueueReport( id, type, len, pData );
}
/*********************************************************************
@fn HidDev_Close
@brief Close the connection or stop advertising.
@return None.
*/
void HidDev_Close( void )
{
uint8 param;
// if connected then disconnect
if ( hidDevGapState == GAPROLE_CONNECTED )
{
GAPRole_TerminateConnection();
}
// else stop advertising
else
{
param = FALSE;
GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
}
}
/*********************************************************************
@fn HidDev_SetParameter
@brief Set a HID Dev parameter.
@param param - Profile parameter ID
@param len - length of data to right
@param pValue - pointer to data to write. This is dependent on
the parameter ID and WILL be cast to the appropriate
data type (example: data type of uint16 will be cast to
uint16 pointer).
@return bStatus_t
*/
bStatus_t HidDev_SetParameter( uint8 param, uint8 len, void* pValue )
{
bStatus_t ret = SUCCESS;
switch ( param )
{
case HIDDEV_ERASE_ALLBONDS:
if ( len == 0 )
{
// See if the last report sent out wasn't a release key
if ( osal_isbufset( lastNoti.value, 0x00, lastNoti.len ) == FALSE )
{
// Send a release report before disconnecting, otherwise
// the last pressed key would get 'stuck' on the HID Host.
osal_memset( lastNoti.value, 0x00, lastNoti.len );
GATT_Notification( gapConnHandle, &lastNoti, FALSE );
}
// Drop connection
if ( hidDevGapState == GAPROLE_CONNECTED )
{
GAPRole_TerminateConnection();
}
// Flush report queue
firstQIdx = lastQIdx = 0;
// Erase bonding info
GAPBondMgr_SetParameter( GAPBOND_ERASE_ALLBONDS, 0, NULL );
}
else
{
ret = bleInvalidRange;
}
break;
default:
ret = INVALIDPARAMETER;
break;
}
return ( ret );
}
/*********************************************************************
@fn HidDev_GetParameter
@brief Get a HID Dev parameter.
@param param - Profile parameter ID
@param pValue - pointer to data to get. This is dependent on
the parameter ID and WILL be cast to the appropriate
data type (example: data type of uint16 will be cast to
uint16 pointer).
@return bStatus_t
*/
bStatus_t HidDev_GetParameter( uint8 param, void* pValue )
{
bStatus_t ret = SUCCESS;
switch ( param )
{
default:
ret = INVALIDPARAMETER;
break;
}
return ( ret );
}
/*********************************************************************
@fn HidDev_PasscodeRsp
@brief Respond to a passcode request.
@param status - SUCCESS if passcode is available, otherwise
see @ref SMP_PAIRING_FAILED_DEFINES.
@param passcode - integer value containing the passcode.
@return none
*/
void HidDev_PasscodeRsp( uint8 status, uint32 passcode )
{
// Send passcode response
GAPBondMgr_PasscodeRsp( gapConnHandle, status, passcode );
}
/*********************************************************************
@fn HidDev_ReadAttrCB
@brief HID Dev attribute read callback.
@param connHandle - connection message was received on
@param pAttr - pointer to attribute
@param pValue - pointer to data to be read
@param pLen - length of data to be read
@param offset - offset of the first octet to be read
@param maxLen - maximum length of data to be read
@param method - type of read message
@return SUCCESS, blePending or Failure
*/
uint8 HidDev_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr,
uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen )
{
bStatus_t status = SUCCESS;
hidRptMap_t* pRpt;
uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
// Only report map is long
if ( offset > 0 && uuid != REPORT_MAP_UUID )
{
return ( ATT_ERR_ATTR_NOT_LONG );
}
if ( uuid == REPORT_UUID ||
uuid == BOOT_KEY_INPUT_UUID ||
uuid == BOOT_KEY_OUTPUT_UUID ||
uuid == BOOT_MOUSE_INPUT_UUID )
{
// find report ID in table
if ( (pRpt = hidDevRptByHandle(pAttr->handle)) != NULL )
{
// execute report callback
status = (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid,
HID_DEV_OPER_READ, pLen, pValue );
}
else
{
*pLen = 0;
}
}
else if ( uuid == REPORT_MAP_UUID )
{
// verify offset
if ( offset >= hidReportMapLen )
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length
*pLen = MIN( maxLen, (hidReportMapLen - offset) );
// copy data
osal_memcpy( pValue, pAttr->pValue + offset, *pLen );
}
}
else if ( uuid == HID_INFORMATION_UUID )
{
*pLen = HID_INFORMATION_LEN;
osal_memcpy( pValue, pAttr->pValue, HID_INFORMATION_LEN );
}
else if ( uuid == GATT_REPORT_REF_UUID )
{
*pLen = HID_REPORT_REF_LEN;
osal_memcpy( pValue, pAttr->pValue, HID_REPORT_REF_LEN );
}
else if ( uuid == PROTOCOL_MODE_UUID )
{
*pLen = HID_PROTOCOL_MODE_LEN;
pValue[0] = pAttr->pValue[0];
}
else if ( uuid == GATT_EXT_REPORT_REF_UUID )
{
*pLen = HID_EXT_REPORT_REF_LEN;
osal_memcpy( pValue, pAttr->pValue, HID_EXT_REPORT_REF_LEN );
}
// restart idle timer
if ( status == SUCCESS )
{
hidDevStartIdleTimer();
}
return ( status );
}
/*********************************************************************
@fn HidDev_WriteAttrCB
@brief HID Dev attribute read callback.
@param connHandle - connection message was received on
@param pAttr - pointer to attribute
@param pValue - pointer to data to be written
@param len - length of data
@param offset - offset of the first octet to be written
@return Success or Failure
*/
bStatus_t HidDev_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr,
uint8* pValue, uint16 len, uint16 offset )
{
bStatus_t status = SUCCESS;
hidRptMap_t* pRpt;
// Make sure it's not a blob operation (no attributes in the profile are long)
if ( offset > 0 )
{
return ( ATT_ERR_ATTR_NOT_LONG );
}
uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
if ( uuid == REPORT_UUID ||
uuid == BOOT_KEY_OUTPUT_UUID )
{
// find report ID in table
if ((pRpt = hidDevRptByHandle(pAttr->handle)) != NULL)
{
// execute report callback
status = (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid,
HID_DEV_OPER_WRITE, &len, pValue );
}
}
else if ( uuid == HID_CTRL_PT_UUID )
{
// Validate length and value range
if ( len == 1 )
{
if ( pValue[0] == HID_CMD_SUSPEND || pValue[0] == HID_CMD_EXIT_SUSPEND )
{
// execute HID app event callback
(*pHidDevCB->evtCB)( (pValue[0] == HID_CMD_SUSPEND) ?
HID_DEV_SUSPEND_EVT : HID_DEV_EXIT_SUSPEND_EVT );
}
else
{
status = ATT_ERR_INVALID_VALUE;
}
}
else
{
status = ATT_ERR_INVALID_VALUE_SIZE;
}
}
else if ( uuid == GATT_CLIENT_CHAR_CFG_UUID )
{
status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
offset, GATT_CLIENT_CFG_NOTIFY );
if ( status == SUCCESS )
{
uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] );
// find report ID in table
if ( (pRpt = hidDevRptByCccdHandle(pAttr->handle)) != NULL )
{
// execute report callback
(*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid,
(charCfg == GATT_CLIENT_CFG_NOTIFY) ?
HID_DEV_OPER_ENABLE : HID_DEV_OPER_DISABLE,
&len, pValue );
}
}
}
else if ( uuid == PROTOCOL_MODE_UUID )
{
if ( len == HID_PROTOCOL_MODE_LEN )
{
if ( pValue[0] == HID_PROTOCOL_MODE_BOOT ||
pValue[0] == HID_PROTOCOL_MODE_REPORT )
{
pAttr->pValue[0] = pValue[0];
// execute HID app event callback
(*pHidDevCB->evtCB)( (pValue[0] == HID_PROTOCOL_MODE_BOOT) ?
HID_DEV_SET_BOOT_EVT : HID_DEV_SET_REPORT_EVT );
}
else
{
status = ATT_ERR_INVALID_VALUE;
}
}
else
{
status = ATT_ERR_INVALID_VALUE_SIZE;
}
}
// restart idle timer
if (status == SUCCESS)
{
hidDevStartIdleTimer();
}
return ( status );
}
/*********************************************************************
@fn hidDev_ProcessOSALMsg
@brief Process an incoming task message.
@param pMsg - message to process
@return none
*/
static void hidDev_ProcessOSALMsg( osal_event_hdr_t* pMsg )
{
switch ( pMsg->event )
{
case GATT_MSG_EVENT:
hidDevProcessGattMsg( (gattMsgEvent_t*) pMsg );
break;
default:
break;
}
}
/*********************************************************************
@fn hidDevProcessGattMsg
@brief Process GATT messages
@return none
*/
static void hidDevProcessGattMsg( gattMsgEvent_t* pMsg )
{
}
/*********************************************************************
@fn hidDevHandleConnStatusCB
@brief Reset client char config.
@param connHandle - connection handle
@param changeType - type of change
@return none
*/
static void hidDevHandleConnStatusCB( uint16 connHandle, uint8 changeType )
{
uint8 i;
hidRptMap_t* p = pHidDevRptTbl;
uint16 retHandle;
gattAttribute_t* pAttr;
// Make sure this is not loopback connection
if ( connHandle != LOOPBACK_CONNHANDLE )
{
if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) ||
( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) &&
( !linkDB_Up( connHandle ) ) ) )
{
for ( i = hidDevRptTblLen; i > 0; i--, p++ )
{
if ( p->cccdHandle != 0 )
{
if ( (pAttr = GATT_FindHandle(p->cccdHandle, &retHandle)) != NULL )
{
GATTServApp_InitCharCfg( connHandle, (gattCharCfg_t*) pAttr->pValue );
}
}
}
}
}
}
/*********************************************************************
@fn hidDevDisconnected
@brief Handle disconnect.
@return none
*/
static void hidDevDisconnected( void )
{
uint8 enable_update_request =FALSE;
// Stop idle timer
hidDevStopIdleTimer();
// Reset client characteristic configuration descriptors
Batt_HandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED );
//ScanParam_HandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED );
hidDevHandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED );
// Reset state variables
hidDevConnSecure = FALSE;
hidProtocolMode = HID_PROTOCOL_MODE_REPORT;
hidDevPairingStarted = FALSE;
// Reset last report sent out
osal_memset( &lastNoti, 0, sizeof( attHandleValueNoti_t ) );
GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &enable_update_request );
osal_stop_timerEx(hidDevTaskId, HID_UPPARAM_EVT);
// if bonded and normally connectable start advertising
if ( ( hidDevBondCount() > 0 ) &&
( pHidDevCfg->hidFlags & HID_FLAGS_REMOTE_WAKE ) ) //HID_FLAGS_REMOTE_WAKE HID_FLAGS_NORMALLY_CONNECTABLE
{
// hidDevDirectAdvertising();
// LOG("hidDev Direct Advertising \n\r");
hidDevLowAdvertising();
LOG("hidDev Low Advertising \n\r");
}
else
{
hidDevLowAdvertising();
LOG("hidDev Low Advertising \n\r");
}
}
/*********************************************************************
@fn hidDevGapStateCB
@brief Notification from the profile of a state change.
@param newState - new state
@return none
*/
void hidDevGapStateCB( gaprole_States_t newState )
{
LOG("%s, %d\n",__FUNCTION__, newState);
// if connected
if ( newState == GAPROLE_CONNECTED )
{
// get connection handle
GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
// connection not secure yet
hidDevConnSecure = FALSE;
uint8 peerAddress[B_ADDR_LEN];
GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress);
LOG("Master Mac:%02X,%02X,%02X,%02X,%02X,%02X\n\r",peerAddress[5],peerAddress[4],peerAddress[3],peerAddress[2],peerAddress[1],peerAddress[0]);
// start idle timer
hidDevStartIdleTimer();
}
// if disconnected
else if ( hidDevGapState == GAPROLE_CONNECTED &&
newState != GAPROLE_CONNECTED )
{
LOG("disconnect advisting \n\r");
hidDevDisconnected();
updateConnParams = TRUE;
g_instant_cnt=0;
if ( pairingStatus == SMP_PAIRING_FAILED_CONFIRM_VALUE )
{
// bonding failed due to mismatched confirm values
hidDevInitialAdvertising();
pairingStatus = SUCCESS;
LOG("hidDev Initial Advertising \n\r");
}
}
// if started
else if ( newState == GAPROLE_STARTED )
{
// nothing to do for now!
}
hidDevGapState = newState;
}
/*********************************************************************
@fn hidDevPairStateCB
@brief Pairing state callback.
@return none
*/
void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status )
{
if ( state == GAPBOND_PAIRING_STATE_STARTED )
{
hidDevPairingStarted = TRUE;
}
else if ( state == GAPBOND_PAIRING_STATE_COMPLETE )
{
hidDevPairingStarted = FALSE;
if ( status == SUCCESS )
{
hidDevConnSecure = TRUE;
LOG("Pair Success\n\r");
osal_start_timerEx(hidKbdTaskId, HID_TEST_EVT, 5000);
//osal_start_timerEx(hidDevTaskId, HID_UPPARAM_EVT, 15000);//3000
}
else
{
LOG("Pair Fail\n\r");
}
pairingStatus = status;
}
else if ( state == GAPBOND_PAIRING_STATE_BONDED )
{
if ( status == SUCCESS )
{
hidDevConnSecure = TRUE;
// osal_start_timerEx(hidKbdTaskId, HID_TEST_EVT, 5000);
// osal_start_timerEx(hidDevTaskId, HID_UPPARAM_EVT, 15000);//3000
osal_start_timerEx(hidKbdTaskId, HID_TEST_EVT, 5000);
LOG("bond Success\n\r");
}
}
//if(hidDevConnSecure){
// osal_start_reload_timer(hidDevTaskId, HID_TEST_EVT, 1000);
//}
//LOG("pair state=%d\n\r",state);
if ( !reportQEmpty() && hidDevConnSecure )
{
LOG("Set Send Report EVENT\n\r");
// Notify our task to send out pending reports
osal_set_event( hidDevTaskId, HID_SEND_REPORT_EVT );
}
}
/*********************************************************************
@fn hidDevPasscodeCB
@brief Passcode callback.
@param deviceAddr - address of device to pair with, and could be either public or random.
@param connectionHandle - connection handle
@param uiInputs - pairing User Interface Inputs - Ask user to input passcode
@param uiOutputs - pairing User Interface Outputs - Display passcode
@return none
*/
void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle,
uint8 uiInputs, uint8 uiOutputs )
{
if ( pHidDevCB && pHidDevCB->passcodeCB )
{
// execute HID app passcode callback
(*pHidDevCB->passcodeCB)( deviceAddr, connectionHandle, uiInputs, uiOutputs );
}
else
{
// Send passcode response
GAPBondMgr_PasscodeRsp( connectionHandle, SUCCESS, 0 );
}
}
/*********************************************************************
@fn hidDevBattCB
@brief Callback function for battery service.
@param event - service event
@return none
*/
void hidDevBattCB( uint8 event )
{
if ( event == BATT_LEVEL_NOTI_ENABLED )
{
// if connected start periodic measurement
if ( hidDevGapState == GAPROLE_CONNECTED )
{
osal_start_timerEx( hidDevTaskId, BATT_PERIODIC_EVT, DEFAULT_BATT_PERIOD );
}
}
else if ( event == BATT_LEVEL_NOTI_DISABLED )
{
// stop periodic measurement
osal_stop_timerEx( hidDevTaskId, BATT_PERIODIC_EVT );
}
}
/*********************************************************************
@fn hidDevScanParamCB
@brief Callback function for scan parameter service.
@param event - service event
@return none
*/
void hidDevScanParamCB( uint8 event )
{
}
/*********************************************************************
@fn hidDevBattPeriodicTask
@brief Perform a periodic task for battery measurement.
@param none
@return none
*/
static void hidDevBattPeriodicTask( void )
{
if ( hidDevGapState == GAPROLE_CONNECTED )
{
// perform battery level check
Batt_MeasLevel( );
// Restart timer
osal_start_timerEx( hidDevTaskId, BATT_PERIODIC_EVT, DEFAULT_BATT_PERIOD );
}
}
/*********************************************************************
@fn hidDevRptByHandle
@brief Find the HID report structure for the given handle.
@param handle - ATT handle
@return Pointer to HID report structure
*/
static hidRptMap_t* hidDevRptByHandle( uint16 handle )
{
uint8 i;
hidRptMap_t* p = pHidDevRptTbl;
for ( i = hidDevRptTblLen; i > 0; i--, p++ )
{
if ( p->handle == handle && p->mode == hidProtocolMode)
{
return p;
}
}
return NULL;
}
/*********************************************************************
@fn hidDevRptByCccdHandle
@brief Find the HID report structure for the given CCC handle.
@param handle - ATT handle
@return Pointer to HID report structure
*/
static hidRptMap_t* hidDevRptByCccdHandle( uint16 handle )
{
uint8 i;
hidRptMap_t* p = pHidDevRptTbl;
for ( i = hidDevRptTblLen; i > 0; i--, p++ )
{
if ( p->cccdHandle == handle)
{
return p;
}
}
return NULL;
}
/*********************************************************************
@fn hidDevRptById
@brief Find the HID report structure for the Report ID and type.
@param id - HID report ID
@param type - HID report type
@return Pointer to HID report structure
*/
static hidRptMap_t* hidDevRptById( uint8 id, uint8 type )
{
uint8 i;
hidRptMap_t* p = pHidDevRptTbl;
for ( i = hidDevRptTblLen; i > 0; i--, p++ )
{
if ( p->id == id && p->type == type && p->mode == hidProtocolMode )
{
return p;
}
}
return NULL;
}
#if CCD_CHECK_EN_FLAG
/*********************************************************************
@fn hidDevSendReport
@brief Send a HID report.
@param id - HID report ID.
@param type - HID report type.
@param len - Length of report.
@param pData - Report data.
@return None.
*/
static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8* pData )
{
hidRptMap_t* pRpt;
gattAttribute_t* pAttr;
uint16 retHandle;
LOG("%s\n",__FUNCTION__);
// Get ATT handle for report
if ( (pRpt = hidDevRptById(id, type)) != NULL )
{
// if notifications are enabled
if ( (pAttr = GATT_FindHandle(pRpt->cccdHandle, &retHandle)) != NULL )
{
uint16 value;
value = GATTServApp_ReadCharCfg( gapConnHandle, (gattCharCfg_t*) pAttr->pValue );
if ( value & GATT_CLIENT_CFG_NOTIFY )
{
// After service discovery and encryption, the HID Device should request to
// change to the preferred connection parameters that best suit its use case.
if ( updateConnParams )
{
GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_REQ, sizeof( uint8 ), &updateConnParams );
updateConnParams = FALSE;
}
// send notification
lastNoti.handle = pRpt->handle;
lastNoti.len = len;
osal_memcpy(lastNoti.value, pData, len);
GATT_Notification( gapConnHandle, &lastNoti, FALSE );
// start idle timer
hidDevStartIdleTimer();
}
else
{
LOG("notify fail\n\r");
}
}
}
}
#else
/*********************************************************************
@fn hidDevSendReport
@brief Send a HID report.
@param id - HID report ID.
@param type - HID report type.
@param len - Length of report.
@param pData - Report data.
@return None.
*/
static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8* pData )
{
hidRptMap_t* pRpt;
gattAttribute_t* pAttr;
uint16 retHandle;
LOG("%s\n",__FUNCTION__);
// Get ATT handle for report
if ( (pRpt = hidDevRptById(id, type)) != NULL )
{
// if notifications are enabled
if ( (pAttr = GATT_FindHandle(pRpt->cccdHandle, &retHandle)) != NULL )
{
uint16 value;
value = GATTServApp_ReadCharCfg( gapConnHandle, (gattCharCfg_t*) pAttr->pValue );
//if ( value & GATT_CLIENT_CFG_NOTIFY )
{
// After service discovery and encryption, the HID Device should request to
// change to the preferred connection parameters that best suit its use case.
if ( updateConnParams )
{
GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_REQ, sizeof( uint8 ), &updateConnParams );
updateConnParams = FALSE;
}
// send notification
lastNoti.handle = pRpt->handle;
lastNoti.len = len;
osal_memcpy(lastNoti.value, pData, len);
GATT_Notification( gapConnHandle, &lastNoti, FALSE );
// start idle timer
hidDevStartIdleTimer();
}
}
}
}
#endif
/*********************************************************************
@fn hidDevEnqueueReport
@brief Enqueue a HID report to be sent later.
@param id - HID report ID.
@param type - HID report type.
@param len - Length of report.
@param pData - Report data.
@return None.
*/
static void hidDevEnqueueReport( uint8 id, uint8 type, uint8 len, uint8* pData )
{
// Enqueue only if bonded
if ( hidDevBondCount() > 0 )
{
// Update last index
lastQIdx = ( lastQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE;
if ( lastQIdx == firstQIdx )
{
// Queue overflow; discard oldest report
firstQIdx = ( firstQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE;
}
// Save report
hidDevReportQ[lastQIdx].id = id;
hidDevReportQ[lastQIdx].type = type;
hidDevReportQ[lastQIdx].len = len;
osal_memcpy( hidDevReportQ[lastQIdx].data, pData, len );
if ( hidDevConnSecure )
{
// Notify our task to send out pending reports
osal_set_event( hidDevTaskId, HID_SEND_REPORT_EVT );
}
}
}
/*********************************************************************
@fn hidDevDequeueReport
@brief Dequeue a HID report to be sent out.
@param id - HID report ID.
@param type - HID report type.
@param len - Length of report.
@param pData - Report data.
@return None.
*/
static hidDevReport_t* hidDevDequeueReport( void )
{
if ( reportQEmpty() )
{
return NULL;
}
// Update first index
firstQIdx = ( firstQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE;
return ( &(hidDevReportQ[firstQIdx]) );
}
/*********************************************************************
@fn hidDevHighAdvertising
@brief Start advertising at a high duty cycle.
@param None.
@return None.
*/
static void hidDevHighAdvertising( void )
{
uint8 param;
VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_HIGH_ADV_INT_MIN );
VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_HIGH_ADV_INT_MAX );
VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_HIGH_ADV_TIMEOUT );
// Setup adverstising filter policy first
param = GAP_FILTER_POLICY_WHITE;
VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), &param );
param = TRUE;
GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
LOG("high adv\n\r");
}
/*********************************************************************
@fn hidDevLowAdvertising
@brief Start advertising at a low duty cycle.
@param None.
@return None.
*/
static void hidDevLowAdvertising( void )
{
uint8 param;
#if 0
static uint8_t cnt=0;
uint8_t macAddr[6]= {0x11,0x22,0x33,0x44,0x55,0x66};
param = FALSE;
GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
cnt++;
macAddr[5]+=cnt;
volatile uint8_t* P_ownPublicAddr=(volatile uint8_t*)0x1fff11f9;
*(P_ownPublicAddr++)=macAddr[0];
*(P_ownPublicAddr++)=macAddr[1];
*(P_ownPublicAddr++)=macAddr[2];
*(P_ownPublicAddr++)=macAddr[3];
*(P_ownPublicAddr++)=macAddr[4];
*(P_ownPublicAddr++)=macAddr[5];
HCI_ReadBDADDRCmd();
#endif
param=GAP_ADRPT_ADV_IND;//GAP_ADRPT_ADV_DIRECT_IND;
GAPRole_SetParameter( GAPROLE_ADV_EVENT_TYPE, sizeof(uint8),&param );
VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_LOW_ADV_INT_MIN );
VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_LOW_ADV_INT_MAX );
VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_LOW_ADV_TIMEOUT );
// Setup adverstising filter policy first
param = GAP_FILTER_POLICY_ALL;//GAP_FILTER_POLICY_WHITE teddy modify
VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), &param );
param = TRUE;
VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
}
/*********************************************************************
@fn hidDevInitialAdvertising
@brief Start advertising for initial connection
@return None.
*/
static void hidDevInitialAdvertising( void )
{
uint8 param;
VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_INITIAL_ADV_INT_MIN );
VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_INITIAL_ADV_INT_MAX );
VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_INITIAL_ADV_TIMEOUT );
// Setup adverstising filter policy first
param = GAP_FILTER_POLICY_ALL;
VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), &param );
param = TRUE;
VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
}
/*********************************************************************
@fn hidDevBondCount
@brief Gets the total number of bonded devices.
@param None.
@return number of bonded devices.
*/
static uint8 hidDevBondCount( void )
{
uint8 bondCnt = 0;
VOID GAPBondMgr_GetParameter( GAPBOND_BOND_COUNT, &bondCnt );
return ( bondCnt );
}
/*********************************************************************
@fn hidDevStartIdleTimer
@brief Start the idle timer.
@return None.
*/
static void hidDevStartIdleTimer( void )
{
if ( pHidDevCfg->idleTimeout > 0 )
{
osal_start_timerEx( hidDevTaskId, HID_IDLE_EVT, pHidDevCfg->idleTimeout );
}
}
/*********************************************************************
@fn hidDevStopIdleTimer
@brief Stop the idle timer.
@return None.
*/
static void hidDevStopIdleTimer( void )
{
osal_stop_timerEx( hidDevTaskId, HID_IDLE_EVT );
}
/*********************************************************************
@fn HidDev_scanParamCB
@brief Callback function for scan parameter service.
@param event - service event
@return none
*/
static void HidDev_scanParamCB(uint8_t event)
{
// Do nothing.
}
/*********************************************************************
*********************************************************************/