hiddev.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. /**************************************************************************************************
  2. Phyplus Microelectronics Limited confidential and proprietary.
  3. All rights reserved.
  4. IMPORTANT: All rights of this software belong to Phyplus Microelectronics
  5. Limited ("Phyplus"). Your use of this Software is limited to those
  6. specific rights granted under the terms of the business contract, the
  7. confidential agreement, the non-disclosure agreement and any other forms
  8. of agreements as a customer or a partner of Phyplus. You may not use this
  9. Software unless you agree to abide by the terms of these agreements.
  10. You acknowledge that the Software may not be modified, copied,
  11. distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy
  12. (BLE) integrated circuit, either as a product or is integrated into your
  13. products. Other than for the aforementioned purposes, you may not use,
  14. reproduce, copy, prepare derivative works of, modify, distribute, perform,
  15. display or sell this Software and/or its documentation for any purposes.
  16. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  17. PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  18. INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  19. NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  20. PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT,
  21. NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  22. LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  23. INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  24. OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  25. OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  26. (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
  27. **************************************************************************************************/
  28. /*********************************************************************
  29. * INCLUDES
  30. */
  31. #include "OSAL.h"
  32. #include "gatt.h"
  33. #include "hci.h"
  34. #include "gapgattserver.h"
  35. #include "gattservapp.h"
  36. #include "gatt_uuid.h"
  37. #include "gatt_profile_uuid.h"
  38. #include "linkdb.h"
  39. #include "peripheral.h"
  40. #include "gapbondmgr.h"
  41. #include "devinfoservice.h"
  42. #include "battservice.h"
  43. #include "hiddev.h"
  44. #include "hidkbdservice.h"
  45. //#include "touch_key.h"
  46. #include "log.h"
  47. /*********************************************************************
  48. * MACROS
  49. */
  50. // Battery measurement period in ms
  51. #define DEFAULT_BATT_PERIOD 15000
  52. // TRUE to run scan parameters refresh notify test
  53. #define DEFAULT_SCAN_PARAM_NOTIFY_TEST TRUE
  54. // Advertising intervals (units of 625us, 160=100ms)
  55. #define HID_INITIAL_ADV_INT_MIN 48
  56. #define HID_INITIAL_ADV_INT_MAX 80
  57. #define HID_HIGH_ADV_INT_MIN 32
  58. #define HID_HIGH_ADV_INT_MAX 48
  59. #define HID_LOW_ADV_INT_MIN 1600
  60. #define HID_LOW_ADV_INT_MAX 1600
  61. // Advertising timeouts in sec
  62. #define HID_INITIAL_ADV_TIMEOUT 60
  63. #define HID_HIGH_ADV_TIMEOUT 5
  64. #define HID_LOW_ADV_TIMEOUT 0
  65. // Heart Rate Task Events
  66. #define START_DEVICE_EVT 0x0001
  67. #define BATT_PERIODIC_EVT 0x0002
  68. #define HID_IDLE_EVT 0x0004
  69. #define HID_SEND_REPORT_EVT 0x0008
  70. #define HID_TEST_EVT 0x0100
  71. #define reportQEmpty() ( firstQIdx == lastQIdx )
  72. /*********************************************************************
  73. * CONSTANTS
  74. */
  75. #define HID_DEV_DATA_LEN 8
  76. #ifdef HID_DEV_RPT_QUEUE_LEN
  77. #define HID_DEV_REPORT_Q_SIZE (HID_DEV_RPT_QUEUE_LEN+1)
  78. #else
  79. #define HID_DEV_REPORT_Q_SIZE (10+1)
  80. #endif
  81. /*********************************************************************
  82. * TYPEDEFS
  83. */
  84. typedef struct
  85. {
  86. uint8 id;
  87. uint8 type;
  88. uint8 len;
  89. uint8 data[HID_DEV_DATA_LEN];
  90. } hidDevReport_t;
  91. /*********************************************************************
  92. * GLOBAL VARIABLES
  93. */
  94. // Task ID
  95. uint8 hidDevTaskId;
  96. /*********************************************************************
  97. * EXTERNAL VARIABLES
  98. */
  99. /*********************************************************************
  100. * EXTERNAL FUNCTIONS
  101. */
  102. /*********************************************************************
  103. * LOCAL VARIABLES
  104. */
  105. // GAP State
  106. static gaprole_States_t hidDevGapState = GAPROLE_INIT;
  107. // TRUE if connection is secure
  108. static uint8 hidDevConnSecure = FALSE;
  109. // GAP connection handle
  110. static uint16 gapConnHandle;
  111. // TRUE if pairing in progress
  112. static uint8 hidDevPairingStarted = FALSE;
  113. // Status of last pairing
  114. static uint8 pairingStatus = SUCCESS;
  115. static hidRptMap_t *pHidDevRptTbl;
  116. static uint8 hidDevRptTblLen;
  117. static hidDevCB_t *pHidDevCB;
  118. static hidDevCfg_t *pHidDevCfg;
  119. // Whether to change to the preferred connection parameters
  120. static uint8 updateConnParams = TRUE;
  121. // Pending reports
  122. static uint8 firstQIdx = 0;
  123. static uint8 lastQIdx = 0;
  124. static hidDevReport_t hidDevReportQ[HID_DEV_REPORT_Q_SIZE];
  125. // Last report sent out
  126. static attHandleValueNoti_t lastNoti = { 0 };
  127. /*********************************************************************
  128. * LOCAL FUNCTIONS
  129. */
  130. static void hidDev_ProcessOSALMsg( osal_event_hdr_t *pMsg );
  131. static void hidDevProcessGattMsg( gattMsgEvent_t *pMsg );
  132. static void hidDevDisconnected( void );
  133. static void hidDevBattPeriodicTask( void );
  134. static hidRptMap_t *hidDevRptByHandle( uint16 handle );
  135. static hidRptMap_t *hidDevRptById( uint8 id, uint8 type );
  136. static hidRptMap_t *hidDevRptByCccdHandle( uint16 handle );
  137. static void hidDevEnqueueReport( uint8 id, uint8 type, uint8 len, uint8 *pData );
  138. static hidDevReport_t *hidDevDequeueReport( void );
  139. static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8 *pData );
  140. static void hidDevHighAdvertising( void );
  141. static void hidDevLowAdvertising( void );
  142. static void hidDevInitialAdvertising( void );
  143. static uint8 hidDevBondCount( void );
  144. static void hidDevStartIdleTimer( void );
  145. static void hidDevStopIdleTimer( void );
  146. /*********************************************************************
  147. * PROFILE CALLBACKS
  148. */
  149. /*********************************************************************
  150. * PUBLIC FUNCTIONS
  151. */
  152. /*********************************************************************
  153. * @fn HidDev_Init
  154. *
  155. * @brief Initialization function for the Hid Dev Task.
  156. * This is called during initialization and should contain
  157. * any application specific initialization (ie. hardware
  158. * initialization/setup, table initialization, power up
  159. * notificaiton ... ).
  160. *
  161. * @param task_id - the ID assigned by OSAL. This ID should be
  162. * used to send messages and set timers.
  163. *
  164. * @return none
  165. */
  166. void HidDev_Init( uint8 task_id )
  167. {
  168. hidDevTaskId = task_id;
  169. // Setup the GAP Bond Manager
  170. {
  171. uint8 syncWL = TRUE;
  172. // If a bond is created, the HID Device should write the address of the
  173. // HID Host in the HID Device controller's white list and set the HID
  174. // Device controller's advertising filter policy to 'process scan and
  175. // connection requests only from devices in the White List'.
  176. VOID GAPBondMgr_SetParameter( GAPBOND_AUTO_SYNC_WL, sizeof( uint8 ), &syncWL );
  177. }
  178. // Set up services
  179. GGS_AddService( GATT_ALL_SERVICES ); // GAP
  180. GATTServApp_AddService( GATT_ALL_SERVICES ); // GATT attributes
  181. DevInfo_AddService( );
  182. Batt_AddService();
  183. Batt_Register(NULL);
  184. //touch_init(on_key);
  185. // Setup a delayed profile startup
  186. osal_set_event( hidDevTaskId, START_DEVICE_EVT );
  187. }
  188. /*********************************************************************
  189. * @fn HidDev_ProcessEvent
  190. *
  191. * @brief Hid Dev Task event processor. This function
  192. * is called to process all events for the task. Events
  193. * include timers, messages and any other user defined events.
  194. *
  195. * @param task_id - The OSAL assigned task ID.
  196. * @param events - events to process. This is a bit map and can
  197. * contain more than one event.
  198. *
  199. * @return events not processed
  200. */
  201. uint16 HidDev_ProcessEvent( uint8 task_id, uint16 events )
  202. {
  203. VOID task_id; // OSAL required parameter that isn't used in this function
  204. LOG("%s\n",__FUNCTION__);
  205. if ( events & SYS_EVENT_MSG )
  206. {
  207. uint8 *pMsg;
  208. if ( (pMsg = osal_msg_receive( hidDevTaskId )) != NULL )
  209. {
  210. hidDev_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );
  211. // Release the OSAL message
  212. VOID osal_msg_deallocate( pMsg );
  213. }
  214. // return unprocessed events
  215. return (events ^ SYS_EVENT_MSG);
  216. }
  217. if ( events & START_DEVICE_EVT )
  218. {
  219. // Start the Device
  220. //VOID GAPRole_StartDevice( &hidDev_PeripheralCBs );
  221. // Register with bond manager after starting device
  222. //GAPBondMgr_Register( (gapBondCBs_t *) &hidDevBondCB );
  223. return ( events ^ START_DEVICE_EVT );
  224. }
  225. if ( events & HID_IDLE_EVT )
  226. {
  227. if ( hidDevGapState == GAPROLE_CONNECTED )
  228. {
  229. // if pairing in progress then restart timer
  230. if ( hidDevPairingStarted )
  231. {
  232. hidDevStartIdleTimer();
  233. }
  234. // else disconnect
  235. else
  236. {
  237. GAPRole_TerminateConnection();
  238. }
  239. }
  240. return ( events ^ HID_IDLE_EVT );
  241. }
  242. if ( events & BATT_PERIODIC_EVT )
  243. {
  244. // Perform periodic battery task
  245. hidDevBattPeriodicTask();
  246. return ( events ^ BATT_PERIODIC_EVT );
  247. }
  248. if ( events & HID_SEND_REPORT_EVT )
  249. {
  250. // if connection is secure
  251. if ( hidDevConnSecure )
  252. {
  253. hidDevReport_t *pReport = hidDevDequeueReport();
  254. if ( pReport != NULL )
  255. {
  256. // Send report
  257. hidDevSendReport( pReport->id, pReport->type, pReport->len, pReport->data );
  258. }
  259. return ( reportQEmpty() ? events ^ HID_SEND_REPORT_EVT : events );
  260. }
  261. return ( events ^ HID_SEND_REPORT_EVT );
  262. }
  263. return 0;
  264. }
  265. /*********************************************************************
  266. * @fn HidDev_Register
  267. *
  268. * @brief Register a callback function with HID Dev.
  269. *
  270. * @param pCfg - Parameter configuration.
  271. * @param pfnServiceCB - Callback function.
  272. *
  273. * @return None.
  274. */
  275. void HidDev_Register( hidDevCfg_t *pCfg, hidDevCB_t *pCBs )
  276. {
  277. pHidDevCB = pCBs;
  278. pHidDevCfg = pCfg;
  279. }
  280. /*********************************************************************
  281. * @fn HidDev_RegisterReports
  282. *
  283. * @brief Register the report table with HID Dev.
  284. *
  285. * @param numReports - Length of report table.
  286. * @param pRpt - Report table.
  287. *
  288. * @return None.
  289. */
  290. void HidDev_RegisterReports( uint8 numReports, hidRptMap_t *pRpt )
  291. {
  292. pHidDevRptTbl = pRpt;
  293. hidDevRptTblLen = numReports;
  294. }
  295. /*********************************************************************
  296. * @fn HidDev_Report
  297. *
  298. * @brief Send a HID report.
  299. *
  300. * @param id - HID report ID.
  301. * @param type - HID report type.
  302. * @param len - Length of report.
  303. * @param pData - Report data.
  304. *
  305. * @return None.
  306. */
  307. void HidDev_Report( uint8 id, uint8 type, uint8 len, uint8*pData )
  308. {
  309. // if connected
  310. if ( hidDevGapState == GAPROLE_CONNECTED )
  311. {
  312. // if connection is secure
  313. if ( hidDevConnSecure )
  314. {
  315. // Make sure there're no pending reports
  316. if ( reportQEmpty() )
  317. {
  318. // send report
  319. hidDevSendReport( id, type, len, pData );
  320. return; // we're done
  321. }
  322. }
  323. }
  324. // else if not already advertising
  325. else if ( hidDevGapState != GAPROLE_ADVERTISING )
  326. {
  327. // if bonded
  328. if ( hidDevBondCount() > 0 )
  329. {
  330. // start high duty cycle advertising
  331. hidDevHighAdvertising();
  332. }
  333. // else not bonded
  334. else
  335. {
  336. // start initial advertising
  337. hidDevInitialAdvertising();
  338. }
  339. }
  340. // hidDev task will send report when secure connection is established
  341. hidDevEnqueueReport( id, type, len, pData );
  342. }
  343. /*********************************************************************
  344. * @fn HidDev_Close
  345. *
  346. * @brief Close the connection or stop advertising.
  347. *
  348. * @return None.
  349. */
  350. void HidDev_Close( void )
  351. {
  352. uint8 param;
  353. // if connected then disconnect
  354. if ( hidDevGapState == GAPROLE_CONNECTED )
  355. {
  356. GAPRole_TerminateConnection();
  357. }
  358. // else stop advertising
  359. else
  360. {
  361. param = FALSE;
  362. GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
  363. }
  364. }
  365. /*********************************************************************
  366. * @fn HidDev_SetParameter
  367. *
  368. * @brief Set a HID Dev parameter.
  369. *
  370. * @param param - Profile parameter ID
  371. * @param len - length of data to right
  372. * @param pValue - pointer to data to write. This is dependent on
  373. * the parameter ID and WILL be cast to the appropriate
  374. * data type (example: data type of uint16 will be cast to
  375. * uint16 pointer).
  376. *
  377. * @return bStatus_t
  378. */
  379. bStatus_t HidDev_SetParameter( uint8 param, uint8 len, void *pValue )
  380. {
  381. bStatus_t ret = SUCCESS;
  382. switch ( param )
  383. {
  384. case HIDDEV_ERASE_ALLBONDS:
  385. if ( len == 0 )
  386. {
  387. // See if the last report sent out wasn't a release key
  388. if ( osal_isbufset( lastNoti.value, 0x00, lastNoti.len ) == FALSE )
  389. {
  390. // Send a release report before disconnecting, otherwise
  391. // the last pressed key would get 'stuck' on the HID Host.
  392. osal_memset( lastNoti.value, 0x00, lastNoti.len );
  393. GATT_Notification( gapConnHandle, &lastNoti, FALSE );
  394. }
  395. // Drop connection
  396. if ( hidDevGapState == GAPROLE_CONNECTED )
  397. {
  398. GAPRole_TerminateConnection();
  399. }
  400. // Flush report queue
  401. firstQIdx = lastQIdx = 0;
  402. // Erase bonding info
  403. GAPBondMgr_SetParameter( GAPBOND_ERASE_ALLBONDS, 0, NULL );
  404. }
  405. else
  406. {
  407. ret = bleInvalidRange;
  408. }
  409. break;
  410. default:
  411. ret = INVALIDPARAMETER;
  412. break;
  413. }
  414. return ( ret );
  415. }
  416. /*********************************************************************
  417. * @fn HidDev_GetParameter
  418. *
  419. * @brief Get a HID Dev parameter.
  420. *
  421. * @param param - Profile parameter ID
  422. * @param pValue - pointer to data to get. This is dependent on
  423. * the parameter ID and WILL be cast to the appropriate
  424. * data type (example: data type of uint16 will be cast to
  425. * uint16 pointer).
  426. *
  427. * @return bStatus_t
  428. */
  429. bStatus_t HidDev_GetParameter( uint8 param, void *pValue )
  430. {
  431. bStatus_t ret = SUCCESS;
  432. switch ( param )
  433. {
  434. default:
  435. ret = INVALIDPARAMETER;
  436. break;
  437. }
  438. return ( ret );
  439. }
  440. /*********************************************************************
  441. * @fn HidDev_PasscodeRsp
  442. *
  443. * @brief Respond to a passcode request.
  444. *
  445. * @param status - SUCCESS if passcode is available, otherwise
  446. * see @ref SMP_PAIRING_FAILED_DEFINES.
  447. * @param passcode - integer value containing the passcode.
  448. *
  449. * @return none
  450. */
  451. void HidDev_PasscodeRsp( uint8 status, uint32 passcode )
  452. {
  453. // Send passcode response
  454. GAPBondMgr_PasscodeRsp( gapConnHandle, status, passcode );
  455. }
  456. /*********************************************************************
  457. * @fn HidDev_ReadAttrCB
  458. *
  459. * @brief HID Dev attribute read callback.
  460. *
  461. * @param connHandle - connection message was received on
  462. * @param pAttr - pointer to attribute
  463. * @param pValue - pointer to data to be read
  464. * @param pLen - length of data to be read
  465. * @param offset - offset of the first octet to be read
  466. * @param maxLen - maximum length of data to be read
  467. * @param method - type of read message
  468. *
  469. * @return SUCCESS, blePending or Failure
  470. */
  471. uint8 HidDev_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
  472. uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen )
  473. {
  474. bStatus_t status = SUCCESS;
  475. hidRptMap_t *pRpt;
  476. uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
  477. // Only report map is long
  478. if ( offset > 0 && uuid != REPORT_MAP_UUID )
  479. {
  480. return ( ATT_ERR_ATTR_NOT_LONG );
  481. }
  482. if ( uuid == REPORT_UUID ||
  483. uuid == BOOT_KEY_INPUT_UUID ||
  484. uuid == BOOT_KEY_OUTPUT_UUID ||
  485. uuid == BOOT_MOUSE_INPUT_UUID )
  486. {
  487. // find report ID in table
  488. if ( (pRpt = hidDevRptByHandle(pAttr->handle)) != NULL )
  489. {
  490. // execute report callback
  491. status = (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid,
  492. HID_DEV_OPER_READ, pLen, pValue );
  493. }
  494. else
  495. {
  496. *pLen = 0;
  497. }
  498. }
  499. else if ( uuid == REPORT_MAP_UUID )
  500. {
  501. // verify offset
  502. if ( offset >= hidReportMapLen )
  503. {
  504. status = ATT_ERR_INVALID_OFFSET;
  505. }
  506. else
  507. {
  508. // determine read length
  509. *pLen = MIN( maxLen, (hidReportMapLen - offset) );
  510. // copy data
  511. osal_memcpy( pValue, pAttr->pValue + offset, *pLen );
  512. }
  513. }
  514. else if ( uuid == HID_INFORMATION_UUID )
  515. {
  516. *pLen = HID_INFORMATION_LEN;
  517. osal_memcpy( pValue, pAttr->pValue, HID_INFORMATION_LEN );
  518. }
  519. else if ( uuid == GATT_REPORT_REF_UUID )
  520. {
  521. *pLen = HID_REPORT_REF_LEN;
  522. osal_memcpy( pValue, pAttr->pValue, HID_REPORT_REF_LEN );
  523. }
  524. else if ( uuid == PROTOCOL_MODE_UUID )
  525. {
  526. *pLen = HID_PROTOCOL_MODE_LEN;
  527. pValue[0] = pAttr->pValue[0];
  528. }
  529. else if ( uuid == GATT_EXT_REPORT_REF_UUID )
  530. {
  531. *pLen = HID_EXT_REPORT_REF_LEN;
  532. osal_memcpy( pValue, pAttr->pValue, HID_EXT_REPORT_REF_LEN );
  533. }
  534. // restart idle timer
  535. if ( status == SUCCESS )
  536. {
  537. hidDevStartIdleTimer();
  538. }
  539. return ( status );
  540. }
  541. /*********************************************************************
  542. * @fn HidDev_WriteAttrCB
  543. *
  544. * @brief HID Dev attribute read callback.
  545. *
  546. * @param connHandle - connection message was received on
  547. * @param pAttr - pointer to attribute
  548. * @param pValue - pointer to data to be written
  549. * @param len - length of data
  550. * @param offset - offset of the first octet to be written
  551. *
  552. * @return Success or Failure
  553. */
  554. bStatus_t HidDev_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
  555. uint8 *pValue, uint8 len, uint16 offset )
  556. {
  557. bStatus_t status = SUCCESS;
  558. hidRptMap_t *pRpt;
  559. // Make sure it's not a blob operation (no attributes in the profile are long)
  560. if ( offset > 0 )
  561. {
  562. return ( ATT_ERR_ATTR_NOT_LONG );
  563. }
  564. uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
  565. if ( uuid == REPORT_UUID ||
  566. uuid == BOOT_KEY_OUTPUT_UUID )
  567. {
  568. // find report ID in table
  569. if ((pRpt = hidDevRptByHandle(pAttr->handle)) != NULL)
  570. {
  571. // execute report callback
  572. status = (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid,
  573. HID_DEV_OPER_WRITE, &len, pValue );
  574. }
  575. }
  576. else if ( uuid == HID_CTRL_PT_UUID )
  577. {
  578. // Validate length and value range
  579. if ( len == 1 )
  580. {
  581. if ( pValue[0] == HID_CMD_SUSPEND || pValue[0] == HID_CMD_EXIT_SUSPEND )
  582. {
  583. // execute HID app event callback
  584. (*pHidDevCB->evtCB)( (pValue[0] == HID_CMD_SUSPEND) ?
  585. HID_DEV_SUSPEND_EVT : HID_DEV_EXIT_SUSPEND_EVT );
  586. }
  587. else
  588. {
  589. status = ATT_ERR_INVALID_VALUE;
  590. }
  591. }
  592. else
  593. {
  594. status = ATT_ERR_INVALID_VALUE_SIZE;
  595. }
  596. }
  597. else if ( uuid == GATT_CLIENT_CHAR_CFG_UUID )
  598. {
  599. status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
  600. offset, GATT_CLIENT_CFG_NOTIFY );
  601. if ( status == SUCCESS )
  602. {
  603. uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] );
  604. // find report ID in table
  605. if ( (pRpt = hidDevRptByCccdHandle(pAttr->handle)) != NULL )
  606. {
  607. // execute report callback
  608. (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid,
  609. (charCfg == GATT_CLIENT_CFG_NOTIFY) ?
  610. HID_DEV_OPER_ENABLE : HID_DEV_OPER_DISABLE,
  611. &len, pValue );
  612. }
  613. }
  614. }
  615. else if ( uuid == PROTOCOL_MODE_UUID )
  616. {
  617. if ( len == HID_PROTOCOL_MODE_LEN )
  618. {
  619. if ( pValue[0] == HID_PROTOCOL_MODE_BOOT ||
  620. pValue[0] == HID_PROTOCOL_MODE_REPORT )
  621. {
  622. pAttr->pValue[0] = pValue[0];
  623. // execute HID app event callback
  624. (*pHidDevCB->evtCB)( (pValue[0] == HID_PROTOCOL_MODE_BOOT) ?
  625. HID_DEV_SET_BOOT_EVT : HID_DEV_SET_REPORT_EVT );
  626. }
  627. else
  628. {
  629. status = ATT_ERR_INVALID_VALUE;
  630. }
  631. }
  632. else
  633. {
  634. status = ATT_ERR_INVALID_VALUE_SIZE;
  635. }
  636. }
  637. // restart idle timer
  638. if (status == SUCCESS)
  639. {
  640. hidDevStartIdleTimer();
  641. }
  642. return ( status );
  643. }
  644. /*********************************************************************
  645. * @fn hidDev_ProcessOSALMsg
  646. *
  647. * @brief Process an incoming task message.
  648. *
  649. * @param pMsg - message to process
  650. *
  651. * @return none
  652. */
  653. static void hidDev_ProcessOSALMsg( osal_event_hdr_t *pMsg )
  654. {
  655. switch ( pMsg->event )
  656. {
  657. case GATT_MSG_EVENT:
  658. hidDevProcessGattMsg( (gattMsgEvent_t *) pMsg );
  659. break;
  660. default:
  661. break;
  662. }
  663. }
  664. /*********************************************************************
  665. * @fn hidDevProcessGattMsg
  666. *
  667. * @brief Process GATT messages
  668. *
  669. * @return none
  670. */
  671. static void hidDevProcessGattMsg( gattMsgEvent_t *pMsg )
  672. {
  673. }
  674. /*********************************************************************
  675. * @fn hidDevHandleConnStatusCB
  676. *
  677. * @brief Reset client char config.
  678. *
  679. * @param connHandle - connection handle
  680. * @param changeType - type of change
  681. *
  682. * @return none
  683. */
  684. static void hidDevHandleConnStatusCB( uint16 connHandle, uint8 changeType )
  685. {
  686. uint8 i;
  687. hidRptMap_t *p = pHidDevRptTbl;
  688. uint16 retHandle;
  689. gattAttribute_t *pAttr;
  690. // Make sure this is not loopback connection
  691. if ( connHandle != LOOPBACK_CONNHANDLE )
  692. {
  693. if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) ||
  694. ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) &&
  695. ( !linkDB_Up( connHandle ) ) ) )
  696. {
  697. for ( i = hidDevRptTblLen; i > 0; i--, p++ )
  698. {
  699. if ( p->cccdHandle != 0 )
  700. {
  701. if ( (pAttr = GATT_FindHandle(p->cccdHandle, &retHandle)) != NULL )
  702. {
  703. GATTServApp_InitCharCfg( connHandle, (gattCharCfg_t *) pAttr->pValue );
  704. }
  705. }
  706. }
  707. }
  708. }
  709. }
  710. /*********************************************************************
  711. * @fn hidDevDisconnected
  712. *
  713. * @brief Handle disconnect.
  714. *
  715. * @return none
  716. */
  717. static void hidDevDisconnected( void )
  718. {
  719. // Stop idle timer
  720. hidDevStopIdleTimer();
  721. // Reset client characteristic configuration descriptors
  722. Batt_HandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED );
  723. //ScanParam_HandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED );
  724. hidDevHandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED );
  725. // Reset state variables
  726. hidDevConnSecure = FALSE;
  727. hidProtocolMode = HID_PROTOCOL_MODE_REPORT;
  728. hidDevPairingStarted = FALSE;
  729. // Reset last report sent out
  730. osal_memset( &lastNoti, 0, sizeof( attHandleValueNoti_t ) );
  731. // if bonded and normally connectable start advertising
  732. if ( ( hidDevBondCount() > 0 ) &&
  733. ( pHidDevCfg->hidFlags & HID_FLAGS_NORMALLY_CONNECTABLE ) )
  734. {
  735. hidDevLowAdvertising();
  736. }
  737. }
  738. /*********************************************************************
  739. * @fn hidDevGapStateCB
  740. *
  741. * @brief Notification from the profile of a state change.
  742. *
  743. * @param newState - new state
  744. *
  745. * @return none
  746. */
  747. void hidDevGapStateCB( gaprole_States_t newState )
  748. {
  749. LOG("%s, %d\n",__FUNCTION__, newState);
  750. // if connected
  751. if ( newState == GAPROLE_CONNECTED )
  752. {
  753. // get connection handle
  754. GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
  755. // connection not secure yet
  756. hidDevConnSecure = FALSE;
  757. // don't start advertising when connection is closed
  758. uint8 param = FALSE;
  759. GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
  760. // start idle timer
  761. hidDevStartIdleTimer();
  762. }
  763. // if disconnected
  764. else if ( hidDevGapState == GAPROLE_CONNECTED &&
  765. newState != GAPROLE_CONNECTED )
  766. {
  767. hidDevDisconnected();
  768. updateConnParams = TRUE;
  769. if ( pairingStatus == SMP_PAIRING_FAILED_CONFIRM_VALUE )
  770. {
  771. // bonding failed due to mismatched confirm values
  772. hidDevInitialAdvertising();
  773. pairingStatus = SUCCESS;
  774. }
  775. }
  776. // if started
  777. else if ( newState == GAPROLE_STARTED )
  778. {
  779. // nothing to do for now!
  780. }
  781. hidDevGapState = newState;
  782. }
  783. /*********************************************************************
  784. * @fn hidDevPairStateCB
  785. *
  786. * @brief Pairing state callback.
  787. *
  788. * @return none
  789. */
  790. void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status )
  791. {
  792. if ( state == GAPBOND_PAIRING_STATE_STARTED )
  793. {
  794. hidDevPairingStarted = TRUE;
  795. }
  796. else if ( state == GAPBOND_PAIRING_STATE_COMPLETE )
  797. {
  798. hidDevPairingStarted = FALSE;
  799. if ( status == SUCCESS )
  800. {
  801. hidDevConnSecure = TRUE;
  802. }
  803. pairingStatus = status;
  804. }
  805. else if ( state == GAPBOND_PAIRING_STATE_BONDED )
  806. {
  807. if ( status == SUCCESS )
  808. {
  809. hidDevConnSecure = TRUE;
  810. }
  811. }
  812. //if(hidDevConnSecure){
  813. // osal_start_reload_timer(hidDevTaskId, HID_TEST_EVT, 1000);
  814. //}
  815. if ( !reportQEmpty() && hidDevConnSecure )
  816. {
  817. // Notify our task to send out pending reports
  818. osal_set_event( hidDevTaskId, HID_SEND_REPORT_EVT );
  819. }
  820. }
  821. /*********************************************************************
  822. * @fn hidDevPasscodeCB
  823. *
  824. * @brief Passcode callback.
  825. *
  826. * @param deviceAddr - address of device to pair with, and could be either public or random.
  827. * @param connectionHandle - connection handle
  828. * @param uiInputs - pairing User Interface Inputs - Ask user to input passcode
  829. * @param uiOutputs - pairing User Interface Outputs - Display passcode
  830. *
  831. * @return none
  832. */
  833. void hidDevPasscodeCB( uint8 *deviceAddr, uint16 connectionHandle,
  834. uint8 uiInputs, uint8 uiOutputs )
  835. {
  836. if ( pHidDevCB && pHidDevCB->passcodeCB )
  837. {
  838. // execute HID app passcode callback
  839. (*pHidDevCB->passcodeCB)( deviceAddr, connectionHandle, uiInputs, uiOutputs );
  840. }
  841. else
  842. {
  843. // Send passcode response
  844. GAPBondMgr_PasscodeRsp( connectionHandle, SUCCESS, 0 );
  845. }
  846. }
  847. /*********************************************************************
  848. * @fn hidDevBattPeriodicTask
  849. *
  850. * @brief Perform a periodic task for battery measurement.
  851. *
  852. * @param none
  853. *
  854. * @return none
  855. */
  856. static void hidDevBattPeriodicTask( void )
  857. {
  858. if ( hidDevGapState == GAPROLE_CONNECTED )
  859. {
  860. // perform battery level check
  861. Batt_MeasLevel( );
  862. // Restart timer
  863. osal_start_timerEx( hidDevTaskId, BATT_PERIODIC_EVT, DEFAULT_BATT_PERIOD );
  864. }
  865. }
  866. /*********************************************************************
  867. * @fn hidDevRptByHandle
  868. *
  869. * @brief Find the HID report structure for the given handle.
  870. *
  871. * @param handle - ATT handle
  872. *
  873. * @return Pointer to HID report structure
  874. */
  875. static hidRptMap_t *hidDevRptByHandle( uint16 handle )
  876. {
  877. uint8 i;
  878. hidRptMap_t *p = pHidDevRptTbl;
  879. for ( i = hidDevRptTblLen; i > 0; i--, p++ )
  880. {
  881. if ( p->handle == handle && p->mode == hidProtocolMode)
  882. {
  883. return p;
  884. }
  885. }
  886. return NULL;
  887. }
  888. /*********************************************************************
  889. * @fn hidDevRptByCccdHandle
  890. *
  891. * @brief Find the HID report structure for the given CCC handle.
  892. *
  893. * @param handle - ATT handle
  894. *
  895. * @return Pointer to HID report structure
  896. */
  897. static hidRptMap_t *hidDevRptByCccdHandle( uint16 handle )
  898. {
  899. uint8 i;
  900. hidRptMap_t *p = pHidDevRptTbl;
  901. for ( i = hidDevRptTblLen; i > 0; i--, p++ )
  902. {
  903. if ( p->cccdHandle == handle)
  904. {
  905. return p;
  906. }
  907. }
  908. return NULL;
  909. }
  910. /*********************************************************************
  911. * @fn hidDevRptById
  912. *
  913. * @brief Find the HID report structure for the Report ID and type.
  914. *
  915. * @param id - HID report ID
  916. * @param type - HID report type
  917. *
  918. * @return Pointer to HID report structure
  919. */
  920. static hidRptMap_t *hidDevRptById( uint8 id, uint8 type )
  921. {
  922. uint8 i;
  923. hidRptMap_t *p = pHidDevRptTbl;
  924. for ( i = hidDevRptTblLen; i > 0; i--, p++ )
  925. {
  926. if ( p->id == id && p->type == type && p->mode == hidProtocolMode )
  927. {
  928. return p;
  929. }
  930. }
  931. return NULL;
  932. }
  933. /*********************************************************************
  934. * @fn hidDevSendReport
  935. *
  936. * @brief Send a HID report.
  937. *
  938. * @param id - HID report ID.
  939. * @param type - HID report type.
  940. * @param len - Length of report.
  941. * @param pData - Report data.
  942. *
  943. * @return None.
  944. */
  945. static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8 *pData )
  946. {
  947. hidRptMap_t *pRpt;
  948. gattAttribute_t *pAttr;
  949. uint16 retHandle;
  950. LOG("%s\n",__FUNCTION__);
  951. // Get ATT handle for report
  952. if ( (pRpt = hidDevRptById(id, type)) != NULL )
  953. {
  954. // if notifications are enabled
  955. if ( (pAttr = GATT_FindHandle(pRpt->cccdHandle, &retHandle)) != NULL )
  956. {
  957. uint16 value;
  958. value = GATTServApp_ReadCharCfg( gapConnHandle, (gattCharCfg_t *) pAttr->pValue );
  959. if ( value & GATT_CLIENT_CFG_NOTIFY )
  960. {
  961. // After service discovery and encryption, the HID Device should request to
  962. // change to the preferred connection parameters that best suit its use case.
  963. if ( updateConnParams )
  964. {
  965. GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_REQ, sizeof( uint8 ), &updateConnParams );
  966. updateConnParams = FALSE;
  967. }
  968. // send notification
  969. lastNoti.handle = pRpt->handle;
  970. lastNoti.len = len;
  971. osal_memcpy(lastNoti.value, pData, len);
  972. GATT_Notification( gapConnHandle, &lastNoti, FALSE );
  973. // start idle timer
  974. hidDevStartIdleTimer();
  975. }
  976. }
  977. }
  978. }
  979. /*********************************************************************
  980. * @fn hidDevEnqueueReport
  981. *
  982. * @brief Enqueue a HID report to be sent later.
  983. *
  984. * @param id - HID report ID.
  985. * @param type - HID report type.
  986. * @param len - Length of report.
  987. * @param pData - Report data.
  988. *
  989. * @return None.
  990. */
  991. static void hidDevEnqueueReport( uint8 id, uint8 type, uint8 len, uint8 *pData )
  992. {
  993. // Enqueue only if bonded
  994. if ( hidDevBondCount() > 0 )
  995. {
  996. // Update last index
  997. lastQIdx = ( lastQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE;
  998. if ( lastQIdx == firstQIdx )
  999. {
  1000. // Queue overflow; discard oldest report
  1001. firstQIdx = ( firstQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE;
  1002. }
  1003. // Save report
  1004. hidDevReportQ[lastQIdx].id = id;
  1005. hidDevReportQ[lastQIdx].type = type;
  1006. hidDevReportQ[lastQIdx].len = len;
  1007. osal_memcpy( hidDevReportQ[lastQIdx].data, pData, len );
  1008. if ( hidDevConnSecure )
  1009. {
  1010. // Notify our task to send out pending reports
  1011. osal_set_event( hidDevTaskId, HID_SEND_REPORT_EVT );
  1012. }
  1013. }
  1014. }
  1015. /*********************************************************************
  1016. * @fn hidDevDequeueReport
  1017. *
  1018. * @brief Dequeue a HID report to be sent out.
  1019. *
  1020. * @param id - HID report ID.
  1021. * @param type - HID report type.
  1022. * @param len - Length of report.
  1023. * @param pData - Report data.
  1024. *
  1025. * @return None.
  1026. */
  1027. static hidDevReport_t *hidDevDequeueReport( void )
  1028. {
  1029. if ( reportQEmpty() )
  1030. {
  1031. return NULL;
  1032. }
  1033. // Update first index
  1034. firstQIdx = ( firstQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE;
  1035. return ( &(hidDevReportQ[firstQIdx]) );
  1036. }
  1037. /*********************************************************************
  1038. * @fn hidDevHighAdvertising
  1039. *
  1040. * @brief Start advertising at a high duty cycle.
  1041. * @param None.
  1042. *
  1043. * @return None.
  1044. */
  1045. static void hidDevHighAdvertising( void )
  1046. {
  1047. uint8 param;
  1048. VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_HIGH_ADV_INT_MIN );
  1049. VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_HIGH_ADV_INT_MAX );
  1050. VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_HIGH_ADV_TIMEOUT );
  1051. // Setup adverstising filter policy first
  1052. param = GAP_FILTER_POLICY_WHITE;
  1053. VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), &param );
  1054. param = TRUE;
  1055. GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
  1056. }
  1057. /*********************************************************************
  1058. * @fn hidDevLowAdvertising
  1059. *
  1060. * @brief Start advertising at a low duty cycle.
  1061. *
  1062. * @param None.
  1063. *
  1064. * @return None.
  1065. */
  1066. static void hidDevLowAdvertising( void )
  1067. {
  1068. uint8 param;
  1069. VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_LOW_ADV_INT_MIN );
  1070. VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_LOW_ADV_INT_MAX );
  1071. VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_LOW_ADV_TIMEOUT );
  1072. // Setup adverstising filter policy first
  1073. param = GAP_FILTER_POLICY_WHITE;
  1074. VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), &param );
  1075. param = TRUE;
  1076. VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
  1077. }
  1078. /*********************************************************************
  1079. * @fn hidDevInitialAdvertising
  1080. *
  1081. * @brief Start advertising for initial connection
  1082. *
  1083. * @return None.
  1084. */
  1085. static void hidDevInitialAdvertising( void )
  1086. {
  1087. uint8 param;
  1088. VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_INITIAL_ADV_INT_MIN );
  1089. VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_INITIAL_ADV_INT_MAX );
  1090. VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_INITIAL_ADV_TIMEOUT );
  1091. // Setup adverstising filter policy first
  1092. param = GAP_FILTER_POLICY_ALL;
  1093. VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), &param );
  1094. param = TRUE;
  1095. VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &param );
  1096. }
  1097. /*********************************************************************
  1098. * @fn hidDevBondCount
  1099. *
  1100. * @brief Gets the total number of bonded devices.
  1101. *
  1102. * @param None.
  1103. *
  1104. * @return number of bonded devices.
  1105. */
  1106. static uint8 hidDevBondCount( void )
  1107. {
  1108. uint8 bondCnt = 0;
  1109. VOID GAPBondMgr_GetParameter( GAPBOND_BOND_COUNT, &bondCnt );
  1110. return ( bondCnt );
  1111. }
  1112. /*********************************************************************
  1113. * @fn hidDevStartIdleTimer
  1114. *
  1115. * @brief Start the idle timer.
  1116. *
  1117. * @return None.
  1118. */
  1119. static void hidDevStartIdleTimer( void )
  1120. {
  1121. if ( pHidDevCfg->idleTimeout > 0 )
  1122. {
  1123. osal_start_timerEx( hidDevTaskId, HID_IDLE_EVT, pHidDevCfg->idleTimeout );
  1124. }
  1125. }
  1126. /*********************************************************************
  1127. * @fn hidDevStopIdleTimer
  1128. *
  1129. * @brief Stop the idle timer.
  1130. *
  1131. * @return None.
  1132. */
  1133. static void hidDevStopIdleTimer( void )
  1134. {
  1135. osal_stop_timerEx( hidDevTaskId, HID_IDLE_EVT );
  1136. }
  1137. /*********************************************************************
  1138. *********************************************************************/