gapgattserver.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. /**
  2. * @file
  3. * @author chipsea
  4. * @brief
  5. * @version 0.1
  6. * @date 2020-11-30
  7. * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
  8. * @note
  9. */
  10. /**************************************************************************************************
  11. Filename: gapgattserver.c
  12. Revised:
  13. Revision:
  14. Description: GAP Attribute Server
  15. **************************************************************************************************/
  16. /*********************************************************************
  17. * INCLUDES
  18. */
  19. #include "sdk_config.h"
  20. #include "bcomdef.h"
  21. #include "OSAL.h"
  22. #include "gap.h"
  23. #include "gapgattserver.h"
  24. #include "att.h"
  25. #include "gatt.h"
  26. #include "gatt_uuid.h"
  27. #include "gattservapp.h"
  28. /*********************************************************************
  29. * MACROS
  30. */
  31. /*********************************************************************
  32. * CONSTANTS
  33. */
  34. // Position of device name in attribute table
  35. #define GAP_DEVICE_NAME_POS 2
  36. #define GAP_APPEARANCE_POS 4
  37. #define GAP_PRIVACY_FLAG_POS 6
  38. /*********************************************************************
  39. * TYPEDEFS
  40. */
  41. /*********************************************************************
  42. * GLOBAL VARIABLES
  43. */
  44. /*********************************************************************
  45. * EXTERNAL VARIABLES
  46. */
  47. /*********************************************************************
  48. * EXTERNAL FUNCTIONS
  49. */
  50. /*********************************************************************
  51. * LOCAL VARIABLES
  52. */
  53. static const ggsAppCBs_t *ggs_AppCBs = NULL;
  54. #if defined ( TESTMODES )
  55. static uint16 paramValue = 0;
  56. #endif
  57. /*********************************************************************
  58. * Profile Attributes - variables
  59. */
  60. // GAP Service
  61. static CONST gattAttrType_t gapService = { ATT_BT_UUID_SIZE, gapServiceUUID };
  62. // Device Name Characteristic Properties
  63. static uint8 deviceNameCharProps = GATT_PROP_READ;
  64. // Device Name attribute (0 - 248 octets) - extra octet for null-terminate char
  65. static uint8 deviceName[GAP_DEVICE_NAME_LEN+1] = { 0 };
  66. // Appearance Characteristic Properties
  67. static uint8 appearanceCharProps = GATT_PROP_READ;
  68. // Appearance attribute (2-octet enumerated value as defined by Bluetooth Assigned Numbers document)
  69. static uint16 appearance = GAP_APPEARE_UNKNOWN;
  70. #if ( HOST_CONFIG & PERIPHERAL_CFG )
  71. #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT)
  72. // Peripheral Privacy Flag Characteristic Properties
  73. static uint8 periPrivacyFlagCharProps = GATT_PROP_READ;
  74. // Peripheral Privacy Flag attribute (1 octet)
  75. static uint8 periPrivacyFlag = GAP_PRIVACY_DISABLED;
  76. #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT
  77. #if defined (GAP_PRIVACY_RECONNECT)
  78. // Reconnection Address Characteristic Properties
  79. static uint8 reconnectAddrCharProps = GATT_PROP_WRITE;
  80. // Reconnection Address attribute (6 octets)
  81. static uint8 reconnectAddr[B_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  82. #endif // GAP_PRIVACY_RECONNECT
  83. // Peripheral Preferred Connection Parameters Characteristic Properties
  84. static uint8 periConnParamCharProps = GATT_PROP_READ;
  85. // Peripheral Preferred Connection Parameters attribute (8 octets)
  86. static gapPeriConnectParams_t periConnParameters = { 80, 160, 0, 1000 };
  87. #endif // PERIPHERAL_CFG
  88. /*********************************************************************
  89. * Profile Attributes - Table
  90. */
  91. // GAP Attribute Table
  92. static gattAttribute_t gapAttrTbl[] =
  93. {
  94. // Generic Access Profile
  95. {
  96. { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
  97. GATT_PERMIT_READ, /* permissions */
  98. 0, /* handle */
  99. (uint8 *)&gapService /* pValue */
  100. },
  101. // Characteristic Declaration
  102. {
  103. { ATT_BT_UUID_SIZE, characterUUID },
  104. GATT_PERMIT_READ,
  105. 0,
  106. &deviceNameCharProps
  107. },
  108. // Device Name attribute
  109. {
  110. { ATT_BT_UUID_SIZE, deviceNameUUID },
  111. GATT_PERMIT_READ,
  112. 0,
  113. deviceName
  114. },
  115. // Characteristic Declaration
  116. {
  117. { ATT_BT_UUID_SIZE, characterUUID },
  118. GATT_PERMIT_READ,
  119. 0,
  120. &appearanceCharProps
  121. },
  122. // Icon attribute
  123. {
  124. { ATT_BT_UUID_SIZE, appearanceUUID },
  125. GATT_PERMIT_READ,
  126. 0,
  127. (uint8 *)&appearance
  128. },
  129. #if ( HOST_CONFIG & PERIPHERAL_CFG )
  130. #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT)
  131. // Characteristic Declaration
  132. {
  133. { ATT_BT_UUID_SIZE, characterUUID },
  134. GATT_PERMIT_READ,
  135. 0,
  136. &periPrivacyFlagCharProps
  137. },
  138. // Peripheral Privacy Flag attribute
  139. {
  140. { ATT_BT_UUID_SIZE, periPrivacyFlagUUID },
  141. GATT_PERMIT_READ,
  142. 0,
  143. (uint8 *)&periPrivacyFlag
  144. },
  145. #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT
  146. #if defined (GAP_PRIVACY_RECONNECT)
  147. // Characteristic Declaration
  148. {
  149. { ATT_BT_UUID_SIZE, characterUUID },
  150. GATT_PERMIT_READ,
  151. 0,
  152. &reconnectAddrCharProps
  153. },
  154. // Reconnection Address attribute
  155. {
  156. { ATT_BT_UUID_SIZE, reconnectAddrUUID },
  157. GATT_PERMIT_AUTHEN_WRITE,
  158. 0,
  159. reconnectAddr
  160. },
  161. #endif // GAP_PRIVACY_RECONNECT
  162. // Characteristic Declaration
  163. {
  164. { ATT_BT_UUID_SIZE, characterUUID },
  165. GATT_PERMIT_READ,
  166. 0,
  167. &periConnParamCharProps
  168. },
  169. // Peripheral Preferred Connection Parameters attribute
  170. {
  171. { ATT_BT_UUID_SIZE, periConnParamUUID },
  172. GATT_PERMIT_READ,
  173. 0,
  174. (uint8 *)&periConnParameters
  175. },
  176. #endif // PERIPHERAL_CFG
  177. };
  178. /*********************************************************************
  179. * LOCAL FUNCTIONS
  180. */
  181. static void ggs_SetAttrWPermit( uint8 wPermit, uint8 *pPermissions, uint8 *pCharProps );
  182. /*********************************************************************
  183. * PUBLIC FUNCTIONS
  184. */
  185. // GGS Callback functions
  186. static uint8 ggs_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
  187. uint8 *pValue, uint16 *pLen, uint16 offset, uint8 maxLen );
  188. static bStatus_t ggs_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
  189. uint8 *pValue, uint16 len, uint16 offset );
  190. /*********************************************************************
  191. * PROFILE CALLBACKS
  192. */
  193. // GAP Service Callbacks
  194. CONST gattServiceCBs_t gapServiceCBs =
  195. {
  196. ggs_ReadAttrCB, // Read callback function pointer
  197. ggs_WriteAttrCB, // Write callback function pointer
  198. NULL // Authorization callback function pointer
  199. };
  200. /*********************************************************************
  201. * @fn GGS_SetParameter
  202. *
  203. * @brief Set a GAP GATT Server parameter.
  204. *
  205. * @param param - Profile parameter ID
  206. * @param len - length of data to right
  207. * @param value - pointer to data to write. This is dependent on
  208. * the parameter ID and WILL be cast to the appropriate
  209. * data type (example: data type of uint16 will be cast to
  210. * uint16 pointer).
  211. *
  212. * @return bStatus_t
  213. */
  214. bStatus_t GGS_SetParameter( uint8 param, uint8 len, void *value )
  215. {
  216. bStatus_t ret = SUCCESS;
  217. switch ( param )
  218. {
  219. case GGS_DEVICE_NAME_ATT:
  220. // Always leave room for null-terminate char
  221. if ( len <= GAP_DEVICE_NAME_LEN )
  222. {
  223. VOID osal_memset( deviceName, 0, GAP_DEVICE_NAME_LEN+1 );
  224. VOID osal_memcpy( deviceName, value, len );
  225. }
  226. else
  227. {
  228. ret = bleInvalidRange;
  229. }
  230. break;
  231. case GGS_APPEARANCE_ATT:
  232. if ( len == sizeof ( uint16 ) )
  233. {
  234. appearance = *((uint16*)value);
  235. }
  236. else
  237. {
  238. ret = bleInvalidRange;
  239. }
  240. break;
  241. #if ( HOST_CONFIG & PERIPHERAL_CFG )
  242. #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT)
  243. case GGS_PERI_PRIVACY_FLAG_ATT:
  244. if ( len == sizeof ( uint8 ) )
  245. {
  246. periPrivacyFlag = *((uint8*)value);
  247. }
  248. else
  249. {
  250. ret = bleInvalidRange;
  251. }
  252. break;
  253. case GGS_PERI_PRIVACY_FLAG_PROPS:
  254. if ( len == sizeof ( uint8 ) )
  255. {
  256. periPrivacyFlagCharProps = *((uint8*)value);
  257. }
  258. else
  259. {
  260. ret = bleInvalidRange;
  261. }
  262. break;
  263. case GGS_W_PERMIT_PRIVACY_FLAG_ATT:
  264. if ( len == sizeof ( uint8 ) )
  265. {
  266. uint8 wPermit = *(uint8 *)value;
  267. // Optionally Writeable with Authentication
  268. if ( !gattPermitWrite( wPermit ) )
  269. {
  270. ggs_SetAttrWPermit( wPermit,
  271. &(gapAttrTbl[GAP_PRIVACY_FLAG_POS].permissions),
  272. gapAttrTbl[GAP_PRIVACY_FLAG_POS-1].pValue );
  273. }
  274. else
  275. {
  276. ret = bleInvalidRange;
  277. }
  278. }
  279. else
  280. {
  281. ret = bleInvalidRange;
  282. }
  283. break;
  284. #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT
  285. #if defined (GAP_PRIVACY_RECONNECT)
  286. case GGS_RECONNCT_ADDR_ATT:
  287. if ( len == B_ADDR_LEN )
  288. {
  289. VOID osal_memcpy( reconnectAddr, value, len );
  290. }
  291. else
  292. {
  293. ret = bleInvalidRange;
  294. }
  295. break;
  296. #endif // GAP_PRIVACY_RECONNECT
  297. case GGS_PERI_CONN_PARAM_ATT:
  298. if ( len == sizeof(gapPeriConnectParams_t) )
  299. {
  300. periConnParameters = *((gapPeriConnectParams_t *)(value));
  301. }
  302. else
  303. {
  304. ret = bleInvalidRange;
  305. }
  306. break;
  307. #endif // PERIPHERAL_CFG
  308. case GGS_W_PERMIT_DEVICE_NAME_ATT:
  309. if ( len == sizeof ( uint8 ) )
  310. {
  311. // Optionally Writeable
  312. ggs_SetAttrWPermit( *(uint8 *)value,
  313. &(gapAttrTbl[GAP_DEVICE_NAME_POS].permissions),
  314. gapAttrTbl[GAP_DEVICE_NAME_POS-1].pValue );
  315. }
  316. else
  317. {
  318. ret = bleInvalidRange;
  319. }
  320. break;
  321. case GGS_W_PERMIT_APPEARANCE_ATT:
  322. if ( len == sizeof ( uint8 ) )
  323. {
  324. // Optionally Writeable
  325. ggs_SetAttrWPermit( *(uint8 *)value,
  326. &(gapAttrTbl[GAP_APPEARANCE_POS].permissions),
  327. gapAttrTbl[GAP_APPEARANCE_POS-1].pValue );
  328. }
  329. else
  330. {
  331. ret = bleInvalidRange;
  332. }
  333. break;
  334. default:
  335. ret = INVALIDPARAMETER;
  336. break;
  337. }
  338. return ( ret );
  339. }
  340. /*********************************************************************
  341. * @fn GGS_GetParameter
  342. *
  343. * @brief Get a GAP GATT Server parameter.
  344. *
  345. * @param param - Profile parameter ID
  346. * @param value - pointer to data to put. This is dependent on
  347. * the parameter ID and WILL be cast to the appropriate
  348. * data type (example: data type of uint16 will be cast to
  349. * uint16 pointer).
  350. *
  351. * @return bStatus_t
  352. */
  353. bStatus_t GGS_GetParameter( uint8 param, void *value )
  354. {
  355. bStatus_t ret = SUCCESS;
  356. switch ( param )
  357. {
  358. case GGS_DEVICE_NAME_ATT:
  359. VOID osal_memcpy( value, deviceName, GAP_DEVICE_NAME_LEN );
  360. break;
  361. case GGS_APPEARANCE_ATT:
  362. *((uint16*)value) = appearance;
  363. break;
  364. #if ( HOST_CONFIG & PERIPHERAL_CFG )
  365. #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT)
  366. case GGS_PERI_PRIVACY_FLAG_ATT:
  367. *((uint8*)value) = periPrivacyFlag;
  368. break;
  369. case GGS_PERI_PRIVACY_FLAG_PROPS:
  370. *((uint8*)value) = periPrivacyFlagCharProps;
  371. break;
  372. #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT
  373. #if defined (GAP_PRIVACY_RECONNECT)
  374. case GGS_RECONNCT_ADDR_ATT:
  375. VOID osal_memcpy( value, reconnectAddr, B_ADDR_LEN );
  376. break;
  377. #endif // GAP_PRIVACY_RECONNECT
  378. case GGS_PERI_CONN_PARAM_ATT:
  379. *((gapPeriConnectParams_t *)(value)) = periConnParameters;
  380. break;
  381. #endif // PERIPHERAL_CFG
  382. default:
  383. ret = INVALIDPARAMETER;
  384. break;
  385. }
  386. return ( ret );
  387. }
  388. /*********************************************************************
  389. * @fn GGS_SetParamValue
  390. *
  391. * @brief Set a GGS Parameter value. Use this function to change
  392. * the default GGS parameter values.
  393. *
  394. * @param value - new GGS param value
  395. *
  396. * @return void
  397. */
  398. void GGS_SetParamValue( uint16 value )
  399. {
  400. #if defined ( TESTMODES )
  401. uint8 wpermit;
  402. paramValue = value;
  403. switch ( value )
  404. {
  405. case GGS_TESTMODE_OFF:
  406. wpermit = 0;
  407. VOID GGS_SetParameter( GGS_W_PERMIT_DEVICE_NAME_ATT, sizeof( uint8 ), (void*)&wpermit );
  408. VOID GGS_SetParameter( GGS_W_PERMIT_APPEARANCE_ATT, sizeof( uint8 ), (void*)&wpermit );
  409. VOID GGS_SetParameter( GGS_W_PERMIT_PRIVACY_FLAG_ATT, sizeof( uint8 ), (void*)&wpermit );
  410. break;
  411. case GGS_TESTMODE_W_PERMIT_DEVICE_NAME:
  412. wpermit = GATT_PERMIT_WRITE;
  413. VOID GGS_SetParameter( GGS_W_PERMIT_DEVICE_NAME_ATT, sizeof( uint8 ), (void*)&wpermit );
  414. break;
  415. case GGS_TESTMODE_W_PERMIT_APPEARANCE:
  416. wpermit = GATT_PERMIT_WRITE;
  417. VOID GGS_SetParameter( GGS_W_PERMIT_APPEARANCE_ATT, sizeof( uint8 ), (void*)&wpermit );
  418. break;
  419. case GGS_TESTMODE_W_PERMIT_PRIVACY_FLAG:
  420. wpermit = GATT_PERMIT_AUTHEN_WRITE;
  421. VOID GGS_SetParameter( GGS_W_PERMIT_PRIVACY_FLAG_ATT, sizeof( uint8 ), (void*)&wpermit );
  422. break;
  423. default:
  424. break;
  425. }
  426. #else
  427. VOID value;
  428. #endif
  429. }
  430. /*********************************************************************
  431. * @fn GGS_GetParamValue
  432. *
  433. * @brief Get a GGS Parameter value.
  434. *
  435. * @param none
  436. *
  437. * @return GGS Parameter value
  438. */
  439. uint16 GGS_GetParamValue( void )
  440. {
  441. #if defined ( TESTMODES )
  442. return ( paramValue );
  443. #else
  444. return ( 0 );
  445. #endif
  446. }
  447. /*********************************************************************
  448. * LOCAL FUNCTION PROTOTYPES
  449. */
  450. /*********************************************************************
  451. * @fn GGS_AddService
  452. *
  453. * @brief Add function for the GAP GATT Service.
  454. *
  455. * @param services - services to add. This is a bit map and can
  456. * contain more than one service.
  457. *
  458. * @return SUCCESS: Service added successfully.
  459. * INVALIDPARAMETER: Invalid service field.
  460. * FAILURE: Not enough attribute handles available.
  461. * bleMemAllocError: Memory allocation error occurred.
  462. */
  463. bStatus_t GGS_AddService( uint32 services )
  464. {
  465. uint8 status = SUCCESS;
  466. if ( services & GAP_SERVICE )
  467. {
  468. // Register GAP attribute list and CBs with GATT Server Server App
  469. status = GATTServApp_RegisterService( gapAttrTbl, GATT_NUM_ATTRS( gapAttrTbl ),
  470. &gapServiceCBs );
  471. }
  472. return ( status );
  473. }
  474. /******************************************************************************
  475. * @fn GATTServApp_DelService
  476. *
  477. * @brief Delete function for the GAP GATT Service.
  478. *
  479. * @param services - services to delete. This is a bit map and can
  480. * contain more than one service.
  481. *
  482. * @return SUCCESS: Service deleted successfully.
  483. * FAILURE: Service not found.
  484. */
  485. bStatus_t GGS_DelService( uint32 services )
  486. {
  487. uint8 status = SUCCESS;
  488. if ( services & GAP_SERVICE )
  489. {
  490. // Deregister GAP attribute list and CBs from GATT Server Application
  491. status = GATTServApp_DeregisterService( GATT_SERVICE_HANDLE( gapAttrTbl ), NULL );
  492. }
  493. return ( status );
  494. }
  495. /*********************************************************************
  496. * @fn GGS_RegisterAppCBs
  497. *
  498. * @brief Registers the application callback function.
  499. *
  500. * Note: Callback registration is needed only when the
  501. * Device Name is made writable. The application
  502. * will be notified when the Device Name is changed
  503. * over the air.
  504. *
  505. * @param appCallbacks - pointer to application callbacks.
  506. *
  507. * @return none
  508. */
  509. void GGS_RegisterAppCBs( ggsAppCBs_t *appCallbacks )
  510. {
  511. ggs_AppCBs = appCallbacks;
  512. }
  513. /*********************************************************************
  514. * @fn ggs_SetAttrWPermit
  515. *
  516. * @brief Update attribute Write access permissions and characteristic
  517. * properties for over-the-air write operations.
  518. *
  519. * @param wPermit - write acces permissions
  520. * @param pPermissions - pointer to attribute permissions
  521. * @param pCharProps - pointer to characteristic properties
  522. *
  523. * @return none
  524. */
  525. static void ggs_SetAttrWPermit( uint8 wPermit, uint8 *pPermissions, uint8 *pCharProps )
  526. {
  527. // Update attribute Write access permissions
  528. if ( gattPermitWrite( wPermit ) )
  529. {
  530. *pPermissions |= GATT_PERMIT_WRITE;
  531. }
  532. else
  533. {
  534. *pPermissions &= ~GATT_PERMIT_WRITE;
  535. }
  536. if ( gattPermitAuthenWrite( wPermit ) )
  537. {
  538. *pPermissions |= GATT_PERMIT_AUTHEN_WRITE;
  539. }
  540. else
  541. {
  542. *pPermissions &= ~GATT_PERMIT_AUTHEN_WRITE;
  543. }
  544. if ( gattPermitAuthorWrite( wPermit ) )
  545. {
  546. *pPermissions |= GATT_PERMIT_AUTHOR_WRITE;
  547. }
  548. else
  549. {
  550. *pPermissions &= ~GATT_PERMIT_AUTHOR_WRITE;
  551. }
  552. // Update attribute Write characteristic properties
  553. if ( gattPermitWrite( wPermit ) ||
  554. gattPermitAuthenWrite( wPermit ) ||
  555. gattPermitAuthorWrite( wPermit ) )
  556. {
  557. *pCharProps |= (GATT_PROP_WRITE_NO_RSP | GATT_PROP_WRITE);
  558. }
  559. else if ( wPermit == 0 )
  560. {
  561. // Attribute not Writable
  562. *pCharProps &= ~(GATT_PROP_WRITE_NO_RSP | GATT_PROP_WRITE);
  563. }
  564. }
  565. /*********************************************************************
  566. * @fn ggs_ReadAttrCB
  567. *
  568. * @brief Read an attribute.
  569. *
  570. * @param connHandle - connection message was received on
  571. * @param pAttr - pointer to attribute
  572. * @param pValue - pointer to data to be read
  573. * @param pLen - length of data to be read
  574. * @param offset - offset of the first octet to be read
  575. * @param maxLen - maximum length of data to be read
  576. *
  577. * @return Success or Failure
  578. */
  579. static uint8 ggs_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
  580. uint8 *pValue, uint16 *pLen, uint16 offset, uint8 maxLen )
  581. {
  582. uint16 uuid;
  583. bStatus_t status = SUCCESS;
  584. VOID connHandle; // Not needed for now!
  585. // Make sure it's not a blob operation
  586. if ( offset > 0 )
  587. {
  588. return ( ATT_ERR_ATTR_NOT_LONG );
  589. }
  590. if ( pAttr->type.len == ATT_BT_UUID_SIZE )
  591. {
  592. // 16-bit UUID
  593. uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
  594. switch ( uuid )
  595. {
  596. case DEVICE_NAME_UUID:
  597. {
  598. uint8 len = osal_strlen( (char *)(pAttr->pValue) );
  599. // If the attribute value is longer than maxLen then maxLen
  600. // octets shall be included in this response.
  601. if ( len > maxLen )
  602. {
  603. len = maxLen;
  604. }
  605. *pLen = len;
  606. VOID osal_memcpy( pValue, pAttr->pValue, len );
  607. }
  608. break;
  609. case APPEARANCE_UUID:
  610. {
  611. uint16 value = *((uint16 *)(pAttr->pValue));
  612. *pLen = 2;
  613. pValue[0] = LO_UINT16( value );
  614. pValue[1] = HI_UINT16( value );
  615. }
  616. break;
  617. case RECONNECT_ADDR_UUID:
  618. *pLen = B_ADDR_LEN;
  619. VOID osal_memcpy( pValue, pAttr->pValue, B_ADDR_LEN );
  620. break;
  621. case PERI_PRIVACY_FLAG_UUID:
  622. *pLen = 1;
  623. *pValue = *pAttr->pValue;
  624. break;
  625. case PERI_CONN_PARAM_UUID:
  626. if ( pAttr->pValue != NULL )
  627. {
  628. gapPeriConnectParams_t *pConnectParam = (gapPeriConnectParams_t *)(pAttr->pValue);
  629. *pLen = 8;
  630. pValue[0] = LO_UINT16( pConnectParam->intervalMin );
  631. pValue[1] = HI_UINT16( pConnectParam->intervalMin );
  632. pValue[2] = LO_UINT16( pConnectParam->intervalMax );
  633. pValue[3] = HI_UINT16( pConnectParam->intervalMax );
  634. pValue[4] = LO_UINT16( pConnectParam->latency );
  635. pValue[5] = HI_UINT16( pConnectParam->latency );
  636. pValue[6] = LO_UINT16( pConnectParam->timeout );
  637. pValue[7] = HI_UINT16( pConnectParam->timeout );
  638. }
  639. else
  640. {
  641. *pLen = 0;
  642. }
  643. break;
  644. default:
  645. // Should never get here!
  646. *pLen = 0;
  647. status = ATT_ERR_INVALID_HANDLE;
  648. break;
  649. }
  650. }
  651. else
  652. {
  653. // 128-bit UUID
  654. *pLen = 0;
  655. status = ATT_ERR_INVALID_HANDLE;
  656. }
  657. return ( status );
  658. }
  659. /*********************************************************************
  660. * @fn ggs_ValidateWriteAttrCB
  661. *
  662. * @brief Validate and Write attribute data
  663. *
  664. * @param connHandle - connection message was received on
  665. * @param pAttr - pointer to attribute
  666. * @param pValue - pointer to data to be written
  667. * @param len - length of data
  668. * @param offset - offset of the first octet to be written
  669. *
  670. * @return Success or Failure
  671. */
  672. static bStatus_t ggs_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
  673. uint8 *pValue, uint16 len, uint16 offset )
  674. {
  675. bStatus_t status = SUCCESS;
  676. VOID connHandle; // Not needed for now!
  677. if ( pAttr->type.len == ATT_BT_UUID_SIZE )
  678. {
  679. // 16-bit UUID
  680. uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
  681. switch ( uuid )
  682. {
  683. case DEVICE_NAME_UUID:
  684. // Validate the long value
  685. {
  686. uint8 curLen = osal_strlen( (char *)(pAttr->pValue) );
  687. // If the value offset is greater than the current length of the
  688. // attribute value then an Error Response shall be sent with the
  689. // error code Invalid Offset.
  690. if ( offset <= curLen )
  691. {
  692. // Always leave room for null-terminate char
  693. if ( ( offset + len ) > GAP_DEVICE_NAME_LEN )
  694. {
  695. // Appliction error
  696. status = ATT_ERR_INVALID_VALUE_SIZE;
  697. }
  698. }
  699. else
  700. {
  701. status = ATT_ERR_INVALID_OFFSET;
  702. }
  703. }
  704. // Write the long value
  705. if ( status == SUCCESS )
  706. {
  707. VOID osal_memcpy( &(pAttr->pValue[offset]), pValue, len );
  708. offset += len;
  709. pAttr->pValue[offset] = '\0';
  710. // Notify application
  711. if ( ggs_AppCBs && ggs_AppCBs->pfnAttrValueChange )
  712. {
  713. ggs_AppCBs->pfnAttrValueChange( GGS_DEVICE_NAME_ID );
  714. }
  715. }
  716. break;
  717. case APPEARANCE_UUID:
  718. // Validate the value
  719. if ( offset == 0 )
  720. {
  721. if ( len != 2 )
  722. {
  723. status = ATT_ERR_INVALID_VALUE_SIZE;
  724. }
  725. }
  726. else
  727. {
  728. status = ATT_ERR_ATTR_NOT_LONG;
  729. }
  730. // Write the value
  731. if ( status == SUCCESS )
  732. {
  733. uint16 *pCurValue = (uint16 *)pAttr->pValue;
  734. *pCurValue = BUILD_UINT16( pValue[0], pValue[1] );
  735. // Notify application
  736. if ( ggs_AppCBs && ggs_AppCBs->pfnAttrValueChange )
  737. {
  738. ggs_AppCBs->pfnAttrValueChange( GGS_APPEARANCE_ID );
  739. }
  740. }
  741. break;
  742. case RECONNECT_ADDR_UUID:
  743. // Validate the value - writable by a bonded device
  744. #if ( HOST_CONFIG & PERIPHERAL_CFG )
  745. #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT)
  746. if ( periPrivacyFlag == GAP_PRIVACY_DISABLED )
  747. {
  748. status = ATT_ERR_WRITE_NOT_PERMITTED;
  749. }
  750. else
  751. #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT
  752. #endif // PERIPHERAL_CFG
  753. if ( offset == 0 )
  754. {
  755. if ( len != B_ADDR_LEN )
  756. {
  757. status = ATT_ERR_INVALID_VALUE_SIZE;
  758. }
  759. }
  760. else
  761. {
  762. status = ATT_ERR_ATTR_NOT_LONG;
  763. }
  764. // Write the value
  765. if ( status == SUCCESS )
  766. {
  767. VOID osal_memcpy( pAttr->pValue, pValue, B_ADDR_LEN );
  768. }
  769. break;
  770. case PERI_PRIVACY_FLAG_UUID:
  771. // Validate the value - writable by a bonded device
  772. #if ( HOST_CONFIG & PERIPHERAL_CFG )
  773. #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT)
  774. if ( (periPrivacyFlagCharProps & GATT_PROP_WRITE) == 0 )
  775. {
  776. status = ATT_ERR_WRITE_NOT_PERMITTED;
  777. }
  778. else
  779. #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT
  780. #endif // PERIPHERAL_CFG
  781. if ( offset == 0 )
  782. {
  783. if ( len == 1 )
  784. {
  785. // Validate characteristic configuration bit field
  786. if ( ( *pValue != GAP_PRIVACY_DISABLED ) &&
  787. ( *pValue != GAP_PRIVACY_ENABLED ) )
  788. {
  789. status = ATT_ERR_INVALID_VALUE;
  790. }
  791. }
  792. else
  793. {
  794. status = ATT_ERR_INVALID_VALUE_SIZE;
  795. }
  796. }
  797. else
  798. {
  799. status = ATT_ERR_ATTR_NOT_LONG;
  800. }
  801. // Write the value
  802. if ( status == SUCCESS )
  803. {
  804. *pAttr->pValue = *pValue;
  805. }
  806. break;
  807. default:
  808. // Should never get here!
  809. status = ATT_ERR_INVALID_HANDLE;
  810. }
  811. }
  812. else
  813. {
  814. // 128-bit UUID
  815. status = ATT_ERR_INVALID_HANDLE;
  816. }
  817. return ( status );
  818. }
  819. /*********************************************************************
  820. *********************************************************************/