1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306 |
- /**************************************************************************************************
-
- Phyplus Microelectronics Limited confidential and proprietary.
- All rights reserved.
- IMPORTANT: All rights of this software belong to Phyplus Microelectronics
- Limited ("Phyplus"). Your use of this Software is limited to those
- specific rights granted under the terms of the business contract, the
- confidential agreement, the non-disclosure agreement and any other forms
- of agreements as a customer or a partner of Phyplus. You may not use this
- Software unless you agree to abide by the terms of these agreements.
- You acknowledge that the Software may not be modified, copied,
- distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy
- (BLE) integrated circuit, either as a product or is integrated into your
- products. Other than for the aforementioned purposes, you may not use,
- reproduce, copy, prepare derivative works of, modify, distribute, perform,
- display or sell this Software and/or its documentation for any purposes.
- YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
- PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
- INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
- NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
- PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT,
- NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
- LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
- INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
- OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
- OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
- (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
-
- **************************************************************************************************/
- /*********************************************************************
- * 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 "hiddev.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 1600
- #define HID_LOW_ADV_INT_MAX 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_TEST_EVT 0x0100
- #define reportQEmpty() ( firstQIdx == lastQIdx )
- /*********************************************************************
- * 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
- */
- /*********************************************************************
- * LOCAL VARIABLES
- */
- // GAP State
- static gaprole_States_t hidDevGapState = GAPROLE_INIT;
- // TRUE if connection is secure
- static uint8 hidDevConnSecure = FALSE;
- // GAP connection handle
- static 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 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 );
- /*********************************************************************
- * PROFILE CALLBACKS
- */
- /*********************************************************************
- * 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();
- Batt_Register(NULL);
- //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 );
- return ( events ^ START_DEVICE_EVT );
- }
- if ( events & HID_IDLE_EVT )
- {
- if ( hidDevGapState == GAPROLE_CONNECTED )
- {
- // if pairing in progress then restart timer
- if ( hidDevPairingStarted )
- {
- hidDevStartIdleTimer();
- }
- // else disconnect
- else
- {
- GAPRole_TerminateConnection();
- }
- }
- 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 )
- {
- 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 );
- }
- 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 );
- 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 ), ¶m );
- }
- }
- /*********************************************************************
- * @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, uint8 *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, uint8 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 )
- {
- // 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 ) );
- // if bonded and normally connectable start advertising
- if ( ( hidDevBondCount() > 0 ) &&
- ( pHidDevCfg->hidFlags & HID_FLAGS_NORMALLY_CONNECTABLE ) )
- {
- hidDevLowAdvertising();
- }
- }
- /*********************************************************************
- * @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;
- // don't start advertising when connection is closed
- uint8 param = FALSE;
- GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m );
- // start idle timer
- hidDevStartIdleTimer();
- }
- // if disconnected
- else if ( hidDevGapState == GAPROLE_CONNECTED &&
- newState != GAPROLE_CONNECTED )
- {
- hidDevDisconnected();
- updateConnParams = TRUE;
- if ( pairingStatus == SMP_PAIRING_FAILED_CONFIRM_VALUE )
- {
- // bonding failed due to mismatched confirm values
- hidDevInitialAdvertising();
- pairingStatus = SUCCESS;
- }
- }
- // 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;
- }
- pairingStatus = status;
- }
- else if ( state == GAPBOND_PAIRING_STATE_BONDED )
- {
- if ( status == SUCCESS )
- {
- hidDevConnSecure = TRUE;
- }
- }
- //if(hidDevConnSecure){
- // osal_start_reload_timer(hidDevTaskId, HID_TEST_EVT, 1000);
- //}
- if ( !reportQEmpty() && hidDevConnSecure )
- {
- // 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 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;
- }
- /*********************************************************************
- * @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();
- }
- }
- }
- }
- /*********************************************************************
- * @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 ), ¶m );
- param = TRUE;
- GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m );
- }
- /*********************************************************************
- * @fn hidDevLowAdvertising
- *
- * @brief Start advertising at a low duty cycle.
- *
- * @param None.
- *
- * @return None.
- */
- static void hidDevLowAdvertising( void )
- {
- 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_WHITE;
- VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), ¶m );
- param = TRUE;
- VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m );
- }
- /*********************************************************************
- * @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 ), ¶m );
- param = TRUE;
- VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m );
- }
- /*********************************************************************
- * @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 );
- }
- /*********************************************************************
- *********************************************************************/
|