Squashed 'bluetooth/ble/' content from commit 2f55eed

git-subtree-dir: bluetooth/ble
git-subtree-split: 2f55eed1fdde06fdabfb66d41ce6cd14e280978f
Vincent Coubard 2016-06-08 22:55:08 +01:00
commit fe28524ee8
55 changed files with 16138 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Ignore the generated Doxygen output
apidoc/

393
CHANGELOG.md Normal file
View File

@ -0,0 +1,393 @@
# Change Log
## [v2.5.2](https://github.com/ARMmbed/ble/tree/v2.5.2) (2016-03-02)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.5.1...v2.5.2)
**Closed issues:**
- Infinite busy [\#69](https://github.com/ARMmbed/ble/issues/69)
## [v2.5.1](https://github.com/ARMmbed/ble/tree/v2.5.1) (2016-01-27)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.5.0...v2.5.1)
**Closed issues:**
- Gap state is not updated when the advertising stop after the timeout [\#80](https://github.com/ARMmbed/ble/issues/80)
- crash on memory allocation [\#26](https://github.com/ARMmbed/ble/issues/26)
**Merged pull requests:**
- Change onShutdown\(obj, func\) definition [\#174](https://github.com/ARMmbed/ble/pull/174) ([andresag01](https://github.com/andresag01))
- Invalid adv payloads are not committed before checking [\#171](https://github.com/ARMmbed/ble/pull/171) ([andresag01](https://github.com/andresag01))
- Update Gap state in startAdvertising\(\) [\#170](https://github.com/ARMmbed/ble/pull/170) ([andresag01](https://github.com/andresag01))
- Improve doxygen documentation: [\#169](https://github.com/ARMmbed/ble/pull/169) ([pan-](https://github.com/pan-))
- Update Gap state after advertising times out [\#168](https://github.com/ARMmbed/ble/pull/168) ([andresag01](https://github.com/andresag01))
- merge version 2.5.0 into master [\#163](https://github.com/ARMmbed/ble/pull/163) ([pan-](https://github.com/pan-))
- Fix doxygen warnings for BLE API [\#162](https://github.com/ARMmbed/ble/pull/162) ([andresag01](https://github.com/andresag01))
## [v2.5.0](https://github.com/ARMmbed/ble/tree/v2.5.0) (2016-01-12)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.4.0...v2.5.0)
**Merged pull requests:**
- merge branch develop \(v2.4.0\) [\#161](https://github.com/ARMmbed/ble/pull/161) ([pan-](https://github.com/pan-))
- Add API to get addresses of peers in bond table [\#160](https://github.com/ARMmbed/ble/pull/160) ([andresag01](https://github.com/andresag01))
## [v2.4.0](https://github.com/ARMmbed/ble/tree/v2.4.0) (2016-01-07)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.3.0...v2.4.0)
**Merged pull requests:**
- Whitelisting experimental API [\#159](https://github.com/ARMmbed/ble/pull/159) ([andresag01](https://github.com/andresag01))
## [v2.3.0](https://github.com/ARMmbed/ble/tree/v2.3.0) (2015-12-23)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.2.3...v2.3.0)
**Merged pull requests:**
- Characteristic descriptor discovery [\#105](https://github.com/ARMmbed/ble/pull/105) ([pan-](https://github.com/pan-))
## [v2.2.3](https://github.com/ARMmbed/ble/tree/v2.2.3) (2015-12-23)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.2.2...v2.2.3)
**Closed issues:**
- Two different enum list of BLE appearances [\#136](https://github.com/ARMmbed/ble/issues/136)
- Gap::updateAdvertisingPayload should work for different length of data [\#84](https://github.com/ARMmbed/ble/issues/84)
**Merged pull requests:**
- Hotfix for backward compatibility [\#158](https://github.com/ARMmbed/ble/pull/158) ([LiyouZhou](https://github.com/LiyouZhou))
- Clean up code in DiscoveredCharacteristic.cpp [\#154](https://github.com/ARMmbed/ble/pull/154) ([andresag01](https://github.com/andresag01))
- Modify functions that manipulate adv payload [\#153](https://github.com/ARMmbed/ble/pull/153) ([andresag01](https://github.com/andresag01))
## [v2.2.2](https://github.com/ARMmbed/ble/tree/v2.2.2) (2015-12-21)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.2.1...v2.2.2)
**Merged pull requests:**
- Add BLE\_ERROR\_INTERNAL\_STACK\_FAILURE error code [\#155](https://github.com/ARMmbed/ble/pull/155) ([andresag01](https://github.com/andresag01))
## [v2.2.1](https://github.com/ARMmbed/ble/tree/v2.2.1) (2015-12-18)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.2.0...v2.2.1)
**Merged pull requests:**
- Remove deprecated appearance enum from blecommon.h [\#150](https://github.com/ARMmbed/ble/pull/150) ([andresag01](https://github.com/andresag01))
## [v2.2.0](https://github.com/ARMmbed/ble/tree/v2.2.0) (2015-12-17)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.16...v2.2.0)
**Merged pull requests:**
- Add onShutdown to register callbacks [\#146](https://github.com/ARMmbed/ble/pull/146) ([andresag01](https://github.com/andresag01))
- transparenly support existing applications which may have used Gap::ADDR\_TYPE\_\* [\#145](https://github.com/ARMmbed/ble/pull/145) ([rgrover](https://github.com/rgrover))
## [v2.1.16](https://github.com/ARMmbed/ble/tree/v2.1.16) (2015-12-16)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.15...v2.1.16)
**Merged pull requests:**
- Improve API to facilitate full shutdown procedure [\#141](https://github.com/ARMmbed/ble/pull/141) ([andresag01](https://github.com/andresag01))
## [v2.1.15](https://github.com/ARMmbed/ble/tree/v2.1.15) (2015-12-15)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.14...v2.1.15)
**Merged pull requests:**
- Extract Adress related types from Gap.h into BLEProtocol.h [\#142](https://github.com/ARMmbed/ble/pull/142) ([rgrover](https://github.com/rgrover))
## [v2.1.14](https://github.com/ARMmbed/ble/tree/v2.1.14) (2015-12-11)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.13...v2.1.14)
## [v2.1.13](https://github.com/ARMmbed/ble/tree/v2.1.13) (2015-12-11)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.11...v2.1.13)
**Merged pull requests:**
- Added SecurityManager::setLinkSecurity call for elevating security settings on a particular connection. [\#140](https://github.com/ARMmbed/ble/pull/140) ([marcuschangarm](https://github.com/marcuschangarm))
## [v2.1.11](https://github.com/ARMmbed/ble/tree/v2.1.11) (2015-12-10)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.10...v2.1.11)
## [v2.1.10](https://github.com/ARMmbed/ble/tree/v2.1.10) (2015-12-07)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.9...v2.1.10)
**Merged pull requests:**
- WIP: UUID endian change [\#128](https://github.com/ARMmbed/ble/pull/128) ([marcuschangarm](https://github.com/marcuschangarm))
## [v2.1.9](https://github.com/ARMmbed/ble/tree/v2.1.9) (2015-12-04)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.8...v2.1.9)
**Merged pull requests:**
- Fix documentation for advertising interval getters [\#134](https://github.com/ARMmbed/ble/pull/134) ([andresag01](https://github.com/andresag01))
- I change the service description [\#132](https://github.com/ARMmbed/ble/pull/132) ([iriark01](https://github.com/iriark01))
- Add a doxyfile that warns for undocumented elements [\#131](https://github.com/ARMmbed/ble/pull/131) ([bremoran](https://github.com/bremoran))
## [v2.1.8](https://github.com/ARMmbed/ble/tree/v2.1.8) (2015-12-03)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.7...v2.1.8)
**Merged pull requests:**
- Edit [\#130](https://github.com/ARMmbed/ble/pull/130) ([iriark01](https://github.com/iriark01))
- Edit [\#129](https://github.com/ARMmbed/ble/pull/129) ([iriark01](https://github.com/iriark01))
## [v2.1.7](https://github.com/ARMmbed/ble/tree/v2.1.7) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.6...v2.1.7)
## [v2.1.6](https://github.com/ARMmbed/ble/tree/v2.1.6) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.5...v2.1.6)
**Closed issues:**
- Terrible handling of initLen / minLen and variable length characteristics. [\#93](https://github.com/ARMmbed/ble/issues/93)
**Merged pull requests:**
- Allow GattAttributes to have variable length [\#127](https://github.com/ARMmbed/ble/pull/127) ([andresag01](https://github.com/andresag01))
## [v2.1.5](https://github.com/ARMmbed/ble/tree/v2.1.5) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.4...v2.1.5)
**Merged pull requests:**
- Edit [\#126](https://github.com/ARMmbed/ble/pull/126) ([iriark01](https://github.com/iriark01))
- Edit [\#125](https://github.com/ARMmbed/ble/pull/125) ([iriark01](https://github.com/iriark01))
- Edit [\#124](https://github.com/ARMmbed/ble/pull/124) ([iriark01](https://github.com/iriark01))
- Edit [\#123](https://github.com/ARMmbed/ble/pull/123) ([iriark01](https://github.com/iriark01))
- Separate the concept of minlen and len in GattAttr [\#122](https://github.com/ARMmbed/ble/pull/122) ([andresag01](https://github.com/andresag01))
- Doxygen fixes [\#120](https://github.com/ARMmbed/ble/pull/120) ([metc](https://github.com/metc))
- Minor edits [\#114](https://github.com/ARMmbed/ble/pull/114) ([iriark01](https://github.com/iriark01))
## [v2.1.4](https://github.com/ARMmbed/ble/tree/v2.1.4) (2015-11-26)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.3...v2.1.4)
**Merged pull requests:**
- Guard nordic specific implementation with \#ifdef TARGET\_NRF51822 [\#119](https://github.com/ARMmbed/ble/pull/119) ([LiyouZhou](https://github.com/LiyouZhou))
## [v2.1.3](https://github.com/ARMmbed/ble/tree/v2.1.3) (2015-11-26)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.2...v2.1.3)
**Merged pull requests:**
- Call bootloader\_start implicitly trough a event handler call [\#118](https://github.com/ARMmbed/ble/pull/118) ([LiyouZhou](https://github.com/LiyouZhou))
## [v2.1.2](https://github.com/ARMmbed/ble/tree/v2.1.2) (2015-11-26)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.1...v2.1.2)
**Merged pull requests:**
- Reintroduce old Eddystone with deprecated warnings [\#117](https://github.com/ARMmbed/ble/pull/117) ([andresag01](https://github.com/andresag01))
## [v2.1.1](https://github.com/ARMmbed/ble/tree/v2.1.1) (2015-11-26)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.1.0...v2.1.1)
## [v2.1.0](https://github.com/ARMmbed/ble/tree/v2.1.0) (2015-11-26)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.0.5...v2.1.0)
**Closed issues:**
- All BLE event handling should happen in thread mode [\#89](https://github.com/ARMmbed/ble/issues/89)
**Merged pull requests:**
- First Doxygen output [\#116](https://github.com/ARMmbed/ble/pull/116) ([metc](https://github.com/metc))
- Minor doc changes [\#113](https://github.com/ARMmbed/ble/pull/113) ([metc](https://github.com/metc))
- Minor edits [\#112](https://github.com/ARMmbed/ble/pull/112) ([iriark01](https://github.com/iriark01))
- Minor edits [\#111](https://github.com/ARMmbed/ble/pull/111) ([iriark01](https://github.com/iriark01))
- Minor edits [\#110](https://github.com/ARMmbed/ble/pull/110) ([iriark01](https://github.com/iriark01))
- Remove persistant callbacks [\#109](https://github.com/ARMmbed/ble/pull/109) ([pan-](https://github.com/pan-))
- Changed GapAdvertisingData.addData to take current fields into account when adding data. [\#108](https://github.com/ARMmbed/ble/pull/108) ([marcuschangarm](https://github.com/marcuschangarm))
- Remove Eddystone implementation in ble/services [\#107](https://github.com/ARMmbed/ble/pull/107) ([andresag01](https://github.com/andresag01))
## [v2.0.5](https://github.com/ARMmbed/ble/tree/v2.0.5) (2015-11-16)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.0.4...v2.0.5)
**Merged pull requests:**
- Edits - with a couple of comments [\#104](https://github.com/ARMmbed/ble/pull/104) ([iriark01](https://github.com/iriark01))
## [v2.0.4](https://github.com/ARMmbed/ble/tree/v2.0.4) (2015-11-13)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.0.3...v2.0.4)
**Merged pull requests:**
- Edits [\#102](https://github.com/ARMmbed/ble/pull/102) ([iriark01](https://github.com/iriark01))
## [v2.0.3](https://github.com/ARMmbed/ble/tree/v2.0.3) (2015-11-03)
[Full Changelog](https://github.com/ARMmbed/ble/compare/mbedos-release-15-11...v2.0.3)
## [mbedos-release-15-11](https://github.com/ARMmbed/ble/tree/mbedos-release-15-11) (2015-11-03)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.0.2...mbedos-release-15-11)
## [v2.0.2](https://github.com/ARMmbed/ble/tree/v2.0.2) (2015-11-03)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.0.1...v2.0.2)
**Merged pull requests:**
- BLE::init\(\) should also be able to take an \<object, member\> tuple for its callback [\#97](https://github.com/ARMmbed/ble/pull/97) ([rgrover](https://github.com/rgrover))
## [v2.0.1](https://github.com/ARMmbed/ble/tree/v2.0.1) (2015-11-02)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v2.0.0...v2.0.1)
**Merged pull requests:**
- Fix beaconPeriod and defaults for voltage/temp [\#94](https://github.com/ARMmbed/ble/pull/94) ([andresag01](https://github.com/andresag01))
## [v2.0.0](https://github.com/ARMmbed/ble/tree/v2.0.0) (2015-11-02)
[Full Changelog](https://github.com/ARMmbed/ble/compare/mbedos-techcon-oob2...v2.0.0)
**Closed issues:**
- BLE::init\(\) should be non-blocking [\#90](https://github.com/ARMmbed/ble/issues/90)
- Wrong include file in HealthTermometerService.h:20:17 [\#86](https://github.com/ARMmbed/ble/issues/86)
- Return error on write request when locked [\#19](https://github.com/ARMmbed/ble/issues/19)
**Merged pull requests:**
- Introduced fixes to Eddystone implementation [\#92](https://github.com/ARMmbed/ble/pull/92) ([andresag01](https://github.com/andresag01))
- BLE::init\(\) now takes in a callback paramter [\#91](https://github.com/ARMmbed/ble/pull/91) ([rgrover](https://github.com/rgrover))
- Fixed include problem in HealthThermometer header [\#87](https://github.com/ARMmbed/ble/pull/87) ([andresag01](https://github.com/andresag01))
- use the github url public url in module.json [\#82](https://github.com/ARMmbed/ble/pull/82) ([jrobeson](https://github.com/jrobeson))
- Reduce the memory consumed by FunctionPointerWithContext instances [\#81](https://github.com/ARMmbed/ble/pull/81) ([pan-](https://github.com/pan-))
- Introduced fix for defect IOTSFW-1058 [\#79](https://github.com/ARMmbed/ble/pull/79) ([andresag01](https://github.com/andresag01))
## [mbedos-techcon-oob2](https://github.com/ARMmbed/ble/tree/mbedos-techcon-oob2) (2015-10-19)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v1.0.0...mbedos-techcon-oob2)
## [v1.0.0](https://github.com/ARMmbed/ble/tree/v1.0.0) (2015-10-19)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v0.4.8...v1.0.0)
**Closed issues:**
- add support for Eddystone [\#57](https://github.com/ARMmbed/ble/issues/57)
**Merged pull requests:**
- Add st-ble-shield as a possible target dependency. [\#76](https://github.com/ARMmbed/ble/pull/76) ([pan-](https://github.com/pan-))
- Support for Environmental Service \(temperature, pressure and humidity\) [\#75](https://github.com/ARMmbed/ble/pull/75) ([crespum](https://github.com/crespum))
## [v0.4.8](https://github.com/ARMmbed/ble/tree/v0.4.8) (2015-09-29)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v0.4.7...v0.4.8)
**Closed issues:**
- ERROR: undefined reference to `createBLEInstance\(\)' [\#68](https://github.com/ARMmbed/ble/issues/68)
**Merged pull requests:**
- Adding Eddystone Support [\#74](https://github.com/ARMmbed/ble/pull/74) ([BlackstoneEngineering](https://github.com/BlackstoneEngineering))
- Changed onConnection and onDisconnection to accept object/methods and… [\#72](https://github.com/ARMmbed/ble/pull/72) ([marcuschangarm](https://github.com/marcuschangarm))
- adding an initial prototype for a yotta-config based initialization f… [\#71](https://github.com/ARMmbed/ble/pull/71) ([rgrover](https://github.com/rgrover))
- Gap.h - Added onConnection callback chain simarly to the currently pr… [\#70](https://github.com/ARMmbed/ble/pull/70) ([marcuschangarm](https://github.com/marcuschangarm))
## [v0.4.7](https://github.com/ARMmbed/ble/tree/v0.4.7) (2015-08-13)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v0.4.6...v0.4.7)
## [v0.4.6](https://github.com/ARMmbed/ble/tree/v0.4.6) (2015-08-11)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v0.4.5...v0.4.6)
**Merged pull requests:**
- Eddystone Service Working [\#66](https://github.com/ARMmbed/ble/pull/66) ([BlackstoneEngineering](https://github.com/BlackstoneEngineering))
## [v0.4.5](https://github.com/ARMmbed/ble/tree/v0.4.5) (2015-08-10)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v0.4.4...v0.4.5)
## [v0.4.4](https://github.com/ARMmbed/ble/tree/v0.4.4) (2015-08-07)
[Full Changelog](https://github.com/ARMmbed/ble/compare/v0.4.3...v0.4.4)
**Closed issues:**
- GapAdvertisingData::getPayload\(\) should not return NULL if payloadLen == 0 [\#64](https://github.com/ARMmbed/ble/issues/64)
- enableActiveScanning\(\) [\#60](https://github.com/ARMmbed/ble/issues/60)
- add central role for s130 [\#58](https://github.com/ARMmbed/ble/issues/58)
- Clash With Definition and Enum Naming [\#46](https://github.com/ARMmbed/ble/issues/46)
- URIBeacon2Service Needs initial AdvertisedTxPowerLevels [\#17](https://github.com/ARMmbed/ble/issues/17)
**Merged pull requests:**
- Conversion from advertisement duration units to ms moved from Gap to … [\#63](https://github.com/ARMmbed/ble/pull/63) ([jslater8](https://github.com/jslater8))
- Add a new function updateAdvertisingPayload\(\) [\#61](https://github.com/ARMmbed/ble/pull/61) ([sunsmilearm](https://github.com/sunsmilearm))
- minor corrections to the comments [\#59](https://github.com/ARMmbed/ble/pull/59) ([ddavidebor](https://github.com/ddavidebor))
## [v0.4.3](https://github.com/ARMmbed/ble/tree/v0.4.3) (2015-07-22)
[Full Changelog](https://github.com/ARMmbed/ble/compare/0.4.1...v0.4.3)
**Closed issues:**
- add GattClient::onHVX [\#53](https://github.com/ARMmbed/ble/issues/53)
- Need some help regarding the development of BLE network simulator [\#52](https://github.com/ARMmbed/ble/issues/52)
**Merged pull requests:**
- expose descriptors optional arg in derived GattChar. constructors [\#56](https://github.com/ARMmbed/ble/pull/56) ([OJFord](https://github.com/OJFord))
- Change DiscoveredCharacteristic API to return long or short UUIDs. [\#55](https://github.com/ARMmbed/ble/pull/55) ([adfernandes](https://github.com/adfernandes))
- Refactor using new include paths [\#51](https://github.com/ARMmbed/ble/pull/51) ([rosterloh](https://github.com/rosterloh))
- Revert "use mbed-classic as mbed dependency" [\#50](https://github.com/ARMmbed/ble/pull/50) ([rgrover](https://github.com/rgrover))
- use mbed-classic as mbed dependency [\#45](https://github.com/ARMmbed/ble/pull/45) ([autopulated](https://github.com/autopulated))
## [0.4.1](https://github.com/ARMmbed/ble/tree/0.4.1) (2015-07-02)
[Full Changelog](https://github.com/ARMmbed/ble/compare/workingOldBootloader...0.4.1)
**Closed issues:**
- DiscoveredCharacteristic::setupOnDataRead\(\) should be GattClient::onDataRead\(\) instead [\#49](https://github.com/ARMmbed/ble/issues/49)
- CONNECTION\_TIMEOUT should be added to DisconnectionReason\_t [\#43](https://github.com/ARMmbed/ble/issues/43)
- Typo in definition of UNIT\_0\_625\_MS in Gap.h [\#40](https://github.com/ARMmbed/ble/issues/40)
- Initial value for \_requiredSecurity member of GattCharacteristic class breaks existing code [\#39](https://github.com/ARMmbed/ble/issues/39)
- Allow adding a User Description descriptor to a GattCharacteristic. [\#38](https://github.com/ARMmbed/ble/issues/38)
- The example code in GattAttribute.h does not refer to GattAttribute [\#37](https://github.com/ARMmbed/ble/issues/37)
- BLEDevice::clearAdvertisingPayload doesn't clear the scan response PDU [\#36](https://github.com/ARMmbed/ble/issues/36)
**Merged pull requests:**
- Added get/set methods for advertisement payload and parameters. [\#42](https://github.com/ARMmbed/ble/pull/42) ([marcuschangarm](https://github.com/marcuschangarm))
## [workingOldBootloader](https://github.com/ARMmbed/ble/tree/workingOldBootloader) (2015-03-02)
**Implemented enhancements:**
- Which are the allowed values for txPower? \> BLEDevice::setTxPower\(int8\_t txPower\) [\#30](https://github.com/ARMmbed/ble/issues/30)
- Modes: UriBeacon and UriBeaconConfig [\#15](https://github.com/ARMmbed/ble/issues/15)
- URIBeacon2Service.h should be called UriBeaconConfigService.h [\#11](https://github.com/ARMmbed/ble/issues/11)
- Lock and Unlock missing from URIBeacon2Service.h [\#10](https://github.com/ARMmbed/ble/issues/10)
- Service Characteristics [\#9](https://github.com/ARMmbed/ble/issues/9)
- URIBeacon2Service.h missing TX Power Mode [\#8](https://github.com/ARMmbed/ble/issues/8)
**Fixed bugs:**
- URIBeacon2Service configure\(\) [\#14](https://github.com/ARMmbed/ble/issues/14)
- URIBeacon2Service.h does not reset to defaults [\#7](https://github.com/ARMmbed/ble/issues/7)
- Uri Data Length and semantics [\#6](https://github.com/ARMmbed/ble/issues/6)
**Closed issues:**
- Inconsistent use of uint\_16\_t and Handle\_t [\#34](https://github.com/ARMmbed/ble/issues/34)
- Incorrect documentation on void setAdvertisingType\(\)? [\#29](https://github.com/ARMmbed/ble/issues/29)
- URIBeacon2Service setTxPowerLevel should follow specification [\#16](https://github.com/ARMmbed/ble/issues/16)
- URIBeacon2Service does not advertise UriBeacon [\#13](https://github.com/ARMmbed/ble/issues/13)
- Roadmap [\#3](https://github.com/ARMmbed/ble/issues/3)
- nRF51822 advertising interval problem [\#2](https://github.com/ARMmbed/ble/issues/2)
- nRF51822 low-power operation [\#1](https://github.com/ARMmbed/ble/issues/1)
**Merged pull requests:**
- Added callback on characteristic reads [\#33](https://github.com/ARMmbed/ble/pull/33) ([jeremybrodt](https://github.com/jeremybrodt))
- Updated UUID class to get length and pointer. Added UUID comparison. [\#32](https://github.com/ARMmbed/ble/pull/32) ([jeremybrodt](https://github.com/jeremybrodt))
- Extended attribute length handling to support dynamic length. [\#31](https://github.com/ARMmbed/ble/pull/31) ([jeremybrodt](https://github.com/jeremybrodt))
- added API for creating iBeacons [\#28](https://github.com/ARMmbed/ble/pull/28) ([BlackstoneEngineering](https://github.com/BlackstoneEngineering))
- Uribeacon update [\#25](https://github.com/ARMmbed/ble/pull/25) ([schilit](https://github.com/schilit))
- Fix README links [\#23](https://github.com/ARMmbed/ble/pull/23) ([shirishb](https://github.com/shirishb))
- Added optional data and length fields to the return struct for authorize... [\#22](https://github.com/ARMmbed/ble/pull/22) ([marcuschangarm](https://github.com/marcuschangarm))
- Chained callbacks for onDataSent [\#21](https://github.com/ARMmbed/ble/pull/21) ([marcuschangarm](https://github.com/marcuschangarm))
- Updated Readme [\#20](https://github.com/ARMmbed/ble/pull/20) ([BlackstoneEngineering](https://github.com/BlackstoneEngineering))
- Add getHandle for readability [\#18](https://github.com/ARMmbed/ble/pull/18) ([schilit](https://github.com/schilit))
- make the library less dependent on the mbed.h header [\#5](https://github.com/ARMmbed/ble/pull/5) ([xiongyihui](https://github.com/xiongyihui))
- adding initial readme with references to developer.mbed.org [\#4](https://github.com/ARMmbed/ble/pull/4) ([BlackstoneEngineering](https://github.com/BlackstoneEngineering))
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

7
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,7 @@
# Hello!
We are an open source project of [ARM mbed](https://www.mbed.com). Contributions via [pull request](https://github.com/ARMmbed/ble/pulls), and [bug reports](https://github.com/ARMmbed/ble/issues) are welcome!
Please submit your pull request to the `develop` branch of [this module](https://github.com/ARMmbed/ble/tree/develop). Commits to develop will be merge into the master branch at the time of the next release.
# Contributor agreement
For your pull request to be accepted, we will need you to agree to our [contributor agreement](https://developer.mbed.org/contributor_agreement/) to give us the necessary rights to use and distribute your contributions. (To click through the agreement create an account on mbed.com and log in.)

30
DOXYGEN_FRONTPAGE.md Normal file
View File

@ -0,0 +1,30 @@
# BLE API {#mainpage}
The BLE module within mbed OS offers a high abstraction level for using
Bluetooth Low Energy on multiple platforms.
This documentation describes the internal structure of the mbed
[BLE API](https://github.com/armmbed/ble).
For getting started with BLE on mbed, check our [introduction
page](https://docs.mbed.com/docs/ble-intros/en/latest/).
For mbed OS examples using BLE, check [this
repository](https://github.com/armmbed/ble-examples). For mbed-classic
examples, please refer to [code under mbed.org](https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/).
## Supported Services
Currently supported reference services include:
* [Battery](@ref BatteryService)
* [Device Firmware Update (DFU)](@ref DFUService)
* [Device Information](@ref DeviceInformationService)
* [Health Thermometer](@ref HealthThermometerService)
* [Heart Rate](@ref HeartRateService)
* [UART](@ref UARTService)
* [UriBeacon](@ref URIBeaconConfigService)
* [iBeacon](@ref iBeacon)
The [documentation](https://docs.mbed.com/docs/ble-intros/en/latest/AdvSamples/Overview/)
contains an overview on how to create new, application-specific services.

2
LICENSE Normal file
View File

@ -0,0 +1,2 @@
Unless specifically indicated otherwise in a file, files are licensed
under the Apache 2.0 license, as can be found in: apache-2.0.txt

28
README.md Normal file
View File

@ -0,0 +1,28 @@
# mbed Bluetooth Low Energy Stack
This is the Github repo for the `BLE_API` used by developer.mbed.org. Please see the [mbed BLE Homepage](https://developer.mbed.org/teams/Bluetooth-Low-Energy/) for all documentation, code examples and general help.
# Supported Services
Supported GATT services and constantly being added and can be found in the [ble/services/](https://github.com/ARMmbed/ble/tree/master/ble/services) folder.
Currently supported services include:
* Battery
* Device Firmware Update (DFU)
* Device Information
* Eddystone Configuration Service
* Health Thermometer
* Heart Rate
* Link Loss
* UART
* UriBeacon
* iBeacon
The [documentation](https://docs.mbed.com/docs/ble-intros/en/latest/AdvSamples/Overview/)
contains an overview on how to create new, application-specific services.
# Getting Started
The mbed BLE API is meant to be used in projects on developer.mbed.org. Please see examples and sample project files there.
A good starting point are these pages:
* [mbed BLE Homepage](https://developer.mbed.org/teams/Bluetooth-Low-Energy/) for all things BLE
* [mbed BLE Getting Started Guide](https://developer.mbed.org/forum/team-63-Bluetooth-Low-Energy-community/topic/5262/) a wonderful primer on using BLE with mbed
* [mbed BLE doc](https://docs.mbed.com/docs/ble-intros/en/latest/) for an introduction to mbed BLE
* [mbed BLE API page](https://docs.mbed.com/docs/ble-api/en/latest/api/index.html) for the Doxygen API documentation

13
apache-2.0.txt Normal file
View File

@ -0,0 +1,13 @@
Copyright (c) 2015 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

2418
ble.doxyfile Normal file

File diff suppressed because it is too large Load Diff

1569
ble/BLE.h Normal file

File diff suppressed because it is too large Load Diff

176
ble/BLEInstanceBase.h Normal file
View File

@ -0,0 +1,176 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_DEVICE_INSTANCE_BASE__
#define __BLE_DEVICE_INSTANCE_BASE__
#include "Gap.h"
#include "ble/SecurityManager.h"
#include "ble/BLE.h"
/* Forward declarations. */
class GattServer;
class GattClient;
/**
* The interface for the transport object to be created by the target library's
* createBLEInstance().
*
* @note This class is part of the interface of BLE API with the implementation;
* therefore, it is meant to be used only by porters rather than normal
* BLE API users.
*/
class BLEInstanceBase
{
public:
BLEInstanceBase() {}
/**
* Virtual destructor of the interface.
*/
virtual ~BLEInstanceBase();
/**
* Initialize the underlying BLE stack. This should be called before
* anything else in the BLE API.
*
* @param[in] instanceID
* The ID of the instance to initialize.
* @param[in] initCallback
* A callback for when initialization completes for a BLE
* instance. This is an optional parameter set to NULL when not
* supplied.
*
* @return BLE_ERROR_NONE if the initialization procedure was started
* successfully.
*/
virtual ble_error_t init(BLE::InstanceID_t instanceID,
FunctionPointerWithContext<BLE::InitializationCompleteCallbackContext *> initCallback) = 0;
/**
* Check whether the underlying stack has already been initialized,
* possible with a call to init().
*
* @return true if the initialization has completed for the underlying BLE
* stack.
*/
virtual bool hasInitialized(void) const = 0;
/**
* Shutdown the underlying BLE stack. This includes purging the stack of
* GATT and GAP state and clearing all state from other BLE components
* such as the SecurityManager. init() must be called afterwards to
* re-instantiate services and GAP state.
*
* @return BLE_ERROR_NONE if the underlying stack and all other services of
* the BLE API were shutdown correctly.
*/
virtual ble_error_t shutdown(void) = 0;
/**
* Fetches a string representation of the underlying BLE stack's version.
*
* @return A pointer to the string representation of the underlying
* BLE stack's version.
*/
virtual const char * getVersion(void) = 0;
/**
* Accessor to Gap. This function is used by BLE::gap().
*
* @return A reference to a Gap object associated to this BLE instance.
*/
virtual Gap& getGap() = 0;
/**
* A const alternative to getGap().
*
* @return A const reference to a Gap object associated to this BLE instance.
*/
virtual const Gap& getGap() const = 0;
/**
* Accessor to GattServer. This function is used by BLE::gattServer().
*
* @return A reference to a GattServer object associated to this BLE instance.
*/
virtual GattServer& getGattServer() = 0;
/**
* A const alternative to getGattServer().
*
* @return A const reference to a GattServer object associated to this BLE instance.
*/
virtual const GattServer& getGattServer() const = 0;
/**
* Accessors to GattClient. This function is used by BLE::gattClient().
*
* @return A reference to a GattClient object associated to this BLE instance.
*/
virtual GattClient& getGattClient() = 0;
/**
* Accessors to SecurityManager. This function is used by BLE::securityManager().
*
* @return A reference to a SecurityManager object associated to this BLE instance.
*/
virtual SecurityManager& getSecurityManager() = 0;
/**
* A const alternative to getSecurityManager().
*
* @return A const reference to a SecurityManager object associated to this BLE instance.
*/
virtual const SecurityManager& getSecurityManager() const = 0;
/**
* Yield control to the BLE stack or to other tasks waiting for events.
* refer to BLE::waitForEvent().
*/
virtual void waitForEvent(void) = 0;
/**
* Process ALL pending events living in the BLE stack .
* Return once all events have been consumed.
*/
virtual void processEvents() = 0;
/**
* This function allow the BLE stack to signal that their is work to do and
* event processing should be done (BLE::processEvent()).
* @param id: The ID of the BLE instance which does have events to process.
*/
void signalEventsToProcess(BLE::InstanceID_t id);
private:
// this class is not a value type.
// prohibit copy construction and copy assignement
BLEInstanceBase(const BLEInstanceBase&);
BLEInstanceBase& operator=(const BLEInstanceBase&);
};
/**
* BLE uses composition to hide an interface object encapsulating the
* backend transport.
*
* The following API is used to create the singleton interface object. An
* implementation for this function must be provided by the device-specific
* library, otherwise there will be a linker error.
*/
extern BLEInstanceBase *createBLEInstance(void);
#endif // ifndef __BLE_DEVICE_INSTANCE_BASE__

80
ble/BLEProtocol.h Normal file
View File

@ -0,0 +1,80 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_PROTOCOL_H__
#define __BLE_PROTOCOL_H__
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
/**
* A common namespace for types and constants used everywhere in BLE API.
*/
namespace BLEProtocol {
/**<
* A simple container for the enumeration of address-types for Protocol addresses.
*
* Adding a struct to encapsulate the contained enumeration prevents
* polluting the BLEProtocol namespace with the enumerated values. It also
* allows type-aliases for the enumeration while retaining the enumerated
* values. i.e. doing:
* typedef AddressType AliasedType;
*
* would allow the use of AliasedType::PUBLIC in code.
*/
struct AddressType {
/**< Address-types for Protocol addresses. */
enum Type {
PUBLIC = 0,
RANDOM_STATIC,
RANDOM_PRIVATE_RESOLVABLE,
RANDOM_PRIVATE_NON_RESOLVABLE
};
};
typedef AddressType::Type AddressType_t; /**< Alias for AddressType::Type */
static const size_t ADDR_LEN = 6; /**< Length (in octets) of the BLE MAC address. */
typedef uint8_t AddressBytes_t[ADDR_LEN]; /**< 48-bit address, in LSB format. */
/**
* BLE address. It contains an address-type (AddressType_t) and bytes (AddressBytes_t).
*/
struct Address_t {
AddressType_t type; /**< The type of the BLE address. */
AddressBytes_t address; /**< The BLE address. */
/**
* Construct an Address_t object with the supplied type and address.
*
* @param[in] typeIn
* The BLE address type.
* @param[in] addressIn
* The BLE address.
*/
Address_t(AddressType_t typeIn, const AddressBytes_t& addressIn) : type(typeIn) {
std::copy(addressIn, addressIn + ADDR_LEN, address);
}
/**
* Empty constructor.
*/
Address_t() : type(), address() {
}
};
};
#endif /* __BLE_PROTOCOL_H__ */

View File

@ -0,0 +1,271 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
#define MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
#include <string.h>
#include "FunctionPointerWithContext.h"
#include "SafeBool.h"
/** Group one or more functions in an instance of a CallChainOfFunctionPointersWithContext, then call them in
* sequence using CallChainOfFunctionPointersWithContext::call(). Used mostly by the interrupt chaining code,
* but can be used for other purposes.
*
* Example:
* @code
*
* CallChainOfFunctionPointersWithContext<void *> chain;
*
* void first(void *context) {
* printf("'first' function.\n");
* }
*
* void second(void *context) {
* printf("'second' function.\n");
* }
*
* class Test {
* public:
* void f(void *context) {
* printf("A::f (class member).\n");
* }
* };
*
* int main() {
* Test test;
*
* chain.add(second);
* chain.add_front(first);
* chain.add(&test, &Test::f);
* chain.call();
* }
* @endcode
*/
template <typename ContextType>
class CallChainOfFunctionPointersWithContext : public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
public:
/**
* The type of each callback in the callchain.
*/
typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
public:
/**
* Create an empty chain.
*/
CallChainOfFunctionPointersWithContext() : chainHead(NULL) {
/* empty */
}
virtual ~CallChainOfFunctionPointersWithContext() {
clear();
}
/**
* Add a function at the front of the chain.
*
* @param[in] function
* A pointer to a void function.
*
* @return The function object created for @p function.
*/
pFunctionPointerWithContext_t add(void (*function)(ContextType context)) {
return common_add(new FunctionPointerWithContext<ContextType>(function));
}
/**
* Add a function at the front of the chain.
*
* @param[in] tptr
* Pointer to the object to call the member function on.
* @param[in] mptr
* Pointer to the member function to be called.
*
* @return The function object created for @p tptr and @p mptr.
*/
template<typename T>
pFunctionPointerWithContext_t add(T *tptr, void (T::*mptr)(ContextType context)) {
return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr));
}
/**
* Add a function at the front of the chain.
*
* @param[in] func
* The FunctionPointerWithContext to add.
*
* @return The function object created for @p func.
*/
pFunctionPointerWithContext_t add(const FunctionPointerWithContext<ContextType>& func) {
return common_add(new FunctionPointerWithContext<ContextType>(func));
}
/**
* Detach a function pointer from a callchain.
*
* @param[in] toDetach
* FunctionPointerWithContext to detach from this callchain.
*
* @return true if a function pointer has been detached and false otherwise.
*
* @note It is safe to remove a function pointer while the chain is
* traversed by call(ContextType).
*/
bool detach(const FunctionPointerWithContext<ContextType>& toDetach) {
pFunctionPointerWithContext_t current = chainHead;
pFunctionPointerWithContext_t previous = NULL;
while (current) {
if(*current == toDetach) {
if(previous == NULL) {
if(currentCalled == current) {
currentCalled = NULL;
}
chainHead = current->getNext();
} else {
if(currentCalled == current) {
currentCalled = previous;
}
previous->chainAsNext(current->getNext());
}
delete current;
return true;
}
previous = current;
current = current->getNext();
}
return false;
}
/**
* Clear the call chain (remove all functions in the chain).
*/
void clear(void) {
pFunctionPointerWithContext_t fptr = chainHead;
while (fptr) {
pFunctionPointerWithContext_t deadPtr = fptr;
fptr = deadPtr->getNext();
delete deadPtr;
}
chainHead = NULL;
}
/**
* Check whether the callchain contains any callbacks.
*
* @return true if the callchain is not empty and false otherwise.
*/
bool hasCallbacksAttached(void) const {
return (chainHead != NULL);
}
/**
* Call all the functions in the chain in sequence.
*/
void call(ContextType context) {
((const CallChainOfFunctionPointersWithContext*) this)->call(context);
}
/**
* Same as call() above, but const.
*/
void call(ContextType context) const {
currentCalled = chainHead;
while(currentCalled) {
currentCalled->call(context);
// if this was the head and the call removed the head
if(currentCalled == NULL) {
currentCalled = chainHead;
} else {
currentCalled = currentCalled->getNext();
}
}
}
/**
* Same as call(), but with function call operator.
* @code
*
* void first(bool);
* void second(bool);
*
* CallChainOfFunctionPointerWithContext<bool> foo;
*
* foo.attach(first);
* foo.attach(second);
*
* // call the callchain like a function
* foo(true);
*
* @endcode
*/
void operator()(ContextType context) const {
call(context);
}
/**
* Bool conversion operation.
*
* @return true if the callchain is not empty and false otherwise.
*/
bool toBool() const {
return chainHead != NULL;
}
private:
/**
* Add a callback to the head of the callchain.
*
* @return A pointer to the head of the callchain.
*/
pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf) {
if (chainHead == NULL) {
chainHead = pf;
} else {
pf->chainAsNext(chainHead);
chainHead = pf;
}
return chainHead;
}
private:
/**
* A pointer to the first callback in the callchain or NULL if the callchain is empty.
*/
pFunctionPointerWithContext_t chainHead;
/**
* Iterator during a function call, this has to be mutable because the call function is const.
*
* @note Mutable is the correct behaviour here, the iterator never leaks outside the object.
* so the object can still be seen as logically const even if it is modified.
*/
mutable pFunctionPointerWithContext_t currentCalled;
/* Disallow copy constructor and assignment operators. */
private:
CallChainOfFunctionPointersWithContext(const CallChainOfFunctionPointersWithContext &);
CallChainOfFunctionPointersWithContext & operator = (const CallChainOfFunctionPointersWithContext &);
};
#endif

View File

@ -0,0 +1,99 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__
#define __CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__
#include "FunctionPointerWithContext.h"
class DiscoveredCharacteristic; // forward declaration
class DiscoveredCharacteristicDescriptor; // forward declaration
/**
* @brief Contain all definitions of callbacks and callbacks parameters types
* related to characteristic descriptor discovery.
*
* @details This class act like a namespace for characteristic descriptor discovery
* types. It act like ServiceDiscovery by providing callbacks and callbacks
* parameters types related to the characteristic descriptor discovery process but
* contrary to ServiceDiscovery class, it does not force the porter to use a
* specific interface for the characteristic descriptor discovery process.
*/
class CharacteristicDescriptorDiscovery {
public:
/**
* @brief Parameter type of CharacteristicDescriptorDiscovery::DiscoveryCallback_t.
* @details Every time a characteristic descriptor has been discovered, the callback
* registered for the discovery operation through GattClient::discoverCharacteristicDescriptors
* or DiscoveredCharacteristic::discoverDescriptors will be called with this parameter.
*
*/
struct DiscoveryCallbackParams_t {
/**
* The characteristic owning the DiscoveredCharacteristicDescriptor
*/
const DiscoveredCharacteristic& characteristic;
/**
* The characteristic descriptor discovered
*/
const DiscoveredCharacteristicDescriptor& descriptor;
};
/**
* @brief Parameter type of CharacteristicDescriptorDiscovery::TerminationCallback_t.
* @details Once a characteristic descriptor discovery process terminate, the termination
* callback registered for the discovery operation through
* GattClient::discoverCharacteristicDescriptors or DiscoveredCharacteristic::discoverDescriptors
* will be called with this parameter.
*/
struct TerminationCallbackParams_t {
/**
* The characteristic for which the descriptors has been discovered
*/
const DiscoveredCharacteristic& characteristic;
/**
* status of the discovery operation
*/
ble_error_t status;
};
/**
* @brief Callback type for when a matching characteristic descriptor is found during
* characteristic descriptor discovery.
*
* @param param A pointer to a DiscoveryCallbackParams_t object which will remain
* valid for the lifetime of the callback. Memory for this object is owned by
* the BLE_API eventing framework. The application can safely make a persistent
* shallow-copy of this object in order to work with the service beyond the
* callback.
*/
typedef FunctionPointerWithContext<const DiscoveryCallbackParams_t*> DiscoveryCallback_t;
/**
* @brief Callback type for when characteristic descriptor discovery terminates.
*
* @param param A pointer to a TerminationCallbackParams_t object which will remain
* valid for the lifetime of the callback. Memory for this object is owned by
* the BLE_API eventing framework. The application can safely make a persistent
* shallow-copy of this object in order to work with the service beyond the
* callback.
*/
typedef FunctionPointerWithContext<const TerminationCallbackParams_t*> TerminationCallback_t;
};
#endif // ifndef __CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__

View File

@ -0,0 +1,433 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DISCOVERED_CHARACTERISTIC_H__
#define __DISCOVERED_CHARACTERISTIC_H__
#include "UUID.h"
#include "Gap.h"
#include "GattAttribute.h"
#include "GattClient.h"
#include "CharacteristicDescriptorDiscovery.h"
#include "ble/DiscoveredCharacteristicDescriptor.h"
/**
* @brief Representation of a characteristic discovered during a GattClient
* discovery procedure (see GattClient::launchServiceDiscovery ).
*
* @details Provide detailed informations about a discovered characteristic like:
* - Its UUID (see getUUID()).
* - The most important handles of the characteristic definition
* (see getDeclHandle(), getValueHandle(), getLastHandle())
* - Its properties (see getProperties()).
* This class also provide functions to operate on the characteristic:
* - Read the characteristic value (see read())
* - Writing a characteristic value (see write() or writeWoResponse())
* - Discover descriptors inside the characteristic definition. These descriptors
* extends the characteristic. More information about descriptor usage is
* available in DiscoveredCharacteristicDescriptor class.
*/
class DiscoveredCharacteristic {
public:
/**
* Structure that encapsulates the properties of a discovered
* characteristic.
*/
struct Properties_t {
uint8_t _broadcast :1; /**< Broadcasting the value permitted. */
uint8_t _read :1; /**< Reading the value permitted. */
uint8_t _writeWoResp :1; /**< Writing the value with Write Command permitted. */
uint8_t _write :1; /**< Writing the value with Write Request permitted. */
uint8_t _notify :1; /**< Notifications of the value permitted. */
uint8_t _indicate :1; /**< Indications of the value permitted. */
uint8_t _authSignedWrite :1; /**< Writing the value with Signed Write Command permitted. */
public:
/**
* @brief Check if broadcasting is permitted.
*
* @return true if broadcasting the value is permitted, and false
* otherwise.
*/
bool broadcast(void) const {
return _broadcast;
}
/**
* @brief Check reading is permitted.
*
* @return true if reading the value is permitted, and false
* otherwise.
*/
bool read(void) const {
return _read;
}
/**
* @brief Check if writing with Write Command is permitted.
*
* @return true if writing the value with Write Command is permitted,
* false otherwise.
*/
bool writeWoResp(void) const {
return _writeWoResp;
}
/**
* @brief Check if writing with Write Request is permitted.
*
* @return true if writing the value with Write Request is permitted,
* false otherwise.
*/
bool write(void) const {
return _write;
}
/**
* @brief Check notifications are permitted.
*
* @return true if notifications of the value are permitted, false
* otherwise.
*/
bool notify(void) const {
return _notify;
}
/**
* @brief Check if indications are permitted.
*
* @return true if indications of the value are permitted, false
* otherwise.
*/
bool indicate(void) const {
return _indicate;
}
/**
* @brief Check if writing with Signed Write Command is permitted.
*
* @return true if writing the value with Signed Write Command is
* permitted, false otherwise.
*/
bool authSignedWrite(void) const {
return _authSignedWrite;
}
/**
* @brief "Equal to" operator for DiscoveredCharacteristic::Properties_t
*
* @param[in] lhs The left hand side of the equality expression
* @param[in] rhs The right hand side of the equality expression
*
* @return true if operands are equals, false otherwise.
*/
friend bool operator==(Properties_t lhs, Properties_t rhs) {
return lhs._broadcast == rhs._broadcast &&
lhs._read == rhs._read &&
lhs._writeWoResp == rhs._writeWoResp &&
lhs._write == rhs._write &&
lhs._notify == rhs._notify &&
lhs._indicate == rhs._indicate &&
lhs._authSignedWrite == rhs._authSignedWrite;
}
/**
* @brief "Not equal to" operator for DiscoveredCharacteristic::Properties_t
*
* @param lhs The right hand side of the expression
* @param rhs The left hand side of the expression
*
* @return true if operands are not equals, false otherwise.
*/
friend bool operator!=(Properties_t lhs, Properties_t rhs) {
return !(lhs == rhs);
}
private:
operator uint8_t() const; /* Disallow implicit conversion into an integer. */
operator unsigned() const; /* Disallow implicit conversion into an integer. */
};
/**
* Initiate (or continue) a read for the value attribute, optionally at a
* given offset. If the characteristic or descriptor to be read is longer
* than ATT_MTU - 1, this function must be called multiple times with
* appropriate offset to read the complete value.
*
* @param[in] offset
* The position - in the characteristic value bytes stream - where
* the read operation begin.
*
* @return BLE_ERROR_NONE if a read has been initiated, or
* BLE_ERROR_INVALID_STATE if some internal state about the connection is invalid, or
* BLE_STACK_BUSY if some client procedure is already in progress, or
* BLE_ERROR_OPERATION_NOT_PERMITTED due to the characteristic's properties.
*/
ble_error_t read(uint16_t offset = 0) const;
/**
* @brief Same as #read(uint16_t) const but allow the user to register a callback
* which will be fired once the read is done.
*
* @param[in] offset
* The position - in the characteristic value bytes stream - where
* the read operation begin.
* @param[in] onRead
* Continuation of the read operation
*/
ble_error_t read(uint16_t offset, const GattClient::ReadCallback_t& onRead) const;
/**
* Perform a write without response procedure.
*
* @param[in] length
* The amount of data being written.
* @param[in] value
* The bytes being written.
*
* @note It is important to note that a write without response will generate
* an onDataSent() callback when the packet has been transmitted. There
* will be a BLE-stack specific limit to the number of pending
* writeWoResponse operations; the user may want to use the onDataSent()
* callback for flow-control.
*
* @retval BLE_ERROR_NONE Successfully started the Write procedure, or
* BLE_ERROR_INVALID_STATE if some internal state about the connection is invalid, or
* BLE_STACK_BUSY if some client procedure is already in progress, or
* BLE_ERROR_NO_MEM if there are no available buffers left to process the request, or
* BLE_ERROR_OPERATION_NOT_PERMITTED due to the characteristic's properties.
*/
ble_error_t writeWoResponse(uint16_t length, const uint8_t *value) const;
/**
* Initiate a GATT Characteristic Descriptor Discovery procedure for descriptors within this characteristic.
*
* @param[in] onDescriptorDiscovered This callback will be called every time a descriptor is discovered
* @param[in] onTermination This callback will be called when the discovery process is over.
*
* @return BLE_ERROR_NONE if descriptor discovery is launched successfully; else an appropriate error.
*/
ble_error_t discoverDescriptors(const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& onDescriptorDiscovered,
const CharacteristicDescriptorDiscovery::TerminationCallback_t& onTermination) const;
/**
* Perform a write procedure.
*
* @param[in] length
* The amount of data being written.
* @param[in] value
* The bytes being written.
*
* @note It is important to note that a write will generate
* an onDataWritten() callback when the peer acknowledges the request.
*
* @retval BLE_ERROR_NONE Successfully started the Write procedure, or
* BLE_ERROR_INVALID_STATE if some internal state about the connection is invalid, or
* BLE_STACK_BUSY if some client procedure is already in progress, or
* BLE_ERROR_NO_MEM if there are no available buffers left to process the request, or
* BLE_ERROR_OPERATION_NOT_PERMITTED due to the characteristic's properties.
*/
ble_error_t write(uint16_t length, const uint8_t *value) const;
/**
* Same as write(uint16_t, const uint8_t *) const but register a callback
* which will be called once the data has been written.
*
* @param[in] length
* The amount of bytes to write.
* @param[in] value
* The bytes to write.
* @param[in] onWrite
* Continuation callback for the write operation
*
* @retval BLE_ERROR_NONE Successfully started the Write procedure, or
* BLE_ERROR_INVALID_STATE if some internal state about the connection is invalid, or
* BLE_STACK_BUSY if some client procedure is already in progress, or
* BLE_ERROR_NO_MEM if there are no available buffers left to process the request, or
* BLE_ERROR_OPERATION_NOT_PERMITTED due to the characteristic's properties.
*/
ble_error_t write(uint16_t length, const uint8_t *value, const GattClient::WriteCallback_t& onWrite) const;
void setupLongUUID(UUID::LongUUIDBytes_t longUUID, UUID::ByteOrder_t order = UUID::MSB) {
uuid.setupLong(longUUID, order);
}
public:
/**
* @brief Get the UUID of the discovered characteristic
* @return the UUID of this characteristic
*/
const UUID& getUUID(void) const {
return uuid;
}
/**
* @brief Get the properties of this characteristic
* @return the set of properties of this characteristic
*/
const Properties_t& getProperties(void) const {
return props;
}
/**
* @brief Get the declaration handle of this characteristic.
* @details The declaration handle is the first handle of a characteristic
* definition. The value accessible at this handle contains the following
* informations:
* - The characteristics properties (see Properties_t). This value can
* be accessed by using #getProperties .
* - The characteristic value attribute handle. This field can be accessed
* by using #getValueHandle .
* - The characteristic UUID, this value can be accessed by using the
* function #getUUID .
* @return the declaration handle of this characteristic.
*/
GattAttribute::Handle_t getDeclHandle(void) const {
return declHandle;
}
/**
* @brief Return the handle used to access the value of this characteristic.
* @details This handle is the one provided in the characteristic declaration
* value. Usually, it is equal to #getDeclHandle() + 1. But it is not always
* the case. Anyway, users are allowed to use #getDeclHandle() + 1 to access
* the value of a characteristic.
* @return The handle to access the value of this characteristic.
*/
GattAttribute::Handle_t getValueHandle(void) const {
return valueHandle;
}
/**
* @brief Return the last handle of the characteristic definition.
* @details A Characteristic definition can contain a lot of handles:
* - one for the declaration (see #getDeclHandle)
* - one for the value (see #getValueHandle)
* - zero of more for the characteristic descriptors.
* This handle is the last handle of the characteristic definition.
* @return The last handle of this characteristic definition.
*/
GattAttribute::Handle_t getLastHandle(void) const {
return lastHandle;
}
/**
* @brief Return the GattClient which can operate on this characteristic.
* @return The GattClient which can operate on this characteristic.
*/
GattClient* getGattClient() {
return gattc;
}
/**
* @brief Return the GattClient which can operate on this characteristic.
* @return The GattClient which can operate on this characteristic.
*/
const GattClient* getGattClient() const {
return gattc;
}
/**
* @brief Return the connection handle to the GattServer which contain
* this characteristic.
* @return the connection handle to the GattServer which contain
* this characteristic.
*/
Gap::Handle_t getConnectionHandle() const {
return connHandle;
}
/**
* @brief "Equal to" operator for DiscoveredCharacteristic
*
* @param[in] lhs
* The left hand side of the equality expression
* @param[in] rhs
* The right hand side of the equality expression
*
* @return true if operands are equals, false otherwise.
*/
friend bool operator==(const DiscoveredCharacteristic& lhs, const DiscoveredCharacteristic& rhs) {
return lhs.gattc == rhs.gattc &&
lhs.uuid == rhs.uuid &&
lhs.props == rhs.props &&
lhs.declHandle == rhs.declHandle &&
lhs.valueHandle == rhs.valueHandle &&
lhs.lastHandle == rhs.lastHandle &&
lhs.connHandle == rhs.connHandle;
}
/**
* @brief "Not equal to" operator for DiscoveredCharacteristic
*
* @param[in] lhs
* The right hand side of the expression
* @param[in] rhs
* The left hand side of the expression
*
* @return true if operands are not equal, false otherwise.
*/
friend bool operator !=(const DiscoveredCharacteristic& lhs, const DiscoveredCharacteristic& rhs) {
return !(lhs == rhs);
}
public:
DiscoveredCharacteristic() : gattc(NULL),
uuid(UUID::ShortUUIDBytes_t(0)),
props(),
declHandle(GattAttribute::INVALID_HANDLE),
valueHandle(GattAttribute::INVALID_HANDLE),
lastHandle(GattAttribute::INVALID_HANDLE),
connHandle() {
/* empty */
}
protected:
/**
* Pointer to the underlying GattClient for this DiscoveredCharacteristic object.
*/
GattClient *gattc;
protected:
/**
* Discovered characteristic's UUID.
*/
UUID uuid;
/**
* Hold the configured properties of the discovered characteristic.
* For more information refer to Properties_t.
*/
Properties_t props;
/**
* Value handle of the discovered characteristic's declaration attribute.
*/
GattAttribute::Handle_t declHandle;
/**
* Value handle of the discovered characteristic's value attribute.
*/
GattAttribute::Handle_t valueHandle;
/**
* Value handle of the discovered characteristic's last attribute.
*/
GattAttribute::Handle_t lastHandle;
/**
* Handle for the connection where the characteristic was discovered.
*/
Gap::Handle_t connHandle;
};
#endif /*__DISCOVERED_CHARACTERISTIC_H__*/

View File

@ -0,0 +1,111 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DISCOVERED_CHARACTERISTIC_DESCRIPTOR_H__
#define __DISCOVERED_CHARACTERISTIC_DESCRIPTOR_H__
#include "UUID.h"
#include "Gap.h"
#include "GattAttribute.h"
#include "GattClient.h"
#include "CharacteristicDescriptorDiscovery.h"
/**
* @brief Representation of a descriptor discovered during a GattClient
* discovery procedure (see GattClient::discoverCharacteristicDescriptors or
* DiscoveredCharacteristic::discoverDescriptors ).
*
* @details Provide detailed informations about a discovered characteristic descriptor
* like:
* - Its UUID (see #getUUID).
* - Its handle (see #getAttributeHandle)
* Basic read (see GattClient::read) and write (see GattClient::write) procedure from
* GattClient can be used access the value of the descriptor.
*
* @todo read member function
* @todo write member function
* @todo enumeration of standard descriptors
*/
class DiscoveredCharacteristicDescriptor {
public:
/**
* @brief construct a new instance of a DiscoveredCharacteristicDescriptor
*
* @param client The client from where the descriptor has been discovered
* @param connectionHandle The connection handle on which the descriptor has
* been discovered
* @param attributeHandle The handle of the attribute containing this descriptor
* @param uuid The UUID of the descriptor
*/
DiscoveredCharacteristicDescriptor(
GattClient* client, Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const UUID& uuid) :
_client(client), _connectionHandle(connectionHandle), _uuid(uuid), _gattHandle(attributeHandle) {
}
/**
* @brief Return the GattClient which can operate on this descriptor.
* @return The GattClient which can operate on this descriptor.
*/
GattClient* getGattClient() {
return _client;
}
/**
* @brief Return the GattClient which can operate on this descriptor.
* @return The GattClient which can operate on this descriptor.
*/
const GattClient* getGattClient() const {
return _client;
}
/**
* @brief Return the connection handle to the GattServer which contain
* this descriptor.
* @return the connection handle to the GattServer which contain
* this descriptor.
*/
Gap::Handle_t getConnectionHandle() const {
return _connectionHandle;
}
/**
* @brief Return the UUID of this descriptor
* @return the UUID of this descriptor
*/
const UUID& getUUID(void) const {
return _uuid;
}
/**
* @brief Return the attribute handle to use to access to this descriptor
* on the gatt server.
* @return The attribute handle of the descriptor
*/
GattAttribute::Handle_t getAttributeHandle() const {
return _gattHandle;
}
private:
GattClient *_client;
Gap::Handle_t _connectionHandle;
UUID _uuid;
GattAttribute::Handle_t _gattHandle;
};
#endif /*__DISCOVERED_CHARACTERISTIC_DESCRIPTOR_H__*/

119
ble/DiscoveredService.h Normal file
View File

@ -0,0 +1,119 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DISCOVERED_SERVICE_H__
#define __DISCOVERED_SERVICE_H__
#include "UUID.h"
#include "GattAttribute.h"
/**@brief Type for holding information about the service and the characteristics found during
* the discovery process.
*/
class DiscoveredService {
public:
/**
* Set information about the discovered service.
*
* @param[in] uuidIn
* The UUID of the discovered service.
* @param[in] startHandleIn
* The start handle of the discovered service in the peer's
* ATT table.
* @param[in] endHandleIn
* The end handle of the discovered service in the peer's
* ATT table.
*/
void setup(UUID uuidIn, GattAttribute::Handle_t startHandleIn, GattAttribute::Handle_t endHandleIn) {
uuid = uuidIn;
startHandle = startHandleIn;
endHandle = endHandleIn;
}
/**
* Set the start and end handle of the discovered service.
* @param[in] startHandleIn
* The start handle of the discovered service in the peer's
* ATT table.
* @param[in] endHandleIn
* The end handle of the discovered service in the peer's
* ATT table.
*/
void setup(GattAttribute::Handle_t startHandleIn, GattAttribute::Handle_t endHandleIn) {
startHandle = startHandleIn;
endHandle = endHandleIn;
}
/**
* Set the long UUID of the discovered service.
*
* @param[in] longUUID
* The long UUID of the discovered service.
* @param[in] order
* The byte ordering of @p longUUID.
*/
void setupLongUUID(UUID::LongUUIDBytes_t longUUID, UUID::ByteOrder_t order = UUID::MSB) {
uuid.setupLong(longUUID, order);
}
public:
/**
* Get the UUID of the discovered service.
*
* @return A reference to the UUID of the discovered service.
*/
const UUID &getUUID(void) const {
return uuid;
}
/**
* Get the start handle of the discovered service in the peer's ATT table.
*
* @return A reference to the start handle.
*/
const GattAttribute::Handle_t& getStartHandle(void) const {
return startHandle;
}
/**
* Get the end handle of the discovered service in the peer's ATT table.
*
* @return A reference to the end handle.
*/
const GattAttribute::Handle_t& getEndHandle(void) const {
return endHandle;
}
public:
/**
* Construct a DiscoveredService instance.
*/
DiscoveredService() : uuid(UUID::ShortUUIDBytes_t(0)),
startHandle(GattAttribute::INVALID_HANDLE),
endHandle(GattAttribute::INVALID_HANDLE) {
/* empty */
}
private:
DiscoveredService(const DiscoveredService &);
private:
UUID uuid; /**< UUID of the service. */
GattAttribute::Handle_t startHandle; /**< Service Handle Range. */
GattAttribute::Handle_t endHandle; /**< Service Handle Range. */
};
#endif /*__DISCOVERED_SERVICE_H__*/

View File

@ -0,0 +1,212 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H
#define MBED_FUNCTIONPOINTER_WITH_CONTEXT_H
#include <string.h>
#include "SafeBool.h"
/** A class for storing and calling a pointer to a static or member void function
* that takes a context.
*/
template <typename ContextType>
class FunctionPointerWithContext : public SafeBool<FunctionPointerWithContext<ContextType> > {
public:
typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
typedef const FunctionPointerWithContext<ContextType> *cpFunctionPointerWithContext_t;
typedef void (*pvoidfcontext_t)(ContextType context);
/** Create a FunctionPointerWithContext, attaching a static function.
*
* @param function The void static function to attach (default is none).
*/
FunctionPointerWithContext(void (*function)(ContextType context) = NULL) :
_memberFunctionAndPointer(), _caller(NULL), _next(NULL) {
attach(function);
}
/** Create a FunctionPointerWithContext, attaching a member function.
*
* @param object The object pointer to invoke the member function on (the "this" pointer).
* @param function The address of the void member function to attach.
*/
template<typename T>
FunctionPointerWithContext(T *object, void (T::*member)(ContextType context)) :
_memberFunctionAndPointer(), _caller(NULL), _next(NULL) {
attach(object, member);
}
FunctionPointerWithContext(const FunctionPointerWithContext& that) :
_memberFunctionAndPointer(that._memberFunctionAndPointer), _caller(that._caller), _next(NULL) {
}
FunctionPointerWithContext& operator=(const FunctionPointerWithContext& that) {
_memberFunctionAndPointer = that._memberFunctionAndPointer;
_caller = that._caller;
_next = NULL;
return *this;
}
/** Attach a static function.
*
* @param function The void static function to attach (default is none).
*/
void attach(void (*function)(ContextType context) = NULL) {
_function = function;
_caller = functioncaller;
}
/** Attach a member function.
*
* @param object The object pointer to invoke the member function on (the "this" pointer).
* @param function The address of the void member function to attach.
*/
template<typename T>
void attach(T *object, void (T::*member)(ContextType context)) {
_memberFunctionAndPointer._object = static_cast<void *>(object);
memcpy(_memberFunctionAndPointer._memberFunction, (char*) &member, sizeof(member));
_caller = &FunctionPointerWithContext::membercaller<T>;
}
/** Call the attached static or member function; if there are chained
* FunctionPointers their callbacks are invoked as well.
* @Note: All chained callbacks stack up, so hopefully there won't be too
* many FunctionPointers in a chain. */
void call(ContextType context) const {
_caller(this, context);
}
/**
* @brief Same as above
*/
void operator()(ContextType context) const {
call(context);
}
/** Same as above, workaround for mbed os FunctionPointer implementation. */
void call(ContextType context) {
((const FunctionPointerWithContext*) this)->call(context);
}
typedef void (FunctionPointerWithContext::*bool_type)() const;
/**
* implementation of safe bool operator
*/
bool toBool() const {
return (_function || _memberFunctionAndPointer._object);
}
/**
* Set up an external FunctionPointer as a next in the chain of related
* callbacks. Invoking call() on the head FunctionPointer will invoke all
* chained callbacks.
*
* Refer to 'CallChain' as an alternative.
*/
void chainAsNext(pFunctionPointerWithContext_t next) {
_next = next;
}
pFunctionPointerWithContext_t getNext(void) const {
return _next;
}
pvoidfcontext_t get_function() const {
return (pvoidfcontext_t)_function;
}
friend bool operator==(const FunctionPointerWithContext& lhs, const FunctionPointerWithContext& rhs) {
return rhs._caller == lhs._caller &&
memcmp(
&rhs._memberFunctionAndPointer,
&lhs._memberFunctionAndPointer,
sizeof(rhs._memberFunctionAndPointer)
) == 0;
}
private:
template<typename T>
static void membercaller(cpFunctionPointerWithContext_t self, ContextType context) {
if (self->_memberFunctionAndPointer._object) {
T *o = static_cast<T *>(self->_memberFunctionAndPointer._object);
void (T::*m)(ContextType);
memcpy((char*) &m, self->_memberFunctionAndPointer._memberFunction, sizeof(m));
(o->*m)(context);
}
}
static void functioncaller(cpFunctionPointerWithContext_t self, ContextType context) {
if (self->_function) {
self->_function(context);
}
}
struct MemberFunctionAndPtr {
/*
* Forward declaration of a class and a member function to this class.
* Because the compiler doesn't know anything about the forwarded member
* function, it will always use the biggest size and the biggest alignment
* that a member function can take for objects of type UndefinedMemberFunction.
*/
class UndefinedClass;
typedef void (UndefinedClass::*UndefinedMemberFunction)(ContextType);
void* _object;
union {
char _memberFunction[sizeof(UndefinedMemberFunction)];
UndefinedMemberFunction _alignment;
};
};
union {
pvoidfcontext_t _function; /**< Static function pointer - NULL if none attached */
/**
* object this pointer and pointer to member -
* _memberFunctionAndPointer._object will be NULL if none attached
*/
mutable MemberFunctionAndPtr _memberFunctionAndPointer;
};
void (*_caller)(const FunctionPointerWithContext*, ContextType);
pFunctionPointerWithContext_t _next; /**< Optional link to make a chain out of functionPointers. This
* allows chaining function pointers without requiring
* external memory to manage the chain. Refer to
* 'CallChain' as an alternative. */
};
/**
* @brief Create a new FunctionPointerWithContext which bind an instance and a
* a member function together.
* @details This little helper is a just here to eliminate the need to write the
* FunctionPointerWithContext type each time you want to create one by kicking
* automatic type deduction of function templates. With this function, it is easy
* to write only one entry point for functions which expect a FunctionPointer
* in parameters.
*
* @param object to bound with member function
* @param member The member function called
* @return a new FunctionPointerWithContext
*/
template<typename T, typename ContextType>
FunctionPointerWithContext<ContextType> makeFunctionPointer(T *object, void (T::*member)(ContextType context))
{
return FunctionPointerWithContext<ContextType>(object, member);
}
#endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H

1919
ble/Gap.h Normal file

File diff suppressed because it is too large Load Diff

567
ble/GapAdvertisingData.h Normal file
View File

@ -0,0 +1,567 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GAP_ADVERTISING_DATA_H__
#define __GAP_ADVERTISING_DATA_H__
#include <stdint.h>
#include <string.h>
#include "blecommon.h"
#define GAP_ADVERTISING_DATA_MAX_PAYLOAD (31)
/**
* @brief This class provides several helper functions to generate properly
* formatted GAP Advertising and Scan Response data payloads.
*
* @note See Bluetooth Specification 4.0 (Vol. 3), Part C, Sections 11 and 18
* for further information on Advertising and Scan Response data.
*
* @par Advertising and Scan Response Payloads
* Advertising data and Scan Response data are organized around a set of
* data types called 'AD types' in Bluetooth 4.0 (see the Bluetooth Core
* Specification v4.0, Vol. 3, Part C, Sections 11 and 18).
*
* @par
* Each AD type has its own standardized assigned number, as defined
* by the Bluetooth SIG:
* https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile.
*
* @par
* For convenience, all appropriate AD types are encapsulated
* in GapAdvertisingData::DataType.
*
* @par
* Before the AD Types and their payload (if any) can be inserted into
* the Advertising or Scan Response frames, they need to be formatted as
* follows:
*
* @li @c Record length (1 byte).
* @li @c AD Type (1 byte).
* @li @c AD payload (optional; only present if record length > 1).
*
* @par
* This class takes care of properly formatting the payload, performs
* some basic checks on the payload length, and tries to avoid common
* errors like adding an exclusive AD field twice in the Advertising
* or Scan Response payload.
*
* @par EXAMPLE
*
* @code
*
* // ToDo
*
* @endcode
*/
class GapAdvertisingData
{
public:
/*!
* @brief A list of Advertising Data types commonly used by peripherals.
* These AD types are used to describe the capabilities of the
* peripheral, and are inserted inside the advertising or scan
* response payloads.
*
* @par Source
*
* @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 11, 18.
* @li @c https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile.
*/
enum DataType_t {
FLAGS = 0x01, /**< Flags, refer to GapAdvertisingData::Flags_t. */
INCOMPLETE_LIST_16BIT_SERVICE_IDS = 0x02, /**< Incomplete list of 16-bit Service IDs. */
COMPLETE_LIST_16BIT_SERVICE_IDS = 0x03, /**< Complete list of 16-bit Service IDs. */
INCOMPLETE_LIST_32BIT_SERVICE_IDS = 0x04, /**< Incomplete list of 32-bit Service IDs (not relevant for Bluetooth 4.0). */
COMPLETE_LIST_32BIT_SERVICE_IDS = 0x05, /**< Complete list of 32-bit Service IDs (not relevant for Bluetooth 4.0). */
INCOMPLETE_LIST_128BIT_SERVICE_IDS = 0x06, /**< Incomplete list of 128-bit Service IDs. */
COMPLETE_LIST_128BIT_SERVICE_IDS = 0x07, /**< Complete list of 128-bit Service IDs. */
SHORTENED_LOCAL_NAME = 0x08, /**< Shortened Local Name. */
COMPLETE_LOCAL_NAME = 0x09, /**< Complete Local Name. */
TX_POWER_LEVEL = 0x0A, /**< TX Power Level (in dBm). */
DEVICE_ID = 0x10, /**< Device ID. */
SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, /**< Slave Connection Interval Range. */
LIST_128BIT_SOLICITATION_IDS = 0x15, /**< List of 128 bit service UUIDs the device is looking for. */
SERVICE_DATA = 0x16, /**< Service Data. */
APPEARANCE = 0x19, /**< Appearance, refer to GapAdvertisingData::Appearance_t. */
ADVERTISING_INTERVAL = 0x1A, /**< Advertising Interval. */
MANUFACTURER_SPECIFIC_DATA = 0xFF /**< Manufacturer Specific Data. */
};
/**
* Type alias for GapAdvertisingData::DataType_t.
*
* @deprecated This type alias will be dropped in future releases.
*/
typedef enum DataType_t DataType;
/**
* @brief A list of values for the FLAGS AD Type.
*
* @note You can use more than one value in the FLAGS AD Type (ex.
* LE_GENERAL_DISCOVERABLE and BREDR_NOT_SUPPORTED).
*
* @par Source
*
* @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 18.1.
*/
enum Flags_t {
LE_LIMITED_DISCOVERABLE = 0x01, /**< Peripheral device is discoverable for a limited period of time. */
LE_GENERAL_DISCOVERABLE = 0x02, /**< Peripheral device is discoverable at any moment. */
BREDR_NOT_SUPPORTED = 0x04, /**< Peripheral device is LE only. */
SIMULTANEOUS_LE_BREDR_C = 0x08, /**< Not relevant - central mode only. */
SIMULTANEOUS_LE_BREDR_H = 0x10 /**< Not relevant - central mode only. */
};
/**
* Type alias for GapAdvertisingData::Flags_t.
*
* @deprecated This type alias will be dropped in future releases.
*/
typedef enum Flags_t Flags;
/**
* @brief
* A list of values for the APPEARANCE AD Type, which describes the
* physical shape or appearance of the device.
*
* @par Source
*
* @li @c Bluetooth Core Specification Supplement, Part A, Section 1.12.
* @li @c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 12.2.
* @li @c https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml.
*/
enum Appearance_t {
UNKNOWN = 0, /**< Unknown or unspecified appearance type. */
GENERIC_PHONE = 64, /**< Generic Phone. */
GENERIC_COMPUTER = 128, /**< Generic Computer. */
GENERIC_WATCH = 192, /**< Generic Watch. */
WATCH_SPORTS_WATCH = 193, /**< Sports Watch. */
GENERIC_CLOCK = 256, /**< Generic Clock. */
GENERIC_DISPLAY = 320, /**< Generic Display. */
GENERIC_REMOTE_CONTROL = 384, /**< Generic Remote Control. */
GENERIC_EYE_GLASSES = 448, /**< Generic Eye Glasses. */
GENERIC_TAG = 512, /**< Generic Tag. */
GENERIC_KEYRING = 576, /**< Generic Keyring. */
GENERIC_MEDIA_PLAYER = 640, /**< Generic Media Player. */
GENERIC_BARCODE_SCANNER = 704, /**< Generic Barcode Scanner. */
GENERIC_THERMOMETER = 768, /**< Generic Thermometer. */
THERMOMETER_EAR = 769, /**< Ear Thermometer. */
GENERIC_HEART_RATE_SENSOR = 832, /**< Generic Heart Rate Sensor. */
HEART_RATE_SENSOR_HEART_RATE_BELT = 833, /**< Belt Heart Rate Sensor. */
GENERIC_BLOOD_PRESSURE = 896, /**< Generic Blood Pressure. */
BLOOD_PRESSURE_ARM = 897, /**< Arm Blood Pressure. */
BLOOD_PRESSURE_WRIST = 898, /**< Wrist Blood Pressure. */
HUMAN_INTERFACE_DEVICE_HID = 960, /**< Human Interface Device (HID). */
KEYBOARD = 961, /**< Keyboard. */
MOUSE = 962, /**< Mouse. */
JOYSTICK = 963, /**< Joystick. */
GAMEPAD = 964, /**< Gamepad. */
DIGITIZER_TABLET = 965, /**< Digitizer Tablet. */
CARD_READER = 966, /**< Card Reader. */
DIGITAL_PEN = 967, /**< Digital Pen. */
BARCODE_SCANNER = 968, /**< Barcode Scanner. */
GENERIC_GLUCOSE_METER = 1024, /**< Generic Glucose Meter. */
GENERIC_RUNNING_WALKING_SENSOR = 1088, /**< Generic Running/Walking Sensor. */
RUNNING_WALKING_SENSOR_IN_SHOE = 1089, /**< In Shoe Running/Walking Sensor. */
RUNNING_WALKING_SENSOR_ON_SHOE = 1090, /**< On Shoe Running/Walking Sensor. */
RUNNING_WALKING_SENSOR_ON_HIP = 1091, /**< On Hip Running/Walking Sensor. */
GENERIC_CYCLING = 1152, /**< Generic Cycling. */
CYCLING_CYCLING_COMPUTER = 1153, /**< Cycling Computer. */
CYCLING_SPEED_SENSOR = 1154, /**< Cycling Speed Sensor. */
CYCLING_CADENCE_SENSOR = 1155, /**< Cycling Cadence Sensor. */
CYCLING_POWER_SENSOR = 1156, /**< Cycling Power Sensor. */
CYCLING_SPEED_AND_CADENCE_SENSOR = 1157, /**< Cycling Speed and Cadence Sensor. */
PULSE_OXIMETER_GENERIC = 3136, /**< Generic Pulse Oximeter. */
PULSE_OXIMETER_FINGERTIP = 3137, /**< Fingertip Pulse Oximeter. */
PULSE_OXIMETER_WRIST_WORN = 3138, /**< Wrist Worn Pulse Oximeter. */
GENERIC_WEIGHT_SCALE = 3200, /**< Generic Weight Scale. */
OUTDOOR_GENERIC = 5184, /**< Generic Outdoor. */
OUTDOOR_LOCATION_DISPLAY_DEVICE = 5185, /**< Outdoor Location Display Device. */
OUTDOOR_LOCATION_AND_NAVIGATION_DISPLAY_DEVICE = 5186, /**< Outdoor Location and Navigation Display Device. */
OUTDOOR_LOCATION_POD = 5187, /**< Outdoor Location Pod. */
OUTDOOR_LOCATION_AND_NAVIGATION_POD = 5188 /**< Outdoor Location and Navigation Pod. */
};
/**
* Type alias for GapAdvertisingData::Appearance_t.
*
* @deprecated This type alias will be dropped in future releases.
*/
typedef enum Appearance_t Appearance;
/**
* Empty constructor.
*/
GapAdvertisingData(void) : _payload(), _payloadLen(0), _appearance(GENERIC_TAG) {
/* empty */
}
/**
* Adds advertising data based on the specified AD type (see GapAdvertisingData::DataType_t).
* If the supplied AD type is already present in the advertising
* payload, then the value is updated.
*
* @param[in] advDataType The Advertising 'DataType' to add.
* @param[in] payload Pointer to the payload contents.
* @param[in] len Size of the payload in bytes.
*
* @return BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
* advertising buffer to overflow. BLE_ERROR_NONE is returned
* on success.
*
* @note When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
* COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
* COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
* COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
* supplied value is appended to the values previously added to the
* payload.
*/
ble_error_t addData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
{
/* Find field */
uint8_t* field = findField(advDataType);
if (field) {
/* Field type already exist, either add to field or replace */
return addField(advDataType, payload, len, field);
} else {
/* Field doesn't exists, insert new */
return appendField(advDataType, payload, len);
}
}
/**
* Update a particular ADV field in the advertising payload (based on
* matching type).
*
* @param[in] advDataType The Advertising 'DataType' to add.
* @param[in] payload Pointer to the payload contents.
* @param[in] len Size of the payload in bytes.
*
* @return BLE_ERROR_UNSPECIFIED if the specified field is not found,
* BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
* advertising buffer to overflow. BLE_ERROR_NONE is returned
* on success.
*/
ble_error_t updateData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
{
/* Find field */
uint8_t* field = findField(advDataType);
if (field) {
/* Field type already exist, replace field contents */
return updateField(advDataType, payload, len, field);
} else {
/* field doesn't exists, return an error */
return BLE_ERROR_UNSPECIFIED;
}
}
/**
* Helper function to add APPEARANCE data to the advertising payload.
*
* @param appearance
* The APPEARANCE value to add.
*
* @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
* advertising buffer to overflow, else BLE_ERROR_NONE.
*/
ble_error_t addAppearance(Appearance appearance = GENERIC_TAG) {
_appearance = appearance;
return addData(GapAdvertisingData::APPEARANCE, (uint8_t *)&appearance, 2);
}
/**
* Helper function to add FLAGS data to the advertising payload.
*
* @param[in] flags
* LE_LIMITED_DISCOVERABLE
* The peripheral is discoverable for a limited period of time.
* LE_GENERAL_DISCOVERABLE
* The peripheral is permanently discoverable.
* BREDR_NOT_SUPPORTED
* This peripheral is a Bluetooth Low Energy only device (no EDR support).
*
* @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
* advertising buffer to overflow, else BLE_ERROR_NONE.
*/
ble_error_t addFlags(uint8_t flags = LE_GENERAL_DISCOVERABLE) {
return addData(GapAdvertisingData::FLAGS, &flags, 1);
}
/**
* Helper function to add TX_POWER_LEVEL data to the advertising payload.
*
* @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
* advertising buffer to overflow, else BLE_ERROR_NONE.
*/
ble_error_t addTxPower(int8_t txPower) {
/* To Do: Basic error checking to make sure txPower is in range. */
return addData(GapAdvertisingData::TX_POWER_LEVEL, (uint8_t *)&txPower, 1);
}
/**
* Clears the payload and resets the payload length counter.
*/
void clear(void) {
memset(&_payload, 0, GAP_ADVERTISING_DATA_MAX_PAYLOAD);
_payloadLen = 0;
}
/**
* Access the current payload.
*
* @return A pointer to the current payload.
*/
const uint8_t *getPayload(void) const {
return _payload;
}
/**
* Get the current payload length.
*
* @return The current payload length (0..31 bytes).
*/
uint8_t getPayloadLen(void) const {
return _payloadLen;
}
/**
* Get the current appearance value.
*
* @return The 16-bit appearance value for this device.
*/
uint16_t getAppearance(void) const {
return (uint16_t)_appearance;
}
/**
* Search advertisement data for a specific field.
*
* @param[in] type
* The type of the field to find.
*
* @return A pointer to the first element in the field if found, NULL otherwise.
* Where the first element is the length of the field.
*/
const uint8_t* findField(DataType_t type) const {
return findField(type);
}
private:
/**
* Append advertising data based on the specified AD type (see
* GapAdvertisingData::DataType_t).
*
* @param[in] advDataType
* The type of the new data.
* @param[in] payload
* A pointer to the data to be appended to the advertising
* payload.
* @param[in] len
* The length of th data pointed to by @p payload.
*
* @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
* advertising buffer to overflow, else BLE_ERROR_NONE.
*/
ble_error_t appendField(DataType advDataType, const uint8_t *payload, uint8_t len)
{
/* Make sure we don't exceed the 31 byte payload limit */
if (_payloadLen + len + 2 > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
return BLE_ERROR_BUFFER_OVERFLOW;
}
/* Field length. */
memset(&_payload[_payloadLen], len + 1, 1);
_payloadLen++;
/* Field ID. */
memset(&_payload[_payloadLen], (uint8_t)advDataType, 1);
_payloadLen++;
/* Payload. */
memcpy(&_payload[_payloadLen], payload, len);
_payloadLen += len;
return BLE_ERROR_NONE;
}
/**
* Search advertisement data for field.
*
* @param[in] type
* The type of the data to find.
*
* @return A pointer to the first element in the field if found, NULL
* otherwise. Where the first element is the length of the field.
*/
uint8_t* findField(DataType_t type) {
/* Scan through advertisement data */
for (uint8_t idx = 0; idx < _payloadLen; ) {
uint8_t fieldType = _payload[idx + 1];
if (fieldType == type) {
return &_payload[idx];
}
/* Advance to next field */
idx += _payload[idx] + 1;
}
/* Field not found */
return NULL;
}
/**
* Given the a pointer to a field in the advertising payload it replaces
* the existing data in the field with the supplied data.
*
* @param[in] advDataType
* The type of the new data.
* @param[in] payload
* A pointer to the data to be added to the advertising
* payload.
* @param[in] len
* The length of th data pointed to by @p payload.
* @param[in] field
* A pointer to the field of type @p advDataType in the
* advertising buffer.
*
* When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
* COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
* COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
* COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
* supplied value is appended to the values previously added to the
* payload.
*
* @return BLE_ERROR_NONE on success.
*/
ble_error_t addField(DataType_t advDataType, const uint8_t *payload, uint8_t len, uint8_t* field)
{
ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
switch(advDataType) {
/* These fields will have the new data appended if there is sufficient space */
case INCOMPLETE_LIST_16BIT_SERVICE_IDS:
case COMPLETE_LIST_16BIT_SERVICE_IDS:
case INCOMPLETE_LIST_32BIT_SERVICE_IDS:
case COMPLETE_LIST_32BIT_SERVICE_IDS:
case INCOMPLETE_LIST_128BIT_SERVICE_IDS:
case COMPLETE_LIST_128BIT_SERVICE_IDS:
case LIST_128BIT_SOLICITATION_IDS: {
/* Check if data fits */
if ((_payloadLen + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
/*
* Make room for new field by moving the remainder of the
* advertisement payload "to the right" starting after the
* TYPE field.
*/
uint8_t* end = &_payload[_payloadLen];
while (&field[1] < end) {
end[len] = *end;
end--;
}
/* Insert new data */
for (uint8_t idx = 0; idx < len; idx++) {
field[2 + idx] = payload[idx];
}
/* Increment lengths */
field[0] += len;
_payloadLen += len;
result = BLE_ERROR_NONE;
}
break;
}
/* These fields will be overwritten with the new value */
default: {
result = updateField(advDataType, payload, len, field);
break;
}
}
return result;
}
/**
* Given the a pointer to a field in the advertising payload it replaces
* the existing data in the field with the supplied data.
*
* @param[in] advDataType
* The type of the data to be updated.
* @param[in] payload
* A pointer to the data to be updated to the advertising
* payload.
* @param[in] len
* The length of th data pointed to by @p payload.
* @param[in] field
* A pointer to the field of type @p advDataType in the
* advertising buffer.
*
* @return BLE_ERROR_NONE on success.
*/
ble_error_t updateField(DataType_t advDataType, const uint8_t *payload, uint8_t len, uint8_t* field)
{
ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
uint8_t dataLength = field[0] - 1;
/* New data has same length, do in-order replacement */
if (len == dataLength) {
for (uint8_t idx = 0; idx < dataLength; idx++) {
field[2 + idx] = payload[idx];
}
result = BLE_ERROR_NONE;
} else {
/* Check if data fits */
if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
/* Remove old field */
while ((field + dataLength + 2) < &_payload[_payloadLen]) {
*field = field[dataLength + 2];
field++;
}
/* Reduce length */
_payloadLen -= dataLength + 2;
/* Add new field */
result = appendField(advDataType, payload, len);
}
}
return result;
}
/**
* The advertising data buffer
*/
uint8_t _payload[GAP_ADVERTISING_DATA_MAX_PAYLOAD];
/**
* The length of the data added to the advertising buffer.
*/
uint8_t _payloadLen;
/**
* Appearance value.
*/
uint16_t _appearance;
};
#endif /* ifndef __GAP_ADVERTISING_DATA_H__ */

207
ble/GapAdvertisingParams.h Normal file
View File

@ -0,0 +1,207 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GAP_ADVERTISING_PARAMS_H__
#define __GAP_ADVERTISING_PARAMS_H__
/**
* This class provides a wrapper for the core advertising parameters,
* including the advertising type (Connectable Undirected,
* Non Connectable Undirected and so on), as well as the advertising and
* timeout intervals.
*/
class GapAdvertisingParams {
public:
/**
* Minimum Advertising interval for connectable undirected and connectable
* directed events in 625us units - 20ms.
*/
static const unsigned GAP_ADV_PARAMS_INTERVAL_MIN = 0x0020;
/**
* Minimum Advertising interval for scannable and non-connectable
* undirected events in 625us units - 100ms.
*/
static const unsigned GAP_ADV_PARAMS_INTERVAL_MIN_NONCON = 0x00A0;
/**
* Maximum Advertising interval in 625us units - 10.24s.
*/
static const unsigned GAP_ADV_PARAMS_INTERVAL_MAX = 0x4000;
/**
* Maximum advertising timeout seconds.
*/
static const unsigned GAP_ADV_PARAMS_TIMEOUT_MAX = 0x3FFF;
/**
* Encapsulates the peripheral advertising modes, which determine how
* the device appears to other central devices in hearing range.
*/
enum AdvertisingType_t {
ADV_CONNECTABLE_UNDIRECTED, /**< Vol 3, Part C, Section 9.3.4 and Vol 6, Part B, Section 2.3.1.1. */
ADV_CONNECTABLE_DIRECTED, /**< Vol 3, Part C, Section 9.3.3 and Vol 6, Part B, Section 2.3.1.2. */
ADV_SCANNABLE_UNDIRECTED, /**< Include support for Scan Response payloads, see Vol 6, Part B, Section 2.3.1.4. */
ADV_NON_CONNECTABLE_UNDIRECTED /**< Vol 3, Part C, Section 9.3.2 and Vol 6, Part B, Section 2.3.1.3. */
};
/**
* Type alias for GapAdvertisingParams::AdvertisingType_t.
*
* @deprecated This type alias will be dropped in future releases.
*/
typedef enum AdvertisingType_t AdvertisingType;
public:
/**
* Construct an instance of GapAdvertisingParams.
*
* @param[in] advType
* Type of advertising. Default is
* GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED.
* @param[in] interval
* Advertising interval in units of 0.625ms. Default is
* GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON.
* @param[in] timeout
* Advertising timeout. Default is 0.
*/
GapAdvertisingParams(AdvertisingType_t advType = ADV_CONNECTABLE_UNDIRECTED,
uint16_t interval = GAP_ADV_PARAMS_INTERVAL_MIN_NONCON,
uint16_t timeout = 0) : _advType(advType), _interval(interval), _timeout(timeout) {
/* Interval checks. */
if (_advType == ADV_CONNECTABLE_DIRECTED) {
/* Interval must be 0 in directed connectable mode. */
_interval = 0;
} else if (_advType == ADV_NON_CONNECTABLE_UNDIRECTED) {
/* Min interval is slightly larger than in other modes. */
if (_interval < GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) {
_interval = GAP_ADV_PARAMS_INTERVAL_MIN_NONCON;
}
if (_interval > GAP_ADV_PARAMS_INTERVAL_MAX) {
_interval = GAP_ADV_PARAMS_INTERVAL_MAX;
}
} else {
/* Stay within interval limits. */
if (_interval < GAP_ADV_PARAMS_INTERVAL_MIN) {
_interval = GAP_ADV_PARAMS_INTERVAL_MIN;
}
if (_interval > GAP_ADV_PARAMS_INTERVAL_MAX) {
_interval = GAP_ADV_PARAMS_INTERVAL_MAX;
}
}
/* Timeout checks. */
if (timeout) {
/* Stay within timeout limits. */
if (_timeout > GAP_ADV_PARAMS_TIMEOUT_MAX) {
_timeout = GAP_ADV_PARAMS_TIMEOUT_MAX;
}
}
}
static const uint16_t UNIT_0_625_MS = 625; /**< Number of microseconds in 0.625 milliseconds. */
/**
* Convert milliseconds to units of 0.625ms.
*
* @param[in] durationInMillis
* The number of milliseconds to convert.
*
* @return The value of @p durationInMillis in units of 0.625ms.
*/
static uint16_t MSEC_TO_ADVERTISEMENT_DURATION_UNITS(uint32_t durationInMillis) {
return (durationInMillis * 1000) / UNIT_0_625_MS;
}
/**
* Convert units of 0.625ms to milliseconds.
*
* @param[in] gapUnits
* The number of units of 0.625ms to convert.
*
* @return The value of @p gapUnits in milliseconds.
*/
static uint16_t ADVERTISEMENT_DURATION_UNITS_TO_MS(uint16_t gapUnits) {
return (gapUnits * UNIT_0_625_MS) / 1000;
}
/**
* Get the advertising type.
*
* @return The advertising type.
*/
AdvertisingType_t getAdvertisingType(void) const {
return _advType;
}
/**
* Get the advertising interval in milliseconds.
*
* @return The advertisement interval (in milliseconds).
*/
uint16_t getInterval(void) const {
return ADVERTISEMENT_DURATION_UNITS_TO_MS(_interval);
}
/**
* Get the advertisement interval in units of 0.625ms.
*
* @return The advertisement interval in advertisement duration units (0.625ms units).
*/
uint16_t getIntervalInADVUnits(void) const {
return _interval;
}
/**
* Get The advertising timeout.
*
* @return The advertising timeout (in seconds).
*/
uint16_t getTimeout(void) const {
return _timeout;
}
/**
* Set the advertising type.
*
* @param[in] newAdvType
* The new advertising type.
*/
void setAdvertisingType(AdvertisingType_t newAdvType) {
_advType = newAdvType;
}
/**
* Set the advertising interval in milliseconds.
*
* @param[in] newInterval
* The new advertising interval in milliseconds.
*/
void setInterval(uint16_t newInterval) {
_interval = MSEC_TO_ADVERTISEMENT_DURATION_UNITS(newInterval);
}
/**
* Set the advertising timeout.
*
* @param[in] newTimeout
* The new advertising timeout (in seconds).
*/
void setTimeout(uint16_t newTimeout) {
_timeout = newTimeout;
}
private:
AdvertisingType_t _advType; /**< The advertising type. */
uint16_t _interval; /**< The advertising interval in ADV duration units (i.e. 0.625ms). */
uint16_t _timeout; /**< The advertising timeout in seconds. */
};
#endif /* ifndef __GAP_ADVERTISING_PARAMS_H__ */

46
ble/GapEvents.h Normal file
View File

@ -0,0 +1,46 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GAP_EVENTS_H__
#define __GAP_EVENTS_H__
#include "blecommon.h"
/**************************************************************************/
/*!
\brief
The base class used to abstract away the callback events that can be
triggered with the GAP.
*/
/**************************************************************************/
class GapEvents
{
public:
/******************************************************************/
/*!
\brief
Identifies GAP events generated by the radio HW when an event
callback occurs.
*/
/******************************************************************/
typedef enum gapEvent_e {
GAP_EVENT_TIMEOUT = 1, /**< Advertising timed out before a connection could be established. */
GAP_EVENT_CONNECTED = 2, /**< A connection was established with a central device. */
GAP_EVENT_DISCONNECTED = 3 /**< A connection was closed or lost with a central device. */
} gapEvent_t;
};
#endif // ifndef __GAP_EVENTS_H__

152
ble/GapScanningParams.h Normal file
View File

@ -0,0 +1,152 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GAP_SCANNING_PARAMS_H__
#define __GAP_SCANNING_PARAMS_H__
class GapScanningParams {
public:
static const unsigned SCAN_INTERVAL_MIN = 0x0004; /**< Minimum Scan interval in 625us units - 2.5ms. */
static const unsigned SCAN_INTERVAL_MAX = 0x4000; /**< Maximum Scan interval in 625us units - 10.24s. */
static const unsigned SCAN_WINDOW_MIN = 0x0004; /**< Minimum Scan window in 625us units - 2.5ms. */
static const unsigned SCAN_WINDOW_MAX = 0x4000; /**< Maximum Scan window in 625us units - 10.24s. */
static const unsigned SCAN_TIMEOUT_MIN = 0x0001; /**< Minimum Scan timeout in seconds. */
static const unsigned SCAN_TIMEOUT_MAX = 0xFFFF; /**< Maximum Scan timeout in seconds. */
public:
/**
* Construct an instance of GapScanningParams.
*
* @param[in] interval
* The scan interval in milliseconds. Default is
* GapScanningParams::SCAN_INTERVAL_MIN.
* @param[in] window
* The scan window in milliseconds. Default is
* GapScanningParams::SCAN_WINDOW_MAX.
* @param[in] timeout
* The scan timeout in seconds. Default is 0.
* @param[in] activeScanning
* Set to True if active-scanning is required. This is used to
* fetch the scan response from a peer if possible. Default is
* false.
*/
GapScanningParams(uint16_t interval = SCAN_INTERVAL_MAX,
uint16_t window = SCAN_WINDOW_MAX,
uint16_t timeout = 0,
bool activeScanning = false);
static const uint16_t UNIT_0_625_MS = 625; /**< Number of microseconds in 0.625 milliseconds. */
/**
* Convert milliseconds to units of 0.625ms.
*
* @param[in] durationInMillis
* The number of milliseconds to convert.
*
* @return The value of @p durationInMillis in units of 0.625ms.
*/
static uint16_t MSEC_TO_SCAN_DURATION_UNITS(uint32_t durationInMillis) {
return (durationInMillis * 1000) / UNIT_0_625_MS;
}
/**
* Set the scan interval.
*
* @param[in] newIntervalInMS
* New scan interval in milliseconds.
*
* @return BLE_ERROR_NONE if the new scan interval was set successfully.
*/
ble_error_t setInterval(uint16_t newIntervalInMS);
/**
* Set the scan window.
*
* @param[in] newWindowInMS
* New scan window in milliseconds.
*
* @return BLE_ERROR_NONE if the new scan window was set successfully.
*/
ble_error_t setWindow(uint16_t newWindowInMS);
/**
* Set the scan timeout.
*
* @param[in] newTimeout
* New scan timeout in seconds.
*
* @return BLE_ERROR_NONE if the new scan window was set successfully.
*/
ble_error_t setTimeout(uint16_t newTimeout);
/**
* Set active scanning. This is used to fetch the scan response from a peer
* if possible.
*
* @param[in] activeScanning
* The new boolean value of active scanning.
*/
void setActiveScanning(bool activeScanning);
public:
/**
* Get the scan interval.
*
* @return the scan interval in units of 0.625ms.
*/
uint16_t getInterval(void) const {
return _interval;
}
/**
* Get the scan window.
*
* @return the scan window in units of 0.625ms.
*/
uint16_t getWindow(void) const {
return _window;
}
/**
* Get the scan timeout.
*
* @return The scan timeout in seconds.
*/
uint16_t getTimeout(void) const {
return _timeout;
}
/**
* Check whether active scanning is set.
*
* @return True if active scanning is set, false otherwise.
*/
bool getActiveScanning(void) const {
return _activeScanning;
}
private:
uint16_t _interval; /**< Scan interval in units of 625us (between 2.5ms and 10.24s). */
uint16_t _window; /**< Scan window in units of 625us (between 2.5ms and 10.24s). */
uint16_t _timeout; /**< Scan timeout between 0x0001 and 0xFFFF in seconds; 0x0000 disables timeout. */
bool _activeScanning; /**< Obtain the peer device's advertising data and (if possible) scanResponse. */
private:
/* Disallow copy constructor. */
GapScanningParams(const GapScanningParams &);
GapScanningParams& operator =(const GapScanningParams &in);
};
#endif /* ifndef __GAP_SCANNING_PARAMS_H__ */

174
ble/GattAttribute.h Normal file
View File

@ -0,0 +1,174 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GATT_ATTRIBUTE_H__
#define __GATT_ATTRIBUTE_H__
#include "UUID.h"
/**
* Instances of this class encapsulate the data that belongs to a Bluetooth Low
* Energy attribute.
*/
class GattAttribute {
public:
/**
* Type for the handle or ID of the attribute in the ATT table. These are
* unique and are usually generated by the underlying BLE stack.
*/
typedef uint16_t Handle_t;
/**
* Define the value of an invalid attribute handle.
*/
static const Handle_t INVALID_HANDLE = 0x0000;
public:
/**
* @brief Creates a new GattAttribute using the specified
* UUID, value length, and inital value.
*
* @param[in] uuid
* The UUID to use for this attribute.
* @param[in] valuePtr
* The memory holding the initial value.
* @param[in] len
* The length in bytes of this attribute's value.
* @param[in] maxLen
* The max length in bytes of this attribute's value.
* @param[in] hasVariableLen
* Whether the attribute's value length changes overtime.
*
* @section EXAMPLE
*
* @code
*
* // UUID = 0x2A19, Min length 2, Max len = 2
* GattAttribute attr = GattAttribute(0x2A19, &someValue, 2, 2);
*
* @endcode
*/
GattAttribute(const UUID &uuid, uint8_t *valuePtr = NULL, uint16_t len = 0, uint16_t maxLen = 0, bool hasVariableLen = true) :
_uuid(uuid), _valuePtr(valuePtr), _lenMax(maxLen), _len(len), _hasVariableLen(hasVariableLen), _handle() {
/* Empty */
}
public:
/**
* Get the attribute's handle in the ATT table.
*
* @return The attribute's handle.
*/
Handle_t getHandle(void) const {
return _handle;
}
/**
* The UUID of the characteristic that this attribute belongs to.
*
* @return The characteristic's UUID.
*/
const UUID &getUUID(void) const {
return _uuid;
}
/**
* Get the current length of the attribute value.
*
* @return The current length of the attribute value.
*/
uint16_t getLength(void) const {
return _len;
}
/**
* Get the maximum length of the attribute value.
*
* The maximum length of the attribute value.
*/
uint16_t getMaxLength(void) const {
return _lenMax;
}
/**
* Get a pointer to the current length of the attribute value.
*
* @return A pointer to the current length of the attribute value.
*/
uint16_t *getLengthPtr(void) {
return &_len;
}
/**
* Set the attribute handle.
*
* @param[in] id
* The new attribute handle.
*/
void setHandle(Handle_t id) {
_handle = id;
}
/**
* Get a pointer to the attribute value.
*
* @return A pointer to the attribute value.
*/
uint8_t *getValuePtr(void) {
return _valuePtr;
}
/**
* Check whether the length of the attribute's value can change over time.
*
* @return true if the attribute has variable length, false otherwise.
*/
bool hasVariableLength(void) const {
return _hasVariableLen;
}
private:
/**
* Characteristic's UUID.
*/
UUID _uuid;
/**
* Pointer to the attribute's value.
*/
uint8_t *_valuePtr;
/**
* Maximum length of the value pointed to by GattAttribute::_valuePtr.
*/
uint16_t _lenMax;
/**
* Current length of the value pointed to by GattAttribute::_valuePtr.
*/
uint16_t _len;
/**
* Whether the length of the value can change over time.
*/
bool _hasVariableLen;
/**
* The attribute's handle in the ATT table.
*/
Handle_t _handle;
private:
/* Disallow copy and assignment. */
GattAttribute(const GattAttribute &);
GattAttribute& operator=(const GattAttribute &);
};
#endif /* ifndef __GATT_ATTRIBUTE_H__ */

View File

@ -0,0 +1,115 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GATT_CALLBACK_PARAM_TYPES_H__
#define __GATT_CALLBACK_PARAM_TYPES_H__
struct GattWriteCallbackParams {
/**
* Enumeration for write operations.
*/
enum WriteOp_t {
OP_INVALID = 0x00, /**< Invalid operation. */
OP_WRITE_REQ = 0x01, /**< Write request. */
OP_WRITE_CMD = 0x02, /**< Write command. */
OP_SIGN_WRITE_CMD = 0x03, /**< Signed write command. */
OP_PREP_WRITE_REQ = 0x04, /**< Prepare write request. */
OP_EXEC_WRITE_REQ_CANCEL = 0x05, /**< Execute write request: cancel all prepared writes. */
OP_EXEC_WRITE_REQ_NOW = 0x06, /**< Execute write request: immediately execute all prepared writes. */
};
Gap::Handle_t connHandle; /**< The handle of the connection that triggered the event */
GattAttribute::Handle_t handle; /**< Attribute Handle to which the write operation applies. */
WriteOp_t writeOp; /**< Type of write operation. */
uint16_t offset; /**< Offset for the write operation. */
uint16_t len; /**< Length (in bytes) of the data to write. */
/**
* Pointer to the data to write.
*
* @note Data might not persist beyond the callback; make a local copy if
* needed.
*/
const uint8_t *data;
};
struct GattReadCallbackParams {
Gap::Handle_t connHandle; /**< The handle of the connection that triggered the event */
GattAttribute::Handle_t handle; /**< Attribute Handle to which the read operation applies. */
uint16_t offset; /**< Offset for the read operation. */
uint16_t len; /**< Length (in bytes) of the data to read. */
/**
* Pointer to the data read.
*
* @note Data might not persist beyond the callback; make a local copy if
* needed.
*/
const uint8_t *data;
};
enum GattAuthCallbackReply_t {
AUTH_CALLBACK_REPLY_SUCCESS = 0x00, /**< Success. */
AUTH_CALLBACK_REPLY_ATTERR_INVALID_HANDLE = 0x0101, /**< ATT Error: Invalid attribute handle. */
AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED = 0x0102, /**< ATT Error: Read not permitted. */
AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED = 0x0103, /**< ATT Error: Write not permitted. */
AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHENTICATION = 0x0105, /**< ATT Error: Authenticated link required. */
AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET = 0x0107, /**< ATT Error: The specified offset was past the end of the attribute. */
AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION = 0x0108, /**< ATT Error: Used in ATT as "insufficient authorization". */
AUTH_CALLBACK_REPLY_ATTERR_PREPARE_QUEUE_FULL = 0x0109, /**< ATT Error: Used in ATT as "prepare queue full". */
AUTH_CALLBACK_REPLY_ATTERR_ATTRIBUTE_NOT_FOUND = 0x010A, /**< ATT Error: Used in ATT as "attribute not found". */
AUTH_CALLBACK_REPLY_ATTERR_ATTRIBUTE_NOT_LONG = 0x010B, /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */
AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH = 0x010D, /**< ATT Error: Invalid value size. */
AUTH_CALLBACK_REPLY_ATTERR_INSUF_RESOURCES = 0x0111, /**< ATT Error: Encrypted link required. */
};
struct GattWriteAuthCallbackParams {
Gap::Handle_t connHandle; /**< The handle of the connection that triggered the event */
GattAttribute::Handle_t handle; /**< Attribute Handle to which the write operation applies. */
uint16_t offset; /**< Offset for the write operation. */
uint16_t len; /**< Length of the incoming data. */
const uint8_t *data; /**< Incoming data, variable length. */
/**
* This is the out parameter that the callback needs to set to
* AUTH_CALLBACK_REPLY_SUCCESS for the request to proceed.
*/
GattAuthCallbackReply_t authorizationReply;
};
struct GattReadAuthCallbackParams {
Gap::Handle_t connHandle; /**< The handle of the connection that triggered the event */
GattAttribute::Handle_t handle; /**< Attribute Handle to which the read operation applies. */
uint16_t offset; /**< Offset for the read operation. */
uint16_t len; /**< Optional: new length of the outgoing data. */
uint8_t *data; /**< Optional: new outgoing data. Leave at NULL if data is unchanged. */
/**
* This is the out parameter that the callback needs to set to
* AUTH_CALLBACK_REPLY_SUCCESS for the request to proceed.
*/
GattAuthCallbackReply_t authorizationReply;
};
/**
* For encapsulating handle-value update events (notifications or indications)
* generated at the remote server.
*/
struct GattHVXCallbackParams {
Gap::Handle_t connHandle; /**< The handle of the connection that triggered the event */
GattAttribute::Handle_t handle; /**< Attribute Handle to which the HVx operation applies. */
HVXType_t type; /**< Indication or Notification, see HVXType_t. */
uint16_t len; /**< Attribute data length. */
const uint8_t *data; /**< Attribute data, variable length. */
};
#endif /*__GATT_CALLBACK_PARAM_TYPES_H__*/

855
ble/GattCharacteristic.h Normal file
View File

@ -0,0 +1,855 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GATT_CHARACTERISTIC_H__
#define __GATT_CHARACTERISTIC_H__
#include "Gap.h"
#include "SecurityManager.h"
#include "GattAttribute.h"
#include "GattCallbackParamTypes.h"
#include "FunctionPointerWithContext.h"
class GattCharacteristic {
public:
enum {
UUID_BATTERY_LEVEL_STATE_CHAR = 0x2A1B,
UUID_BATTERY_POWER_STATE_CHAR = 0x2A1A,
UUID_REMOVABLE_CHAR = 0x2A3A,
UUID_SERVICE_REQUIRED_CHAR = 0x2A3B,
UUID_ALERT_CATEGORY_ID_CHAR = 0x2A43,
UUID_ALERT_CATEGORY_ID_BIT_MASK_CHAR = 0x2A42,
UUID_ALERT_LEVEL_CHAR = 0x2A06,
UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR = 0x2A44,
UUID_ALERT_STATUS_CHAR = 0x2A3F,
UUID_BATTERY_LEVEL_CHAR = 0x2A19,
UUID_BLOOD_PRESSURE_FEATURE_CHAR = 0x2A49,
UUID_BLOOD_PRESSURE_MEASUREMENT_CHAR = 0x2A35,
UUID_BODY_SENSOR_LOCATION_CHAR = 0x2A38,
UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR = 0x2A22,
UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR = 0x2A32,
UUID_BOOT_MOUSE_INPUT_REPORT_CHAR = 0x2A33,
UUID_CURRENT_TIME_CHAR = 0x2A2B,
UUID_DATE_TIME_CHAR = 0x2A08,
UUID_DAY_DATE_TIME_CHAR = 0x2A0A,
UUID_DAY_OF_WEEK_CHAR = 0x2A09,
UUID_DST_OFFSET_CHAR = 0x2A0D,
UUID_EXACT_TIME_256_CHAR = 0x2A0C,
UUID_FIRMWARE_REVISION_STRING_CHAR = 0x2A26,
UUID_GLUCOSE_FEATURE_CHAR = 0x2A51,
UUID_GLUCOSE_MEASUREMENT_CHAR = 0x2A18,
UUID_GLUCOSE_MEASUREMENT_CONTEXT_CHAR = 0x2A34,
UUID_HARDWARE_REVISION_STRING_CHAR = 0x2A27,
UUID_HEART_RATE_CONTROL_POINT_CHAR = 0x2A39,
UUID_HEART_RATE_MEASUREMENT_CHAR = 0x2A37,
UUID_HID_CONTROL_POINT_CHAR = 0x2A4C,
UUID_HID_INFORMATION_CHAR = 0x2A4A,
UUID_HUMIDITY_CHAR = 0x2A6F,
UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR = 0x2A2A,
UUID_INTERMEDIATE_CUFF_PRESSURE_CHAR = 0x2A36,
UUID_INTERMEDIATE_TEMPERATURE_CHAR = 0x2A1E,
UUID_LOCAL_TIME_INFORMATION_CHAR = 0x2A0F,
UUID_MANUFACTURER_NAME_STRING_CHAR = 0x2A29,
UUID_MEASUREMENT_INTERVAL_CHAR = 0x2A21,
UUID_MODEL_NUMBER_STRING_CHAR = 0x2A24,
UUID_UNREAD_ALERT_CHAR = 0x2A45,
UUID_NEW_ALERT_CHAR = 0x2A46,
UUID_PNP_ID_CHAR = 0x2A50,
UUID_PRESSURE_CHAR = 0x2A6D,
UUID_PROTOCOL_MODE_CHAR = 0x2A4E,
UUID_RECORD_ACCESS_CONTROL_POINT_CHAR = 0x2A52,
UUID_REFERENCE_TIME_INFORMATION_CHAR = 0x2A14,
UUID_REPORT_CHAR = 0x2A4D,
UUID_REPORT_MAP_CHAR = 0x2A4B,
UUID_RINGER_CONTROL_POINT_CHAR = 0x2A40,
UUID_RINGER_SETTING_CHAR = 0x2A41,
UUID_SCAN_INTERVAL_WINDOW_CHAR = 0x2A4F,
UUID_SCAN_REFRESH_CHAR = 0x2A31,
UUID_SERIAL_NUMBER_STRING_CHAR = 0x2A25,
UUID_SOFTWARE_REVISION_STRING_CHAR = 0x2A28,
UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR = 0x2A47,
UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR = 0x2A48,
UUID_SYSTEM_ID_CHAR = 0x2A23,
UUID_TEMPERATURE_CHAR = 0x2A6E,
UUID_TEMPERATURE_MEASUREMENT_CHAR = 0x2A1C,
UUID_TEMPERATURE_TYPE_CHAR = 0x2A1D,
UUID_TIME_ACCURACY_CHAR = 0x2A12,
UUID_TIME_SOURCE_CHAR = 0x2A13,
UUID_TIME_UPDATE_CONTROL_POINT_CHAR = 0x2A16,
UUID_TIME_UPDATE_STATE_CHAR = 0x2A17,
UUID_TIME_WITH_DST_CHAR = 0x2A11,
UUID_TIME_ZONE_CHAR = 0x2A0E,
UUID_TX_POWER_LEVEL_CHAR = 0x2A07,
UUID_CSC_FEATURE_CHAR = 0x2A5C,
UUID_CSC_MEASUREMENT_CHAR = 0x2A5B,
UUID_RSC_FEATURE_CHAR = 0x2A54,
UUID_RSC_MEASUREMENT_CHAR = 0x2A53
};
/**
* @brief Standard GATT characteristic presentation format unit types.
* These unit types are used to describe what the raw numeric
* data in a characteristic actually represents.
*
* @note See https://developer.bluetooth.org/gatt/units/Pages/default.aspx
*/
enum {
BLE_GATT_UNIT_NONE = 0x2700, /**< No specified unit type. */
BLE_GATT_UNIT_LENGTH_METRE = 0x2701, /**< Length, metre. */
BLE_GATT_UNIT_MASS_KILOGRAM = 0x2702, /**< Mass, kilogram. */
BLE_GATT_UNIT_TIME_SECOND = 0x2703, /**< Time, second. */
BLE_GATT_UNIT_ELECTRIC_CURRENT_AMPERE = 0x2704, /**< Electric current, ampere. */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_KELVIN = 0x2705, /**< Thermodynamic temperature, kelvin. */
BLE_GATT_UNIT_AMOUNT_OF_SUBSTANCE_MOLE = 0x2706, /**< Amount of substance, mole. */
BLE_GATT_UNIT_LUMINOUS_INTENSITY_CANDELA = 0x2707, /**< Luminous intensity, candela. */
BLE_GATT_UNIT_AREA_SQUARE_METRES = 0x2710, /**< Area, square metres. */
BLE_GATT_UNIT_VOLUME_CUBIC_METRES = 0x2711, /**< Volume, cubic metres. */
BLE_GATT_UNIT_VELOCITY_METRES_PER_SECOND = 0x2712, /**< Velocity, metres per second. */
BLE_GATT_UNIT_ACCELERATION_METRES_PER_SECOND_SQUARED = 0x2713, /**< Acceleration, metres per second squared. */
BLE_GATT_UNIT_WAVENUMBER_RECIPROCAL_METRE = 0x2714, /**< Wave number reciprocal, metre. */
BLE_GATT_UNIT_DENSITY_KILOGRAM_PER_CUBIC_METRE = 0x2715, /**< Density, kilogram per cubic metre. */
BLE_GATT_UNIT_SURFACE_DENSITY_KILOGRAM_PER_SQUARE_METRE = 0x2716, /**< */
BLE_GATT_UNIT_SPECIFIC_VOLUME_CUBIC_METRE_PER_KILOGRAM = 0x2717, /**< */
BLE_GATT_UNIT_CURRENT_DENSITY_AMPERE_PER_SQUARE_METRE = 0x2718, /**< */
BLE_GATT_UNIT_MAGNETIC_FIELD_STRENGTH_AMPERE_PER_METRE = 0x2719, /**< Magnetic field strength, ampere per metre. */
BLE_GATT_UNIT_AMOUNT_CONCENTRATION_MOLE_PER_CUBIC_METRE = 0x271A, /**< */
BLE_GATT_UNIT_MASS_CONCENTRATION_KILOGRAM_PER_CUBIC_METRE = 0x271B, /**< */
BLE_GATT_UNIT_LUMINANCE_CANDELA_PER_SQUARE_METRE = 0x271C, /**< */
BLE_GATT_UNIT_REFRACTIVE_INDEX = 0x271D, /**< */
BLE_GATT_UNIT_RELATIVE_PERMEABILITY = 0x271E, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_RADIAN = 0x2720, /**< */
BLE_GATT_UNIT_SOLID_ANGLE_STERADIAN = 0x2721, /**< */
BLE_GATT_UNIT_FREQUENCY_HERTZ = 0x2722, /**< Frequency, hertz. */
BLE_GATT_UNIT_FORCE_NEWTON = 0x2723, /**< Force, newton. */
BLE_GATT_UNIT_PRESSURE_PASCAL = 0x2724, /**< Pressure, pascal. */
BLE_GATT_UNIT_ENERGY_JOULE = 0x2725, /**< Energy, joule. */
BLE_GATT_UNIT_POWER_WATT = 0x2726, /**< Power, watt. */
BLE_GATT_UNIT_ELECTRIC_CHARGE_COULOMB = 0x2727, /**< Electrical charge, coulomb. */
BLE_GATT_UNIT_ELECTRIC_POTENTIAL_DIFFERENCE_VOLT = 0x2728, /**< Electrical potential difference, voltage. */
BLE_GATT_UNIT_CAPACITANCE_FARAD = 0x2729, /**< */
BLE_GATT_UNIT_ELECTRIC_RESISTANCE_OHM = 0x272A, /**< */
BLE_GATT_UNIT_ELECTRIC_CONDUCTANCE_SIEMENS = 0x272B, /**< */
BLE_GATT_UNIT_MAGNETIC_FLEX_WEBER = 0x272C, /**< */
BLE_GATT_UNIT_MAGNETIC_FLEX_DENSITY_TESLA = 0x272D, /**< */
BLE_GATT_UNIT_INDUCTANCE_HENRY = 0x272E, /**< */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_CELSIUS = 0x272F, /**< */
BLE_GATT_UNIT_LUMINOUS_FLUX_LUMEN = 0x2730, /**< */
BLE_GATT_UNIT_ILLUMINANCE_LUX = 0x2731, /**< */
BLE_GATT_UNIT_ACTIVITY_REFERRED_TO_A_RADIONUCLIDE_BECQUEREL = 0x2732, /**< */
BLE_GATT_UNIT_ABSORBED_DOSE_GRAY = 0x2733, /**< */
BLE_GATT_UNIT_DOSE_EQUIVALENT_SIEVERT = 0x2734, /**< */
BLE_GATT_UNIT_CATALYTIC_ACTIVITY_KATAL = 0x2735, /**< */
BLE_GATT_UNIT_DYNAMIC_VISCOSITY_PASCAL_SECOND = 0x2740, /**< */
BLE_GATT_UNIT_MOMENT_OF_FORCE_NEWTON_METRE = 0x2741, /**< */
BLE_GATT_UNIT_SURFACE_TENSION_NEWTON_PER_METRE = 0x2742, /**< */
BLE_GATT_UNIT_ANGULAR_VELOCITY_RADIAN_PER_SECOND = 0x2743, /**< */
BLE_GATT_UNIT_ANGULAR_ACCELERATION_RADIAN_PER_SECOND_SQUARED = 0x2744, /**< */
BLE_GATT_UNIT_HEAT_FLUX_DENSITY_WATT_PER_SQUARE_METRE = 0x2745, /**< */
BLE_GATT_UNIT_HEAT_CAPACITY_JOULE_PER_KELVIN = 0x2746, /**< */
BLE_GATT_UNIT_SPECIFIC_HEAT_CAPACITY_JOULE_PER_KILOGRAM_KELVIN = 0x2747, /**< */
BLE_GATT_UNIT_SPECIFIC_ENERGY_JOULE_PER_KILOGRAM = 0x2748, /**< */
BLE_GATT_UNIT_THERMAL_CONDUCTIVITY_WATT_PER_METRE_KELVIN = 0x2749, /**< */
BLE_GATT_UNIT_ENERGY_DENSITY_JOULE_PER_CUBIC_METRE = 0x274A, /**< */
BLE_GATT_UNIT_ELECTRIC_FIELD_STRENGTH_VOLT_PER_METRE = 0x274B, /**< */
BLE_GATT_UNIT_ELECTRIC_CHARGE_DENSITY_COULOMB_PER_CUBIC_METRE = 0x274C, /**< */
BLE_GATT_UNIT_SURFACE_CHARGE_DENSITY_COULOMB_PER_SQUARE_METRE = 0x274D, /**< */
BLE_GATT_UNIT_ELECTRIC_FLUX_DENSITY_COULOMB_PER_SQUARE_METRE = 0x274E, /**< */
BLE_GATT_UNIT_PERMITTIVITY_FARAD_PER_METRE = 0x274F, /**< */
BLE_GATT_UNIT_PERMEABILITY_HENRY_PER_METRE = 0x2750, /**< */
BLE_GATT_UNIT_MOLAR_ENERGY_JOULE_PER_MOLE = 0x2751, /**< */
BLE_GATT_UNIT_MOLAR_ENTROPY_JOULE_PER_MOLE_KELVIN = 0x2752, /**< */
BLE_GATT_UNIT_EXPOSURE_COULOMB_PER_KILOGRAM = 0x2753, /**< */
BLE_GATT_UNIT_ABSORBED_DOSE_RATE_GRAY_PER_SECOND = 0x2754, /**< */
BLE_GATT_UNIT_RADIANT_INTENSITY_WATT_PER_STERADIAN = 0x2755, /**< */
BLE_GATT_UNIT_RADIANCE_WATT_PER_SQUARE_METRE_STERADIAN = 0x2756, /**< */
BLE_GATT_UNIT_CATALYTIC_ACTIVITY_CONCENTRATION_KATAL_PER_CUBIC_METRE = 0x2757, /**< */
BLE_GATT_UNIT_TIME_MINUTE = 0x2760, /**< Time, minute. */
BLE_GATT_UNIT_TIME_HOUR = 0x2761, /**< Time, hour. */
BLE_GATT_UNIT_TIME_DAY = 0x2762, /**< Time, day. */
BLE_GATT_UNIT_PLANE_ANGLE_DEGREE = 0x2763, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_MINUTE = 0x2764, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_SECOND = 0x2765, /**< */
BLE_GATT_UNIT_AREA_HECTARE = 0x2766, /**< */
BLE_GATT_UNIT_VOLUME_LITRE = 0x2767, /**< */
BLE_GATT_UNIT_MASS_TONNE = 0x2768, /**< */
BLE_GATT_UNIT_PRESSURE_BAR = 0x2780, /**< Pressure, bar. */
BLE_GATT_UNIT_PRESSURE_MILLIMETRE_OF_MERCURY = 0x2781, /**< Pressure, millimetre of mercury. */
BLE_GATT_UNIT_LENGTH_ANGSTROM = 0x2782, /**< */
BLE_GATT_UNIT_LENGTH_NAUTICAL_MILE = 0x2783, /**< */
BLE_GATT_UNIT_AREA_BARN = 0x2784, /**< */
BLE_GATT_UNIT_VELOCITY_KNOT = 0x2785, /**< */
BLE_GATT_UNIT_LOGARITHMIC_RADIO_QUANTITY_NEPER = 0x2786, /**< */
BLE_GATT_UNIT_LOGARITHMIC_RADIO_QUANTITY_BEL = 0x2787, /**< */
BLE_GATT_UNIT_LENGTH_YARD = 0x27A0, /**< Length, yard. */
BLE_GATT_UNIT_LENGTH_PARSEC = 0x27A1, /**< Length, parsec. */
BLE_GATT_UNIT_LENGTH_INCH = 0x27A2, /**< Length, inch. */
BLE_GATT_UNIT_LENGTH_FOOT = 0x27A3, /**< Length, foot. */
BLE_GATT_UNIT_LENGTH_MILE = 0x27A4, /**< Length, mile. */
BLE_GATT_UNIT_PRESSURE_POUND_FORCE_PER_SQUARE_INCH = 0x27A5, /**< */
BLE_GATT_UNIT_VELOCITY_KILOMETRE_PER_HOUR = 0x27A6, /**< Velocity, kilometre per hour. */
BLE_GATT_UNIT_VELOCITY_MILE_PER_HOUR = 0x27A7, /**< Velocity, mile per hour. */
BLE_GATT_UNIT_ANGULAR_VELOCITY_REVOLUTION_PER_MINUTE = 0x27A8, /**< Angular Velocity, revolution per minute. */
BLE_GATT_UNIT_ENERGY_GRAM_CALORIE = 0x27A9, /**< Energy, gram calorie. */
BLE_GATT_UNIT_ENERGY_KILOGRAM_CALORIE = 0x27AA, /**< Energy, kilogram calorie. */
BLE_GATT_UNIT_ENERGY_KILOWATT_HOUR = 0x27AB, /**< Energy, killowatt hour. */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_FAHRENHEIT = 0x27AC, /**< */
BLE_GATT_UNIT_PERCENTAGE = 0x27AD, /**< Percentage. */
BLE_GATT_UNIT_PER_MILLE = 0x27AE, /**< */
BLE_GATT_UNIT_PERIOD_BEATS_PER_MINUTE = 0x27AF, /**< */
BLE_GATT_UNIT_ELECTRIC_CHARGE_AMPERE_HOURS = 0x27B0, /**< */
BLE_GATT_UNIT_MASS_DENSITY_MILLIGRAM_PER_DECILITRE = 0x27B1, /**< */
BLE_GATT_UNIT_MASS_DENSITY_MILLIMOLE_PER_LITRE = 0x27B2, /**< */
BLE_GATT_UNIT_TIME_YEAR = 0x27B3, /**< Time, year. */
BLE_GATT_UNIT_TIME_MONTH = 0x27B4, /**< Time, month. */
BLE_GATT_UNIT_CONCENTRATION_COUNT_PER_CUBIC_METRE = 0x27B5, /**< */
BLE_GATT_UNIT_IRRADIANCE_WATT_PER_SQUARE_METRE = 0x27B6 /**< */
};
/**
* @brief Standard GATT number types.
*
* @note See Bluetooth Specification 4.0 (Vol. 3), Part G, Section 3.3.3.5.2.
*
* @note See http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
*/
enum {
BLE_GATT_FORMAT_RFU = 0x00, /**< Reserved for future use. */
BLE_GATT_FORMAT_BOOLEAN = 0x01, /**< Boolean. */
BLE_GATT_FORMAT_2BIT = 0x02, /**< Unsigned 2-bit integer. */
BLE_GATT_FORMAT_NIBBLE = 0x03, /**< Unsigned 4-bit integer. */
BLE_GATT_FORMAT_UINT8 = 0x04, /**< Unsigned 8-bit integer. */
BLE_GATT_FORMAT_UINT12 = 0x05, /**< Unsigned 12-bit integer. */
BLE_GATT_FORMAT_UINT16 = 0x06, /**< Unsigned 16-bit integer. */
BLE_GATT_FORMAT_UINT24 = 0x07, /**< Unsigned 24-bit integer. */
BLE_GATT_FORMAT_UINT32 = 0x08, /**< Unsigned 32-bit integer. */
BLE_GATT_FORMAT_UINT48 = 0x09, /**< Unsigned 48-bit integer. */
BLE_GATT_FORMAT_UINT64 = 0x0A, /**< Unsigned 64-bit integer. */
BLE_GATT_FORMAT_UINT128 = 0x0B, /**< Unsigned 128-bit integer. */
BLE_GATT_FORMAT_SINT8 = 0x0C, /**< Signed 2-bit integer. */
BLE_GATT_FORMAT_SINT12 = 0x0D, /**< Signed 12-bit integer. */
BLE_GATT_FORMAT_SINT16 = 0x0E, /**< Signed 16-bit integer. */
BLE_GATT_FORMAT_SINT24 = 0x0F, /**< Signed 24-bit integer. */
BLE_GATT_FORMAT_SINT32 = 0x10, /**< Signed 32-bit integer. */
BLE_GATT_FORMAT_SINT48 = 0x11, /**< Signed 48-bit integer. */
BLE_GATT_FORMAT_SINT64 = 0x12, /**< Signed 64-bit integer. */
BLE_GATT_FORMAT_SINT128 = 0x13, /**< Signed 128-bit integer. */
BLE_GATT_FORMAT_FLOAT32 = 0x14, /**< IEEE-754 32-bit floating point. */
BLE_GATT_FORMAT_FLOAT64 = 0x15, /**< IEEE-754 64-bit floating point. */
BLE_GATT_FORMAT_SFLOAT = 0x16, /**< IEEE-11073 16-bit SFLOAT. */
BLE_GATT_FORMAT_FLOAT = 0x17, /**< IEEE-11073 32-bit FLOAT. */
BLE_GATT_FORMAT_DUINT16 = 0x18, /**< IEEE-20601 format. */
BLE_GATT_FORMAT_UTF8S = 0x19, /**< UTF-8 string. */
BLE_GATT_FORMAT_UTF16S = 0x1A, /**< UTF-16 string. */
BLE_GATT_FORMAT_STRUCT = 0x1B /**< Opaque Structure. */
};
/*!
* @brief Standard GATT characteristic properties.
*
* @note See Bluetooth Specification 4.0 (Vol. 3), Part G, Section 3.3.1.1
* and Section 3.3.3.1 for Extended Properties.
*/
enum Properties_t {
BLE_GATT_CHAR_PROPERTIES_NONE = 0x00,
BLE_GATT_CHAR_PROPERTIES_BROADCAST = 0x01, /**< Permits broadcasts of the characteristic value using the Server Characteristic Configuration descriptor. */
BLE_GATT_CHAR_PROPERTIES_READ = 0x02, /**< Permits reads of the characteristic value. */
BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE = 0x04, /**< Permits writes of the characteristic value without response. */
BLE_GATT_CHAR_PROPERTIES_WRITE = 0x08, /**< Permits writes of the characteristic value with response. */
BLE_GATT_CHAR_PROPERTIES_NOTIFY = 0x10, /**< Permits notifications of a characteristic value without acknowledgment. */
BLE_GATT_CHAR_PROPERTIES_INDICATE = 0x20, /**< Permits indications of a characteristic value with acknowledgment. */
BLE_GATT_CHAR_PROPERTIES_AUTHENTICATED_SIGNED_WRITES = 0x40, /**< Permits signed writes to the characteristic value. */
BLE_GATT_CHAR_PROPERTIES_EXTENDED_PROPERTIES = 0x80 /**< Additional characteristic properties are defined in the Characteristic Extended Properties descriptor */
};
/**
* @brief GATT presentation format wrapper.
*
* @note See Bluetooth Specification 4.0 (Vol. 3), Part G, Section 3.3.3.5.
*
* @note See https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
*/
struct PresentationFormat_t {
uint8_t gatt_format; /**< Format of the value. */
int8_t exponent; /**< Exponent for integer data types. Example: if Exponent = -3 and the char value is 3892, the actual value is 3.892 */
uint16_t gatt_unit; /**< UUID from Bluetooth Assigned Numbers. */
uint8_t gatt_namespace; /**< Namespace from Bluetooth Assigned Numbers, normally '1'. */
uint16_t gatt_nsdesc; /**< Namespace description from Bluetooth Assigned Numbers, normally '0'. */
};
/**
* @brief Creates a new GattCharacteristic using the specified 16-bit
* UUID, value length, and properties.
*
* @param[in] uuid
* The UUID to use for this characteristic.
* @param[in] valuePtr
* The memory holding the initial value. The value is copied
* into the stack when the enclosing service is added, and
* is thereafter maintained internally by the stack.
* @param[in] len
* The length in bytes of this characteristic's value.
* @param[in] maxLen
* The max length in bytes of this characteristic's value.
* @param[in] props
* The 8-bit field containing the characteristic's properties.
* @param[in] descriptors
* A pointer to an array of descriptors to be included within
* this characteristic. The memory for the descriptor array is
* owned by the caller, and should remain valid at least until
* the enclosing service is added to the GATT table.
* @param[in] numDescriptors
* The number of descriptors in the previous array.
* @param[in] hasVariableLen
* Whether the attribute's value length changes over time.
*
* @note The UUID value must be unique in the service and is normally >1.
*
* @note If valuePtr == NULL, length == 0, and properties == READ
* for the value attribute of a characteristic, then that particular
* characteristic may be considered optional and dropped while
* instantiating the service with the underlying BLE stack.
*/
GattCharacteristic(const UUID &uuid,
uint8_t *valuePtr = NULL,
uint16_t len = 0,
uint16_t maxLen = 0,
uint8_t props = BLE_GATT_CHAR_PROPERTIES_NONE,
GattAttribute *descriptors[] = NULL,
unsigned numDescriptors = 0,
bool hasVariableLen = true) :
_valueAttribute(uuid, valuePtr, len, maxLen, hasVariableLen),
_properties(props),
_requiredSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK),
_descriptors(descriptors),
_descriptorCount(numDescriptors),
enabledReadAuthorization(false),
enabledWriteAuthorization(false),
readAuthorizationCallback(),
writeAuthorizationCallback() {
/* empty */
}
public:
/**
* Set up the minimum security (mode and level) requirements for access to
* the characteristic's value attribute.
*
* @param[in] securityMode
* Can be one of encryption or signing, with or without
* protection for man in the middle attacks (MITM).
*/
void requireSecurity(SecurityManager::SecurityMode_t securityMode) {
_requiredSecurity = securityMode;
}
public:
/**
* Set up callback that will be triggered before the GATT Client is allowed
* to write this characteristic. The handler will determine the
* authorization reply for the write.
*
* @param[in] callback
* Event handler being registered.
*/
void setWriteAuthorizationCallback(void (*callback)(GattWriteAuthCallbackParams *)) {
writeAuthorizationCallback.attach(callback);
enabledWriteAuthorization = true;
}
/**
* Same as GattCharacrteristic::setWriteAuthorizationCallback(), but allows
* the possibility to add an object reference and member function as
* handler for connection event callbacks.
*
* @param[in] object
* Pointer to the object of a class defining the member callback
* function (@p member).
* @param[in] member
* The member callback (within the context of an object) to be
* invoked.
*/
template <typename T>
void setWriteAuthorizationCallback(T *object, void (T::*member)(GattWriteAuthCallbackParams *)) {
writeAuthorizationCallback.attach(object, member);
enabledWriteAuthorization = true;
}
/**
* Set up callback that will be triggered before the GATT Client is allowed
* to read this characteristic. The handler will determine the
* authorizaion reply for the read.
*
* @param[in] callback
* Event handler being registered.
*/
void setReadAuthorizationCallback(void (*callback)(GattReadAuthCallbackParams *)) {
readAuthorizationCallback.attach(callback);
enabledReadAuthorization = true;
}
/**
* Same as GattCharacrteristic::setReadAuthorizationCallback(), but allows
* the possibility to add an object reference and member function as
* handler for connection event callbacks.
*
* @param[in] object
* Pointer to the object of a class defining the member callback
* function (@p member).
* @param[in] member
* The member callback (within the context of an object) to be
* invoked.
*/
template <typename T>
void setReadAuthorizationCallback(T *object, void (T::*member)(GattReadAuthCallbackParams *)) {
readAuthorizationCallback.attach(object, member);
enabledReadAuthorization = true;
}
/**
* Helper that calls the registered handler to determine the authorization
* reply for a write request. This function is meant to be called from the
* BLE stack specific implementation.
*
* @param[in] params
* To capture the context of the write-auth request. Also
* contains an out-parameter for reply.
*
* @return A GattAuthCallbackReply_t value indicating whether authorization
* is granted.
*/
GattAuthCallbackReply_t authorizeWrite(GattWriteAuthCallbackParams *params) {
if (!isWriteAuthorizationEnabled()) {
return AUTH_CALLBACK_REPLY_SUCCESS;
}
params->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS; /* Initialized to no-error by default. */
writeAuthorizationCallback.call(params);
return params->authorizationReply;
}
/**
* Helper that calls the registered handler to determine the authorization
* reply for a read request. This function is meant to be called from the
* BLE stack specific implementation.
*
* @param[in] params
* To capture the context of the read-auth request.
*
* @return A GattAuthCallbackReply_t value indicating whether authorization
* is granted.
*
* @note To authorize or deny the read the params->authorizationReply field
* should be set to true (authorize) or false (deny).
*
* @note If the read is approved and params->data is unchanged (NULL),
* the current characteristic value will be used.
*
* @note If the read is approved, a new value can be provided by setting
* the params->data pointer and params->len fields.
*/
GattAuthCallbackReply_t authorizeRead(GattReadAuthCallbackParams *params) {
if (!isReadAuthorizationEnabled()) {
return AUTH_CALLBACK_REPLY_SUCCESS;
}
params->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS; /* Initialized to no-error by default. */
readAuthorizationCallback.call(params);
return params->authorizationReply;
}
public:
/**
* Get the characteristic's value attribute.
*
* @return A reference to the characteristic's value attribute.
*/
GattAttribute& getValueAttribute() {
return _valueAttribute;
}
/**
* A const alternative to GattCharacteristic::getValueAttribute().
*
* @return A const reference to the characteristic's value attribute.
*/
const GattAttribute& getValueAttribute() const {
return _valueAttribute;
}
/**
* Get the characteristic's value attribute handle in the ATT table.
*
* @return The value attribute handle.
*
* @note The attribute handle is typically assigned by the underlying BLE
* stack.
*/
GattAttribute::Handle_t getValueHandle(void) const {
return getValueAttribute().getHandle();
}
/**
* Get the characteristic's propertied. Refer to
* GattCharacteristic::Properties_t.
*
* @return The characteristic's properties.
*/
uint8_t getProperties(void) const {
return _properties;
}
/**
* Get the characteristic's required security.
*
* @return The characteristic's required security.
*/
SecurityManager::SecurityMode_t getRequiredSecurity() const {
return _requiredSecurity;
}
/**
* Get the total number of descriptors within this characteristic.
*
* @return The total number of descriptors.
*/
uint8_t getDescriptorCount(void) const {
return _descriptorCount;
}
/**
* Check whether read authorization is enabled i.e. check whether a
* read authorization callback was previously registered. Refer to
* GattCharacteristic::setReadAuthorizationCallback().
*
* @return true if read authorization is enabled, false otherwise.
*/
bool isReadAuthorizationEnabled() const {
return enabledReadAuthorization;
}
/**
* Check whether write authorization is enabled i.e. check whether a
* write authorization callback was previously registered. Refer to
* GattCharacteristic::setReadAuthorizationCallback().
*
* @return true if write authorization is enabled, false otherwise.
*/
bool isWriteAuthorizationEnabled() const {
return enabledWriteAuthorization;
}
/**
* Get this characteristic's descriptor at a specific index.
*
* @param[in] index
* The descriptor's index.
*
* @return A pointer the requested descriptor if @p index contains a valid
* descriptor, or NULL otherwise.
*/
GattAttribute *getDescriptor(uint8_t index) {
if (index >= _descriptorCount) {
return NULL;
}
return _descriptors[index];
}
private:
/**
* Attribute that contains the actual value of this characteristic.
*/
GattAttribute _valueAttribute;
/**
* The characteristic's properties. Refer to
* GattCharacteristic::Properties_t.
*/
uint8_t _properties;
/**
* The characteristic's required security.
*/
SecurityManager::SecurityMode_t _requiredSecurity;
/**
* The characteristic's descriptor attributes.
*/
GattAttribute **_descriptors;
/**
* The number of descriptors in this characteristic.
*/
uint8_t _descriptorCount;
/**
* Whether read authorization is enabled i.e. whether there is a registered
* callback to determine read authorization reply.
*/
bool enabledReadAuthorization;
/**
* Whether write authorization is enabled i.e. whether there is a registered
* callback to determine write authorization reply.
*/
bool enabledWriteAuthorization;
/**
* The registered callback handler for read authorization reply.
*/
FunctionPointerWithContext<GattReadAuthCallbackParams *> readAuthorizationCallback;
/**
* The registered callback handler for write authorization reply.
*/
FunctionPointerWithContext<GattWriteAuthCallbackParams *> writeAuthorizationCallback;
private:
/* Disallow copy and assignment. */
GattCharacteristic(const GattCharacteristic &);
GattCharacteristic& operator=(const GattCharacteristic &);
};
/**
* Helper class to construct a read-only GattCharacteristic.
*/
template <typename T>
class ReadOnlyGattCharacteristic : public GattCharacteristic {
public:
/**
* Construct a ReadOnlyGattCharacteristic.
*
* @param[in] uuid
* The characteristic's UUID.
* @param[in] valuePtr
* Pointer to the characterisitic's initial value.
* @param[in] additionalProperties
* Additional characterisitic properties. By default, the
* properties are set to
* Properties_t::BLE_GATT_CHAR_PROPERTIES_READ.
* @param[in] descriptors
* An array of pointers to descriptors to be added to the new
* characteristic.
* @param[in] numDescriptors
* The total number of descriptors in @p descriptors.
*
* @note Instances of ReadOnlyGattCharacteristic have a fixed length
* attribute value that equals sizeof(T). For a variable length
* alternative use GattCharacteristic directly.
*/
ReadOnlyGattCharacteristic<T>(const UUID &uuid,
T *valuePtr,
uint8_t additionalProperties = BLE_GATT_CHAR_PROPERTIES_NONE,
GattAttribute *descriptors[] = NULL,
unsigned numDescriptors = 0) :
GattCharacteristic(uuid, reinterpret_cast<uint8_t *>(valuePtr), sizeof(T), sizeof(T),
BLE_GATT_CHAR_PROPERTIES_READ | additionalProperties, descriptors, numDescriptors, false) {
/* empty */
}
};
/**
* Helper class to construct a write-only GattCharacteristic.
*/
template <typename T>
class WriteOnlyGattCharacteristic : public GattCharacteristic {
public:
/**
* Construct a WriteOnlyGattCharacteristic.
*
* @param[in] uuid
* The characteristic's UUID.
* @param[in] valuePtr
* Pointer to the characterisitic's initial value.
* @param[in] additionalProperties
* Additional characterisitic properties. By default, the
* properties are set to
* Properties_t::BLE_GATT_CHAR_PROPERTIES_WRITE.
* @param[in] descriptors
* An array of pointers to descriptors to be added to the new
* characteristic.
* @param[in] numDescriptors
* The total number of descriptors in @p descriptors.
*
* @note Instances of WriteOnlyGattCharacteristic have variable length
* attribute value with maximum size equal to sizeof(T). For a fixed length
* alternative use GattCharacteristic directly.
*/
WriteOnlyGattCharacteristic<T>(const UUID &uuid,
T *valuePtr,
uint8_t additionalProperties = BLE_GATT_CHAR_PROPERTIES_NONE,
GattAttribute *descriptors[] = NULL,
unsigned numDescriptors = 0) :
GattCharacteristic(uuid, reinterpret_cast<uint8_t *>(valuePtr), sizeof(T), sizeof(T),
BLE_GATT_CHAR_PROPERTIES_WRITE | additionalProperties, descriptors, numDescriptors) {
/* empty */
}
};
/**
* Helper class to construct a readable and writable GattCharacteristic.
*/
template <typename T>
class ReadWriteGattCharacteristic : public GattCharacteristic {
public:
/**
* Construct a ReadWriteGattCharacteristic.
*
* @param[in] uuid
* The characteristic's UUID.
* @param[in] valuePtr
* Pointer to the characterisitic's initial value.
* @param[in] additionalProperties
* Additional characterisitic properties. By default, the
* properties are set to
* Properties_t::BLE_GATT_CHAR_PROPERTIES_WRITE |
* Properties_t::BLE_GATT_CHAR_PROPERTIES_READ.
* @param[in] descriptors
* An array of pointers to descriptors to be added to the new
* characteristic.
* @param[in] numDescriptors
* The total number of descriptors in @p descriptors.
*
* @note Instances of ReadWriteGattCharacteristic have variable length
* attribute value with maximum size equal to sizeof(T). For a fixed length
* alternative use GattCharacteristic directly.
*/
ReadWriteGattCharacteristic<T>(const UUID &uuid,
T *valuePtr,
uint8_t additionalProperties = BLE_GATT_CHAR_PROPERTIES_NONE,
GattAttribute *descriptors[] = NULL,
unsigned numDescriptors = 0) :
GattCharacteristic(uuid, reinterpret_cast<uint8_t *>(valuePtr), sizeof(T), sizeof(T),
BLE_GATT_CHAR_PROPERTIES_READ | BLE_GATT_CHAR_PROPERTIES_WRITE | additionalProperties, descriptors, numDescriptors) {
/* empty */
}
};
/**
* Helper class to construct a write-only GattCharacteristic with an array
* value.
*/
template <typename T, unsigned NUM_ELEMENTS>
class WriteOnlyArrayGattCharacteristic : public GattCharacteristic {
public:
/**
* Construct a WriteOnlyGattCharacteristic.
*
* @param[in] uuid
* The characteristic's UUID.
* @param[in] valuePtr
* Pointer to an array of length NUM_ELEMENTS containing the
* characteristic's intitial value.
* @param[in] additionalProperties
* Additional characterisitic properties. By default, the
* properties are set to
* Properties_t::BLE_GATT_CHAR_PROPERTIES_WRITE.
* @param[in] descriptors
* An array of pointers to descriptors to be added to the new
* characteristic.
* @param[in] numDescriptors
* The total number of descriptors in @p descriptors.
*
* @note Instances of WriteOnlyGattCharacteristic have variable length
* attribute value with maximum size equal to sizeof(T) * NUM_ELEMENTS.
* For a fixed length alternative use GattCharacteristic directly.
*/
WriteOnlyArrayGattCharacteristic<T, NUM_ELEMENTS>(const UUID &uuid,
T valuePtr[NUM_ELEMENTS],
uint8_t additionalProperties = BLE_GATT_CHAR_PROPERTIES_NONE,
GattAttribute *descriptors[] = NULL,
unsigned numDescriptors = 0) :
GattCharacteristic(uuid, reinterpret_cast<uint8_t *>(valuePtr), sizeof(T) * NUM_ELEMENTS, sizeof(T) * NUM_ELEMENTS,
BLE_GATT_CHAR_PROPERTIES_WRITE | additionalProperties, descriptors, numDescriptors) {
/* empty */
}
};
/**
* Helper class to construct a read-only GattCharacteristic with an array
* value.
*/
template <typename T, unsigned NUM_ELEMENTS>
class ReadOnlyArrayGattCharacteristic : public GattCharacteristic {
public:
/**
* Construct a ReadOnlyGattCharacteristic.
*
* @param[in] uuid
* The characteristic's UUID.
* @param[in] valuePtr
* Pointer to an array of length NUM_ELEMENTS containing the
* characteristic's intitial value.
* @param[in] additionalProperties
* Additional characterisitic properties. By default, the
* properties are set to
* Properties_t::BLE_GATT_CHAR_PROPERTIES_READ.
* @param[in] descriptors
* An array of pointers to descriptors to be added to the new
* characteristic.
* @param[in] numDescriptors
* The total number of descriptors in @p descriptors.
*
* @note Instances of ReadOnlyGattCharacteristic have fixed length
* attribute value that equals sizeof(T) * NUM_ELEMENTS.
* For a variable length alternative use GattCharacteristic directly.
*/
ReadOnlyArrayGattCharacteristic<T, NUM_ELEMENTS>(const UUID &uuid,
T valuePtr[NUM_ELEMENTS],
uint8_t additionalProperties = BLE_GATT_CHAR_PROPERTIES_NONE,
GattAttribute *descriptors[] = NULL,
unsigned numDescriptors = 0) :
GattCharacteristic(uuid, reinterpret_cast<uint8_t *>(valuePtr), sizeof(T) * NUM_ELEMENTS, sizeof(T) * NUM_ELEMENTS,
BLE_GATT_CHAR_PROPERTIES_READ | additionalProperties, descriptors, numDescriptors, false) {
/* empty */
}
};
/**
* Helper class to construct a readable and writable GattCharacteristic with an array
* value.
*/
template <typename T, unsigned NUM_ELEMENTS>
class ReadWriteArrayGattCharacteristic : public GattCharacteristic {
public:
/**
* Construct a ReadWriteGattCharacteristic.
*
* @param[in] uuid
* The characteristic's UUID.
* @param[in] valuePtr
* Pointer to an array of length NUM_ELEMENTS containing the
* characteristic's intitial value.
* @param[in] additionalProperties
* Additional characterisitic properties. By default, the
* properties are set to
* Properties_t::BLE_GATT_CHAR_PROPERTIES_WRITE |
* Properties_t::BLE_GATT_CHAR_PROPERTIES_READ.
* @param[in] descriptors
* An array of pointers to descriptors to be added to the new
* characteristic.
* @param[in] numDescriptors
* The total number of descriptors in @p descriptors.
*
* @note Instances of ReadWriteGattCharacteristic have variable length
* attribute value with maximum size equal to sizeof(T) * NUM_ELEMENTS.
* For a fixed length alternative use GattCharacteristic directly.
*/
ReadWriteArrayGattCharacteristic<T, NUM_ELEMENTS>(const UUID &uuid,
T valuePtr[NUM_ELEMENTS],
uint8_t additionalProperties = BLE_GATT_CHAR_PROPERTIES_NONE,
GattAttribute *descriptors[] = NULL,
unsigned numDescriptors = 0) :
GattCharacteristic(uuid, reinterpret_cast<uint8_t *>(valuePtr), sizeof(T) * NUM_ELEMENTS, sizeof(T) * NUM_ELEMENTS,
BLE_GATT_CHAR_PROPERTIES_READ | BLE_GATT_CHAR_PROPERTIES_WRITE | additionalProperties, descriptors, numDescriptors) {
/* empty */
}
};
#endif /* ifndef __GATT_CHARACTERISTIC_H__ */

626
ble/GattClient.h Normal file
View File

@ -0,0 +1,626 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GATT_CLIENT_H__
#define __GATT_CLIENT_H__
#include "Gap.h"
#include "GattAttribute.h"
#include "ServiceDiscovery.h"
#include "CharacteristicDescriptorDiscovery.h"
#include "GattCallbackParamTypes.h"
#include "CallChainOfFunctionPointersWithContext.h"
class GattClient {
public:
/**
* Type for the registered callbacks added to the data read callchain.
* Refer to GattClient::onDataRead().
*/
typedef FunctionPointerWithContext<const GattReadCallbackParams*> ReadCallback_t;
/**
* Type for the data read event callchain. Refer to GattClient::onDataRead().
*/
typedef CallChainOfFunctionPointersWithContext<const GattReadCallbackParams*> ReadCallbackChain_t;
/**
* Enumerator for write operations.
*/
enum WriteOp_t {
GATT_OP_WRITE_REQ = 0x01, /**< Write request. */
GATT_OP_WRITE_CMD = 0x02, /**< Write command. */
};
/**
* Type for the registered callbacks added to the data write callchain.
* Refer to GattClient::onDataWrite().
*/
typedef FunctionPointerWithContext<const GattWriteCallbackParams*> WriteCallback_t;
/**
* Type for the data write event callchain. Refer to GattClient::onDataWrite().
*/
typedef CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams*> WriteCallbackChain_t;
/**
* Type for the registered callbacks added to the update event callchain.
* Refer to GattClient::onHVX().
*/
typedef FunctionPointerWithContext<const GattHVXCallbackParams*> HVXCallback_t;
/**
* Type for the update event callchain. Refer to GattClient::onHVX().
*/
typedef CallChainOfFunctionPointersWithContext<const GattHVXCallbackParams*> HVXCallbackChain_t;
/**
* Type for the registered callbacks added to the shutdown callchain.
* Refer to GattClient::onShutdown().
*/
typedef FunctionPointerWithContext<const GattClient *> GattClientShutdownCallback_t;
/**
* Type for the shutdown event callchain. Refer to GattClient::onShutown().
*/
typedef CallChainOfFunctionPointersWithContext<const GattClient *> GattClientShutdownCallbackChain_t;
/*
* The following functions are meant to be overridden in the platform-specific sub-class.
*/
public:
/**
* Launch service discovery. Once launched, application callbacks will be
* invoked for matching services or characteristics. isServiceDiscoveryActive()
* can be used to determine status, and a termination callback (if one was set up)
* will be invoked at the end. Service discovery can be terminated prematurely,
* if needed, using terminateServiceDiscovery().
*
* @param[in] connectionHandle
* Handle for the connection with the peer.
* @param[in] sc
* This is the application callback for a matching service. Taken as
* NULL by default. Note: service discovery may still be active
* when this callback is issued; calling asynchronous BLE-stack
* APIs from within this application callback might cause the
* stack to abort service discovery. If this becomes an issue, it
* may be better to make a local copy of the discoveredService and
* wait for service discovery to terminate before operating on the
* service.
* @param[in] cc
* This is the application callback for a matching characteristic.
* Taken as NULL by default. Note: service discovery may still be
* active when this callback is issued; calling asynchronous
* BLE-stack APIs from within this application callback might cause
* the stack to abort service discovery. If this becomes an issue,
* it may be better to make a local copy of the discoveredCharacteristic
* and wait for service discovery to terminate before operating on the
* characteristic.
* @param[in] matchingServiceUUID
* UUID-based filter for specifying a service in which the application is
* interested. By default it is set as the wildcard UUID_UNKNOWN,
* in which case it matches all services. If characteristic-UUID
* filter (below) is set to the wildcard value, then a service
* callback will be invoked for the matching service (or for every
* service if the service filter is a wildcard).
* @param[in] matchingCharacteristicUUIDIn
* UUID-based filter for specifying characteristic in which the application
* is interested. By default it is set as the wildcard UUID_UKNOWN
* to match against any characteristic. If both service-UUID
* filter and characteristic-UUID filter are used with non-wildcard
* values, then only a single characteristic callback is
* invoked for the matching characteristic.
*
* @note Using wildcard values for both service-UUID and characteristic-
* UUID will result in complete service discovery: callbacks being
* called for every service and characteristic.
*
* @note Providing NULL for the characteristic callback will result in
* characteristic discovery being skipped for each matching
* service. This allows for an inexpensive method to discover only
* services.
*
* @return
* BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error.
*/
virtual ble_error_t launchServiceDiscovery(Gap::Handle_t connectionHandle,
ServiceDiscovery::ServiceCallback_t sc = NULL,
ServiceDiscovery::CharacteristicCallback_t cc = NULL,
const UUID &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN),
const UUID &matchingCharacteristicUUIDIn = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) {
/* Avoid compiler warnings about unused variables. */
(void)connectionHandle;
(void)sc;
(void)cc;
(void)matchingServiceUUID;
(void)matchingCharacteristicUUIDIn;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Launch service discovery for services. Once launched, service discovery will remain
* active with service-callbacks being issued back into the application for matching
* services. isServiceDiscoveryActive() can be used to
* determine status, and a termination callback (if set up) will be invoked
* at the end. Service discovery can be terminated prematurely, if needed,
* using terminateServiceDiscovery().
*
* @param[in] connectionHandle
* Handle for the connection with the peer.
* @param[in] callback
* This is the application callback for a matching service.
* Note: service discovery may still be active
* when this callback is issued; calling asynchronous BLE-stack
* APIs from within this application callback might cause the
* stack to abort service discovery. If this becomes an issue, it
* may be better to make a local copy of the discoveredService and
* wait for service discovery to terminate before operating on the
* service.
* @param[in] matchingServiceUUID
* UUID-based filter for specifying a service in which the application is
* interested. By default it is set as the wildcard UUID_UNKNOWN,
* in which case it matches all services.
*
* @return
* BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error.
*/
virtual ble_error_t discoverServices(Gap::Handle_t connectionHandle,
ServiceDiscovery::ServiceCallback_t callback,
const UUID &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) {
return launchServiceDiscovery(connectionHandle, callback, NULL, matchingServiceUUID); /* We take advantage of the property
* that providing NULL for the characteristic callback will result in
* characteristic discovery being skipped for each matching
* service. This allows for an inexpensive method to discover only
* services. Porters are free to override this. */
}
/**
* Launch service discovery for services. Once launched, service discovery will remain
* active with service-callbacks being issued back into the application for matching
* services. isServiceDiscoveryActive() can be used to
* determine status, and a termination callback (if set up) will be invoked
* at the end. Service discovery can be terminated prematurely, if needed,
* using terminateServiceDiscovery().
*
* @param[in] connectionHandle
* Handle for the connection with the peer.
* @param[in] callback
* This is the application callback for a matching service.
* Note: service discovery may still be active
* when this callback is issued; calling asynchronous BLE-stack
* APIs from within this application callback might cause the
* stack to abort service discovery. If this becomes an issue, it
* may be better to make a local copy of the discoveredService and
* wait for service discovery to terminate before operating on the
* service.
* @param[in] startHandle, endHandle
* Handle range within which to limit the search.
*
* @return
* BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error.
*/
virtual ble_error_t discoverServices(Gap::Handle_t connectionHandle,
ServiceDiscovery::ServiceCallback_t callback,
GattAttribute::Handle_t startHandle,
GattAttribute::Handle_t endHandle) {
/* Avoid compiler warnings about unused variables. */
(void)connectionHandle;
(void)callback;
(void)startHandle;
(void)endHandle;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Check if service-discovery is currently active.
*
* @return true if service-discovery is active, false otherwise.
*/
virtual bool isServiceDiscoveryActive(void) const {
return false; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Terminate an ongoing service discovery. This should result in an
* invocation of TerminationCallback if service-discovery is active.
*/
virtual void terminateServiceDiscovery(void) {
/* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Initiate a GATT Client read procedure by attribute-handle.
*
* @param[in] connHandle
* Handle for the connection with the peer.
* @param[in] attributeHandle
* Handle of the attribute to read data from.
* @param[in] offset
* The offset from the start of the attribute value to be read.
*
* @return
* BLE_ERROR_NONE if read procedure was successfully started.
*/
virtual ble_error_t read(Gap::Handle_t connHandle, GattAttribute::Handle_t attributeHandle, uint16_t offset) const {
/* Avoid compiler warnings about unused variables. */
(void)connHandle;
(void)attributeHandle;
(void)offset;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Initiate a GATT Client write procedure.
*
* @param[in] cmd
* Command can be either a write-request (which generates a
* matching response from the peripheral), or a write-command
* (which doesn't require the connected peer to respond).
* @param[in] connHandle
* Connection handle.
* @param[in] attributeHandle
* Handle for the target attribtue on the remote GATT server.
* @param[in] length
* Length of the new value.
* @param[in] value
* New value being written.
*
* @return
* BLE_ERROR_NONE if write procedure was successfully started.
*/
virtual ble_error_t write(GattClient::WriteOp_t cmd,
Gap::Handle_t connHandle,
GattAttribute::Handle_t attributeHandle,
size_t length,
const uint8_t *value) const {
/* Avoid compiler warnings about unused variables. */
(void)cmd;
(void)connHandle;
(void)attributeHandle;
(void)length;
(void)value;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/* Event callback handlers. */
public:
/**
* Set up a callback for read response events.
*
* @param[in] callback
* Event handler being registered.
*
* @note It is possible to chain together multiple onDataRead callbacks
* (potentially from different modules of an application).
*
* @note It is possible to unregister a callback using
* onDataRead().detach(callbackToRemove).
*/
void onDataRead(ReadCallback_t callback) {
onDataReadCallbackChain.add(callback);
}
/**
* @brief Provide access to the callchain of read event callbacks.
*
* @return A reference to the read event callback chain.
*
* @note It is possible to register callbacks using onDataRead().add(callback).
*
* @note It is possible to unregister callbacks using onDataRead().detach(callback).
*/
ReadCallbackChain_t& onDataRead() {
return onDataReadCallbackChain;
}
/**
* Set up a callback for write response events.
*
* @param[in] callback
* Event handler being registered.
*
* @note It is possible to remove registered callbacks using
* onDataWritten().detach(callbackToRemove).
*
* @note Write commands (issued using writeWoResponse) don't generate a response.
*/
void onDataWritten(WriteCallback_t callback) {
onDataWriteCallbackChain.add(callback);
}
/**
* @brief Provide access to the callchain of data written callbacks.
*
* @return A reference to the data written callbacks chain.
*
* @note It is possible to register callbacks using onDataWritten().add(callback).
*
* @note It is possible to unregister callbacks using onDataWritten().detach(callback).
*/
WriteCallbackChain_t& onDataWritten() {
return onDataWriteCallbackChain;
}
/**
* Set up a callback for write response events.
*
* @param[in] callback
* Event handler being registered.
*
* @note Write commands (issued using writeWoResponse) don't generate a response.
*
* @deprecated Please use GattServer::onDataWritten() instead.
*/
void onDataWrite(WriteCallback_t callback) {
onDataWritten(callback);
}
/**
* Set up a callback for when serviceDiscovery terminates.
*
* @param[in] callback
* Event handler being registered.
*/
virtual void onServiceDiscoveryTermination(ServiceDiscovery::TerminationCallback_t callback) {
(void)callback; /* Avoid compiler warnings about ununsed variables. */
/* Requesting action from porters: override this API if this capability is supported. */
}
/**
* @brief Launch discovery of descriptors for a given characteristic.
*
* @details This function will discover all descriptors available for a
* specific characteristic.
*
* @param[in] characteristic
* The characteristic targeted by this discovery procedure.
* @param[in] discoveryCallback
* User function called each time a descriptor is found during
* the procedure.
* @param[in] terminationCallback
* User provided function which will be called once the
* discovery procedure is terminating. This will get called
* when all the descriptors have been discovered or if an
* error occur during the discovery procedure.
*
* @return
* BLE_ERROR_NONE if characteristic descriptor discovery is launched
* successfully; else an appropriate error.
*/
virtual ble_error_t discoverCharacteristicDescriptors(
const DiscoveredCharacteristic& characteristic,
const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback) {
(void) characteristic;
(void) discoveryCallback;
(void) terminationCallback;
/* Requesting action from porter(s): override this API if this capability is supported. */
return BLE_ERROR_NOT_IMPLEMENTED;
}
/**
* @brief Indicate if the discovery of characteristic descriptors is active
* for a given characteristic or not.
*
* @param[in] characteristic
* The characteristic concerned by the descriptors discovery.
*
* @return true if a descriptors discovery is active for the characteristic
* in input; otherwise false.
*/
virtual bool isCharacteristicDescriptorDiscoveryActive(const DiscoveredCharacteristic& characteristic) const
{
(void) characteristic;
return false; /* Requesting action from porter(s): override this API if this capability is supported. */
}
/**
* @brief Terminate an ongoing characteristic descriptor discovery.
*
* @details This should result in an invocation of the TerminationCallback if
* the characteristic descriptor discovery is active.
*
* @param[in] characteristic
* The characteristic on which the running descriptors
* discovery should be stopped.
*/
virtual void terminateCharacteristicDescriptorDiscovery(const DiscoveredCharacteristic& characteristic) {
/* Requesting action from porter(s): override this API if this capability is supported. */
(void) characteristic;
}
/**
* Set up a callback for when the GATT Client receives an update event
* corresponding to a change in the value of a characteristic on the remote
* GATT Server.
*
* @note It is possible to unregister callbacks using
* onHVX().detach(callbackToRemove).
*/
void onHVX(HVXCallback_t callback) {
onHVXCallbackChain.add(callback);
}
/**
* Setup a callback to be invoked to notify the user application that the
* GattClient instance is about to shutdown (possibly as a result of a call
* to BLE::shutdown()).
*
* @param[in] callback
* Event handler being registered.
*
* @note It is possible to chain together multiple onShutdown callbacks
* (potentially from different modules of an application) to be notified
* before the GattClient is shutdown.
*
* @note It is also possible to set up a callback into a member function of
* some object.
*
* @note It is possible to unregister a callback using onShutdown().detach(callback).
*/
void onShutdown(const GattClientShutdownCallback_t& callback) {
shutdownCallChain.add(callback);
}
/**
* Same as GattClient::onShutdown(), but allows the possibility to add an object
* reference and member function as handler for shutdown event
* callbacks.
*
* @param[in] objPtr
* Pointer to the object of a class defining the member callback
* function (@p memberPtr).
* @param[in] memberPtr
* The member callback (within the context of an object) to be
* invoked.
*/
template <typename T>
void onShutdown(T *objPtr, void (T::*memberPtr)(const GattClient *)) {
shutdownCallChain.add(objPtr, memberPtr);
}
/**
* @brief Provide access to the callchain of shutdown event callbacks.
*
* @return A reference to the shutdown event callbacks chain.
*
* @note It is possible to register callbacks using onShutdown().add(callback).
*
* @note It is possible to unregister callbacks using onShutdown().detach(callback).
*/
GattClientShutdownCallbackChain_t& onShutdown() {
return shutdownCallChain;
}
/**
* @brief provide access to the callchain of HVX callbacks.
*
* @return A reference to the HVX callbacks chain.
*
* @note It is possible to register callbacks using onHVX().add(callback).
*
* @note It is possible to unregister callbacks using onHVX().detach(callback).
*/
HVXCallbackChain_t& onHVX() {
return onHVXCallbackChain;
}
public:
/**
* Notify all registered onShutdown callbacks that the GattClient is
* about to be shutdown and clear all GattClient state of the
* associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in GattClient members. This shall be achieved
* by a call to GattClient::reset() from the sub-class' reset()
* implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
/* Notify that the instance is about to shutdown */
shutdownCallChain.call(this);
shutdownCallChain.clear();
onDataReadCallbackChain.clear();
onDataWriteCallbackChain.clear();
onHVXCallbackChain.clear();
return BLE_ERROR_NONE;
}
protected:
GattClient() {
/* Empty */
}
/* Entry points for the underlying stack to report events back to the user. */
public:
/**
* Helper function that notifies all registered handlers of an occurrence
* of a data read event. This function is meant to be called from the
* BLE stack specific implementation when a data read event occurs.
*
* @param[in] params
* The data read parameters passed to the registered
* handlers.
*/
void processReadResponse(const GattReadCallbackParams *params) {
onDataReadCallbackChain(params);
}
/**
* Helper function that notifies all registered handlers of an occurrence
* of a data written event. This function is meant to be called from the
* BLE stack specific implementation when a data written event occurs.
*
* @param[in] params
* The data written parameters passed to the registered
* handlers.
*/
void processWriteResponse(const GattWriteCallbackParams *params) {
onDataWriteCallbackChain(params);
}
/**
* Helper function that notifies all registered handlers of an occurrence
* of an update event. This function is meant to be called from the
* BLE stack specific implementation when an update event occurs.
*
* @param[in] params
* The update event parameters passed to the registered
* handlers.
*/
void processHVXEvent(const GattHVXCallbackParams *params) {
if (onHVXCallbackChain) {
onHVXCallbackChain(params);
}
}
protected:
/**
* Callchain containing all registered callback handlers for data read
* events.
*/
ReadCallbackChain_t onDataReadCallbackChain;
/**
* Callchain containing all registered callback handlers for data write
* events.
*/
WriteCallbackChain_t onDataWriteCallbackChain;
/**
* Callchain containing all registered callback handlers for update
* events.
*/
HVXCallbackChain_t onHVXCallbackChain;
/**
* Callchain containing all registered callback handlers for shutdown
* events.
*/
GattClientShutdownCallbackChain_t shutdownCallChain;
private:
/* Disallow copy and assignment. */
GattClient(const GattClient &);
GattClient& operator=(const GattClient &);
};
#endif /* ifndef __GATT_CLIENT_H__ */

689
ble/GattServer.h Normal file
View File

@ -0,0 +1,689 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GATT_SERVER_H__
#define __GATT_SERVER_H__
#include "Gap.h"
#include "GattService.h"
#include "GattAttribute.h"
#include "GattServerEvents.h"
#include "GattCallbackParamTypes.h"
#include "CallChainOfFunctionPointersWithContext.h"
class GattServer {
public:
/**
* Type for the registered callbacks added to the data sent callchain.
* Refer to GattServer::onDataSent().
*/
typedef FunctionPointerWithContext<unsigned> DataSentCallback_t;
/**
* Type for the data sent event callchain. Refer to GattServer::onDataSent().
*/
typedef CallChainOfFunctionPointersWithContext<unsigned> DataSentCallbackChain_t;
/**
* Type for the registered callbacks added to the data written callchain.
* Refer to GattServer::onDataWritten().
*/
typedef FunctionPointerWithContext<const GattWriteCallbackParams*> DataWrittenCallback_t;
/**
* Type for the data written event callchain. Refer to GattServer::onDataWritten().
*/
typedef CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams*> DataWrittenCallbackChain_t;
/**
* Type for the registered callbacks added to the data read callchain.
* Refer to GattServer::onDataRead().
*/
typedef FunctionPointerWithContext<const GattReadCallbackParams*> DataReadCallback_t;
/**
* Type for the data read event callchain. Refer to GattServer::onDataRead().
*/
typedef CallChainOfFunctionPointersWithContext<const GattReadCallbackParams *> DataReadCallbackChain_t;
/**
* Type for the registered callbacks added to the shutdown callchain.
* Refer to GattServer::onShutdown().
*/
typedef FunctionPointerWithContext<const GattServer *> GattServerShutdownCallback_t;
/**
* Type for the shutdown event callchain. Refer to GattServer::onShutdown().
*/
typedef CallChainOfFunctionPointersWithContext<const GattServer *> GattServerShutdownCallbackChain_t;
/**
* Type for the registered callback for various events. Refer to
* GattServer::onUpdatesEnabled(), GattServer::onUpdateDisabled() and
* GattServer::onConfirmationReceived().
*/
typedef FunctionPointerWithContext<GattAttribute::Handle_t> EventCallback_t;
protected:
/**
* Construct a GattServer instance.
*/
GattServer() :
serviceCount(0),
characteristicCount(0),
dataSentCallChain(),
dataWrittenCallChain(),
dataReadCallChain(),
updatesEnabledCallback(NULL),
updatesDisabledCallback(NULL),
confirmationReceivedCallback(NULL) {
/* empty */
}
/*
* The following functions are meant to be overridden in the platform-specific sub-class.
*/
public:
/**
* Add a service declaration to the local server ATT table. Also add the
* characteristics contained within.
*
* @param[in] service
* The service to be added.
*
* @return BLE_ERROR_NONE if the service was successfully added.
*/
virtual ble_error_t addService(GattService &service) {
/* Avoid compiler warnings about unused variables. */
(void)service;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Read the value of a characteristic from the local GATT server.
*
* @param[in] attributeHandle
* Attribute handle for the value attribute of the characteristic.
* @param[out] buffer
* A buffer to hold the value being read.
* @param[in,out] lengthP
* Length of the buffer being supplied. If the attribute
* value is longer than the size of the supplied buffer,
* this variable will hold upon return the total attribute value length
* (excluding offset). The application may use this
* information to allocate a suitable buffer size.
*
* @return BLE_ERROR_NONE if a value was read successfully into the buffer.
*/
virtual ble_error_t read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) {
/* Avoid compiler warnings about unused variables. */
(void)attributeHandle;
(void)buffer;
(void)lengthP;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Read the value of a characteristic from the local GATT server.
*
* @param[in] connectionHandle
* Connection handle.
* @param[in] attributeHandle
* Attribute handle for the value attribute of the characteristic.
* @param[out] buffer
* A buffer to hold the value being read.
* @param[in,out] lengthP
* Length of the buffer being supplied. If the attribute
* value is longer than the size of the supplied buffer,
* this variable will hold upon return the total attribute value length
* (excluding offset). The application may use this
* information to allocate a suitable buffer size.
*
* @return BLE_ERROR_NONE if a value was read successfully into the buffer.
*
* @note This API is a version of the above, with an additional connection handle
* parameter to allow fetches for connection-specific multivalued
* attributes (such as the CCCDs).
*/
virtual ble_error_t read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP) {
/* Avoid compiler warnings about unused variables. */
(void)connectionHandle;
(void)attributeHandle;
(void)buffer;
(void)lengthP;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Update the value of a characteristic on the local GATT server.
*
* @param[in] attributeHandle
* Handle for the value attribute of the characteristic.
* @param[in] value
* A pointer to a buffer holding the new value.
* @param[in] size
* Size of the new value (in bytes).
* @param[in] localOnly
* Should this update be kept on the local
* GATT server regardless of the state of the
* notify/indicate flag in the CCCD for this
* Characteristic? If set to true, no notification
* or indication is generated.
*
* @return BLE_ERROR_NONE if we have successfully set the value of the attribute.
*/
virtual ble_error_t write(GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly = false) {
/* Avoid compiler warnings about unused variables. */
(void)attributeHandle;
(void)value;
(void)size;
(void)localOnly;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Update the value of a characteristic on the local GATT server. A version
* of the same as the above, with a connection handle parameter to allow updates
* for connection-specific multivalued attributes (such as the CCCDs).
*
* @param[in] connectionHandle
* Connection handle.
* @param[in] attributeHandle
* Handle for the value attribute of the characteristic.
* @param[in] value
* A pointer to a buffer holding the new value.
* @param[in] size
* Size of the new value (in bytes).
* @param[in] localOnly
* Should this update be kept on the local
* GattServer regardless of the state of the
* notify/indicate flag in the CCCD for this
* Characteristic? If set to true, no notification
* or indication is generated.
*
* @return BLE_ERROR_NONE if we have successfully set the value of the attribute.
*/
virtual ble_error_t write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly = false) {
/* Avoid compiler warnings about unused variables. */
(void)connectionHandle;
(void)attributeHandle;
(void)value;
(void)size;
(void)localOnly;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Determine the updates-enabled status (notification or indication) for the current connection from a characteristic's CCCD.
*
* @param[in] characteristic
* The characteristic.
* @param[out] enabledP
* Upon return, *enabledP is true if updates are enabled, else false.
*
* @return BLE_ERROR_NONE if the connection and handle are found. False otherwise.
*/
virtual ble_error_t areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP) {
/* Avoid compiler warnings about unused variables. */
(void)characteristic;
(void)enabledP;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* Determine the connection-specific updates-enabled status (notification or indication) from a characteristic's CCCD.
*
* @param[in] connectionHandle
* The connection handle.
* @param[in] characteristic
* The characteristic.
* @param[out] enabledP
* Upon return, *enabledP is true if updates are enabled, else false.
*
* @return BLE_ERROR_NONE if the connection and handle are found. False otherwise.
*/
virtual ble_error_t areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) {
/* Avoid compiler warnings about unused variables. */
(void)connectionHandle;
(void)characteristic;
(void)enabledP;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if this capability is supported. */
}
/**
* A virtual function to allow underlying stacks to indicate if they support
* onDataRead(). It should be overridden to return true as applicable.
*
* @return true if onDataRead is supported, false otherwise.
*/
virtual bool isOnDataReadAvailable() const {
return false; /* Requesting action from porters: override this API if this capability is supported. */
}
/*
* APIs with non-virtual implementations.
*/
public:
/**
* Add a callback for the GATT event DATA_SENT (which is triggered when
* updates are sent out by GATT in the form of notifications).
*
* @param[in] callback
* Event handler being registered.
*
* @note It is possible to chain together multiple onDataSent callbacks
* (potentially from different modules of an application) to receive updates
* to characteristics.
*
* @note It is also possible to set up a callback into a member function of
* some object.
*/
void onDataSent(const DataSentCallback_t& callback) {
dataSentCallChain.add(callback);
}
/**
* Same as GattServer::onDataSent(), but allows the possibility to add an object
* reference and member function as handler for DATA_SENT event
* callbacks.
*
* @param[in] objPtr
* Pointer to the object of a class defining the member callback
* function (@p memberPtr).
* @param[in] memberPtr
* The member callback (within the context of an object) to be
* invoked.
*/
template <typename T>
void onDataSent(T *objPtr, void (T::*memberPtr)(unsigned count)) {
dataSentCallChain.add(objPtr, memberPtr);
}
/**
* @brief Provide access to the callchain of DATA_SENT event callbacks.
*
* @return A reference to the DATA_SENT event callback chain.
*/
DataSentCallbackChain_t& onDataSent() {
return dataSentCallChain;
}
/**
* Set up a callback for when an attribute has its value updated by or at the
* connected peer. For a peripheral, this callback is triggered when the local
* GATT server has an attribute updated by a write command from the peer.
* For a central, this callback is triggered when a response is received for
* a write request.
*
* @param[in] callback
* Event handler being registered.
*
* @note It is possible to chain together multiple onDataWritten callbacks
* (potentially from different modules of an application) to receive updates
* to characteristics. Many services, such as DFU and UART, add their own
* onDataWritten callbacks behind the scenes to trap interesting events.
*
* @note It is also possible to set up a callback into a member function of
* some object.
*
* @note It is possible to unregister a callback using onDataWritten().detach(callback)
*/
void onDataWritten(const DataWrittenCallback_t& callback) {
dataWrittenCallChain.add(callback);
}
/**
* Same as GattServer::onDataWritten(), but allows the possibility to add an object
* reference and member function as handler for data written event
* callbacks.
*
* @param[in] objPtr
* Pointer to the object of a class defining the member callback
* function (@p memberPtr).
* @param[in] memberPtr
* The member callback (within the context of an object) to be
* invoked.
*/
template <typename T>
void onDataWritten(T *objPtr, void (T::*memberPtr)(const GattWriteCallbackParams *context)) {
dataWrittenCallChain.add(objPtr, memberPtr);
}
/**
* @brief Provide access to the callchain of data written event callbacks.
*
* @return A reference to the data written event callbacks chain.
*
* @note It is possible to register callbacks using onDataWritten().add(callback).
*
* @note It is possible to unregister callbacks using onDataWritten().detach(callback).
*/
DataWrittenCallbackChain_t& onDataWritten() {
return dataWrittenCallChain;
}
/**
* Setup a callback to be invoked on the peripheral when an attribute is
* being read by a remote client.
*
* @param[in] callback
* Event handler being registered.
*
* @return BLE_ERROR_NOT_IMPLEMENTED if this functionality isn't available;
* else BLE_ERROR_NONE.
*
* @note This functionality may not be available on all underlying stacks.
* You could use GattCharacteristic::setReadAuthorizationCallback() as an
* alternative. Refer to isOnDataReadAvailable().
*
* @note It is possible to chain together multiple onDataRead callbacks
* (potentially from different modules of an application) to receive updates
* to characteristics. Services may add their own onDataRead callbacks
* behind the scenes to trap interesting events.
*
* @note It is also possible to set up a callback into a member function of
* some object.
*
* @note It is possible to unregister a callback using onDataRead().detach(callback).
*/
ble_error_t onDataRead(const DataReadCallback_t& callback) {
if (!isOnDataReadAvailable()) {
return BLE_ERROR_NOT_IMPLEMENTED;
}
dataReadCallChain.add(callback);
return BLE_ERROR_NONE;
}
/**
* Same as GattServer::onDataRead(), but allows the possibility to add an object
* reference and member function as handler for data read event
* callbacks.
*
* @param[in] objPtr
* Pointer to the object of a class defining the member callback
* function (@p memberPtr).
* @param[in] memberPtr
* The member callback (within the context of an object) to be
* invoked.
*/
template <typename T>
ble_error_t onDataRead(T *objPtr, void (T::*memberPtr)(const GattReadCallbackParams *context)) {
if (!isOnDataReadAvailable()) {
return BLE_ERROR_NOT_IMPLEMENTED;
}
dataReadCallChain.add(objPtr, memberPtr);
return BLE_ERROR_NONE;
}
/**
* @brief Provide access to the callchain of data read event callbacks.
*
* @return A reference to the data read event callbacks chain.
*
* @note It is possible to register callbacks using onDataRead().add(callback).
*
* @note It is possible to unregister callbacks using onDataRead().detach(callback).
*/
DataReadCallbackChain_t& onDataRead() {
return dataReadCallChain;
}
/**
* Setup a callback to be invoked to notify the user application that the
* GattServer instance is about to shutdown (possibly as a result of a call
* to BLE::shutdown()).
*
* @param[in] callback
* Event handler being registered.
*
* @note It is possible to chain together multiple onShutdown callbacks
* (potentially from different modules of an application) to be notified
* before the GattServer is shutdown.
*
* @note It is also possible to set up a callback into a member function of
* some object.
*
* @note It is possible to unregister a callback using onShutdown().detach(callback)
*/
void onShutdown(const GattServerShutdownCallback_t& callback) {
shutdownCallChain.add(callback);
}
/**
* Same as GattServer::onShutdown(), but allows the possibility to add an object
* reference and member function as handler for shutdown event
* callbacks.
*
* @param[in] objPtr
* Pointer to the object of a class defining the member callback
* function (@p memberPtr).
* @param[in] memberPtr
* The member callback (within the context of an object) to be
* invoked.
*/
template <typename T>
void onShutdown(T *objPtr, void (T::*memberPtr)(const GattServer *)) {
shutdownCallChain.add(objPtr, memberPtr);
}
/**
* @brief Provide access to the callchain of shutdown event callbacks.
*
* @return A reference to the shutdown event callbacks chain.
*
* @note It is possible to register callbacks using onShutdown().add(callback).
*
* @note It is possible to unregister callbacks using onShutdown().detach(callback).
*/
GattServerShutdownCallbackChain_t& onShutdown() {
return shutdownCallChain;
}
/**
* Set up a callback for when notifications or indications are enabled for a
* characteristic on the local GATT server.
*
* @param[in] callback
* Event handler being registered.
*/
void onUpdatesEnabled(EventCallback_t callback) {
updatesEnabledCallback = callback;
}
/**
* Set up a callback for when notifications or indications are disabled for a
* characteristic on the local GATT server.
*
* @param[in] callback
* Event handler being registered.
*/
void onUpdatesDisabled(EventCallback_t callback) {
updatesDisabledCallback = callback;
}
/**
* Set up a callback for when the GATT server receives a response for an
* indication event sent previously.
*
* @param[in] callback
* Event handler being registered.
*/
void onConfirmationReceived(EventCallback_t callback) {
confirmationReceivedCallback = callback;
}
/* Entry points for the underlying stack to report events back to the user. */
protected:
/**
* Helper function that notifies all registered handlers of an occurrence
* of a data written event. This function is meant to be called from the
* BLE stack specific implementation when a data written event occurs.
*
* @param[in] params
* The data written parameters passed to the registered
* handlers.
*/
void handleDataWrittenEvent(const GattWriteCallbackParams *params) {
dataWrittenCallChain.call(params);
}
/**
* Helper function that notifies all registered handlers of an occurrence
* of a data read event. This function is meant to be called from the
* BLE stack specific implementation when a data read event occurs.
*
* @param[in] params
* The data read parameters passed to the registered
* handlers.
*/
void handleDataReadEvent(const GattReadCallbackParams *params) {
dataReadCallChain.call(params);
}
/**
* Helper function that notifies the registered handler of an occurrence
* of updates enabled, updates disabled and confirmation received events.
* This function is meant to be called from the BLE stack specific
* implementation when any of these events occurs.
*
* @param[in] type
* The type of event that occurred.
* @param[in] attributeHandle
* The handle of the attribute that was modified.
*/
void handleEvent(GattServerEvents::gattEvent_e type, GattAttribute::Handle_t attributeHandle) {
switch (type) {
case GattServerEvents::GATT_EVENT_UPDATES_ENABLED:
if (updatesEnabledCallback) {
updatesEnabledCallback(attributeHandle);
}
break;
case GattServerEvents::GATT_EVENT_UPDATES_DISABLED:
if (updatesDisabledCallback) {
updatesDisabledCallback(attributeHandle);
}
break;
case GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED:
if (confirmationReceivedCallback) {
confirmationReceivedCallback(attributeHandle);
}
break;
default:
break;
}
}
/**
* Helper function that notifies all registered handlers of an occurrence
* of a data sent event. This function is meant to be called from the
* BLE stack specific implementation when a data sent event occurs.
*
* @param[in] count
* Number of packets sent.
*/
void handleDataSentEvent(unsigned count) {
dataSentCallChain.call(count);
}
public:
/**
* Notify all registered onShutdown callbacks that the GattServer is
* about to be shutdown and clear all GattServer state of the
* associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in GattServer members. This shall be achieved
* by a call to GattServer::reset() from the sub-class' reset()
* implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
/* Notify that the instance is about to shutdown */
shutdownCallChain.call(this);
shutdownCallChain.clear();
serviceCount = 0;
characteristicCount = 0;
dataSentCallChain.clear();
dataWrittenCallChain.clear();
dataReadCallChain.clear();
updatesEnabledCallback = NULL;
updatesDisabledCallback = NULL;
confirmationReceivedCallback = NULL;
return BLE_ERROR_NONE;
}
protected:
/**
* The total number of services added to the ATT table.
*/
uint8_t serviceCount;
/**
* The total number of characteristics added to the ATT table.
*/
uint8_t characteristicCount;
private:
/**
* Callchain containing all registered callback handlers for data sent
* events.
*/
DataSentCallbackChain_t dataSentCallChain;
/**
* Callchain containing all registered callback handlers for data written
* events.
*/
DataWrittenCallbackChain_t dataWrittenCallChain;
/**
* Callchain containing all registered callback handlers for data read
* events.
*/
DataReadCallbackChain_t dataReadCallChain;
/**
* Callchain containing all registered callback handlers for shutdown
* events.
*/
GattServerShutdownCallbackChain_t shutdownCallChain;
/**
* The registered callback handler for updates enabled events.
*/
EventCallback_t updatesEnabledCallback;
/**
* The registered callback handler for updates disabled events.
*/
EventCallback_t updatesDisabledCallback;
/**
* The registered callback handler for confirmation received events.
*/
EventCallback_t confirmationReceivedCallback;
private:
/* Disallow copy and assignment. */
GattServer(const GattServer &);
GattServer& operator=(const GattServer &);
};
#endif /* ifndef __GATT_SERVER_H__ */

41
ble/GattServerEvents.h Normal file
View File

@ -0,0 +1,41 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GATT_SERVER_EVENTS_H__
#define __GATT_SERVER_EVENTS_H__
/**
* @brief The base class used to abstract away the callback events that can be
* triggered with the GATT Server.
*/
class GattServerEvents
{
public:
/**
* Enumeration for GattServer events.
*/
typedef enum gattEvent_e {
GATT_EVENT_DATA_SENT = 1, /**< Fired when a message was successfully sent out (notify only?) */
GATT_EVENT_DATA_WRITTEN = 2, /**< Client wrote data to the server (separate into char and descriptor writes?) */
GATT_EVENT_UPDATES_ENABLED = 3, /**< Notify/Indicate enabled in CCCD. */
GATT_EVENT_UPDATES_DISABLED = 4, /**< Notify/Indicate disabled in CCCD. */
GATT_EVENT_CONFIRMATION_RECEIVED = 5, /**< Response received from Indicate message. */
GATT_EVENT_READ_AUTHORIZATION_REQ = 6, /**< Request application to authorize read. */
GATT_EVENT_WRITE_AUTHORIZATION_REQ = 7, /**< Request application to authorize write. */
} gattEvent_t;
};
#endif /* ifndef __GATT_SERVER_EVENTS_H__ */

144
ble/GattService.h Normal file
View File

@ -0,0 +1,144 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GATT_SERVICE_H__
#define __GATT_SERVICE_H__
#include "UUID.h"
#include "GattCharacteristic.h"
class GattService {
public:
enum {
UUID_ALERT_NOTIFICATION_SERVICE = 0x1811,
UUID_BATTERY_SERVICE = 0x180F,
UUID_BLOOD_PRESSURE_SERVICE = 0x1810,
UUID_CURRENT_TIME_SERVICE = 0x1805,
UUID_CYCLING_SPEED_AND_CADENCE = 0x1816,
UUID_DEVICE_INFORMATION_SERVICE = 0x180A,
UUID_ENVIRONMENTAL_SERVICE = 0x181A,
UUID_GLUCOSE_SERVICE = 0x1808,
UUID_HEALTH_THERMOMETER_SERVICE = 0x1809,
UUID_HEART_RATE_SERVICE = 0x180D,
UUID_HUMAN_INTERFACE_DEVICE_SERVICE = 0x1812,
UUID_IMMEDIATE_ALERT_SERVICE = 0x1802,
UUID_LINK_LOSS_SERVICE = 0x1803,
UUID_NEXT_DST_CHANGE_SERVICE = 0x1807,
UUID_PHONE_ALERT_STATUS_SERVICE = 0x180E,
UUID_REFERENCE_TIME_UPDATE_SERVICE = 0x1806,
UUID_RUNNING_SPEED_AND_CADENCE = 0x1814,
UUID_SCAN_PARAMETERS_SERVICE = 0x1813,
UUID_TX_POWER_SERVICE = 0x1804
};
public:
/**
* @brief Creates a new GattService using the specified 16-bit
* UUID, value length, and properties.
*
* @note The UUID value must be unique and is normally >1.
*
* @param[in] uuid
* The UUID to use for this service.
* @param[in] characteristics
* A pointer to an array of characteristics to be included within this service.
* @param[in] numCharacteristics
* The number of characteristics.
*/
GattService(const UUID &uuid, GattCharacteristic *characteristics[], unsigned numCharacteristics) :
_primaryServiceID(uuid),
_characteristicCount(numCharacteristics),
_characteristics(characteristics),
_handle(0) {
/* empty */
}
/**
* Get this service's UUID.
*
* @return A reference to the service's UUID.
*/
const UUID &getUUID(void) const {
return _primaryServiceID;
}
/**
* Get handle of the service declaration attribute in the ATT table.
*
* @return The service's handle.
*/
uint16_t getHandle(void) const {
return _handle;
}
/**
* Get the total number of characteristics within this service.
*
* @return The total number of characteristics within this service.
*/
uint8_t getCharacteristicCount(void) const {
return _characteristicCount;
}
/**
* Set the handle of the service declaration attribute in the ATT table.
*
* @param[in] handle
* The service's handle.
*/
void setHandle(uint16_t handle) {
_handle = handle;
}
/**
* Get this service's characteristic at a specific index.
*
* @param[in] index
* The index of the characteristic.
*
* @return A pointer to the characterisitic at index @p index.
*/
GattCharacteristic *getCharacteristic(uint8_t index) {
if (index >= _characteristicCount) {
return NULL;
}
return _characteristics[index];
}
private:
/**
* This service's UUID.
*/
UUID _primaryServiceID;
/**
* Total number of characteristics within this service.
*/
uint8_t _characteristicCount;
/**
* An array with pointers to the characteristics added to this service.
*/
GattCharacteristic **_characteristics;
/**
* Handle of the service declaration attribute in the ATT table.
*
* @note This handle is generally assigned by the underlying BLE stack when the
* service is added to the ATT table.
*/
uint16_t _handle;
};
#endif /* ifndef __GATT_SERVICE_H__ */

124
ble/SafeBool.h Normal file
View File

@ -0,0 +1,124 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BLE_API_SAFE_BOOL_H_
#define BLE_API_SAFE_BOOL_H_
/* Safe bool idiom, see : http://www.artima.com/cppsource/safebool.html */
namespace SafeBool_ {
/**
* @brief Base class for all intances of SafeBool.
* This base class reduces instantiation of trueTag function.
*/
class base {
template<typename>
friend class SafeBool;
protected:
/**
* The bool type is a pointer to method which can be used in boolean context.
*/
typedef void (base::*BoolType_t)() const;
/**
* Non implemented call, use to disallow conversion between unrelated types.
*/
void invalidTag() const;
/**
* Member function which indicate true value.
*/
void trueTag() const {}
};
}
/**
* @brief template class SafeBool use CRTP to made boolean conversion easy and correct.
* Derived class should implement the function bool toBool() const to make this work. Inheritance
* should be public.
*
* @tparam T Type of the derived class
*
* @code
*
* class A : public SafeBool<A> {
* public:
*
* // boolean conversion
* bool toBool() {
*
* }
* };
*
* class B : public SafeBool<B> {
* public:
*
* // boolean conversion
* bool toBool() const {
*
* }
* };
*
* A a;
* B b;
*
* // will compile
* if(a) {
*
* }
*
* // compilation error
* if(a == b) {
*
* }
*
*
* @endcode
*/
template <typename T>
class SafeBool : public SafeBool_::base {
public:
/**
* Bool operator implementation, derived class has to provide bool toBool() const function.
*/
operator BoolType_t() const {
return (static_cast<const T*>(this))->toBool()
? &SafeBool<T>::trueTag : 0;
}
};
/**
* Avoid conversion to bool between different classes.
*/
template <typename T, typename U>
void operator==(const SafeBool<T>& lhs,const SafeBool<U>& rhs) {
lhs.invalidTag();
// return false;
}
/**
* Avoid conversion to bool between different classes.
*/
template <typename T,typename U>
void operator!=(const SafeBool<T>& lhs,const SafeBool<U>& rhs) {
lhs.invalidTag();
// return false;
}
#endif /* BLE_API_SAFE_BOOL_H_ */

331
ble/SecurityManager.h Normal file
View File

@ -0,0 +1,331 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SECURITY_MANAGER_H__
#define __SECURITY_MANAGER_H__
#include <stdint.h>
#include "Gap.h"
#include "CallChainOfFunctionPointersWithContext.h"
class SecurityManager {
public:
enum SecurityMode_t {
SECURITY_MODE_NO_ACCESS,
SECURITY_MODE_ENCRYPTION_OPEN_LINK, /**< Require no protection, open link. */
SECURITY_MODE_ENCRYPTION_NO_MITM, /**< Require encryption, but no MITM protection. */
SECURITY_MODE_ENCRYPTION_WITH_MITM, /**< Require encryption and MITM protection. */
SECURITY_MODE_SIGNED_NO_MITM, /**< Require signing or encryption, but no MITM protection. */
SECURITY_MODE_SIGNED_WITH_MITM, /**< Require signing or encryption, and MITM protection. */
};
/**
* @brief Defines possible security status or states.
*
* @details Defines possible security status or states of a link when requested by getLinkSecurity().
*/
enum LinkSecurityStatus_t {
NOT_ENCRYPTED, /**< The link is not secured. */
ENCRYPTION_IN_PROGRESS, /**< Link security is being established.*/
ENCRYPTED /**< The link is secure.*/
};
enum SecurityIOCapabilities_t {
IO_CAPS_DISPLAY_ONLY = 0x00, /**< Display only. */
IO_CAPS_DISPLAY_YESNO = 0x01, /**< Display and yes/no entry. */
IO_CAPS_KEYBOARD_ONLY = 0x02, /**< Keyboard only. */
IO_CAPS_NONE = 0x03, /**< No I/O capabilities. */
IO_CAPS_KEYBOARD_DISPLAY = 0x04, /**< Keyboard and display. */
};
enum SecurityCompletionStatus_t {
SEC_STATUS_SUCCESS = 0x00, /**< Procedure completed with success. */
SEC_STATUS_TIMEOUT = 0x01, /**< Procedure timed out. */
SEC_STATUS_PDU_INVALID = 0x02, /**< Invalid PDU received. */
SEC_STATUS_PASSKEY_ENTRY_FAILED = 0x81, /**< Passkey entry failed (user canceled or other). */
SEC_STATUS_OOB_NOT_AVAILABLE = 0x82, /**< Out of Band Key not available. */
SEC_STATUS_AUTH_REQ = 0x83, /**< Authentication requirements not met. */
SEC_STATUS_CONFIRM_VALUE = 0x84, /**< Confirm value failed. */
SEC_STATUS_PAIRING_NOT_SUPP = 0x85, /**< Pairing not supported. */
SEC_STATUS_ENC_KEY_SIZE = 0x86, /**< Encryption key size. */
SEC_STATUS_SMP_CMD_UNSUPPORTED = 0x87, /**< Unsupported SMP command. */
SEC_STATUS_UNSPECIFIED = 0x88, /**< Unspecified reason. */
SEC_STATUS_REPEATED_ATTEMPTS = 0x89, /**< Too little time elapsed since last attempt. */
SEC_STATUS_INVALID_PARAMS = 0x8A, /**< Invalid parameters. */
};
/**
* Declaration of type containing a passkey to be used during pairing. This
* is passed into initializeSecurity() to specify a pre-programmed passkey
* for authentication instead of generating a random one.
*/
static const unsigned PASSKEY_LEN = 6;
typedef uint8_t Passkey_t[PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */
public:
typedef void (*HandleSpecificEvent_t)(Gap::Handle_t handle);
typedef void (*SecuritySetupInitiatedCallback_t)(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps);
typedef void (*SecuritySetupCompletedCallback_t)(Gap::Handle_t, SecurityCompletionStatus_t status);
typedef void (*LinkSecuredCallback_t)(Gap::Handle_t handle, SecurityMode_t securityMode);
typedef void (*PasskeyDisplayCallback_t)(Gap::Handle_t handle, const Passkey_t passkey);
typedef FunctionPointerWithContext<const SecurityManager *> SecurityManagerShutdownCallback_t;
typedef CallChainOfFunctionPointersWithContext<const SecurityManager *> SecurityManagerShutdownCallbackChain_t;
/*
* The following functions are meant to be overridden in the platform-specific sub-class.
*/
public:
/**
* Enable the BLE stack's Security Manager. The Security Manager implements
* the actual cryptographic algorithms and protocol exchanges that allow two
* devices to securely exchange data and privately detect each other.
* Calling this API is a prerequisite for encryption and pairing (bonding).
*
* @param[in] enableBonding Allow for bonding.
* @param[in] requireMITM Require protection for man-in-the-middle attacks.
* @param[in] iocaps To specify the I/O capabilities of this peripheral,
* such as availability of a display or keyboard, to
* support out-of-band exchanges of security data.
* @param[in] passkey To specify a static passkey.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t init(bool enableBonding = true,
bool requireMITM = true,
SecurityIOCapabilities_t iocaps = IO_CAPS_NONE,
const Passkey_t passkey = NULL) {
/* Avoid compiler warnings about unused variables. */
(void)enableBonding;
(void)requireMITM;
(void)iocaps;
(void)passkey;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Get the security status of a connection.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[out] securityStatusP Security status.
*
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t getLinkSecurity(Gap::Handle_t connectionHandle, LinkSecurityStatus_t *securityStatusP) {
/* Avoid compiler warnings about unused variables. */
(void)connectionHandle;
(void)securityStatusP;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Set the security mode on a connection. Useful for elevating the security mode
* once certain conditions are met, e.g., a particular service is found.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] securityMode Requested security mode.
*
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setLinkSecurity(Gap::Handle_t connectionHandle, SecurityMode_t securityMode) {
/* Avoid compiler warnings about unused variables. */
(void)connectionHandle;
(void)securityMode;
return BLE_ERROR_NOT_IMPLEMENTED;
}
/**
* Delete all peer device context and all related bonding information from
* the database within the security manager.
*
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure.
* @retval BLE_ERROR_INVALID_STATE If the API is called without module initialization or
* application registration.
*/
virtual ble_error_t purgeAllBondingState(void) {
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Get a list of addresses from all peers in the bond table.
*
* @param[in,out] addresses
* (on input) addresses.capacity contains the maximum
* number of addresses to be returned.
* (on output) The populated table with copies of the
* addresses in the implementation's whitelist.
*
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure.
* @retval BLE_ERROR_INVALID_STATE If the API is called without module initialization or
* application registration.
*
* @experimental
*/
virtual ble_error_t getAddressesFromBondTable(Gap::Whitelist_t &addresses) const {
/* Avoid compiler warnings about unused variables */
(void) addresses;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/* Event callback handlers. */
public:
/**
* Setup a callback to be invoked to notify the user application that the
* SecurityManager instance is about to shutdown (possibly as a result of a call
* to BLE::shutdown()).
*
* @note It is possible to chain together multiple onShutdown callbacks
* (potentially from different modules of an application) to be notified
* before the SecurityManager is shutdown.
*
* @note It is also possible to set up a callback into a member function of
* some object.
*
* @note It is possible to unregister a callback using onShutdown().detach(callback)
*/
void onShutdown(const SecurityManagerShutdownCallback_t& callback) {
shutdownCallChain.add(callback);
}
template <typename T>
void onShutdown(T *objPtr, void (T::*memberPtr)(const SecurityManager *)) {
shutdownCallChain.add(objPtr, memberPtr);
}
/**
* @brief provide access to the callchain of shutdown event callbacks
* It is possible to register callbacks using onShutdown().add(callback);
* It is possible to unregister callbacks using onShutdown().detach(callback)
* @return The shutdown event callbacks chain
*/
SecurityManagerShutdownCallbackChain_t& onShutdown() {
return shutdownCallChain;
}
/**
* To indicate that a security procedure for the link has started.
*/
virtual void onSecuritySetupInitiated(SecuritySetupInitiatedCallback_t callback) {securitySetupInitiatedCallback = callback;}
/**
* To indicate that the security procedure for the link has completed.
*/
virtual void onSecuritySetupCompleted(SecuritySetupCompletedCallback_t callback) {securitySetupCompletedCallback = callback;}
/**
* To indicate that the link with the peer is secured. For bonded devices,
* subsequent reconnections with a bonded peer will result only in this callback
* when the link is secured; setup procedures will not occur (unless the
* bonding information is either lost or deleted on either or both sides).
*/
virtual void onLinkSecured(LinkSecuredCallback_t callback) {linkSecuredCallback = callback;}
/**
* To indicate that device context is stored persistently.
*/
virtual void onSecurityContextStored(HandleSpecificEvent_t callback) {securityContextStoredCallback = callback;}
/**
* To set the callback for when the passkey needs to be displayed on a peripheral with DISPLAY capability.
*/
virtual void onPasskeyDisplay(PasskeyDisplayCallback_t callback) {passkeyDisplayCallback = callback;}
/* Entry points for the underlying stack to report events back to the user. */
public:
void processSecuritySetupInitiatedEvent(Gap::Handle_t handle, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps) {
if (securitySetupInitiatedCallback) {
securitySetupInitiatedCallback(handle, allowBonding, requireMITM, iocaps);
}
}
void processSecuritySetupCompletedEvent(Gap::Handle_t handle, SecurityCompletionStatus_t status) {
if (securitySetupCompletedCallback) {
securitySetupCompletedCallback(handle, status);
}
}
void processLinkSecuredEvent(Gap::Handle_t handle, SecurityMode_t securityMode) {
if (linkSecuredCallback) {
linkSecuredCallback(handle, securityMode);
}
}
void processSecurityContextStoredEvent(Gap::Handle_t handle) {
if (securityContextStoredCallback) {
securityContextStoredCallback(handle);
}
}
void processPasskeyDisplayEvent(Gap::Handle_t handle, const Passkey_t passkey) {
if (passkeyDisplayCallback) {
passkeyDisplayCallback(handle, passkey);
}
}
protected:
SecurityManager() :
securitySetupInitiatedCallback(),
securitySetupCompletedCallback(),
linkSecuredCallback(),
securityContextStoredCallback(),
passkeyDisplayCallback() {
/* empty */
}
public:
/**
* Notify all registered onShutdown callbacks that the SecurityManager is
* about to be shutdown and clear all SecurityManager state of the
* associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in SecurityManager members. This shall be
* achieved by a call to SecurityManager::reset() from the sub-class'
* reset() implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
/* Notify that the instance is about to shutdown */
shutdownCallChain.call(this);
shutdownCallChain.clear();
securitySetupInitiatedCallback = NULL;
securitySetupCompletedCallback = NULL;
linkSecuredCallback = NULL;
securityContextStoredCallback = NULL;
passkeyDisplayCallback = NULL;
return BLE_ERROR_NONE;
}
protected:
SecuritySetupInitiatedCallback_t securitySetupInitiatedCallback;
SecuritySetupCompletedCallback_t securitySetupCompletedCallback;
LinkSecuredCallback_t linkSecuredCallback;
HandleSpecificEvent_t securityContextStoredCallback;
PasskeyDisplayCallback_t passkeyDisplayCallback;
private:
SecurityManagerShutdownCallbackChain_t shutdownCallChain;
};
#endif /*__SECURITY_MANAGER_H__*/

183
ble/ServiceDiscovery.h Normal file
View File

@ -0,0 +1,183 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SERVICE_DISOVERY_H__
#define __SERVICE_DISOVERY_H__
#include "UUID.h"
#include "Gap.h"
#include "GattAttribute.h"
class DiscoveredService;
class DiscoveredCharacteristic;
class ServiceDiscovery {
public:
/*
* Exposed application callback types.
*/
/**
* Callback type for when a matching service is found during service-
* discovery. The receiving function is passed in a pointer to a
* DiscoveredService object, which will remain valid for the lifetime of the
* callback. Memory for this object is owned by the BLE_API eventing
* framework. The application can safely make a persistent shallow-copy of
* this object to work with the service beyond the callback.
*/
typedef FunctionPointerWithContext<const DiscoveredService *> ServiceCallback_t;
/**
* Callback type for when a matching characteristic is found during service-
* discovery. The receiving function is passed in a pointer to a
* DiscoveredCharacteristic object, which will remain valid for the lifetime
* of the callback. Memory for this object is owned by the BLE_API eventing
* framework. The application can safely make a persistent shallow-copy of
* this object to work with the characteristic beyond the callback.
*/
typedef FunctionPointerWithContext<const DiscoveredCharacteristic *> CharacteristicCallback_t;
/**
* Callback type for when serviceDiscovery terminates.
*/
typedef FunctionPointerWithContext<Gap::Handle_t> TerminationCallback_t;
public:
/**
* Launch service discovery. Once launched, service discovery will remain
* active with callbacks being issued back into the application for matching
* services or characteristics. isActive() can be used to determine status, and
* a termination callback (if set up) will be invoked at the end. Service
* discovery can be terminated prematurely, if needed, using terminate().
*
* @param connectionHandle
* Handle for the connection with the peer.
* @param sc
* This is the application callback for a matching service. Taken as
* NULL by default. Note: service discovery may still be active
* when this callback is issued; calling asynchronous BLE-stack
* APIs from within this application callback might cause the
* stack to abort service discovery. If this becomes an issue, it
* may be better to make a local copy of the discoveredService and
* wait for service discovery to terminate before operating on the
* service.
* @param cc
* This is the application callback for a matching characteristic.
* Taken as NULL by default. Note: service discovery may still be
* active when this callback is issued; calling asynchronous
* BLE-stack APIs from within this application callback might cause
* the stack to abort service discovery. If this becomes an issue,
* it may be better to make a local copy of the discoveredCharacteristic
* and wait for service discovery to terminate before operating on the
* characteristic.
* @param matchingServiceUUID
* UUID-based filter for specifying a service in which the application is
* interested. By default it is set as the wildcard UUID_UNKNOWN,
* in which case it matches all services. If characteristic-UUID
* filter (below) is set to the wildcard value, then a service
* callback will be invoked for the matching service (or for every
* service if the service filter is a wildcard).
* @param matchingCharacteristicUUIDIn
* UUID-based filter for specifying a characteristic in which the application
* is interested. By default it is set as the wildcard UUID_UKNOWN
* to match against any characteristic. If both service-UUID
* filter and characteristic-UUID filter are used with non-wildcard
* values, then only a single characteristic callback is
* invoked for the matching characteristic.
*
* @note Using wildcard values for both service-UUID and characteristic-
* UUID will result in complete service discovery: callbacks being
* called for every service and characteristic.
*
* @note Providing NULL for the characteristic callback will result in
* characteristic discovery being skipped for each matching
* service. This allows for an inexpensive method to discover only
* services.
*
* @return
* BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error.
*/
virtual ble_error_t launch(Gap::Handle_t connectionHandle,
ServiceCallback_t sc = NULL,
CharacteristicCallback_t cc = NULL,
const UUID &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN),
const UUID &matchingCharacteristicUUIDIn = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) = 0;
/**
* Check whether service-discovery is currently active.
*/
virtual bool isActive(void) const = 0;
/**
* Terminate an ongoing service discovery. This should result in an
* invocation of the TerminationCallback if service discovery is active.
*/
virtual void terminate(void) = 0;
/**
* Set up a callback to be invoked when service discovery is terminated.
*/
virtual void onTermination(TerminationCallback_t callback) = 0;
/**
* Clear all ServiceDiscovery state of the associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in ServiceDiscovery members. This shall be
* achieved by a call to ServiceDiscovery::reset() from the sub-class'
* reset() implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
connHandle = 0;
matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN);
serviceCallback = NULL;
matchingCharacteristicUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN);
characteristicCallback = NULL;
return BLE_ERROR_NONE;
}
protected:
/**
* Connection handle as provided by the SoftDevice.
*/
Gap::Handle_t connHandle;
/**
* UUID-based filter that specifies the service that the application is
* interested in.
*/
UUID matchingServiceUUID;
/**
* The registered callback handle for when a matching service is found
* during service-discovery.
*/
ServiceCallback_t serviceCallback;
/**
* UUID-based filter that specifies the characteristic that the
* application is interested in.
*/
UUID matchingCharacteristicUUID;
/**
* The registered callback handler for when a matching characteristic is
* found during service-discovery.
*/
CharacteristicCallback_t characteristicCallback;
};
#endif /* ifndef __SERVICE_DISOVERY_H__ */

331
ble/UUID.h Normal file
View File

@ -0,0 +1,331 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __UUID_H__
#define __UUID_H__
#include <stdint.h>
#include <string.h>
#include <algorithm>
#include "blecommon.h"
/**
* A trivial converter for single hexadecimal character to an unsigned integer.
*
* @param c
* Hexadecimal character.
*
* @return The corresponding value as unsigned integer.
*/
static uint8_t char2int(char c) {
if ((c >= '0') && (c <= '9')) {
return c - '0';
} else if ((c >= 'a') && (c <= 'f')) {
return c - 'a' + 10;
} else if ((c >= 'A') && (c <= 'F')) {
return c - 'A' + 10;
} else {
return 0;
}
}
/**
* An instance of this class represents a Universally Unique Identifier (UUID)
* in the BLE API.
*/
class UUID {
public:
/**
* Enumeration of the possible types of UUIDs in BLE with regards to length.
*/
enum UUID_Type_t {
UUID_TYPE_SHORT = 0, /**< Short 16-bit UUID. */
UUID_TYPE_LONG = 1 /**< Full 128-bit UUID. */
};
/**
* Enumeration to specify byte ordering of the long version of the UUID.
*/
typedef enum {
MSB, /**< Most-significant byte first (at the smallest address) */
LSB /**< least-significant byte first (at the smallest address) */
} ByteOrder_t;
/**
* Type for a 16-bit UUID.
*/
typedef uint16_t ShortUUIDBytes_t;
/**
* Length of a long UUID in bytes.
*/
static const unsigned LENGTH_OF_LONG_UUID = 16;
/**
* Type for a 128-bit UUID.
*/
typedef uint8_t LongUUIDBytes_t[LENGTH_OF_LONG_UUID];
/**
* Maximum length of a string representation of a UUID not including the
* null termination ('\0'): two characters per
* byte plus four '-' characters.
*/
static const unsigned MAX_UUID_STRING_LENGTH = LENGTH_OF_LONG_UUID * 2 + 4;
public:
/**
* Creates a new 128-bit UUID.
*
* @note The UUID is a unique 128-bit (16 byte) ID used to identify
* different service or characteristics on the BLE device.
*
* @param stringUUID
* The 128-bit (16-byte) UUID as a human readable const-string.
* Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
* Upper and lower case supported. Hyphens are optional, but only
* upto four of them. The UUID is stored internally as a 16 byte
* array, LSB (little endian), which is opposite from the string.
*/
UUID(const char* stringUUID) : type(UUID_TYPE_LONG), baseUUID(), shortUUID(0) {
bool nibble = false;
uint8_t byte = 0;
size_t baseIndex = 0;
uint8_t tempUUID[LENGTH_OF_LONG_UUID];
/*
* Iterate through string, abort if NULL is encountered prematurely.
* Ignore upto four hyphens.
*/
for (size_t index = 0; (index < MAX_UUID_STRING_LENGTH) && (baseIndex < LENGTH_OF_LONG_UUID); index++) {
if (stringUUID[index] == '\0') {
/* Error abort */
break;
} else if (stringUUID[index] == '-') {
/* Ignore hyphen */
continue;
} else if (nibble) {
/* Got second nibble */
byte |= char2int(stringUUID[index]);
nibble = false;
/* Store copy */
tempUUID[baseIndex++] = byte;
} else {
/* Got first nibble */
byte = char2int(stringUUID[index]) << 4;
nibble = true;
}
}
/* Populate internal variables if string was successfully parsed */
if (baseIndex == LENGTH_OF_LONG_UUID) {
setupLong(tempUUID, UUID::MSB);
} else {
const uint8_t sig[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
setupLong(sig, UUID::MSB);
}
}
/**
* Creates a new 128-bit UUID.
*
* @param[in] longUUID
* The 128-bit (16-byte) UUID value.
* @param[in] order
* The bit order of the UUID, MSB by default.
*
* @note The UUID is a unique 128-bit (16 byte) ID used to identify
* different service or characteristics on the BLE device.
*/
UUID(const LongUUIDBytes_t longUUID, ByteOrder_t order = UUID::MSB) : type(UUID_TYPE_LONG), baseUUID(), shortUUID(0) {
setupLong(longUUID, order);
}
/**
* Creates a new 16-bit UUID.
*
* For efficiency, and because 16 bytes would take a large chunk of the
* 27-byte data payload length of the Link Layer, the BLE specification adds
* two additional UUID formats: 16-bit and 32-bit UUIDs. These shortened
* formats can be used only with UUIDs that are defined in the Bluetooth
* specification (listed by the Bluetooth SIG as standard
* Bluetooth UUIDs).
*
* To reconstruct the full 128-bit UUID from the shortened version, insert
* the 16-bit short value (indicated by xxxx, including leading zeros) into
* the Bluetooth Base UUID:
*
* 0000xxxx-0000-1000-8000-00805F9B34FB
*
* @param[in] _shortUUID
* The short UUID value.
*
* @note Shortening is not available for UUIDs that are not derived from the
* Bluetooth Base UUID. Such non-standard UUIDs are commonly called
* vendor-specific UUIDs. In these cases, youll need to use the full
* 128-bit UUID value at all times.
*
* @note The UUID is a unique 16-bit (2 byte) ID used to identify
* different service or characteristics on the BLE device.
*
* @note We do not yet support 32-bit shortened UUIDs.
*/
UUID(ShortUUIDBytes_t _shortUUID) : type(UUID_TYPE_SHORT), baseUUID(), shortUUID(_shortUUID) {
/* Empty */
}
/**
* Copy constructor.
*
* @param[in] source
* The UUID to copy.
*/
UUID(const UUID &source) {
type = source.type;
shortUUID = source.shortUUID;
memcpy(baseUUID, source.baseUUID, LENGTH_OF_LONG_UUID);
}
/**
* The empty constructor.
*
* @note The type of the resulting UUID instance is UUID_TYPE_SHORT and the
* value BLE_UUID_UNKNOWN.
*/
UUID(void) : type(UUID_TYPE_SHORT), shortUUID(BLE_UUID_UNKNOWN) {
/* empty */
}
/**
* Fill in a 128-bit UUID; this is useful when the UUID is not known at the
* time of the object construction.
*
* @param[in] longUUID
* The UUID value to copy.
* @param[in] order
* The byte ordering of the UUID at @p longUUID.
*/
void setupLong(const LongUUIDBytes_t longUUID, ByteOrder_t order = UUID::MSB) {
type = UUID_TYPE_LONG;
if (order == UUID::MSB) {
/*
* Switch endian. Input is big-endian, internal representation
* is little endian.
*/
std::reverse_copy(longUUID, longUUID + LENGTH_OF_LONG_UUID, baseUUID);
} else {
std::copy(longUUID, longUUID + LENGTH_OF_LONG_UUID, baseUUID);
}
shortUUID = (uint16_t)((baseUUID[13] << 8) | (baseUUID[12]));
}
public:
/**
* Check whether this UUID is short or long.
*
* @return UUID_TYPE_SHORT if the UUID is short, UUID_TYPE_LONG otherwise.
*/
UUID_Type_t shortOrLong(void) const {
return type;
}
/**
* Get a pointer to the UUID value based on the current UUID type.
*
* @return A pointer to the short UUID if the type is set to
* UUID_TYPE_SHORT. Otherwise, a pointer to the long UUID if the
* type is set to UUID_TYPE_LONG.
*/
const uint8_t *getBaseUUID(void) const {
if (type == UUID_TYPE_SHORT) {
return (const uint8_t*)&shortUUID;
} else {
return baseUUID;
}
}
/**
* Get the short UUID.
*
* @return The short UUID.
*/
ShortUUIDBytes_t getShortUUID(void) const {
return shortUUID;
}
/**
* Get the length (in bytes) of the UUID based on its type.
*
* @retval sizeof(ShortUUIDBytes_t) if the UUID type is UUID_TYPE_SHORT.
* @retval LENGTH_OF_LONG_UUID if the UUID type is UUID_TYPE_LONG.
*/
uint8_t getLen(void) const {
return ((type == UUID_TYPE_SHORT) ? sizeof(ShortUUIDBytes_t) : LENGTH_OF_LONG_UUID);
}
/**
* Overload == operator to enable UUID comparisons.
*
* @param[in] other
* The other UUID in the comparison.
*
* @return true if this == @p other, false otherwise.
*/
bool operator== (const UUID &other) const {
if ((this->type == UUID_TYPE_SHORT) && (other.type == UUID_TYPE_SHORT) &&
(this->shortUUID == other.shortUUID)) {
return true;
}
if ((this->type == UUID_TYPE_LONG) && (other.type == UUID_TYPE_LONG) &&
(memcmp(this->baseUUID, other.baseUUID, LENGTH_OF_LONG_UUID) == 0)) {
return true;
}
return false;
}
/**
* Overload != operator to enable UUID comparisons.
*
* @param[in] other
* The other UUID in the comparison.
*
* @return true if this != @p other, false otherwise.
*/
bool operator!= (const UUID &other) const {
return !(*this == other);
}
private:
/**
* The UUID type. Refer to UUID_Type_t.
*/
UUID_Type_t type;
/**
* The long UUID value.
*/
LongUUIDBytes_t baseUUID;
/**
* The short UUID value.
*/
ShortUUIDBytes_t shortUUID;
};
#endif // ifndef __UUID_H__

81
ble/blecommon.h Normal file
View File

@ -0,0 +1,81 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_COMMON_H__
#define __BLE_COMMON_H__
#ifdef __cplusplus
extern "C" {
#endif
/*! @brief Assigned values for BLE UUIDs. */
enum {
BLE_UUID_UNKNOWN = 0x0000, /**< Reserved UUID. */
BLE_UUID_SERVICE_PRIMARY = 0x2800, /**< Primary Service. */
BLE_UUID_SERVICE_SECONDARY = 0x2801, /**< Secondary Service. */
BLE_UUID_SERVICE_INCLUDE = 0x2802, /**< Include. */
BLE_UUID_CHARACTERISTIC = 0x2803, /**< Characteristic. */
BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP = 0x2900, /**< Characteristic Extended Properties Descriptor. */
BLE_UUID_DESCRIPTOR_CHAR_USER_DESC = 0x2901, /**< Characteristic User Description Descriptor. */
BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG = 0x2902, /**< Client Characteristic Configuration Descriptor. */
BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG = 0x2903, /**< Server Characteristic Configuration Descriptor. */
BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT = 0x2904, /**< Characteristic Presentation Format Descriptor. */
BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT = 0x2905, /**< Characteristic Aggregate Format Descriptor. */
/* GATT specific UUIDs */
BLE_UUID_GATT = 0x1801, /**< Generic Attribute Profile. */
BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED = 0x2A05, /**< Service Changed Characteristic. */
/* GAP specific UUIDs */
BLE_UUID_GAP = 0x1800, /**< Generic Access Profile. */
BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME = 0x2A00, /**< Device Name Characteristic. */
BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE = 0x2A01, /**< Appearance Characteristic. */
BLE_UUID_GAP_CHARACTERISTIC_PPF = 0x2A02, /**< Peripheral Privacy Flag Characteristic. */
BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR = 0x2A03, /**< Reconnection Address Characteristic. */
BLE_UUID_GAP_CHARACTERISTIC_PPCP = 0x2A04, /**< Peripheral Preferred Connection Parameters Characteristic. */
};
/*! @brief Error codes for the BLE API. */
enum ble_error_t {
BLE_ERROR_NONE = 0, /**< No error. */
BLE_ERROR_BUFFER_OVERFLOW = 1, /**< The requested action would cause a buffer overflow and has been aborted. */
BLE_ERROR_NOT_IMPLEMENTED = 2, /**< Requested a feature that isn't yet implemented or isn't supported by the target HW. */
BLE_ERROR_PARAM_OUT_OF_RANGE = 3, /**< One of the supplied parameters is outside the valid range. */
BLE_ERROR_INVALID_PARAM = 4, /**< One of the supplied parameters is invalid. */
BLE_STACK_BUSY = 5, /**< The stack is busy. */
BLE_ERROR_INVALID_STATE = 6, /**< Invalid state. */
BLE_ERROR_NO_MEM = 7, /**< Out of memory */
BLE_ERROR_OPERATION_NOT_PERMITTED = 8,
BLE_ERROR_INITIALIZATION_INCOMPLETE = 9,
BLE_ERROR_ALREADY_INITIALIZED = 10,
BLE_ERROR_UNSPECIFIED = 11, /**< Unknown error. */
BLE_ERROR_INTERNAL_STACK_FAILURE = 12, /**< The platform-specific stack failed */
};
/** @brief Default MTU size. */
static const unsigned BLE_GATT_MTU_SIZE_DEFAULT = 23;
enum HVXType_t {
BLE_HVX_NOTIFICATION = 0x01, /**< Handle Value Notification. */
BLE_HVX_INDICATION = 0x02, /**< Handle Value Indication. */
};
#ifdef __cplusplus
}
#endif
#endif // ifndef __BLE_COMMON_H__

26
ble/deprecate.h Normal file
View File

@ -0,0 +1,26 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DEPRECATE_H__
#define __DEPRECATE_H__
#ifdef YOTTA_CFG_MBED_OS
#include "compiler-polyfill/attributes.h"
#else
#define __deprecated_message(msg)
#endif
#endif

View File

@ -0,0 +1,77 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_BATTERY_SERVICE_H__
#define __BLE_BATTERY_SERVICE_H__
#include "ble/BLE.h"
/**
* @class BatteryService
* @brief BLE Battery Service. This service displays the battery level from 0% to 100%, represented as an 8bit number.
* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml
* Battery Level Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.battery_level.xml
*/
class BatteryService {
public:
/**
* @param[in] _ble
* BLE object for the underlying controller.
* @param[in] level
* 8bit batterly level. Usually used to represent percentage of batterly charge remaining.
*/
BatteryService(BLE &_ble, uint8_t level = 100) :
ble(_ble),
batteryLevel(level),
batteryLevelCharacteristic(GattCharacteristic::UUID_BATTERY_LEVEL_CHAR, &batteryLevel, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
GattCharacteristic *charTable[] = {&batteryLevelCharacteristic};
GattService batteryService(GattService::UUID_BATTERY_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
ble.addService(batteryService);
}
/**
* @brief Update the battery level with a new value. Valid values lie between 0 and 100,
* anything outside this range will be ignored.
*
* @param newLevel
* Update to battery level.
*/
void updateBatteryLevel(uint8_t newLevel) {
batteryLevel = newLevel;
ble.gattServer().write(batteryLevelCharacteristic.getValueHandle(), &batteryLevel, 1);
}
protected:
/**
* A reference to the underlying BLE instance that this object is attached to.
* The services and characteristics will be registered in this BLE instance.
*/
BLE &ble;
/**
* The current battery level represented as an integer from 0% to 100%.
*/
uint8_t batteryLevel;
/**
* A ReadOnlyGattCharacteristic that allows access to the peer device to the
* batteryLevel value through BLE.
*/
ReadOnlyGattCharacteristic<uint8_t> batteryLevelCharacteristic;
};
#endif /* #ifndef __BLE_BATTERY_SERVICE_H__*/

146
ble/services/DFUService.h Normal file
View File

@ -0,0 +1,146 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef TARGET_NRF51822 /* DFU only supported on nrf51 platforms */
#ifndef __BLE_DFU_SERVICE_H__
#define __BLE_DFU_SERVICE_H__
#include "ble/BLE.h"
#include "ble/UUID.h"
extern "C" {
#include "dfu_app_handler.h"
}
extern const uint8_t DFUServiceBaseUUID[];
extern const uint16_t DFUServiceShortUUID;
extern const uint16_t DFUServiceControlCharacteristicShortUUID;
extern const uint8_t DFUServiceUUID[];
extern const uint8_t DFUServiceControlCharacteristicUUID[];
extern const uint8_t DFUServicePacketCharacteristicUUID[];
/**
* @class DFUService
* @brief Device Firmware Update Service.
*/
class DFUService {
public:
/**
* @brief Signature for the handover callback. The application may provide this
* callback when setting up the DFU service. The callback is then
* invoked before handing control over to the bootloader.
*/
typedef void (*ResetPrepare_t)(void);
public:
/**
* @brief Adds Device Firmware Update Service to an existing BLE object.
*
* @param[ref] _ble
* BLE object for the underlying controller.
* @param[in] _handoverCallback
* Application-specific handover callback.
*/
DFUService(BLE &_ble, ResetPrepare_t _handoverCallback = NULL) :
ble(_ble),
controlPoint(DFUServiceControlCharacteristicUUID, controlBytes, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
packet(DFUServicePacketCharacteristicUUID, packetBytes, SIZEOF_PACKET_BYTES, SIZEOF_PACKET_BYTES,
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
controlBytes(),
packetBytes() {
static bool serviceAdded = false; /* We only add the DFU service once. */
if (serviceAdded) {
return;
}
/* Set an initial value for control bytes, so that the application's DFU service can
* be distinguished from the real DFU service provided by the bootloader. */
controlBytes[0] = 0xFF;
controlBytes[1] = 0xFF;
GattCharacteristic *dfuChars[] = {&controlPoint, &packet};
GattService dfuService(DFUServiceUUID, dfuChars, sizeof(dfuChars) / sizeof(GattCharacteristic *));
ble.addService(dfuService);
handoverCallback = _handoverCallback;
serviceAdded = true;
ble.onDataWritten(this, &DFUService::onDataWritten);
}
/**
* @brief Get the handle for the value attribute of the control characteristic.
*/
uint16_t getControlHandle(void) const {
return controlPoint.getValueHandle();
}
/**
* @brief This callback allows the DFU service to receive the initial trigger to
* hand control over to the bootloader. First, the application is given a
* chance to clean up.
*
* @param[in] params
* Information about the characterisitc being updated.
*/
virtual void onDataWritten(const GattWriteCallbackParams *params) {
if (params->handle == controlPoint.getValueHandle()) {
/* At present, writing anything will do the trick - this needs to be improved. */
if (handoverCallback) {
handoverCallback();
}
// Call bootloader_start implicitly trough a event handler call
// it is a work around for bootloader_start not being public in sdk 8.1
ble_dfu_t p_dfu;
ble_dfu_evt_t p_evt;
p_dfu.conn_handle = params->connHandle;
p_evt.ble_dfu_evt_type = BLE_DFU_START;
dfu_app_on_dfu_evt(&p_dfu, &p_evt);
}
}
protected:
static const unsigned SIZEOF_CONTROL_BYTES = 2;
static const unsigned SIZEOF_PACKET_BYTES = 20;
protected:
BLE &ble;
/**< Writing to the control characteristic triggers the handover to DFU
* bootloader. At present, writing anything will do the trick - this needs
* to be improved. */
WriteOnlyArrayGattCharacteristic<uint8_t, SIZEOF_CONTROL_BYTES> controlPoint;
/**< The packet characteristic in this service doesn't do anything meaningful;
* it is only a placeholder to mimic the corresponding characteristic in the
* actual DFU service implemented by the bootloader. Without this, some
* FOTA clients might get confused, because service definitions change after
* handing control over to the bootloader. */
GattCharacteristic packet;
uint8_t controlBytes[SIZEOF_CONTROL_BYTES];
uint8_t packetBytes[SIZEOF_PACKET_BYTES];
static ResetPrepare_t handoverCallback; /**< Application-specific handover callback. */
};
#endif /* #ifndef __BLE_DFU_SERVICE_H__*/
#endif /* #ifdef TARGET_NRF51822 */

View File

@ -0,0 +1,138 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_DEVICE_INFORMATION_SERVICE_H__
#define __BLE_DEVICE_INFORMATION_SERVICE_H__
#include "ble/BLE.h"
/**
* @class DeviceInformationService
* @brief BLE Device Information Service
* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.device_information.xml
* Manufacturer Name String Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.manufacturer_name_string.xml
*/
class DeviceInformationService {
public:
/**
* @brief Device Information Service Constructor: copies device-specific information
* into the BLE stack.
*
* @param[in] _ble
* A reference to a BLE object for the underlying controller.
* @param[in] manufacturersName
* The name of the manufacturer of the device.
* @param[in] modelNumber
* The model number that is assigned by the device vendor.
* @param[in] serialNumber
* The serial number for a particular instance of the device.
* @param[in] hardwareRevision
* The hardware revision for the hardware within the device.
* @param[in] firmwareRevision
* The device's firmware version.
* @param[in] softwareRevision
* The device's software version.
*/
DeviceInformationService(BLE &_ble,
const char *manufacturersName = NULL,
const char *modelNumber = NULL,
const char *serialNumber = NULL,
const char *hardwareRevision = NULL,
const char *firmwareRevision = NULL,
const char *softwareRevision = NULL) :
ble(_ble),
manufacturersNameStringCharacteristic(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR,
(uint8_t *)manufacturersName,
(manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* Min length */
(manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
modelNumberStringCharacteristic(GattCharacteristic::UUID_MODEL_NUMBER_STRING_CHAR,
(uint8_t *)modelNumber,
(modelNumber != NULL) ? strlen(modelNumber) : 0, /* Min length */
(modelNumber != NULL) ? strlen(modelNumber) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
serialNumberStringCharacteristic(GattCharacteristic::UUID_SERIAL_NUMBER_STRING_CHAR,
(uint8_t *)serialNumber,
(serialNumber != NULL) ? strlen(serialNumber) : 0, /* Min length */
(serialNumber != NULL) ? strlen(serialNumber) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
hardwareRevisionStringCharacteristic(GattCharacteristic::UUID_HARDWARE_REVISION_STRING_CHAR,
(uint8_t *)hardwareRevision,
(hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* Min length */
(hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
firmwareRevisionStringCharacteristic(GattCharacteristic::UUID_FIRMWARE_REVISION_STRING_CHAR,
(uint8_t *)firmwareRevision,
(firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* Min length */
(firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
softwareRevisionStringCharacteristic(GattCharacteristic::UUID_SOFTWARE_REVISION_STRING_CHAR,
(uint8_t *)softwareRevision,
(softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* Min length */
(softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)
{
static bool serviceAdded = false; /* We only add the information service once. */
if (serviceAdded) {
return;
}
GattCharacteristic *charTable[] = {&manufacturersNameStringCharacteristic,
&modelNumberStringCharacteristic,
&serialNumberStringCharacteristic,
&hardwareRevisionStringCharacteristic,
&firmwareRevisionStringCharacteristic,
&softwareRevisionStringCharacteristic};
GattService deviceInformationService(GattService::UUID_DEVICE_INFORMATION_SERVICE, charTable,
sizeof(charTable) / sizeof(GattCharacteristic *));
ble.addService(deviceInformationService);
serviceAdded = true;
}
protected:
/**
* A reference to the BLE instance object to which the services and
* characteristics will be added.
*/
BLE &ble;
/**
* BLE characterising to allow BLE peers access to the manufacturer's name.
*/
GattCharacteristic manufacturersNameStringCharacteristic;
/**
* BLE characterising to allow BLE peers access to the model number.
*/
GattCharacteristic modelNumberStringCharacteristic;
/**
* BLE characterising to allow BLE peers access to the serial number.
*/
GattCharacteristic serialNumberStringCharacteristic;
/**
* BLE characterising to allow BLE peers access to the hardware revision string.
*/
GattCharacteristic hardwareRevisionStringCharacteristic;
/**
* BLE characterising to allow BLE peers access to the firmware revision string.
*/
GattCharacteristic firmwareRevisionStringCharacteristic;
/**
* BLE characterising to allow BLE peers access to the software revision string.
*/
GattCharacteristic softwareRevisionStringCharacteristic;
};
#endif /* #ifndef __BLE_DEVICE_INFORMATION_SERVICE_H__*/

View File

@ -0,0 +1,542 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SERVICES_EDDYSTONE_BEACON_CONFIG_SERVICE_H_
#define SERVICES_EDDYSTONE_BEACON_CONFIG_SERVICE_H_
#warning ble/services/EddystoneConfigService.h is deprecated. Please use the example in 'github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService'.
#include "mbed.h"
#include "ble/BLE.h"
#include "ble/services/EddystoneService.h"
#define UUID_URI_BEACON(FIRST, SECOND) { \
0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba, \
0xab, 0x96, 0x99, 0xb9, 0x1a, 0xc9, 0x81, 0xd8, \
}
static const uint8_t UUID_URI_BEACON_SERVICE[] = UUID_URI_BEACON(0x20, 0x80);
static const uint8_t UUID_LOCK_STATE_CHAR[] = UUID_URI_BEACON(0x20, 0x81);
static const uint8_t UUID_LOCK_CHAR[] = UUID_URI_BEACON(0x20, 0x82);
static const uint8_t UUID_UNLOCK_CHAR[] = UUID_URI_BEACON(0x20, 0x83);
static const uint8_t UUID_URI_DATA_CHAR[] = UUID_URI_BEACON(0x20, 0x84);
static const uint8_t UUID_FLAGS_CHAR[] = UUID_URI_BEACON(0x20, 0x85);
static const uint8_t UUID_ADV_POWER_LEVELS_CHAR[] = UUID_URI_BEACON(0x20, 0x86);
static const uint8_t UUID_TX_POWER_MODE_CHAR[] = UUID_URI_BEACON(0x20, 0x87);
static const uint8_t UUID_BEACON_PERIOD_CHAR[] = UUID_URI_BEACON(0x20, 0x88);
static const uint8_t UUID_RESET_CHAR[] = UUID_URI_BEACON(0x20, 0x89);
extern const uint8_t BEACON_EDDYSTONE[2];
/**
* @class EddystoneConfigService
* @brief Eddystone Configuration Service. Used to set URL, adjust power levels, and set flags.
* See https://github.com/google/eddystone
*
*/
class EddystoneConfigService
{
public:
/**
* @brief Transmission Power Modes for UriBeacon
*/
enum {
TX_POWER_MODE_LOWEST,
TX_POWER_MODE_LOW,
TX_POWER_MODE_MEDIUM,
TX_POWER_MODE_HIGH,
NUM_POWER_MODES
};
static const unsigned ADVERTISING_INTERVAL_MSEC = 1000; // Advertising interval for config service.
static const unsigned SERVICE_DATA_MAX = 31; // Maximum size of service data in ADV packets.
typedef uint8_t Lock_t[16]; /* 128 bits. */
typedef int8_t PowerLevels_t[NUM_POWER_MODES];
// There are currently three subframes defined: URI, UID, and TLM.
#define EDDYSTONE_MAX_FRAMETYPE 3
static const unsigned URI_DATA_MAX = 18;
typedef uint8_t UriData_t[URI_DATA_MAX];
// UID Frame Type subfields.
static const size_t UID_NAMESPACEID_SIZE = 10;
typedef uint8_t UIDNamespaceID_t[UID_NAMESPACEID_SIZE];
static const size_t UID_INSTANCEID_SIZE = 6;
typedef uint8_t UIDInstanceID_t[UID_INSTANCEID_SIZE];
// Eddystone Frame Type ID.
static const uint8_t FRAME_TYPE_UID = 0x00;
static const uint8_t FRAME_TYPE_URL = 0x10;
static const uint8_t FRAME_TYPE_TLM = 0x20;
static const uint8_t FRAME_SIZE_TLM = 14; // TLM frame is a constant 14B.
static const uint8_t FRAME_SIZE_UID = 20; // includes RFU bytes.
struct Params_t {
// Config Data
bool isConfigured; // Flag for configuration being complete:
// True = configured, False = not configured. Reset at instantiation, used for external callbacks.
uint8_t lockedState;
Lock_t lock;
uint8_t flags;
PowerLevels_t advPowerLevels; // Current value of AdvertisedPowerLevels.
uint8_t txPowerMode; // Firmware power levels used with setTxPower().
uint16_t beaconPeriod;
// TLM Frame Data
uint8_t tlmVersion; // Version of TLM packet.
bool tlmEnabled;
float tlmBeaconPeriod; // How often to broadcat TLM frame, in seconds.
// URI Frame Data
uint8_t uriDataLength;
UriData_t uriData;
bool uriEnabled;
float uriBeaconPeriod; // How often to broadcast URIFrame, in seconds.
// UID Frame Data
UIDNamespaceID_t uidNamespaceID; // UUID type, Namespace ID, 10B.
UIDInstanceID_t uidInstanceID; // UUID type, Instance ID, 6B.
bool uidEnabled;
float uidBeaconPeriod; // How often to broadcast UID Frame, in seconds.
};
/**
* @param[ref] ble
* BLEDevice object for the underlying controller.
* @param[in/out] paramsIn
* Reference to application-visible beacon state, loaded
* from persistent storage at startup.
* @param[in] defaultAdvPowerLevelsIn
* Default power-levels array; applies only if resetToDefaultsFlag is true.
*/
EddystoneConfigService(BLEDevice &bleIn,
Params_t &paramsIn,
PowerLevels_t &defaultAdvPowerLevelsIn,
PowerLevels_t &radioPowerLevelsIn) :
ble(bleIn),
params(paramsIn), // Initialize URL data.
defaultAdvPowerLevels(defaultAdvPowerLevelsIn),
radioPowerLevels(radioPowerLevelsIn),
initSucceeded(false),
resetFlag(),
defaultUidNamespaceID(), // Initialize UID data.
defaultUidInstanceID(),
defaultUidPower(defaultAdvPowerLevelsIn[params.txPowerMode]),
uidIsSet(false),
defaultUriDataLength(),
defaultUriData(),
defaultUrlPower(defaultAdvPowerLevelsIn[params.txPowerMode]),
urlIsSet(false),
tlmIsSet(false),
lockedStateChar(UUID_LOCK_STATE_CHAR, &params.lockedState),
lockChar(UUID_LOCK_CHAR, &params.lock),
uriDataChar(UUID_URI_DATA_CHAR, params.uriData, 0, URI_DATA_MAX,
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
unlockChar(UUID_UNLOCK_CHAR, &params.lock),
flagsChar(UUID_FLAGS_CHAR, &params.flags),
advPowerLevelsChar(UUID_ADV_POWER_LEVELS_CHAR, &params.advPowerLevels),
txPowerModeChar(UUID_TX_POWER_MODE_CHAR, &params.txPowerMode),
beaconPeriodChar(UUID_BEACON_PERIOD_CHAR, &params.beaconPeriod),
resetChar(UUID_RESET_CHAR, &resetFlag) {
// Set Eddystone as not configured yet. Used to exit config before timeout if GATT services are written to.
params.isConfigured = false;
lockChar.setWriteAuthorizationCallback(this, &EddystoneConfigService::lockAuthorizationCallback);
unlockChar.setWriteAuthorizationCallback(this, &EddystoneConfigService::unlockAuthorizationCallback);
uriDataChar.setWriteAuthorizationCallback(this, &EddystoneConfigService::uriDataWriteAuthorizationCallback);
flagsChar.setWriteAuthorizationCallback(this, &EddystoneConfigService::basicAuthorizationCallback<uint8_t>);
advPowerLevelsChar.setWriteAuthorizationCallback(this, &EddystoneConfigService::basicAuthorizationCallback<PowerLevels_t>);
txPowerModeChar.setWriteAuthorizationCallback(this, &EddystoneConfigService::powerModeAuthorizationCallback);
beaconPeriodChar.setWriteAuthorizationCallback(this, &EddystoneConfigService::basicAuthorizationCallback<uint16_t>);
resetChar.setWriteAuthorizationCallback(this, &EddystoneConfigService::basicAuthorizationCallback<uint8_t>);
static GattCharacteristic *charTable[] = {
&lockedStateChar, &lockChar, &unlockChar, &uriDataChar,
&flagsChar, &advPowerLevelsChar, &txPowerModeChar, &beaconPeriodChar, &resetChar
};
GattService configService(UUID_URI_BEACON_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
ble.addService(configService);
ble.onDataWritten(this, &EddystoneConfigService::onDataWrittenCallback);
}
/**
* @brief Start EddystoneConfig advertising. This function should be called
* after the EddystoneConfig constructor and after all the frames have been added.
*
* @paramsP[in] resetToDefaultsFlag
* Applies to the state of the 'paramsIn' parameter.
* If true, it indicates that paramsIn is potentially
* un-initialized, and default values should be used
* instead. Otherwise, paramsIn overrides the defaults.
*/
void start(bool resetToDefaultsFlag){
INFO("reset to defaults flag = %d", resetToDefaultsFlag);
if (!resetToDefaultsFlag && (params.uriDataLength > URI_DATA_MAX)) {
INFO("Reset to Defaults triggered");
resetToDefaultsFlag = true;
}
if (resetToDefaultsFlag) {
resetToDefaults();
} else {
updateCharacteristicValues();
}
setupEddystoneConfigAdvertisements(); /* Set up advertising for the config service. */
initSucceeded = true;
}
/*
* Check if Eddystone initialized successfully.
*/
bool initSuccessfully(void) const {
return initSucceeded;
}
/*
* @brief Function to update the default values for the TLM frame. Only applied if Reset Defaults is applied.
*
* @param[in] tlmVersionIn Version of the TLM frame being used.
* @param[in] advPeriodInMin How long between TLM frames being advertised, measured in minutes.
*
*/
void setDefaultTLMFrameData(uint8_t tlmVersionIn = 0, float advPeriodInSec = 60){
DBG("Setting Default TLM Data, version = %d, advPeriodInMind= %f", tlmVersionIn, advPeriodInSec);
defaultTlmVersion = tlmVersionIn;
TlmBatteryVoltage = 0;
TlmBeaconTemp = 0x8000;
TlmPduCount = 0;
TlmTimeSinceBoot = 0;
defaultTlmAdvPeriod = advPeriodInSec;
tlmIsSet = true; // Flag to add this to Eddystone service when config is done.
}
/*
* @brief Function to update the default values for the URI frame. Only applied if Reset Defaults is applied.
*
* @param[in] uriIn URL to advertise.
* @param[in] advPeriod How long to advertise the URL, measured in number of ADV frames.
*
*/
void setDefaultURIFrameData(const char *uriIn, float advPeriod = 1){
DBG("Setting Default URI Data");
// Set URL Frame
EddystoneService::encodeURL(uriIn, defaultUriData, defaultUriDataLength); // Encode URL to URL Formatting.
if (defaultUriDataLength > URI_DATA_MAX) {
return;
}
INFO("\t URI input = %s : %d", uriIn, defaultUriDataLength);
INFO("\t default URI = %s : %d ", defaultUriData, defaultUriDataLength );
defaultUriAdvPeriod = advPeriod;
urlIsSet = true; // Flag to add this to Eddystone service when config is done.
}
/*
* @brief Function to update the default values for the UID frame. Only applied if Reset Defaults is applied.
*
* @param[in] namespaceID 10Byte Namespace ID.
* @param[in] instanceID 6Byte Instance ID.
* @param[in] advPeriod How long to advertise the URL, measured in the number of ADV frames.
*
*/
void setDefaultUIDFrameData(UIDNamespaceID_t *namespaceID, UIDInstanceID_t *instanceID, float advPeriod = 10){
//Set UID frame
DBG("Setting default UID Data");
memcpy(defaultUidNamespaceID, namespaceID, UID_NAMESPACEID_SIZE);
memcpy(defaultUidInstanceID, instanceID, UID_INSTANCEID_SIZE);
defaultUidAdvPeriod = advPeriod;
uidIsSet = true; // Flag to add this to Eddystone service when config is done.
}
/* Start out by advertising the config service for a limited time after
* startup, then switch to the normal non-connectible beacon functionality.
*/
void setupEddystoneConfigAdvertisements() {
const char DEVICE_NAME[] = "eddystone Config";
ble.clearAdvertisingPayload();
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
// UUID is in a different order in the ADV frame (!)
uint8_t reversedServiceUUID[sizeof(UUID_URI_BEACON_SERVICE)];
for (unsigned int i = 0; i < sizeof(UUID_URI_BEACON_SERVICE); i++) {
reversedServiceUUID[i] = UUID_URI_BEACON_SERVICE[sizeof(UUID_URI_BEACON_SERVICE) - i - 1];
}
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, reversedServiceUUID, sizeof(reversedServiceUUID));
ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG);
ble.accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME, reinterpret_cast<const uint8_t *>(&DEVICE_NAME), sizeof(DEVICE_NAME));
ble.accumulateScanResponse(
GapAdvertisingData::TX_POWER_LEVEL,
reinterpret_cast<uint8_t *>(&defaultAdvPowerLevels[EddystoneConfigService::TX_POWER_MODE_LOW]),
sizeof(uint8_t));
ble.setTxPower(radioPowerLevels[params.txPowerMode]);
ble.setDeviceName(reinterpret_cast<const uint8_t *>(&DEVICE_NAME));
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.setAdvertisingInterval(ADVERTISING_INTERVAL_MSEC);
}
/*
* This function actually impliments the Eddystone Beacon service. It can be called with the help of the wrapper function
* to load saved config params, or it can be called explicitly to reset the Eddystone beacon to hardcoded values on each reset.
*
*/
void setupEddystoneAdvertisements() {
DBG("Switching Config -> adv");
// Save params to storage.
extern void saveURIBeaconConfigParams(const Params_t *paramsP); /* forward declaration; necessary to avoid a circular dependency. */
saveURIBeaconConfigParams(&params);
INFO("Saved Params to Memory.")
// Set up Eddystone Service.
static EddystoneService eddyServ(ble, params.beaconPeriod, radioPowerLevels[params.txPowerMode]);
// Set configured frames (TLM, UID, URI and so on).
if (params.tlmEnabled) {
eddyServ.setTLMFrameData(params.tlmVersion, params.tlmBeaconPeriod);
}
if (params.uriEnabled) {
eddyServ.setURLFrameEncodedData(params.advPowerLevels[params.txPowerMode], (const char *) params.uriData, params.uriDataLength, params.uriBeaconPeriod);
}
if (params.uidEnabled) {
eddyServ.setUIDFrameData(params.advPowerLevels[params.txPowerMode],
(uint8_t *)params.uidNamespaceID,
(uint8_t *)params.uidInstanceID,
params.uidBeaconPeriod);
}
// Start advertising the Eddystone service.
eddyServ.start();
}
private:
/*
* This callback is invoked when a GATT client attempts to modify any of the
* characteristics of this service. Attempts to do so are also applied to
* the internal state of this service object.
*/
void onDataWrittenCallback(const GattWriteCallbackParams *writeParams) {
uint16_t handle = writeParams->handle;
if (handle == lockChar.getValueHandle()) {
// Validated earlier.
memcpy(params.lock, writeParams->data, sizeof(Lock_t));
// Set the state to be locked by the lock code (note: zeros are a valid lock).
params.lockedState = true;
INFO("Device Locked");
} else if (handle == unlockChar.getValueHandle()) {
// Validated earlier.
params.lockedState = false;
INFO("Device Unlocked");
} else if (handle == uriDataChar.getValueHandle()) {
params.uriDataLength = writeParams->len;
memset(params.uriData, 0x00, URI_DATA_MAX); // Clear URI string.
memcpy(params.uriData, writeParams->data, writeParams->len); // Set URI string.
params.uriEnabled = true;
INFO("URI = %s, URILen = %d", writeParams->data, writeParams->len);
} else if (handle == flagsChar.getValueHandle()) {
params.flags = *(writeParams->data);
INFO("flagsChar = 0x%x", params.flags);
} else if (handle == advPowerLevelsChar.getValueHandle()) {
memcpy(params.advPowerLevels, writeParams->data, sizeof(PowerLevels_t));
INFO("PowerLevelsChar = %4x", params.advPowerLevels);
} else if (handle == txPowerModeChar.getValueHandle()) {
params.txPowerMode = *(writeParams->data);
INFO("TxPowerModeChar = %d", params.txPowerMode);
} else if (handle == beaconPeriodChar.getValueHandle()) {
params.beaconPeriod = *((uint16_t *)(writeParams->data));
INFO("BeaconPeriod = %d", params.beaconPeriod);
/* Re-map beaconPeriod to within permissible bounds if necessary. */
if (params.beaconPeriod != 0) {
bool paramsUpdated = false;
if (params.beaconPeriod < ble.getMinAdvertisingInterval()) {
params.beaconPeriod = ble.getMinAdvertisingInterval();
paramsUpdated = true;
} else if (params.beaconPeriod > ble.getMaxAdvertisingInterval()) {
params.beaconPeriod = ble.getMaxAdvertisingInterval();
paramsUpdated = true;
}
if (paramsUpdated) {
ble.updateCharacteristicValue(beaconPeriodChar.getValueHandle(), reinterpret_cast<uint8_t *>(&params.beaconPeriod), sizeof(uint16_t));
}
}
} else if (handle == resetChar.getValueHandle()) {
INFO("Reset triggered from Config Service, resetting to defaults");
resetToDefaults();
}
updateCharacteristicValues();
params.isConfigured = true; // Some configuration data has been passed; on disconnect switch to advertising mode.
}
/*
* Reset the default values.
*/
void resetToDefaults(void) {
INFO("Resetting to defaults");
// General.
params.lockedState = false;
memset(params.lock, 0, sizeof(Lock_t));
params.flags = 0x10;
memcpy(params.advPowerLevels, defaultAdvPowerLevels, sizeof(PowerLevels_t));
params.txPowerMode = TX_POWER_MODE_LOW;
params.beaconPeriod = (uint16_t) defaultUriAdvPeriod * 1000;
// TLM Frame.
params.tlmVersion = defaultTlmVersion;
params.tlmBeaconPeriod = defaultTlmAdvPeriod;
params.tlmEnabled = tlmIsSet;
// URL Frame.
memcpy(params.uriData, defaultUriData, URI_DATA_MAX);
params.uriDataLength = defaultUriDataLength;
params.uriBeaconPeriod = defaultUriAdvPeriod;
params.uriEnabled = urlIsSet;
// UID Frame.
memcpy(params.uidNamespaceID, defaultUidNamespaceID, UID_NAMESPACEID_SIZE);
memcpy(params.uidInstanceID, defaultUidInstanceID, UID_INSTANCEID_SIZE);
params.uidBeaconPeriod = defaultUidAdvPeriod;
params.uidEnabled = uidIsSet;
updateCharacteristicValues();
}
/*
* Internal helper function used to update the GATT database following any
* change to the internal state of the service object.
*/
void updateCharacteristicValues(void) {
ble.updateCharacteristicValue(lockedStateChar.getValueHandle(), &params.lockedState, 1);
ble.updateCharacteristicValue(uriDataChar.getValueHandle(), params.uriData, params.uriDataLength);
ble.updateCharacteristicValue(flagsChar.getValueHandle(), &params.flags, 1);
ble.updateCharacteristicValue(beaconPeriodChar.getValueHandle(),
reinterpret_cast<uint8_t *>(&params.beaconPeriod), sizeof(uint16_t));
ble.updateCharacteristicValue(txPowerModeChar.getValueHandle(), &params.txPowerMode, 1);
ble.updateCharacteristicValue(advPowerLevelsChar.getValueHandle(),
reinterpret_cast<uint8_t *>(params.advPowerLevels), sizeof(PowerLevels_t));
}
private:
void lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (params.lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else if (authParams->len != sizeof(Lock_t)) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
void unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if ((!params.lockedState) && (authParams->len == sizeof(Lock_t))) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
} else if (authParams->len != sizeof(Lock_t)) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else if (memcmp(authParams->data, params.lock, sizeof(Lock_t)) != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
void uriDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (params.lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
void powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (params.lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else if (authParams->len != sizeof(uint8_t)) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else if (*((uint8_t *)authParams->data) >= NUM_POWER_MODES) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
template <typename T>
void basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (params.lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else if (authParams->len != sizeof(T)) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
BLEDevice &ble;
Params_t &params;
Ticker timeSinceBootTick;
Timeout switchFrame;
// Default value that is restored on reset.
PowerLevels_t &defaultAdvPowerLevels; // This goes into the advertising frames (radio power measured at 1m from device).
PowerLevels_t &radioPowerLevels; // This configures the power levels of the radio.
uint8_t lockedState;
bool initSucceeded;
uint8_t resetFlag;
bool switchFlag;
//UID default value that is restored on reset.
UIDNamespaceID_t defaultUidNamespaceID;
UIDInstanceID_t defaultUidInstanceID;
float defaultUidAdvPeriod;
int8_t defaultUidPower;
uint16_t uidRFU;
bool uidIsSet;
//URI default value that is restored on reset.
uint8_t defaultUriDataLength;
UriData_t defaultUriData;
int8_t defaultUrlPower;
float defaultUriAdvPeriod;
bool urlIsSet;
//TLM default value that is restored on reset.
uint8_t defaultTlmVersion;
float defaultTlmAdvPeriod;
volatile uint16_t TlmBatteryVoltage;
volatile uint16_t TlmBeaconTemp;
volatile uint32_t TlmPduCount;
volatile uint32_t TlmTimeSinceBoot;
bool tlmIsSet;
ReadOnlyGattCharacteristic<uint8_t> lockedStateChar;
WriteOnlyGattCharacteristic<Lock_t> lockChar;
GattCharacteristic uriDataChar;
WriteOnlyGattCharacteristic<Lock_t> unlockChar;
ReadWriteGattCharacteristic<uint8_t> flagsChar;
ReadWriteGattCharacteristic<PowerLevels_t> advPowerLevelsChar;
ReadWriteGattCharacteristic<uint8_t> txPowerModeChar;
ReadWriteGattCharacteristic<uint16_t> beaconPeriodChar;
WriteOnlyGattCharacteristic<uint8_t> resetChar;
};
#endif // SERVICES_EDDYSTONE_BEACON_CONFIG_SERVICE_H_

View File

@ -0,0 +1,653 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SERVICES_EDDYSTONEBEACON_H_
#define SERVICES_EDDYSTONEBEACON_H_
#warning ble/services/EddystoneService.h is deprecated. Please use the example in 'github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService'.
#include "ble/BLE.h"
#include "mbed.h"
#include "CircularBuffer.h"
static const uint8_t BEACON_EDDYSTONE[] = {0xAA, 0xFE};
//Debug is disabled by default
#if 0
#define DBG(MSG, ...) printf("[EddyStone: DBG]" MSG " \t[%s,%d]\r\n", \
## __VA_ARGS__, \
__FILE__, \
__LINE__);
#define WARN(MSG, ...) printf("[EddyStone: WARN]" MSG " \t[%s,%d]\r\n", \
## __VA_ARGS__, \
__FILE__, \
__LINE__);
#define ERR(MSG, ...) printf("[EddyStone: ERR]" MSG " \t[%s,%d]\r\n", \
## __VA_ARGS__, \
__FILE__, \
__LINE__);
#else // if 0
#define DBG(x, ...) //wait_us(10);
#define WARN(x, ...) //wait_us(10);
#define ERR(x, ...)
#endif // if 0
#if 0
#define INFO(x, ...) printf("[EddyStone: INFO]"x " \t[%s,%d]\r\n", \
## __VA_ARGS__, \
__FILE__, \
__LINE__);
#else // if 0
#define INFO(x, ...)
#endif // if 0
/**
* @class Eddystone
* @brief Eddystone Configuration Service. Can be used to set URL, adjust power levels, and set flags.
* See https://github.com/google/eddystone
*
*/
class EddystoneService
{
public:
enum FrameTypes {
NONE,
url,
uid,
tlm
};
static const int SERVICE_DATA_MAX = 31; // Maximum size of service data in ADV packets
// There are currently 3 subframes defined, URI, UID, and TLM
#define EDDYSTONE_MAX_FRAMETYPE 3
void (*frames[EDDYSTONE_MAX_FRAMETYPE])(uint8_t *, uint32_t);
static const int URI_DATA_MAX = 18;
typedef uint8_t UriData_t[URI_DATA_MAX];
CircularBuffer<FrameTypes, EDDYSTONE_MAX_FRAMETYPE> overflow;
// UID Frame Type subfields
static const int UID_NAMESPACEID_SIZE = 10;
typedef uint8_t UIDNamespaceID_t[UID_NAMESPACEID_SIZE];
static const int UID_INSTANCEID_SIZE = 6;
typedef uint8_t UIDInstanceID_t[UID_INSTANCEID_SIZE];
// Eddystone Frame Type ID
static const uint8_t FRAME_TYPE_UID = 0x00;
static const uint8_t FRAME_TYPE_URL = 0x10;
static const uint8_t FRAME_TYPE_TLM = 0x20;
static const uint8_t FRAME_SIZE_TLM = 14; // TLM frame is a constant 14Bytes
static const uint8_t FRAME_SIZE_UID = 20; // includes RFU bytes
/**
* Set Eddystone UID Frame information.
*
* @param[in] power TX Power in dB measured at 0 meters from the device. Range of -100 to +20 dB.
* @param[in] namespaceID 10B namespace ID
* @param[in] instanceID 6B instance ID
* @param[in] RFU 2B of RFU, initialized to 0x0000 and not broadcast, included for future reference.
*/
void setUIDFrameData(int8_t power,
UIDNamespaceID_t namespaceID,
UIDInstanceID_t instanceID,
float uidAdvPeriodIn,
uint16_t RFU = 0x0000) {
if (0.0f == uidAdvPeriodIn) {
uidIsSet = false;
return;
}
if (power > 20) {
power = 20;
}
if (power < -100) {
power = -100;
}
defaultUidPower = power;
memcpy(defaultUidNamespaceID, namespaceID, UID_NAMESPACEID_SIZE);
memcpy(defaultUidInstanceID, instanceID, UID_INSTANCEID_SIZE);
uidRFU = (uint16_t)RFU; // this is probably bad form, but it doesn't really matter yet.
uidAdvPeriod = uidAdvPeriodIn;
uidIsSet = true; // set toggle to advertise UID frames
}
/*
* Construct UID frame from private variables
* @param[in/out] Data pointer to array to store constructed frame in
* @param[in] maxSize number of bytes left in array, effectively how much empty space is available to write to
* @return number of bytes used. negative number indicates error message.
*/
unsigned constructUIDFrame(uint8_t *Data, uint8_t maxSize) {
unsigned index = 0;
Data[index++] = FRAME_TYPE_UID; // 1B Type
if (defaultUidPower > 20) {
defaultUidPower = 20; // enforce range of vaild values.
}
if (defaultUidPower < -100) {
defaultUidPower = -100;
}
Data[index++] = defaultUidPower; // 1B Power @ 0meter
DBG("UID NamespaceID = '0x");
for (size_t x = 0; x < UID_NAMESPACEID_SIZE; x++) { // 10B Namespace ID
Data[index++] = defaultUidNamespaceID[x];
DBG("%x,", defaultUidNamespaceID[x]);
}
DBG("'\r\n");
DBG("UID InstanceID = '0x");
for (size_t x = 0; x< UID_INSTANCEID_SIZE; x++) { // 6B Instance ID
Data[index++] = defaultUidInstanceID[x];
DBG("%x,", defaultUidInstanceID[x]);
}
DBG("'\r\n");
if (0 != uidRFU) { // 2B RFU, include if non-zero, otherwise ignore
Data[index++] = (uint8_t)(uidRFU >> 0);
Data[index++] = (uint8_t)(uidRFU >> 8);
}
DBG("construcUIDFrame %d, %d", maxSize, index);
return index;
}
/**
* Set Eddystone URL Frame information.
* @param[in] power TX Power in dB measured at 0 meters from the device.
* @param[in] url URL to encode
* @param[in] urlAdvPeriodIn How long to advertise the URL frame (measured in # of adv periods)
* @return false on success, true on failure.
*/
bool setURLFrameData(int8_t power, const char *urlIn, float urlAdvPeriodIn) {
if (0.0f == urlAdvPeriodIn) {
urlIsSet = false;
return false;
}
encodeURL(urlIn, defaultUriData, defaultUriDataLength); // encode URL to URL Formatting
if (defaultUriDataLength > URI_DATA_MAX) {
return true; // error, URL is too big
}
defaultUrlPower = power;
urlAdvPeriod = urlAdvPeriodIn;
urlIsSet = true;
return false;
}
/**
* Set Eddystone URL Frame information.
* @param[in] power TX Power in dB measured at 0 meters from the device.
* @param[in] encodedUrlIn Encoded URL
* @param[in] encodedUrlInLength Length of the encoded URL
* @param[in] urlAdvPeriodIn How long to advertise the URL frame (measured in # of adv periods)
* @return false on success, true on failure.
*/
bool setURLFrameEncodedData(int8_t power, const char *encodedUrlIn, uint8_t encodedUrlInLength, float urlAdvPeriodIn) {
if (0.0f == urlAdvPeriodIn) {
urlIsSet = false;
return false;
}
memcpy(defaultUriData, encodedUrlIn, encodedUrlInLength);
if (defaultUriDataLength > URI_DATA_MAX) {
return true; // error, URL is too big
}
defaultUrlPower = power;
defaultUriDataLength = encodedUrlInLength;
urlAdvPeriod = urlAdvPeriodIn;
urlIsSet = true;
return false;
}
/*
* Construct URL frame from private variables
* @param[in/out] Data pointer to array to store constructed frame in
* @param[in] maxSize number of bytes left in array, effectively how much emtpy space is available to write to
* @return number of bytes used. negative number indicates error message.
*/
int constructURLFrame(uint8_t *Data, uint8_t maxSize) {
int index = 0;
Data[index++] = FRAME_TYPE_URL; // 1B Type
Data[index++] = defaultUrlPower; // 1B TX Power
for (int x = 0; x < defaultUriDataLength; x++) { // 18B of URL Prefix + encoded URL
Data[index++] = defaultUriData[x];
}
DBG("constructURLFrame: %d, %d", maxSize, index);
return index;
}
/*
* Set Eddystone TLM Frame information.
* @param[in] Version of the TLM beacon data format
* @param[in] advPeriod how often to advertise the TLM frame for (in minutes)
* @param batteryVoltage in milivolts
* @param beaconTemp in 8.8 floating point notation
*
*/
void setTLMFrameData(uint8_t version = 0,
float advPeriod = 60.0f,
uint16_t batteryVoltage = 0,
uint16_t beaconTemp = 0x8000,
uint32_t pduCount = 0,
uint32_t timeSinceBoot = 0) {
if (0.0f == advPeriod) {
tlmIsSet = false;
return;
}
TlmVersion = version;
TlmBatteryVoltage = batteryVoltage;
TlmBeaconTemp = beaconTemp;
TlmPduCount = pduCount; // reset
TlmTimeSinceBoot = timeSinceBoot; // reset
TlmAdvPeriod = advPeriod;
tlmIsSet = true; // TLM Data has been enabled
}
/*
* Construct TLM frame from private variables
* @param[in/out] Data pointer to array to store constructed frame in
* @param[in] maxSize number of bytes left in array, effectively how much emtpy space is available to write to
* @return number of bytes used. negative number indicates error message.
*/
int constructTLMFrame(uint8_t *Data, uint8_t maxSize) {
uint32_t now = timeSinceBootTimer.read_ms();
TlmTimeSinceBoot += (now - lastBootTimerRead) / 100;
lastBootTimerRead = now;
int index = 0;
Data[index++] = FRAME_TYPE_TLM; // Eddystone frame type = Telemetry
Data[index++] = TlmVersion; // TLM Version Number
Data[index++] = (uint8_t)(TlmBatteryVoltage >> 8); // Battery Voltage[0]
Data[index++] = (uint8_t)(TlmBatteryVoltage >> 0); // Battery Voltage[1]
Data[index++] = (uint8_t)(TlmBeaconTemp >> 8); // Beacon Temp[0]
Data[index++] = (uint8_t)(TlmBeaconTemp >> 0); // Beacon Temp[1]
Data[index++] = (uint8_t)(TlmPduCount >> 24); // PDU Count [0]
Data[index++] = (uint8_t)(TlmPduCount >> 16); // PDU Count [1]
Data[index++] = (uint8_t)(TlmPduCount >> 8); // PDU Count [2]
Data[index++] = (uint8_t)(TlmPduCount >> 0); // PDU Count [3]
Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 24); // Time Since Boot [0]
Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 16); // Time Since Boot [1]
Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 8); // Time Since Boot [2]
Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 0); // Time Since Boot [3]
DBG("constructURLFrame: %d, %d", maxSize, index);
return index;
}
/*
* Update the TLM frame battery voltage value
* @param[in] voltagemv Voltage to update the TLM field battery voltage with (in mV)
* @return nothing
*/
void updateTlmBatteryVoltage(uint16_t voltagemv) {
TlmBatteryVoltage = voltagemv;
}
/*
* Update the TLM frame beacon temperature
* @param[in] temp Temperature of beacon (in 8.8fpn)
* @return nothing
*/
void updateTlmBeaconTemp(uint16_t temp) {
TlmBeaconTemp = temp;
}
/*
* Update the TLM frame PDU Count field
* @param[in] pduCount Number of Advertisiting frames sent since powerup
* @return nothing
*/
void updateTlmPduCount(uint32_t pduCount) {
TlmPduCount = pduCount;
}
/*
* Update the TLM frame Time since boot in 0.1s incriments
* @param[in] timeSinceBoot Time since boot in 0.1s incriments
* @return nothing
*/
void updateTlmTimeSinceBoot(uint32_t timeSinceBoot) {
TlmTimeSinceBoot = timeSinceBoot;
}
/*
* Update advertising data
* @return true on success, false on failure
*/
bool updateAdvPacket(uint8_t serviceData[], unsigned serviceDataLen) {
// Fields from the Service
DBG("Updating AdvFrame: %d", serviceDataLen);
ble.clearAdvertisingPayload();
ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
ble.setAdvertisingInterval(100);
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_EDDYSTONE, sizeof(BEACON_EDDYSTONE));
ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen);
return true;
}
/*
* State machine for switching out frames.
* This function is called by the radioNotificationCallback when a frame needs to get swapped out.
* This function exists because of time constraints in the radioNotificationCallback, so it is effectively
* broken up into two functions.
*/
void swapOutFrames(FrameTypes frameType) {
uint8_t serviceData[SERVICE_DATA_MAX];
unsigned serviceDataLen = 0;
//hard code in the eddystone UUID
serviceData[serviceDataLen++] = BEACON_EDDYSTONE[0];
serviceData[serviceDataLen++] = BEACON_EDDYSTONE[1];
// if certain frames are not enabled, then skip them. Worst case TLM is always enabled
switch (frameType) {
case tlm:
// TLM frame
if (tlmIsSet) {
DBG("Swapping in TLM Frame: version=%x, Batt=%d, Temp = %d, PDUCnt = %d, TimeSinceBoot=%d",
TlmVersion,
TlmBatteryVoltage,
TlmBeaconTemp,
TlmPduCount,
TlmTimeSinceBoot);
serviceDataLen += constructTLMFrame(serviceData + serviceDataLen, 20);
DBG("\t Swapping in TLM Frame: len=%d", serviceDataLen);
updateAdvPacket(serviceData, serviceDataLen);
}
break;
case url:
// URL Frame
if (urlIsSet) {
DBG("Swapping in URL Frame: Power: %d", defaultUrlPower);
serviceDataLen += constructURLFrame(serviceData + serviceDataLen, 20);
DBG("\t Swapping in URL Frame: len=%d ", serviceDataLen);
updateAdvPacket(serviceData, serviceDataLen);
//switchFlag = false;
}
break;
case uid:
// UID Frame
if (uidIsSet) {
DBG("Swapping in UID Frame: Power: %d", defaultUidPower);
serviceDataLen += constructUIDFrame(serviceData + serviceDataLen, 20);
DBG("\t Swapping in UID Frame: len=%d", serviceDataLen);
updateAdvPacket(serviceData, serviceDataLen);
//switchFlag = false;
}
break;
default:
ERR("You have not initialized a Frame yet, please initialize one before starting a beacon");
ERR("uidIsSet = %d, urlIsSet = %d, tlmIsSet = %d", uidIsSet, urlIsSet, tlmIsSet);
}
}
/*
* Callback to swap in URL frame
*/
void urlCallback(void) {
DBG("urlCallback");
if (false == advLock) {
advLock = true;
DBG("advLock = url")
frameIndex = url;
swapOutFrames(frameIndex);
ble.startAdvertising();
} else {
// Someone else is broadcasting, toss it into the overflow buffer to retransmit when free
INFO("URI(%d) cannot complete, %d is currently broadcasting", url, frameIndex);
FrameTypes x = url;
overflow.push(x);
}
}
/*
* Callback to swap in UID frame
*/
void uidCallback(void) {
DBG("uidCallback");
if (false == advLock) {
advLock = true;
DBG("advLock = uid")
frameIndex = uid;
swapOutFrames(frameIndex);
ble.startAdvertising();
} else {
// Someone else is broadcasting, toss it into the overflow buffer to retransmit when free
INFO("UID(%d) cannot complete, %d is currently broadcasting", uid, frameIndex);
FrameTypes x = uid; // have to do this to satisfy cont vs volatile keywords... sigh...
overflow.push(x);
}
}
/*
* Callback to swap in TLM frame
*/
void tlmCallback(void) {
DBG("tlmCallback");
if (false == advLock) {
// OK to broadcast
advLock = true;
DBG("advLock = tlm")
frameIndex = tlm;
swapOutFrames(frameIndex);
ble.startAdvertising();
} else {
// Someone else is broadcasting, toss it into the overflow buffer to retransmit when free
INFO("TLM(%d) cannot complete, %d is currently broadcasting", tlm, frameIndex);
FrameTypes x = tlm;
overflow.push(x);
}
}
void stopAdvCallback(void) {
if (overflow.empty()) {
// if nothing left to transmit, stop
ble.stopAdvertising();
advLock = false; // unlock lock
} else {
// transmit other packets at current time index
FrameTypes x = NONE;
overflow.pop(x);
INFO("Re-Transmitting %d", x);
swapOutFrames(x);
}
}
/*
* Callback from onRadioNotification(), used to update the PDUCounter and process next state.
*/
#define EDDYSTONE_SWAPFRAME_DELAYMS 1
void radioNotificationCallback(bool radioActive) {
// Update PDUCount
TlmPduCount++;
// True just before an frame is sent, false just after a frame is sent
if (radioActive) {
// Do Nothing
} else {
// Packet has been sent, disable advertising
stopAdv.attach_us(this, &EddystoneService::stopAdvCallback, 1);
}
}
/*
* This function explicityly sets the parameters used by the Eddystone beacon.
* this function should be used in leu of the config service.
*
* @param bleIn ble object used to broadcast eddystone information
* @param beaconPeriodus is how often ble broadcasts are mde, in mili seconds
* @param txPowerLevel sets the broadcasting power level.
*
*/
EddystoneService(BLEDevice &bleIn,
uint16_t beaconPeriodus = 100,
uint8_t txPowerIn = 0) :
ble(bleIn),
advPeriodus(beaconPeriodus),
txPower(txPowerIn),
advLock(false),
frameIndex(NONE) {
}
/*
* @breif this function starts eddystone advertising based on configured frames.
*/
void start(void) {
// Initialize Frame transition, start with URL to pass eddystone validator app on first try
if (urlIsSet) {
frameIndex = url;
urlTicker.attach(this, &EddystoneService::urlCallback, (float) advPeriodus / 1000.0f);
DBG("attached urlCallback every %d seconds", urlAdvPeriod);
}
if (uidIsSet) {
frameIndex = uid;
uidTicker.attach(this, &EddystoneService::uidCallback, uidAdvPeriod);
DBG("attached uidCallback every %d seconds", uidAdvPeriod);
}
if (tlmIsSet) {
frameIndex = tlm;
// Make double sure the PDUCount and TimeSinceBoot fields are set to zero at reset
updateTlmPduCount(0);
updateTlmTimeSinceBoot(0);
lastBootTimerRead = 0;
timeSinceBootTimer.start();
tlmTicker.attach(this, &EddystoneService::tlmCallback, TlmAdvPeriod);
DBG("attached tlmCallback every %d seconds", TlmAdvPeriod);
}
if (NONE == frameIndex) {
error("No Frames were Initialized! Please initialize a frame before starting an eddystone beacon.");
}
//uidRFU = 0;
ble.setTxPower(txPower);
ble.gap().onRadioNotification(this, &EddystoneService::radioNotificationCallback);
}
private:
// Eddystone Variables
BLEDevice &ble;
uint16_t advPeriodus;
uint8_t txPower;
Timer timeSinceBootTimer;
volatile uint32_t lastBootTimerRead;
volatile bool advLock;
volatile FrameTypes frameIndex;
Timeout stopAdv;
// URI Frame Variables
uint8_t defaultUriDataLength;
UriData_t defaultUriData;
int8_t defaultUrlPower;
bool urlIsSet; // flag that enables / disable URI Frames
float urlAdvPeriod; // how long the url frame will be advertised for
Ticker urlTicker;
// UID Frame Variables
UIDNamespaceID_t defaultUidNamespaceID;
UIDInstanceID_t defaultUidInstanceID;
int8_t defaultUidPower;
uint16_t uidRFU;
bool uidIsSet; // flag that enables / disable UID Frames
float uidAdvPeriod; // how long the uid frame will be advertised for
Ticker uidTicker;
// TLM Frame Variables
uint8_t TlmVersion;
volatile uint16_t TlmBatteryVoltage;
volatile uint16_t TlmBeaconTemp;
volatile uint32_t TlmPduCount;
volatile uint32_t TlmTimeSinceBoot;
bool tlmIsSet; // flag that enables / disables TLM frames
float TlmAdvPeriod; // number of minutes between adv frames
Ticker tlmTicker;
public:
/*
* Encode a human-readable URI into the binary format defined by URIBeacon spec (https://github.com/google/uribeacon/tree/master/specification).
*/
static void encodeURL(const char *uriDataIn, UriData_t uriDataOut, uint8_t &sizeofURIDataOut) {
DBG("Encode URL = %s", uriDataIn);
const char *prefixes[] = {
"http://www.",
"https://www.",
"http://",
"https://",
};
const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
const char *suffixes[] = {
".com/",
".org/",
".edu/",
".net/",
".info/",
".biz/",
".gov/",
".com",
".org",
".edu",
".net",
".info",
".biz",
".gov"
};
const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
sizeofURIDataOut = 0;
memset(uriDataOut, 0, sizeof(UriData_t));
if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) {
return;
}
/*
* handle prefix
*/
for (unsigned i = 0; i < NUM_PREFIXES; i++) {
size_t prefixLen = strlen(prefixes[i]);
if (strncmp(uriDataIn, prefixes[i], prefixLen) == 0) {
uriDataOut[sizeofURIDataOut++] = i;
uriDataIn += prefixLen;
break;
}
}
/*
* handle suffixes
*/
while (*uriDataIn && (sizeofURIDataOut < URI_DATA_MAX)) {
/* check for suffix match */
unsigned i;
for (i = 0; i < NUM_SUFFIXES; i++) {
size_t suffixLen = strlen(suffixes[i]);
if (strncmp(uriDataIn, suffixes[i], suffixLen) == 0) {
uriDataOut[sizeofURIDataOut++] = i;
uriDataIn += suffixLen;
break; /* from the for loop for checking against suffixes */
}
}
/* This is the default case where we've got an ordinary character which doesn't match a suffix. */
INFO("Encoding URI: No Suffix Found");
if (i == NUM_SUFFIXES) {
uriDataOut[sizeofURIDataOut++] = *uriDataIn;
++uriDataIn;
}
}
}
};
#endif // SERVICES_EDDYSTONEBEACON_H_

View File

@ -0,0 +1,106 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_ENVIRONMENTAL_SERVICE_H__
#define __BLE_ENVIRONMENTAL_SERVICE_H__
#include "ble/BLE.h"
/**
* @class EnvironmentalService
* @brief BLE Environmental Service. This service provides temperature, humidity and pressure measurement.
* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.environmental_sensing.xml
* Temperature: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature.xml
* Humidity: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.humidity.xml
* Pressure: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.pressure.xml
*/
class EnvironmentalService {
public:
typedef int16_t TemperatureType_t;
typedef uint16_t HumidityType_t;
typedef uint32_t PressureType_t;
/**
* @brief EnvironmentalService constructor.
* @param ble Reference to BLE device.
* @param temperature_en Enable this characteristic.
* @param humidity_en Enable this characteristic.
* @param pressure_en Enable this characteristic.
*/
EnvironmentalService(BLE& _ble) :
ble(_ble),
temperatureCharacteristic(GattCharacteristic::UUID_TEMPERATURE_CHAR, &temperature),
humidityCharacteristic(GattCharacteristic::UUID_HUMIDITY_CHAR, &humidity),
pressureCharacteristic(GattCharacteristic::UUID_PRESSURE_CHAR, &pressure)
{
static bool serviceAdded = false; /* We should only ever need to add the information service once. */
if (serviceAdded) {
return;
}
GattCharacteristic *charTable[] = { &humidityCharacteristic,
&pressureCharacteristic,
&temperatureCharacteristic };
GattService environmentalService(GattService::UUID_ENVIRONMENTAL_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
ble.gattServer().addService(environmentalService);
serviceAdded = true;
}
/**
* @brief Update humidity characteristic.
* @param newHumidityVal New humidity measurement.
*/
void updateHumidity(HumidityType_t newHumidityVal)
{
humidity = (HumidityType_t) (newHumidityVal * 100);
ble.gattServer().write(humidityCharacteristic.getValueHandle(), (uint8_t *) &humidity, sizeof(HumidityType_t));
}
/**
* @brief Update pressure characteristic.
* @param newPressureVal New pressure measurement.
*/
void updatePressure(PressureType_t newPressureVal)
{
pressure = (PressureType_t) (newPressureVal * 10);
ble.gattServer().write(pressureCharacteristic.getValueHandle(), (uint8_t *) &pressure, sizeof(PressureType_t));
}
/**
* @brief Update temperature characteristic.
* @param newTemperatureVal New temperature measurement.
*/
void updateTemperature(float newTemperatureVal)
{
temperature = (TemperatureType_t) (newTemperatureVal * 100);
ble.gattServer().write(temperatureCharacteristic.getValueHandle(), (uint8_t *) &temperature, sizeof(TemperatureType_t));
}
private:
BLE& ble;
TemperatureType_t temperature;
HumidityType_t humidity;
PressureType_t pressure;
ReadOnlyGattCharacteristic<TemperatureType_t> temperatureCharacteristic;
ReadOnlyGattCharacteristic<HumidityType_t> humidityCharacteristic;
ReadOnlyGattCharacteristic<PressureType_t> pressureCharacteristic;
};
#endif /* #ifndef __BLE_ENVIRONMENTAL_SERVICE_H__*/

View File

@ -0,0 +1,150 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_HEALTH_THERMOMETER_SERVICE_H__
#define __BLE_HEALTH_THERMOMETER_SERVICE_H__
#include "ble/BLE.h"
/**
* @class HealthThermometerService
* @brief BLE Health Thermometer Service. This service provides the location of the thermometer and the temperature.
* Service: https://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.health_thermometer.xml
* Temperature Measurement: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml
* Temperature Type: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_type.xml
*/
class HealthThermometerService {
public:
/**
* @enum Sensor Location.
* @brief Location of sensor on the body.
*/
enum SensorLocation_t {
LOCATION_ARMPIT = 1, /*!< Armpit. */
LOCATION_BODY, /*!< Body. */
LOCATION_EAR, /*!< Ear. */
LOCATION_FINGER, /*!< Finger. */
LOCATION_GI_TRACT, /*!< GI tract */
LOCATION_MOUTH, /*!< Mouth. */
LOCATION_RECTUM, /*!< Rectum. */
LOCATION_TOE, /*!< Toe. */
LOCATION_EAR_DRUM, /*!< Eardrum. */
};
public:
/**
* @brief Add the Health Thermometer Service to an existing BLE object, initialize with temperature and location.
* @param[ref] _ble Reference to the BLE device.
* @param[in] initialTemp Initial value in celsius.
* @param[in] _location
*/
HealthThermometerService(BLE &_ble, float initialTemp, uint8_t _location) :
ble(_ble),
valueBytes(initialTemp),
tempMeasurement(GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, (TemperatureValueBytes *)valueBytes.getPointer(), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
tempLocation(GattCharacteristic::UUID_TEMPERATURE_TYPE_CHAR, &_location) {
GattCharacteristic *hrmChars[] = {&tempMeasurement, &tempLocation, };
GattService hrmService(GattService::UUID_HEALTH_THERMOMETER_SERVICE, hrmChars, sizeof(hrmChars) / sizeof(GattCharacteristic *));
ble.addService(hrmService);
}
/**
* @brief Update the temperature being broadcast.
*
* @param[in] temperature
* Floating point value of the temperature.
*
*/
void updateTemperature(float temperature) {
if (ble.getGapState().connected) {
valueBytes.updateTemperature(temperature);
ble.gattServer().write(tempMeasurement.getValueHandle(), valueBytes.getPointer(), sizeof(TemperatureValueBytes));
}
}
/**
* @brief Update the location.
* @param loc
* New location value.
*/
void updateLocation(SensorLocation_t loc) {
ble.gattServer().write(tempLocation.getValueHandle(), reinterpret_cast<uint8_t *>(&loc), sizeof(uint8_t));
}
private:
/* Private internal representation for the bytes used to work with the vaulue of the temperature characteristic. */
struct TemperatureValueBytes {
static const unsigned OFFSET_OF_FLAGS = 0;
static const unsigned OFFSET_OF_VALUE = OFFSET_OF_FLAGS + sizeof(uint8_t);
static const unsigned SIZEOF_VALUE_BYTES = sizeof(uint8_t) + sizeof(float);
static const unsigned TEMPERATURE_UNITS_FLAG_POS = 0;
static const unsigned TIMESTAMP_FLAG_POS = 1;
static const unsigned TEMPERATURE_TYPE_FLAG_POS = 2;
static const uint8_t TEMPERATURE_UNITS_CELSIUS = 0;
static const uint8_t TEMPERATURE_UNITS_FAHRENHEIT = 1;
TemperatureValueBytes(float initialTemperature) : bytes() {
/* Assumption: temperature values are expressed in celsius */
bytes[OFFSET_OF_FLAGS] = (TEMPERATURE_UNITS_CELSIUS << TEMPERATURE_UNITS_FLAG_POS) |
(false << TIMESTAMP_FLAG_POS) |
(false << TEMPERATURE_TYPE_FLAG_POS);
updateTemperature(initialTemperature);
}
void updateTemperature(float temp) {
uint32_t temp_ieee11073 = quick_ieee11073_from_float(temp);
memcpy(&bytes[OFFSET_OF_VALUE], &temp_ieee11073, sizeof(float));
}
uint8_t *getPointer(void) {
return bytes;
}
const uint8_t *getPointer(void) const {
return bytes;
}
private:
/**
* @brief A very quick conversion between a float temperature and 11073-20601 FLOAT-Type.
* @param temperature The temperature as a float.
* @return The temperature in 11073-20601 FLOAT-Type format.
*/
uint32_t quick_ieee11073_from_float(float temperature) {
uint8_t exponent = 0xFE; //Exponent is -2
uint32_t mantissa = (uint32_t)(temperature * 100);
return (((uint32_t)exponent) << 24) | mantissa;
}
private:
/* First byte: 8-bit flags. Second field is a float holding the temperature value. */
/* See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml */
uint8_t bytes[SIZEOF_VALUE_BYTES];
};
protected:
BLE &ble;
TemperatureValueBytes valueBytes;
ReadOnlyGattCharacteristic<TemperatureValueBytes> tempMeasurement;
ReadOnlyGattCharacteristic<uint8_t> tempLocation;
};
#endif /* #ifndef __BLE_HEALTH_THERMOMETER_SERVICE_H__*/

View File

@ -0,0 +1,194 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_HEART_RATE_SERVICE_H__
#define __BLE_HEART_RATE_SERVICE_H__
#include "ble/BLE.h"
/**
* @class HeartRateService
* @brief BLE Service for HeartRate. This BLE Service contains the location of the sensor and the heart rate in beats per minute.
* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml
* HRM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
* Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml
*/
class HeartRateService {
public:
/**
* @enum SensorLocation
* @brief Location of the heart rate sensor on body.
*/
enum {
LOCATION_OTHER = 0, /*!< Other location. */
LOCATION_CHEST, /*!< Chest. */
LOCATION_WRIST, /*!< Wrist. */
LOCATION_FINGER, /*!< Finger. */
LOCATION_HAND, /*!< Hand. */
LOCATION_EAR_LOBE, /*!< Earlobe. */
LOCATION_FOOT, /*!< Foot. */
};
public:
/**
* @brief Constructor with 8-bit HRM Counter value.
*
* @param[ref] _ble
* Reference to the underlying BLE.
* @param[in] hrmCounter (8-bit)
* Initial value for the HRM counter.
* @param[in] location
* Sensor's location.
*/
HeartRateService(BLE &_ble, uint8_t hrmCounter, uint8_t location) :
ble(_ble),
valueBytes(hrmCounter),
hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(),
valueBytes.getNumValueBytes(), HeartRateValueBytes::MAX_VALUE_BYTES,
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, &location),
controlPoint(GattCharacteristic::UUID_HEART_RATE_CONTROL_POINT_CHAR, &controlPointValue) {
setupService();
}
/**
* @brief Constructor with a 16-bit HRM Counter value.
*
* @param[in] _ble
* Reference to the underlying BLE.
* @param[in] hrmCounter (8-bit)
* Initial value for the HRM counter.
* @param[in] location
* Sensor's location.
*/
HeartRateService(BLE &_ble, uint16_t hrmCounter, uint8_t location) :
ble(_ble),
valueBytes(hrmCounter),
hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(),
valueBytes.getNumValueBytes(), HeartRateValueBytes::MAX_VALUE_BYTES,
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, &location),
controlPoint(GattCharacteristic::UUID_HEART_RATE_CONTROL_POINT_CHAR, &controlPointValue) {
setupService();
}
/**
* @brief Set a new 8-bit value for the heart rate.
*
* @param[in] hrmCounter
* Heart rate in BPM.
*/
void updateHeartRate(uint8_t hrmCounter) {
valueBytes.updateHeartRate(hrmCounter);
ble.gattServer().write(hrmRate.getValueHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes());
}
/**
* Set a new 16-bit value for the heart rate.
*
* @param[in] hrmCounter
* Heart rate in BPM.
*/
void updateHeartRate(uint16_t hrmCounter) {
valueBytes.updateHeartRate(hrmCounter);
ble.gattServer().write(hrmRate.getValueHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes());
}
/**
* This callback allows the heart rate service to receive updates to the
* controlPoint characteristic.
*
* @param[in] params
* Information about the characterisitc being updated.
*/
virtual void onDataWritten(const GattWriteCallbackParams *params) {
if (params->handle == controlPoint.getValueAttribute().getHandle()) {
/* Do something here if the new value is 1; else you can override this method by
* extending this class.
* @NOTE: If you are extending this class, be sure to also call
* ble.onDataWritten(this, &ExtendedHRService::onDataWritten); in
* your constructor.
*/
}
}
protected:
void setupService(void) {
GattCharacteristic *charTable[] = {&hrmRate, &hrmLocation, &controlPoint};
GattService hrmService(GattService::UUID_HEART_RATE_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
ble.addService(hrmService);
ble.onDataWritten(this, &HeartRateService::onDataWritten);
}
protected:
/* Private internal representation for the bytes used to work with the value of the heart rate characteristic. */
struct HeartRateValueBytes {
static const unsigned MAX_VALUE_BYTES = 3; /* Flags, and up to two bytes for heart rate. */
static const unsigned FLAGS_BYTE_INDEX = 0;
static const unsigned VALUE_FORMAT_BITNUM = 0;
static const uint8_t VALUE_FORMAT_FLAG = (1 << VALUE_FORMAT_BITNUM);
HeartRateValueBytes(uint8_t hrmCounter) : valueBytes() {
updateHeartRate(hrmCounter);
}
HeartRateValueBytes(uint16_t hrmCounter) : valueBytes() {
updateHeartRate(hrmCounter);
}
void updateHeartRate(uint8_t hrmCounter) {
valueBytes[FLAGS_BYTE_INDEX] &= ~VALUE_FORMAT_FLAG;
valueBytes[FLAGS_BYTE_INDEX + 1] = hrmCounter;
}
void updateHeartRate(uint16_t hrmCounter) {
valueBytes[FLAGS_BYTE_INDEX] |= VALUE_FORMAT_FLAG;
valueBytes[FLAGS_BYTE_INDEX + 1] = (uint8_t)(hrmCounter & 0xFF);
valueBytes[FLAGS_BYTE_INDEX + 2] = (uint8_t)(hrmCounter >> 8);
}
uint8_t *getPointer(void) {
return valueBytes;
}
const uint8_t *getPointer(void) const {
return valueBytes;
}
unsigned getNumValueBytes(void) const {
return 1 + ((valueBytes[FLAGS_BYTE_INDEX] & VALUE_FORMAT_FLAG) ? sizeof(uint16_t) : sizeof(uint8_t));
}
private:
/* First byte: 8-bit values, no extra info. Second byte: uint8_t HRM value */
/* See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml */
uint8_t valueBytes[MAX_VALUE_BYTES];
};
protected:
BLE &ble;
HeartRateValueBytes valueBytes;
uint8_t controlPointValue;
GattCharacteristic hrmRate;
ReadOnlyGattCharacteristic<uint8_t> hrmLocation;
WriteOnlyGattCharacteristic<uint8_t> controlPoint;
};
#endif /* #ifndef __BLE_HEART_RATE_SERVICE_H__*/

View File

@ -0,0 +1,103 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_LINK_LOSS_SERVICE_H__
#define __BLE_LINK_LOSS_SERVICE_H__
#include "ble/Gap.h"
/**
* @class LinkLossService
* @brief This service defines behavior when a link is lost between two devices.
* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.link_loss.xml
* Alertness Level Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.alert_level.xml
*/
class LinkLossService {
public:
enum AlertLevel_t {
NO_ALERT = 0,
MILD_ALERT = 1,
HIGH_ALERT = 2
};
typedef void (* callback_t)(AlertLevel_t level);
/**
* @param[ref] ble
* BLE object for the underlying controller.
*/
LinkLossService(BLE &bleIn, callback_t callbackIn, AlertLevel_t levelIn = NO_ALERT) :
ble(bleIn),
alertLevel(levelIn),
callback(callbackIn),
alertLevelChar(GattCharacteristic::UUID_ALERT_LEVEL_CHAR, reinterpret_cast<uint8_t *>(&alertLevel)) {
static bool serviceAdded = false; /* We should only ever add one LinkLoss service. */
if (serviceAdded) {
return;
}
GattCharacteristic *charTable[] = {&alertLevelChar};
GattService linkLossService(GattService::UUID_LINK_LOSS_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
ble.gattServer().addService(linkLossService);
serviceAdded = true;
ble.gap().onDisconnection(this, &LinkLossService::onDisconnectionFilter);
ble.gattServer().onDataWritten(this, &LinkLossService::onDataWritten);
}
/**
* Update the callback.
*/
void setCallback(callback_t newCallback) {
callback = newCallback;
}
/**
* Update alertness level.
*/
void setAlertLevel(AlertLevel_t newLevel) {
alertLevel = newLevel;
}
protected:
/**
* This callback allows receiving updates to the AlertLevel characteristic.
*
* @param[in] params
* Information about the characterisitc being updated.
*/
virtual void onDataWritten(const GattWriteCallbackParams *params) {
if (params->handle == alertLevelChar.getValueHandle()) {
alertLevel = *reinterpret_cast<const AlertLevel_t *>(params->data);
}
}
void onDisconnectionFilter(const Gap::DisconnectionCallbackParams_t *params) {
if (alertLevel != NO_ALERT) {
callback(alertLevel);
}
}
protected:
BLE &ble;
AlertLevel_t alertLevel;
callback_t callback;
ReadWriteGattCharacteristic<uint8_t> alertLevelChar;
};
#endif /* __BLE_LINK_LOSS_SERVICE_H__ */

206
ble/services/UARTService.h Normal file
View File

@ -0,0 +1,206 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_UART_SERVICE_H__
#define __BLE_UART_SERVICE_H__
#ifdef YOTTA_CFG_MBED_OS
#include "mbed-drivers/mbed.h"
#include "mbed-drivers/Stream.h"
#else
#include "mbed.h"
#include "Stream.h"
#endif
#include "ble/UUID.h"
#include "ble/BLE.h"
extern const uint8_t UARTServiceBaseUUID[UUID::LENGTH_OF_LONG_UUID];
extern const uint16_t UARTServiceShortUUID;
extern const uint16_t UARTServiceTXCharacteristicShortUUID;
extern const uint16_t UARTServiceRXCharacteristicShortUUID;
extern const uint8_t UARTServiceUUID[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UARTServiceUUID_reversed[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UARTServiceTXCharacteristicUUID[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UARTServiceRXCharacteristicUUID[UUID::LENGTH_OF_LONG_UUID];
/**
* @class UARTService.
* @brief BLE Service to enable UART over BLE.
*/
class UARTService {
public:
/**< Maximum length of data (in bytes) that the UART service module can transmit to the peer. */
static const unsigned BLE_UART_SERVICE_MAX_DATA_LEN = (BLE_GATT_MTU_SIZE_DEFAULT - 3);
public:
/**
* @param[ref] ble
* BLE object for the underlying controller.
*/
UARTService(BLE &_ble) :
ble(_ble),
receiveBuffer(),
sendBuffer(),
sendBufferIndex(0),
numBytesReceived(0),
receiveBufferIndex(0),
txCharacteristic(UARTServiceTXCharacteristicUUID, receiveBuffer, 1, BLE_UART_SERVICE_MAX_DATA_LEN,
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
rxCharacteristic(UARTServiceRXCharacteristicUUID, sendBuffer, 1, BLE_UART_SERVICE_MAX_DATA_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
GattCharacteristic *charTable[] = {&txCharacteristic, &rxCharacteristic};
GattService uartService(UARTServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
ble.addService(uartService);
ble.onDataWritten(this, &UARTService::onDataWritten);
}
/**
* Note: TX and RX characteristics are to be interpreted from the viewpoint of the GATT client using this service.
*/
uint16_t getTXCharacteristicHandle() {
return txCharacteristic.getValueAttribute().getHandle();
}
/**
* Note: TX and RX characteristics are to be interpreted from the viewpoint of the GATT client using this service.
*/
uint16_t getRXCharacteristicHandle() {
return rxCharacteristic.getValueAttribute().getHandle();
}
/**
* We attempt to collect bytes before pushing them to the UART RX
* characteristic; writing to the RX characteristic then generates
* notifications for the client. Updates made in quick succession to a
* notification-generating characteristic result in data being buffered
* in the Bluetooth stack as notifications are sent out. The stack has
* its limits for this buffering - typically a small number under 10.
* Collecting data into the sendBuffer buffer helps mitigate the rate of
* updates. But we shouldn't buffer a large amount of data before updating
* the characteristic, otherwise the client needs to turn around and make
* a long read request; this is because notifications include only the first
* 20 bytes of the updated data.
*
* @param buffer The received update.
* @param length Number of characters to be appended.
* @return Number of characters appended to the rxCharacteristic.
*/
size_t write(const void *_buffer, size_t length) {
size_t origLength = length;
const uint8_t *buffer = static_cast<const uint8_t *>(_buffer);
if (ble.getGapState().connected) {
unsigned bufferIndex = 0;
while (length) {
unsigned bytesRemainingInSendBuffer = BLE_UART_SERVICE_MAX_DATA_LEN - sendBufferIndex;
unsigned bytesToCopy = (length < bytesRemainingInSendBuffer) ? length : bytesRemainingInSendBuffer;
/* Copy bytes into sendBuffer. */
memcpy(&sendBuffer[sendBufferIndex], &buffer[bufferIndex], bytesToCopy);
length -= bytesToCopy;
sendBufferIndex += bytesToCopy;
bufferIndex += bytesToCopy;
/* Have we collected enough? */
if ((sendBufferIndex == BLE_UART_SERVICE_MAX_DATA_LEN) ||
// (sendBuffer[sendBufferIndex - 1] == '\r') ||
(sendBuffer[sendBufferIndex - 1] == '\n')) {
ble.gattServer().write(getRXCharacteristicHandle(), static_cast<const uint8_t *>(sendBuffer), sendBufferIndex);
sendBufferIndex = 0;
}
}
}
return origLength;
}
/**
* Helper function to write out strings.
* @param str The received string.
* @return Number of characters appended to the rxCharacteristic.
*/
size_t writeString(const char *str) {
return write(str, strlen(str));
}
/**
* Override for Stream::_putc().
* @param c
* This function writes the character c, cast to an unsigned char, to stream.
* @return
* The character written as an unsigned char cast to an int or EOF on error.
*/
int _putc(int c) {
return (write(&c, 1) == 1) ? 1 : EOF;
}
/**
* Override for Stream::_getc().
* @return
* The character read.
*/
int _getc() {
if (receiveBufferIndex == numBytesReceived) {
return EOF;
}
return receiveBuffer[receiveBufferIndex++];
}
protected:
/**
* This callback allows the UART service to receive updates to the
* txCharacteristic. The application should forward the call to this
* function from the global onDataWritten() callback handler; if that's
* not used, this method can be used as a callback directly.
*/
void onDataWritten(const GattWriteCallbackParams *params) {
if (params->handle == getTXCharacteristicHandle()) {
uint16_t bytesRead = params->len;
if (bytesRead <= BLE_UART_SERVICE_MAX_DATA_LEN) {
numBytesReceived = bytesRead;
receiveBufferIndex = 0;
memcpy(receiveBuffer, params->data, numBytesReceived);
}
}
}
protected:
BLE &ble;
uint8_t receiveBuffer[BLE_UART_SERVICE_MAX_DATA_LEN]; /**< The local buffer into which we receive
* inbound data before forwarding it to the
* application. */
uint8_t sendBuffer[BLE_UART_SERVICE_MAX_DATA_LEN]; /**< The local buffer into which outbound data is
* accumulated before being pushed to the
* rxCharacteristic. */
uint8_t sendBufferIndex;
uint8_t numBytesReceived;
uint8_t receiveBufferIndex;
GattCharacteristic txCharacteristic; /**< From the point of view of the external client, this is the characteristic
* they'd write into in order to communicate with this application. */
GattCharacteristic rxCharacteristic; /**< From the point of view of the external client, this is the characteristic
* they'd read from in order to receive the bytes transmitted by this
* application. */
};
#endif /* #ifndef __BLE_UART_SERVICE_H__*/

View File

@ -0,0 +1,472 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SERVICES_URIBEACONCONFIGSERVICE_H_
#define SERVICES_URIBEACONCONFIGSERVICE_H_
#include "ble/BLE.h"
#ifdef YOTTA_CFG_MBED_OS
#include "mbed-drivers/mbed.h"
#else
#include "mbed.h"
#endif
extern const uint8_t UUID_URI_BEACON_SERVICE[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_LOCK_STATE_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_LOCK_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_UNLOCK_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_URI_DATA_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_FLAGS_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_ADV_POWER_LEVELS_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_TX_POWER_MODE_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_BEACON_PERIOD_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t UUID_RESET_CHAR[UUID::LENGTH_OF_LONG_UUID];
extern const uint8_t BEACON_UUID[sizeof(UUID::ShortUUIDBytes_t)];
/**
* @class URIBeaconConfigService
* @brief UriBeacon Configuration Service. Can be used to set URL, adjust power levels, and set flags.
* See http://uribeacon.org
*
*/
class URIBeaconConfigService {
public:
/**
* @brief Transmission power modes for UriBeacon.
*/
static const uint8_t TX_POWER_MODE_LOWEST = 0; /*!< Lowest TX power mode. */
static const uint8_t TX_POWER_MODE_LOW = 1; /*!< Low TX power mode. */
static const uint8_t TX_POWER_MODE_MEDIUM = 2; /*!< Medium TX power mode. */
static const uint8_t TX_POWER_MODE_HIGH = 3; /*!< High TX power mode. */
static const unsigned NUM_POWER_MODES = 4; /*!< Number of power modes defined. */
static const int ADVERTISING_INTERVAL_MSEC = 1000; // Advertising interval for config service.
static const int SERVICE_DATA_MAX = 31; // Maximum size of service data in ADV packets.
typedef uint8_t Lock_t[16]; /* 128 bits. */
typedef int8_t PowerLevels_t[NUM_POWER_MODES];
static const int URI_DATA_MAX = 18;
typedef uint8_t UriData_t[URI_DATA_MAX];
struct Params_t {
Lock_t lock;
uint8_t uriDataLength;
UriData_t uriData;
uint8_t flags;
PowerLevels_t advPowerLevels; // Current value of AdvertisedPowerLevels.
uint8_t txPowerMode; // Firmware power levels used with setTxPower().
uint16_t beaconPeriod;
};
/**
* @param[ref] ble
* BLE object for the underlying controller.
* @param[in/out] paramsIn
* Reference to application-visible beacon state, loaded
* from persistent storage at startup.
* @paramsP[in] resetToDefaultsFlag
* Applies to the state of the 'paramsIn' parameter.
* If true, it indicates that paramsIn is potentially
* un-initialized, and default values should be used
* instead. Otherwise, paramsIn overrides the defaults.
* @param[in] defaultUriDataIn
* Default un-encoded URI. Applies only if the resetToDefaultsFlag is true.
* @param[in] defaultAdvPowerLevelsIn
* Default power-levels array. Applies only if the resetToDefaultsFlag is true.
*/
URIBeaconConfigService(BLE &bleIn,
Params_t &paramsIn,
bool resetToDefaultsFlag,
const char *defaultURIDataIn,
PowerLevels_t &defaultAdvPowerLevelsIn) :
ble(bleIn),
params(paramsIn),
defaultUriDataLength(),
defaultUriData(),
defaultAdvPowerLevels(defaultAdvPowerLevelsIn),
initSucceeded(false),
resetFlag(),
lockedStateChar(UUID_LOCK_STATE_CHAR, &lockedState),
lockChar(UUID_LOCK_CHAR, &params.lock),
uriDataChar(UUID_URI_DATA_CHAR, params.uriData, 0, URI_DATA_MAX,
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
unlockChar(UUID_UNLOCK_CHAR, &params.lock),
flagsChar(UUID_FLAGS_CHAR, &params.flags),
advPowerLevelsChar(UUID_ADV_POWER_LEVELS_CHAR, &params.advPowerLevels),
txPowerModeChar(UUID_TX_POWER_MODE_CHAR, &params.txPowerMode),
beaconPeriodChar(UUID_BEACON_PERIOD_CHAR, &params.beaconPeriod),
resetChar(UUID_RESET_CHAR, &resetFlag) {
encodeURI(defaultURIDataIn, defaultUriData, defaultUriDataLength);
if (defaultUriDataLength > URI_DATA_MAX) {
return;
}
if (!resetToDefaultsFlag && (params.uriDataLength > URI_DATA_MAX)) {
resetToDefaultsFlag = true;
}
if (resetToDefaultsFlag) {
resetToDefaults();
} else {
updateCharacteristicValues();
}
lockedState = isLocked();
lockChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::lockAuthorizationCallback);
unlockChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::unlockAuthorizationCallback);
uriDataChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::uriDataWriteAuthorizationCallback);
flagsChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint8_t>);
advPowerLevelsChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<PowerLevels_t>);
txPowerModeChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::powerModeAuthorizationCallback);
beaconPeriodChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint16_t>);
resetChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint8_t>);
static GattCharacteristic *charTable[] = {
&lockedStateChar, &lockChar, &unlockChar, &uriDataChar,
&flagsChar, &advPowerLevelsChar, &txPowerModeChar, &beaconPeriodChar, &resetChar
};
GattService configService(UUID_URI_BEACON_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
ble.addService(configService);
ble.onDataWritten(this, &URIBeaconConfigService::onDataWrittenCallback);
setupURIBeaconConfigAdvertisements(); /* Set up advertising for the config service. */
initSucceeded = true;
}
bool configuredSuccessfully(void) const {
return initSucceeded;
}
/* Start out by advertising the config service for a limited time after
* startup. Then switch to the normal non-connectible beacon functionality.
*/
void setupURIBeaconConfigAdvertisements()
{
const char DEVICE_NAME[] = "mUriBeacon Config";
ble.gap().clearAdvertisingPayload();
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
// UUID is in different order in the ADV frame (!)
uint8_t reversedServiceUUID[sizeof(UUID_URI_BEACON_SERVICE)];
for (unsigned int i = 0; i < sizeof(UUID_URI_BEACON_SERVICE); i++) {
reversedServiceUUID[i] = UUID_URI_BEACON_SERVICE[sizeof(UUID_URI_BEACON_SERVICE) - i - 1];
}
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, reversedServiceUUID, sizeof(reversedServiceUUID));
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG);
ble.gap().accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME, reinterpret_cast<const uint8_t *>(&DEVICE_NAME), sizeof(DEVICE_NAME));
ble.gap().accumulateScanResponse(GapAdvertisingData::TX_POWER_LEVEL,
reinterpret_cast<uint8_t *>(&defaultAdvPowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]),
sizeof(uint8_t));
ble.gap().setTxPower(params.advPowerLevels[params.txPowerMode]);
ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(&DEVICE_NAME));
ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.gap().setAdvertisingInterval(GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC));
}
/* Helper function to switch to the non-connectible normal mode for UriBeacon. This gets called after a timeout. */
void setupURIBeaconAdvertisements()
{
/* Reinitialize the BLE stack. This will clear away the existing services and advertising state. */
ble.shutdown();
ble.init();
// Fields from the service.
unsigned beaconPeriod = params.beaconPeriod;
unsigned txPowerMode = params.txPowerMode;
unsigned uriDataLength = params.uriDataLength;
URIBeaconConfigService::UriData_t &uriData = params.uriData;
URIBeaconConfigService::PowerLevels_t &advPowerLevels = params.advPowerLevels;
uint8_t flags = params.flags;
extern void saveURIBeaconConfigParams(const Params_t *paramsP); /* Forward declaration; necessary to avoid a circular dependency. */
saveURIBeaconConfigParams(&params);
ble.gap().clearAdvertisingPayload();
ble.gap().setTxPower(params.advPowerLevels[params.txPowerMode]);
ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
ble.gap().setAdvertisingInterval(beaconPeriod);
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID));
uint8_t serviceData[SERVICE_DATA_MAX];
unsigned serviceDataLen = 0;
serviceData[serviceDataLen++] = BEACON_UUID[0];
serviceData[serviceDataLen++] = BEACON_UUID[1];
serviceData[serviceDataLen++] = flags;
serviceData[serviceDataLen++] = advPowerLevels[txPowerMode];
for (unsigned j = 0; j < uriDataLength; j++) {
serviceData[serviceDataLen++] = uriData[j];
}
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen);
}
private:
// True if the lock bits are non-zero.
bool isLocked() {
Lock_t testLock;
memset(testLock, 0, sizeof(Lock_t));
return memcmp(params.lock, testLock, sizeof(Lock_t));
}
/*
* This callback is invoked when a GATT client attempts to modify any of the
* characteristics of this service. These attempts are also applied to
* the internal state of this service object.
*/
void onDataWrittenCallback(const GattWriteCallbackParams *writeParams) {
uint16_t handle = writeParams->handle;
if (handle == lockChar.getValueHandle()) {
// Validated earlier,
memcpy(params.lock, writeParams->data, sizeof(Lock_t));
// Use isLocked() in case bits are being set to all zeros.
lockedState = isLocked();
} else if (handle == unlockChar.getValueHandle()) {
// Validated earlier.
memset(params.lock, 0, sizeof(Lock_t));
lockedState = false;
} else if (handle == uriDataChar.getValueHandle()) {
params.uriDataLength = writeParams->len;
memcpy(params.uriData, writeParams->data, params.uriDataLength);
} else if (handle == flagsChar.getValueHandle()) {
params.flags = *(writeParams->data);
} else if (handle == advPowerLevelsChar.getValueHandle()) {
memcpy(params.advPowerLevels, writeParams->data, sizeof(PowerLevels_t));
} else if (handle == txPowerModeChar.getValueHandle()) {
params.txPowerMode = *(writeParams->data);
} else if (handle == beaconPeriodChar.getValueHandle()) {
params.beaconPeriod = *((uint16_t *)(writeParams->data));
/* Remap beaconPeriod to within permissible bounds if necessary. */
if (params.beaconPeriod != 0) {
bool paramsUpdated = false;
if (params.beaconPeriod < ble.gap().getMinAdvertisingInterval()) {
params.beaconPeriod = ble.gap().getMinAdvertisingInterval();
paramsUpdated = true;
} else if (params.beaconPeriod > ble.gap().getMaxAdvertisingInterval()) {
params.beaconPeriod = ble.gap().getMaxAdvertisingInterval();
paramsUpdated = true;
}
if (paramsUpdated) {
ble.gattServer().write(beaconPeriodChar.getValueHandle(), reinterpret_cast<uint8_t *>(&params.beaconPeriod), sizeof(uint16_t));
}
}
} else if (handle == resetChar.getValueHandle()) {
resetToDefaults();
}
}
/*
* Reset the default values.
*/
void resetToDefaults(void) {
lockedState = false;
memset(params.lock, 0, sizeof(Lock_t));
memcpy(params.uriData, defaultUriData, URI_DATA_MAX);
params.uriDataLength = defaultUriDataLength;
params.flags = 0;
memcpy(params.advPowerLevels, defaultAdvPowerLevels, sizeof(PowerLevels_t));
params.txPowerMode = TX_POWER_MODE_LOW;
params.beaconPeriod = 1000;
updateCharacteristicValues();
}
/*
* Internal helper function used to update the GATT database following any
* change to the internal state of the service object.
*/
void updateCharacteristicValues(void) {
ble.gattServer().write(lockedStateChar.getValueHandle(), &lockedState, 1);
ble.gattServer().write(uriDataChar.getValueHandle(), params.uriData, params.uriDataLength);
ble.gattServer().write(flagsChar.getValueHandle(), &params.flags, 1);
ble.gattServer().write(beaconPeriodChar.getValueHandle(),
reinterpret_cast<uint8_t *>(&params.beaconPeriod), sizeof(uint16_t));
ble.gattServer().write(txPowerModeChar.getValueHandle(), &params.txPowerMode, 1);
ble.gattServer().write(advPowerLevelsChar.getValueHandle(),
reinterpret_cast<uint8_t *>(params.advPowerLevels), sizeof(PowerLevels_t));
}
protected:
void lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else if (authParams->len != sizeof(Lock_t)) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
void unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (!lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
} else if (authParams->len != sizeof(Lock_t)) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else if (memcmp(authParams->data, params.lock, sizeof(Lock_t)) != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
void uriDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
void powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else if (authParams->len != sizeof(uint8_t)) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else if (*((uint8_t *)authParams->data) >= NUM_POWER_MODES) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
template <typename T>
void basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams) {
if (lockedState) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
} else if (authParams->len != sizeof(T)) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
} else if (authParams->offset != 0) {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
} else {
authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
}
protected:
BLE &ble;
Params_t &params;
size_t defaultUriDataLength; // Default value that is restored on reset.
UriData_t defaultUriData; // Default value that is restored on reset.
PowerLevels_t &defaultAdvPowerLevels; // Default value that is restored on reset.
uint8_t lockedState;
bool initSucceeded;
uint8_t resetFlag;
ReadOnlyGattCharacteristic<uint8_t> lockedStateChar;
WriteOnlyGattCharacteristic<Lock_t> lockChar;
GattCharacteristic uriDataChar;
WriteOnlyGattCharacteristic<Lock_t> unlockChar;
ReadWriteGattCharacteristic<uint8_t> flagsChar;
ReadWriteGattCharacteristic<PowerLevels_t> advPowerLevelsChar;
ReadWriteGattCharacteristic<uint8_t> txPowerModeChar;
ReadWriteGattCharacteristic<uint16_t> beaconPeriodChar;
WriteOnlyGattCharacteristic<uint8_t> resetChar;
public:
/*
* Encode a human-readable URI into the binary format defined by the UriBeacon spec (https://github.com/google/uribeacon/tree/master/specification).
*/
static void encodeURI(const char *uriDataIn, UriData_t uriDataOut, size_t &sizeofURIDataOut) {
const char *prefixes[] = {
"http://www.",
"https://www.",
"http://",
"https://",
"urn:uuid:"
};
const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
const char *suffixes[] = {
".com/",
".org/",
".edu/",
".net/",
".info/",
".biz/",
".gov/",
".com",
".org",
".edu",
".net",
".info",
".biz",
".gov"
};
const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
sizeofURIDataOut = 0;
memset(uriDataOut, 0, sizeof(UriData_t));
if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) {
return;
}
/*
* handle prefix
*/
for (unsigned i = 0; i < NUM_PREFIXES; i++) {
size_t prefixLen = strlen(prefixes[i]);
if (strncmp(uriDataIn, prefixes[i], prefixLen) == 0) {
uriDataOut[sizeofURIDataOut++] = i;
uriDataIn += prefixLen;
break;
}
}
/*
* Handle suffixes.
*/
while (*uriDataIn && (sizeofURIDataOut < URI_DATA_MAX)) {
/* check for suffix match */
unsigned i;
for (i = 0; i < NUM_SUFFIXES; i++) {
size_t suffixLen = strlen(suffixes[i]);
if (strncmp(uriDataIn, suffixes[i], suffixLen) == 0) {
uriDataOut[sizeofURIDataOut++] = i;
uriDataIn += suffixLen;
break; /* From the for loop for checking against suffixes. */
}
}
/* This is the default case where we've got an ordinary character that doesn't match a suffix. */
if (i == NUM_SUFFIXES) {
uriDataOut[sizeofURIDataOut++] = *uriDataIn;
++uriDataIn;
}
}
}
};
#endif // SERVICES_URIBEACONCONFIGSERVICE_H_

75
ble/services/iBeacon.h Normal file
View File

@ -0,0 +1,75 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_IBEACON_H__
#define __BLE_IBEACON_H__
#include "core_cmInstr.h"
#include "ble/BLE.h"
/**
* @class iBeacon
* @brief iBeacon Service. This sets up a device to broadcast advertising packets to mimic an iBeacon.
*/
class iBeacon
{
public:
typedef const uint8_t LocationUUID_t[16];
union Payload {
uint8_t raw[25];
struct {
uint16_t companyID;
uint8_t ID;
uint8_t len;
uint8_t proximityUUID[16];
uint16_t majorNumber;
uint16_t minorNumber;
uint8_t txPower;
};
Payload(LocationUUID_t uuid, uint16_t majNum, uint16_t minNum, uint8_t transmitPower, uint16_t companyIDIn) :
companyID(companyIDIn), ID(0x02), len(0x15), majorNumber(__REV16(majNum)), minorNumber(__REV16(minNum)), txPower(transmitPower)
{
memcpy(proximityUUID, uuid, sizeof(LocationUUID_t));
}
};
public:
iBeacon(BLE &_ble,
LocationUUID_t uuid,
uint16_t majNum,
uint16_t minNum,
uint8_t txP = 0xC8,
uint16_t compID = 0x004C) :
ble(_ble), data(uuid, majNum, minNum, txP, compID)
{
// Generate the 0x020106 part of the iBeacon Prefix.
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE );
// Generate the 0x1AFF part of the iBeacon Prefix.
ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, data.raw, sizeof(data.raw));
// Set advertising type.
ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
}
protected:
BLE &ble;
Payload data;
};
typedef iBeacon iBeaconService; /* This type-alias is deprecated. Please use iBeacon directly. This alias may be dropped from a future release. */
#endif //__BLE_IBEACON_H__

45
module.json Normal file
View File

@ -0,0 +1,45 @@
{
"name": "ble",
"version": "2.6.0",
"description": "The BLE module offers a high level abstraction for using Bluetooth Low Energy on multiple platforms.",
"keywords": [
"Bluetooth",
"BLE",
"mbed",
"mbed-official"
],
"author": "Rohit Grover",
"repository": {
"url": "https://github.com/ARMmbed/ble.git",
"type": "git"
},
"homepage": "https://developer.mbed.org/teams/Bluetooth-Low-Energy/",
"licenses": [
{
"url": "https://spdx.org/licenses/Apache-2.0",
"type": "Apache-2.0"
}
],
"dependencies": {},
"targetDependencies": {
"st-ble-shield": {
"x-nucleo-idb0xa1": "^2.0.0"
},
"nrf51822": {
"ble-nrf51822": "^2.2.8"
},
"nrf52832": {
"ble-nrf52832": "ARMmbed/ble-nrf52832"
},
"cordio": {
"ble-wicentric": "~0.0.4"
},
"mbed-classic": {
"mbed-classic": "~0.0.1"
},
"mbed-os": {
"mbed-drivers": "*",
"compiler-polyfill": "^1.2.1"
}
}
}

267
source/BLE.cpp Normal file
View File

@ -0,0 +1,267 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ble/BLE.h"
#include "ble/BLEInstanceBase.h"
#if defined(TARGET_OTA_ENABLED)
#include "ble/services/DFUService.h"
#endif
#ifdef YOTTA_CFG_MBED_OS
#include <minar/minar.h>
#endif
ble_error_t
BLE::initImplementation(FunctionPointerWithContext<InitializationCompleteCallbackContext*> callback)
{
ble_error_t err = transport->init(instanceID, callback);
if (err != BLE_ERROR_NONE) {
return err;
}
/* Platforms enabled for DFU should introduce the DFU Service into
* applications automatically. */
#if defined(TARGET_OTA_ENABLED)
static DFUService dfu(*this); // defined static so that the object remains alive
#endif // TARGET_OTA_ENABLED
return BLE_ERROR_NONE;
}
/**
* BLE::Instance() and BLE constructor rely upon a static array of initializers
* to create actual BLE transport instances. A description of these instances
* and initializers is supposed to be put in some .json file contributing to
* yotta's configuration (typically in the target definition described by
* target.json). Here's a sample:
*
* "config": {
* ...
* "ble_instances": {
* "count": 1,
* "0" : {
* "initializer" : "createBLEInstance"
* }
* }
* ...
* }
*
* The following macros result in translating the above config into a static
* array: instanceConstructors.
*/
#ifdef YOTTA_CFG_BLE_INSTANCES_COUNT
#define CONCATENATE(A, B) A ## B
#define EXPAND(X) X /* this adds a level of indirection needed to allow macro-expansion following a token-paste operation (see use of CONCATENATE() below). */
#define INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_1 YOTTA_CFG_BLE_INSTANCES_0_INITIALIZER
#define INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_2 INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_1, YOTTA_CFG_BLE_INSTANCES_1_INITIALIZER
#define INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_3 INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_2, YOTTA_CFG_BLE_INSTANCES_2_INITIALIZER
#define INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_4 INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_3, YOTTA_CFG_BLE_INSTANCES_3_INITIALIZER
#define INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_5 INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_4, YOTTA_CFG_BLE_INSTANCES_4_INITIALIZER
/* ... add more of the above if ever needed */
#define INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS(N) EXPAND(CONCATENATE(INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS_, N))
#elif !defined(INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS)
/*
* The following applies when building without yotta. By default BLE_API provides
* a trivial initializer list containing a single constructor: createBLEInstance.
* This may be overridden.
*/
#define INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS createBLEInstance
#endif /* YOTTA_CFG_BLE_INSTANCES_COUNT */
typedef BLEInstanceBase *(*InstanceConstructor_t)(void);
static const InstanceConstructor_t instanceConstructors[BLE::NUM_INSTANCES] = {
#ifndef YOTTA_CFG_BLE_INSTANCES_COUNT
INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS
#else
INITIALIZER_LIST_FOR_INSTANCE_CONSTRUCTORS(YOTTA_CFG_BLE_INSTANCES_COUNT)
#endif
};
BLE &
BLE::Instance(InstanceID_t id)
{
static BLE *singletons[NUM_INSTANCES];
if (id < NUM_INSTANCES) {
if (singletons[id] == NULL) {
singletons[id] = new BLE(id); /* This object will never be freed. */
}
return *singletons[id];
}
/* we come here only in the case of a bad interfaceID. */
static BLE badSingleton(NUM_INSTANCES /* this is a bad index; and will result in a NULL transport. */);
return badSingleton;
}
#ifdef YOTTA_CFG_MBED_OS
void defaultSchedulingCallback(BLE::OnEventsToProcessCallbackContext* params) {
minar::Scheduler::postCallback(&params->ble, &BLE::processEvents);
}
#else
#define defaultSchedulingCallback NULL
#endif
BLE::BLE(InstanceID_t instanceIDIn) : instanceID(instanceIDIn), transport(),
whenEventsToProcess(defaultSchedulingCallback)
{
static BLEInstanceBase *transportInstances[NUM_INSTANCES];
if (instanceID < NUM_INSTANCES) {
if (!transportInstances[instanceID]) {
transportInstances[instanceID] = instanceConstructors[instanceID](); /* Call the stack's initializer for the transport object. */
}
transport = transportInstances[instanceID];
} else {
transport = NULL;
}
}
bool BLE::hasInitialized(void) const
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->hasInitialized();
}
ble_error_t BLE::shutdown(void)
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->shutdown();
}
const char *BLE::getVersion(void)
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getVersion();
}
const Gap &BLE::gap() const
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getGap();
}
Gap &BLE::gap()
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getGap();
}
const GattServer& BLE::gattServer() const
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getGattServer();
}
GattServer& BLE::gattServer()
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getGattServer();
}
const GattClient& BLE::gattClient() const
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getGattClient();
}
GattClient& BLE::gattClient()
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getGattClient();
}
const SecurityManager& BLE::securityManager() const
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getSecurityManager();
}
SecurityManager& BLE::securityManager()
{
if (!transport) {
error("bad handle to underlying transport");
}
return transport->getSecurityManager();
}
void BLE::waitForEvent(void)
{
if (!transport) {
error("bad handle to underlying transport");
}
transport->waitForEvent();
}
void BLE::processEvents()
{
if (!transport) {
error("bad handle to underlying transport");
}
transport->processEvents();
}
void BLE::onEventsToProcess(const BLE::OnEventsToProcessCallback_t& callback)
{
whenEventsToProcess = callback;
}
void BLE::signalEventsToProcess()
{
if (whenEventsToProcess) {
OnEventsToProcessCallbackContext params = {
*this
};
whenEventsToProcess(&params);
}
}

View File

@ -0,0 +1,28 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ble/BLE.h"
#include "ble/BLEInstanceBase.h"
BLEInstanceBase::~BLEInstanceBase()
{
// empty destructor
}
void BLEInstanceBase::signalEventsToProcess(BLE::InstanceID_t id)
{
BLE::Instance(id).signalEventsToProcess();
}

View File

@ -0,0 +1,167 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ble/DiscoveredCharacteristic.h"
#include "ble/GattClient.h"
ble_error_t
DiscoveredCharacteristic::read(uint16_t offset) const
{
if (!props.read()) {
return BLE_ERROR_OPERATION_NOT_PERMITTED;
}
if (!gattc) {
return BLE_ERROR_INVALID_STATE;
}
return gattc->read(connHandle, valueHandle, offset);
}
struct OneShotReadCallback {
static void launch(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) {
OneShotReadCallback* oneShot = new OneShotReadCallback(client, connHandle, handle, cb);
oneShot->attach();
// delete will be made when this callback is called
}
private:
OneShotReadCallback(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) :
_client(client),
_connHandle(connHandle),
_handle(handle),
_callback(cb) { }
void attach() {
_client->onDataRead(makeFunctionPointer(this, &OneShotReadCallback::call));
}
void call(const GattReadCallbackParams* params) {
// verifiy that it is the right characteristic on the right connection
if (params->connHandle == _connHandle && params->handle == _handle) {
_callback(params);
_client->onDataRead().detach(makeFunctionPointer(this, &OneShotReadCallback::call));
delete this;
}
}
GattClient* _client;
Gap::Handle_t _connHandle;
GattAttribute::Handle_t _handle;
GattClient::ReadCallback_t _callback;
};
ble_error_t DiscoveredCharacteristic::read(uint16_t offset, const GattClient::ReadCallback_t& onRead) const {
ble_error_t error = read(offset);
if (error) {
return error;
}
OneShotReadCallback::launch(gattc, connHandle, valueHandle, onRead);
return error;
}
ble_error_t
DiscoveredCharacteristic::write(uint16_t length, const uint8_t *value) const
{
if (!props.write()) {
return BLE_ERROR_OPERATION_NOT_PERMITTED;
}
if (!gattc) {
return BLE_ERROR_INVALID_STATE;
}
return gattc->write(GattClient::GATT_OP_WRITE_REQ, connHandle, valueHandle, length, value);
}
ble_error_t
DiscoveredCharacteristic::writeWoResponse(uint16_t length, const uint8_t *value) const
{
if (!props.writeWoResp()) {
return BLE_ERROR_OPERATION_NOT_PERMITTED;
}
if (!gattc) {
return BLE_ERROR_INVALID_STATE;
}
return gattc->write(GattClient::GATT_OP_WRITE_CMD, connHandle, valueHandle, length, value);
}
struct OneShotWriteCallback {
static void launch(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) {
OneShotWriteCallback* oneShot = new OneShotWriteCallback(client, connHandle, handle, cb);
oneShot->attach();
// delete will be made when this callback is called
}
private:
OneShotWriteCallback(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) :
_client(client),
_connHandle(connHandle),
_handle(handle),
_callback(cb) { }
void attach() {
_client->onDataWritten(makeFunctionPointer(this, &OneShotWriteCallback::call));
}
void call(const GattWriteCallbackParams* params) {
// verifiy that it is the right characteristic on the right connection
if (params->connHandle == _connHandle && params->handle == _handle) {
_callback(params);
_client->onDataWritten().detach(makeFunctionPointer(this, &OneShotWriteCallback::call));
delete this;
}
}
GattClient* _client;
Gap::Handle_t _connHandle;
GattAttribute::Handle_t _handle;
GattClient::WriteCallback_t _callback;
};
ble_error_t DiscoveredCharacteristic::write(uint16_t length, const uint8_t *value, const GattClient::WriteCallback_t& onRead) const {
ble_error_t error = write(length, value);
if (error) {
return error;
}
OneShotWriteCallback::launch(gattc, connHandle, valueHandle, onRead);
return error;
}
ble_error_t DiscoveredCharacteristic::discoverDescriptors(
const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& onCharacteristicDiscovered,
const CharacteristicDescriptorDiscovery::TerminationCallback_t& onTermination) const {
if(!gattc) {
return BLE_ERROR_INVALID_STATE;
}
ble_error_t err = gattc->discoverCharacteristicDescriptors(
*this, onCharacteristicDiscovered, onTermination
);
return err;
}

View File

@ -0,0 +1,75 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ble/Gap.h"
#include "ble/GapScanningParams.h"
GapScanningParams::GapScanningParams(uint16_t interval, uint16_t window, uint16_t timeout, bool activeScanning) :
_interval(MSEC_TO_SCAN_DURATION_UNITS(interval)),
_window(MSEC_TO_SCAN_DURATION_UNITS(window)),
_timeout(timeout),
_activeScanning(activeScanning) {
/* stay within limits */
if (_interval < SCAN_INTERVAL_MIN) {
_interval = SCAN_INTERVAL_MIN;
}
if (_interval > SCAN_INTERVAL_MAX) {
_interval = SCAN_INTERVAL_MAX;
}
if (_window < SCAN_WINDOW_MIN) {
_window = SCAN_WINDOW_MIN;
}
if (_window > SCAN_WINDOW_MAX) {
_window = SCAN_WINDOW_MAX;
}
}
ble_error_t
GapScanningParams::setInterval(uint16_t newIntervalInMS)
{
uint16_t newInterval = MSEC_TO_SCAN_DURATION_UNITS(newIntervalInMS);
if ((newInterval >= SCAN_INTERVAL_MIN) && (newInterval < SCAN_INTERVAL_MAX)) {
_interval = newInterval;
return BLE_ERROR_NONE;
}
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
ble_error_t
GapScanningParams::setWindow(uint16_t newWindowInMS)
{
uint16_t newWindow = MSEC_TO_SCAN_DURATION_UNITS(newWindowInMS);
if ((newWindow >= SCAN_WINDOW_MIN) && (newWindow < SCAN_WINDOW_MAX)) {
_window = newWindow;
return BLE_ERROR_NONE;
}
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
ble_error_t
GapScanningParams::setTimeout(uint16_t newTimeout)
{
_timeout = newTimeout;
return BLE_ERROR_NONE;
}
void
GapScanningParams::setActiveScanning(bool activeScanning)
{
_activeScanning = activeScanning;
}

View File

@ -0,0 +1,44 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef TARGET_NRF51822 /* DFU only supported on nrf51 platforms */
#include "ble/services/DFUService.h"
const uint8_t DFUServiceBaseUUID[] = {
0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0xEF, 0xDE,
0x15, 0x23, 0x78, 0x5F, 0xEA, 0xBC, 0xD1, 0x23,
};
const uint16_t DFUServiceShortUUID = 0x1530;
const uint16_t DFUServiceControlCharacteristicShortUUID = 0x1531;
const uint16_t DFUServicePacketCharacteristicShortUUID = 0x1532;
const uint8_t DFUServiceUUID[] = {
0x00, 0x00, (uint8_t)(DFUServiceShortUUID >> 8), (uint8_t)(DFUServiceShortUUID & 0xFF), 0x12, 0x12, 0xEF, 0xDE,
0x15, 0x23, 0x78, 0x5F, 0xEA, 0xBC, 0xD1, 0x23,
};
const uint8_t DFUServiceControlCharacteristicUUID[] = {
0x00, 0x00, (uint8_t)(DFUServiceControlCharacteristicShortUUID >> 8), (uint8_t)(DFUServiceControlCharacteristicShortUUID & 0xFF), 0x12, 0x12, 0xEF, 0xDE,
0x15, 0x23, 0x78, 0x5F, 0xEA, 0xBC, 0xD1, 0x23,
};
const uint8_t DFUServicePacketCharacteristicUUID[] = {
0x00, 0x00, (uint8_t)(DFUServicePacketCharacteristicShortUUID >> 8), (uint8_t)(DFUServicePacketCharacteristicShortUUID & 0xFF), 0x12, 0x12, 0xEF, 0xDE,
0x15, 0x23, 0x78, 0x5F, 0xEA, 0xBC, 0xD1, 0x23,
};
DFUService::ResetPrepare_t DFUService::handoverCallback = NULL;
#endif /* #ifdef TARGET_NRF51822 */

View File

@ -0,0 +1,41 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ble/services/UARTService.h"
const uint8_t UARTServiceBaseUUID[UUID::LENGTH_OF_LONG_UUID] = {
0x6E, 0x40, 0x00, 0x00, 0xB5, 0xA3, 0xF3, 0x93,
0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E,
};
const uint16_t UARTServiceShortUUID = 0x0001;
const uint16_t UARTServiceTXCharacteristicShortUUID = 0x0002;
const uint16_t UARTServiceRXCharacteristicShortUUID = 0x0003;
const uint8_t UARTServiceUUID[UUID::LENGTH_OF_LONG_UUID] = {
0x6E, 0x40, (uint8_t)(UARTServiceShortUUID >> 8), (uint8_t)(UARTServiceShortUUID & 0xFF), 0xB5, 0xA3, 0xF3, 0x93,
0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E,
};
const uint8_t UARTServiceUUID_reversed[UUID::LENGTH_OF_LONG_UUID] = {
0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0,
0x93, 0xF3, 0xA3, 0xB5, (uint8_t)(UARTServiceShortUUID & 0xFF), (uint8_t)(UARTServiceShortUUID >> 8), 0x40, 0x6E
};
const uint8_t UARTServiceTXCharacteristicUUID[UUID::LENGTH_OF_LONG_UUID] = {
0x6E, 0x40, (uint8_t)(UARTServiceTXCharacteristicShortUUID >> 8), (uint8_t)(UARTServiceTXCharacteristicShortUUID & 0xFF), 0xB5, 0xA3, 0xF3, 0x93,
0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E,
};
const uint8_t UARTServiceRXCharacteristicUUID[UUID::LENGTH_OF_LONG_UUID] = {
0x6E, 0x40, (uint8_t)(UARTServiceRXCharacteristicShortUUID >> 8), (uint8_t)(UARTServiceRXCharacteristicShortUUID & 0xFF), 0xB5, 0xA3, 0xF3, 0x93,
0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E,
};

View File

@ -0,0 +1,35 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ble/services/URIBeaconConfigService.h"
#define UUID_URI_BEACON(FIRST, SECOND) { \
0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba, \
0xab, 0x96, 0x99, 0xb9, 0x1a, 0xc9, 0x81, 0xd8, \
}
const uint8_t UUID_URI_BEACON_SERVICE[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x80);
const uint8_t UUID_LOCK_STATE_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x81);
const uint8_t UUID_LOCK_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x82);
const uint8_t UUID_UNLOCK_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x83);
const uint8_t UUID_URI_DATA_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x84);
const uint8_t UUID_FLAGS_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x85);
const uint8_t UUID_ADV_POWER_LEVELS_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x86);
const uint8_t UUID_TX_POWER_MODE_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x87);
const uint8_t UUID_BEACON_PERIOD_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x88);
const uint8_t UUID_RESET_CHAR[UUID::LENGTH_OF_LONG_UUID] = UUID_URI_BEACON(0x20, 0x89);
const uint8_t BEACON_UUID[sizeof(UUID::ShortUUIDBytes_t)] = {0xD8, 0xFE};