Move ARMmbed/feature/FEATURE_BLE into mbedmicro/mbed.

In the process, the path has been shortened and the unecessary ble
directory between FEATURE_BLE and the actual implementation has been
removed.

commit id of ARMmbed : 17728a824c7273e16b6b74fae871e2997c88ecd1
pull/2200/head
Vincent Coubard 2016-07-20 22:10:36 +01:00
parent 48c1d2eb7a
commit 2259e0d539
241 changed files with 67434 additions and 0 deletions

2
features/FEATURE_BLE/.gitignore vendored Normal file
View File

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

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)*

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.)

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.

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

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

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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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__

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__*/

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

File diff suppressed because it is too large Load Diff

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__ */

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__ */

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__

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__ */

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__*/

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__ */

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__ */

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__ */

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__ */

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__ */

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_ */

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__*/

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__ */

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__

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__

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__*/

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__ */

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_

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__

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"
}
}
}

View File

@ -0,0 +1,286 @@
/* 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
#if !defined(YOTTA_CFG_MBED_OS)
#include <mbed_error.h>
#include <toolchain.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
// yotta unlike mbed-cli has proper dependency mechanisms
// It is not required to defined a stub for createBLEInstance
#if !defined(YOTTA_CFG_MBED_OS)
// this stub is required by ARMCC otherwise link will systematically fail
MBED_WEAK BLEInstanceBase* createBLEInstance() {
error("Please provide an implementation for mbed BLE");
return NULL;
}
#endif
#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};

View File

@ -0,0 +1,77 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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 _ARMBLE_H_
#define _ARMBLE_H_
#include "BLE.h"
#include "blecommon.h"
#include "BLEInstanceBase.h"
#include "ArmGap.h"
#include "ArmGattServer.h"
#include "ArmGattClient.h"
#include "ArmSecurityManager.h"
class ArmBLE : public BLEInstanceBase
{
public:
ArmBLE(void);
virtual ~ArmBLE(void);
virtual ble_error_t init(BLE::InstanceID_t instanceID, FunctionPointerWithContext<BLE::InitializationCompleteCallbackContext *> initCallback);
virtual bool hasInitialized(void) const {
return initialized;
}
virtual ble_error_t shutdown(void);
virtual const char *getVersion(void);
virtual Gap &getGap() {
return ArmGap::getInstance();
};
virtual const Gap &getGap() const {
return ArmGap::getInstance();
};
virtual GattServer &getGattServer() {
return ArmGattServer::getInstance();
};
virtual const GattServer &getGattServer() const {
return ArmGattServer::getInstance();
};
virtual GattClient &getGattClient() {
return ArmGattClient::getInstance();
};
virtual SecurityManager &getSecurityManager() {
return ArmSecurityManager::getInstance();
};
virtual const SecurityManager &getSecurityManager() const {
return ArmSecurityManager::getInstance();
};
virtual void waitForEvent(void);
virtual void processEvents();
private:
bool initialized;
BLE::InstanceID_t instanceID;
static void timeoutCallback(void);
void callDispatcher(void);
};
#endif /* _ARMBLE_H_ */

View File

@ -0,0 +1,91 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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 _ARM_GAP_H_
#define _ARM_GAP_H_
#include "mbed.h"
#include "blecommon.h"
#include "GapAdvertisingParams.h"
#include "GapAdvertisingData.h"
#include "Gap.h"
#include "GapScanningParams.h"
#include "dm_api.h"
#include "att_api.h"
/**************************************************************************/
/*!
\brief
*/
/**************************************************************************/
class ArmGap : public Gap
{
public:
static ArmGap &getInstance();
/* Functions that must be implemented from Gap */
virtual ble_error_t setAddress(AddressType_t type, const Address_t address);
virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &);
#define BLE_GAP_ADV_INTERVAL_MIN 0x0020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */
#define BLE_GAP_ADV_NONCON_INTERVAL_MIN 0x00A0 /**< Minimum Advertising interval in 625 us units for non connectable mode, i.e. 100 ms. */
#define BLE_GAP_ADV_INTERVAL_MAX 0x4000 /**< Armum Advertising interval in 625 us units, i.e. 10.24 s. */
virtual uint16_t getMinAdvertisingInterval(void) const { return BLE_GAP_ADV_INTERVAL_MIN; }
virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const { return BLE_GAP_ADV_NONCON_INTERVAL_MIN; }
virtual uint16_t getMaxAdvertisingInterval(void) const { return BLE_GAP_ADV_INTERVAL_MAX; }
virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
virtual ble_error_t stopAdvertising(void);
virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason);
virtual ble_error_t disconnect(DisconnectionReason_t reason);
virtual ble_error_t setDeviceName(const uint8_t *deviceName);
virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance);
virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP);
virtual ble_error_t setTxPower(int8_t txPower);
virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP);
void setConnectionHandle(uint16_t m_connectionHandle);
uint16_t getConnectionHandle(void);
virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params);
virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params);
virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params);
virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams);
virtual ble_error_t stopScan(void);
void advertisingStopped(void);
private:
uint16_t m_connectionHandle;
addr_type_t m_type;
ArmGap() {
m_connectionHandle = DM_CONN_ID_NONE;
m_type = BLEProtocol::AddressType::RANDOM_STATIC;
}
ArmGap(ArmGap const &);
void operator=(ArmGap const &);
};
#endif /* _ARM_GAP_H_ */

View File

@ -0,0 +1,42 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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 _ARM_GATT_CLIENT_H_
#define _ARM_GATT_CLIENT_H_
#include <stddef.h>
#include "GattClient.h"
class ArmGattClient : public GattClient
{
public:
static ArmGattClient &getInstance() {
static ArmGattClient m_instance;
return m_instance;
}
public:
ArmGattClient() {
/* empty */
}
private:
};
#endif /* _ARM_GATT_CLIENT_H_ */

View File

@ -0,0 +1,68 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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 _ARM_GATT_SERVER_H_
#define _ARM_GATT_SERVER_H_
#include <stddef.h>
#include "blecommon.h"
#include "GattServer.h"
#include "generic/wsf_types.h"
#include "att_api.h"
class ArmGattServer : public GattServer
{
public:
static ArmGattServer &getInstance();
/* Functions that must be implemented from GattServer */
virtual ble_error_t addService(GattService &);
virtual ble_error_t read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP);
virtual ble_error_t read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP);
virtual ble_error_t write(GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false);
virtual ble_error_t write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false);
virtual ble_error_t areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP);
virtual ble_error_t areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP);
virtual bool isOnDataReadAvailable() const { return true; }
private:
static void cccCback(attsCccEvt_t *pEvt);
static void attCback(attEvt_t *pEvt);
static uint8_t attsReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, attsAttr_t *pAttr);
static uint8_t attsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
/*! client characteristic configuration descriptors settings */
#define MAX_CCC_CNT 20
attsCccSet_t cccSet[MAX_CCC_CNT];
uint16_t cccValues[MAX_CCC_CNT];
uint16_t cccHandles[MAX_CCC_CNT];
uint8_t cccCnt;
private:
ArmGattServer() : GattServer(), cccSet(), cccValues(), cccHandles(), cccCnt(0) {
/* empty */
}
ArmGattServer(const ArmGattServer &);
const ArmGattServer& operator=(const ArmGattServer &);
};
#endif /* _ARM_GATT_SERVER_H_ */

View File

@ -0,0 +1,39 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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 _ARM_SECURITY_MANAGER_H_
#define _ARM_SECURITY_MANAGER_H_
#include <stddef.h>
#include "SecurityManager.h"
class ArmSecurityManager : public SecurityManager
{
public:
static ArmSecurityManager &getInstance() {
static ArmSecurityManager m_instance;
return m_instance;
}
public:
ArmSecurityManager() {
/* empty */
}
};
#endif /* _ARM_SECURITY_MANAGER_H_ */

View File

@ -0,0 +1,568 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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 "mbed.h"
#include "ArmBLE.h"
extern "C" {
#include "cordio_sdk_version.h"
#include "chip.h"
#include "board.h"
#include "utils.h"
#include "hpal_blep.h"
#include "hpal_hci.h"
#include "ble_init.h"
#include "main_board.h"
#include "wsf_assert.h"
#include "wsf_buf.h"
#include "wsf_math.h"
#include "wsf_msg.h"
#include "wsf_os.h"
#include "wsf_mbed_os.h"
#include "wsf_sec.h"
#include "wsf_timer.h"
#include "wsf_types.h"
#include "wsf_trace.h"
#include "bstream.h"
#include "hci_handler.h"
#include "hci_tr.h"
#include "dm_handler.h"
#include "l2c_handler.h"
#include "att_handler.h"
#include "smp_handler.h"
#include "l2c_api.h"
#include "att_api.h"
#include "smp_api.h"
#include "hci_core.h"
#include "hci_drv.h"
}
/* Number of WSF buffer pools. */
#define WSF_BUF_POOLS 4
/* Buffer size. */
#define ACL_BUF_SIZE 256
/* Total number of buffers. */
#define NUM_BUFS 8
/* Total size in bytes for buffer memory. */
#define BUF_MEM_SIZE (1024 * 4)
/*! Free memory for pool buffers. */
static uint32_t mainBufMem[BUF_MEM_SIZE/sizeof(uint32_t)];
/*! Default pool descriptor. */
static wsfBufPoolDesc_t mainPoolDesc[WSF_BUF_POOLS] =
{
{ 16, 8 },
{ 32, 8 },
{ 64, 8 },
{ ACL_BUF_SIZE + 16, NUM_BUFS }
};
/* Store the Event signalling */
bool isEventsSignaled = false;
/*! WSF handler ID */
wsfHandlerId_t armHandlerId;
wsfHandlerId_t BleHandlerId;
static volatile int reset_complete;
/* Beetle Internal Functions */
/* HCI callback prototypes. */
static uint8_t *mainHciBufAlloc(uint16_t len);
static void mainHciBufFree(uint8_t *buf);
static void mainHciReadDone(uint8_t type, uint8_t *pData, uint16_t len);
static void mainHciWriteDone(uint8_t type, uint8_t *pData, int32_t err, void *pContext);
/*! \brief HCI callbacks. */
static const hpalHciCbacks_t mainHciCbacks =
{
mainHciBufAlloc,
mainHciBufFree,
mainHciReadDone,
mainHciWriteDone
};
/**************************************************************************************************
Stack HCI
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Allocate a buffer for a received message.
*
* This function is called from an interrupt context.
*
* \param len Length of buffer
*
** \return Pointer to buffer or NULL if buffer could not be allocated
*/
/*************************************************************************************************/
static uint8_t *mainHciBufAlloc(uint16_t len)
{
return (uint8_t*)WsfMsgAlloc(len);
}
/*************************************************************************************************/
/*!
* \brief Free a buffer previously allocated with `BufAlloc()`.
*
* \param pData Pointer to buffer
*/
/*************************************************************************************************/
static void mainHciBufFree(uint8_t *pData)
{
WsfMsgFree(pData);
}
/*************************************************************************************************/
/*!
* \brief Handle read completion.
*
* This function is called from an interrupt context.
*
* \param type Packet type
* \param pData Packet data, which was allocated with `BufAlloc()`. The caller must free
* this buffer
* \param len Length of packet data, in bytes
*
* \return None.
*/
/*************************************************************************************************/
static void mainHciReadDone(uint8_t type, uint8_t *pData, uint16_t len)
{
WSF_ASSERT(align == 0);
switch (type)
{
/* Route standard types to stack. */
case HCI_CMD_TYPE:
case HCI_ACL_TYPE:
case HCI_EVT_TYPE:
{
hciCoreRecv(type, pData);
break;
}
/* We should not get anything else. */
default:
{
WsfMsgFree(pData);
break;
}
}
}
/*************************************************************************************************/
/*!
* \brief Handle write completion.
*
* This function is called from an interrupt context.
*
* \param type Packet type.
* \param pData Pointer to buffer that held written data, which was passed to
* `HpalHciWrite()`
* \param err Indicates success (0) or error (one of the `HPAL_HCI_ERROR_####` codes)
* \param pContext Context pointer passed to `HpalHciWrite()`
*
* \return None.
*/
/*************************************************************************************************/
static void mainHciWriteDone(uint8_t type, uint8_t *pData, int32_t err, void *pContext)
{
switch (type)
{
case HCI_CMD_TYPE:
{
WsfMsgFree(pData);
break;
}
case HCI_ACL_TYPE:
{
hciCoreTxAclComplete((hciCoreConn_t *)pContext, pData);
break;
}
}
}
/*************************************************************************************************/
/*!
* \fn hciTrSendAclData
*
* \brief Send a complete HCI ACL packet to the transport.
*
* \param pContext Connection context.
* \param pData WSF msg buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciTrSendAclData(void *pContext, uint8_t *pData)
{
uint16_t len;
/* get 16-bit length */
BYTES_TO_UINT16(len, &pData[2]);
len += HCI_ACL_HDR_LEN;
/* transmit ACL header and data */
HpalHciWrite(HCI_ACL_TYPE, pData, len, pContext);
}
/*************************************************************************************************/
/*!
* \fn hciTrSendCmd
*
* \brief Send a complete HCI command to the transport.
*
* \param pData WSF msg buffer containing an HCI command.
*
* \return None.
*/
/*************************************************************************************************/
void hciTrSendCmd(uint8_t *pData)
{
uint8_t len;
/* get length */
len = pData[2] + HCI_CMD_HDR_LEN;
/* dump event for protocol analysis */
HCI_PDUMP_CMD(len, pData);
/* transmit ACL header and data */
HpalHciWrite(HCI_CMD_TYPE, pData, len, NULL);
}
void beetleCordioReset(void)
{
CORDIO_LLCCTRL_LLC_RESET_ASSERT();
CORDIO_LLCCTRL_RESETX_ASSERT();
CORDIO_LLCCTRL_VMEM_ON_ASSERT();
wait_ms(2);
CORDIO_LLCCTRL_RESETX_NEGATE();
CORDIO_LLCCTRL_LLC_RESET_NEGATE();
}
/* End Beetle Internal Functions */
/**
* The singleton which represents the ArmBLE transport for the BLE.
*/
static ArmBLE deviceInstance;
/**
* BLE-API requires an implementation of the following function in order to
* obtain its transport handle.
*/
BLEInstanceBase *createBLEInstance(void)
{
return (&deviceInstance);
}
ArmBLE::ArmBLE(void) : initialized(false), instanceID(BLE::DEFAULT_INSTANCE)
{
}
ArmBLE::~ArmBLE(void)
{
}
const char *ArmBLE::getVersion(void)
{
static char versionString[32];
strncpy(versionString, "unknown", sizeof(versionString));
return versionString;
}
static void DmCback(dmEvt_t *pDmEvt)
{
dmEvt_t *pMsg;
if ((pMsg = (dmEvt_t*)WsfMsgAlloc(sizeof(dmEvt_t))) != NULL)
{
memcpy(pMsg, pDmEvt, sizeof(dmEvt_t));
WsfMsgSend(armHandlerId, pMsg);
}
}
static void armHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
if (pMsg != NULL)
{
switch(pMsg->event)
{
case DM_RESET_CMPL_IND:
reset_complete = 1;
break;
case DM_ADV_START_IND:
break;
case DM_ADV_STOP_IND:
ArmGap::getInstance().advertisingStopped();
break;
case DM_SCAN_REPORT_IND:
{
dmEvt_t *scan = (dmEvt_t*)pMsg;
ArmGap::getInstance().processAdvertisementReport( scan->scanReport.addr,
scan->scanReport.rssi,
(scan->scanReport.eventType == DM_ADV_SCAN_RESPONSE) ? true : false,
(GapAdvertisingParams::AdvertisingType_t)scan->scanReport.eventType,
scan->scanReport.len,
scan->scanReport.pData);
}
break;
case DM_CONN_OPEN_IND:
{
dmEvt_t *conn = (dmEvt_t*)pMsg;
ArmGap::getInstance().setConnectionHandle(conn->hdr.param);
Gap::ConnectionParams_t params = { conn->connOpen.connInterval, conn->connOpen.connInterval, conn->connOpen.connLatency, conn->connOpen.supTimeout };
Gap::AddressType_t ownAddrType;
Gap::Address_t ownAddr;
ArmGap::getInstance().getAddress(&ownAddrType, ownAddr);
ArmGap::getInstance().processConnectionEvent(conn->hdr.param,
Gap::PERIPHERAL,
(Gap::AddressType_t)conn->connOpen.addrType,
conn->connOpen.peerAddr,
ownAddrType,
ownAddr,
&params);
}
break;
case DM_CONN_CLOSE_IND:
{
dmEvt_t *conn = (dmEvt_t*)pMsg;
ArmGap::getInstance().setConnectionHandle(DM_CONN_ID_NONE);
ArmGap::getInstance().processDisconnectionEvent(conn->hdr.param, (Gap::DisconnectionReason_t)conn->connClose.reason);
}
break;
default:
break;
}
}
}
/*
* AttServerInitDeInitCback callback is used to Initialize/Deinitialize
* the CCC Table of the ATT Server when a remote peer requests to Open
* or Close the connection.
*/
static void AttServerInitDeInitCback(dmEvt_t *pDmEvt)
{
dmConnId_t connId = (dmConnId_t)pDmEvt->hdr.param;
switch (pDmEvt->hdr.event)
{
case DM_CONN_OPEN_IND:
/* set up CCC table with uninitialized (all zero) values */
AttsCccInitTable(connId, NULL);
break;
case DM_CONN_CLOSE_IND:
/* clear CCC table on connection close */
AttsCccClearTable(connId);
break;
default:
break;
}
}
/*
* This function will signal to the user code by calling signalEventsToProcess.
* It is registered and called into the Wsf Stack.
*/
static uint32_t signalEvent()
{
if(isEventsSignaled == false) {
isEventsSignaled = true;
deviceInstance.signalEventsToProcess(BLE::DEFAULT_INSTANCE);
}
return BLE_ERROR_NONE;
}
static void ArmBLEInit(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
wsfHandlerId_t handlerId;
/*
* The init sequence is taken from the Cordio Stack Porting Guide version
* 1.1 Chapter 2.6.
*/
/* init OS subsystems */
/* initialize WSF services */
WsfSecInit();
/* Disabled WsfSecAesInit(); */
/* initialize HCI */
handlerId = WsfOsSetNextHandler(HciHandler);
HciHandlerInit(handlerId);
/* initialize DM */
handlerId = WsfOsSetNextHandler(DmHandler);
DmAdvInit();
DmConnInit();
DmConnSlaveInit();
DmSecInit();
DmHandlerInit(handlerId);
/* initialize L2CAP */
handlerId = WsfOsSetNextHandler(L2cSlaveHandler);
L2cSlaveHandlerInit(handlerId);
L2cInit();
L2cSlaveInit();
/* initialize ATT */
handlerId = WsfOsSetNextHandler(AttHandler);
AttHandlerInit(handlerId);
AttsInit();
AttsIndInit();
/* initialize SMP */
handlerId = WsfOsSetNextHandler(SmpHandler);
SmpHandlerInit(handlerId);
SmprInit();
/* store handler ID */
armHandlerId = WsfOsSetNextHandler(armHandler);
/* Register for stack callbacks */
HpalHciSetCbacks(&mainHciCbacks);
HpalHciSetLoggingLevel(HPAL_HCI_LOGGING_LEVEL_VERBOSE);
HpalHciTakeUp();
DmRegister(DmCback);
DmConnRegister(DM_CLIENT_ID_APP, DmCback);
AttConnRegister(AttServerInitDeInitCback);
/* Register MBED OS Signal Event */
mbedOSRegisterSignalEventCallback(&signalEvent);
/* Reset the device */
reset_complete = 0;
DmDevReset();
}
static void ArmBLEStartCallback(bool_t ok)
{
if (ok)
{
/* If started up, allow remaining application to run. */
WsfSetEvent(BleHandlerId, 1);
}
}
ble_error_t ArmBLE::init(BLE::InstanceID_t instanceID, FunctionPointerWithContext<BLE::InitializationCompleteCallbackContext *> initCallback)
{
wsfHandlerId_t handlerId;
beetleCordioReset();
Main_BoardInit();
/* init OS subsystems */
WsfTimerInit();
WsfBufInit(sizeof(mainBufMem), (uint8_t*)mainBufMem, WSF_BUF_POOLS, mainPoolDesc);
/* init stack */
handlerId = WsfOsSetNextHandler(HpalBlepHandler);
HpalBlepInit(handlerId);
BleHandlerId = WsfOsSetNextHandler(ArmBLEInit);
HpalBlepSetStartupCback(ArmBLEStartCallback);
/*
* Initialize BLE:
* - Download the Cordio FW
* - Initialize the lower layers
*/
BleInitStart();
/* Wait for BLE device to boot */
while (!reset_complete) {
callDispatcher();
}
initialized = true;
BLE::InitializationCompleteCallbackContext context = {
BLE::Instance(instanceID),
BLE_ERROR_NONE
};
initCallback.call(&context);
return BLE_ERROR_NONE;
}
ble_error_t ArmBLE::shutdown(void)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
void ArmBLE::waitForEvent(void)
{
timestamp_t nextTimestamp;
bool_t pTimerRunning;
processEvents();
if (wsfOsReadyToSleep()) {
// setup an mbed timer for the next Wicentric timeout
nextTimestamp = (timestamp_t)WsfTimerNextExpiration(&pTimerRunning) * 1000;
if (pTimerRunning) {
/*
* go to sleep to nextTimestamp: The ble stack here has to inform
* the system that is ready and not really go to sleep.
* TO BE DONE
*/
}
}
}
void ArmBLE::processEvents()
{
if (isEventsSignaled) {
isEventsSignaled = false;
callDispatcher();
}
}
void ArmBLE::timeoutCallback(void)
{
// do nothing. just an interrupt for wake up.
}
void ArmBLE::callDispatcher(void)
{
static uint32_t lastTimeUs = us_ticker_read();
uint32_t currTimeUs, deltaTimeMs;
// Update the current Wicentric time
currTimeUs = us_ticker_read();
deltaTimeMs = (currTimeUs - lastTimeUs) / 1000;
if (deltaTimeMs > 0) {
WsfTimerUpdate(deltaTimeMs);
lastTimeUs += deltaTimeMs * 1000;
}
wsfOsDispatcher();
}

View File

@ -0,0 +1,230 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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 "ArmGap.h"
#include "mbed.h"
ArmGap &ArmGap::getInstance() {
static ArmGap m_instance;
return m_instance;
}
ble_error_t ArmGap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse)
{
/* Make sure we don't exceed the advertising payload length */
if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
return BLE_ERROR_BUFFER_OVERFLOW;
}
/* Make sure we have a payload! */
if (advData.getPayloadLen() == 0) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
/* set advertising and scan response data for discoverable mode */
DmAdvSetData(DM_DATA_LOC_ADV, advData.getPayloadLen(), (uint8_t*)advData.getPayload());
DmAdvSetData(DM_DATA_LOC_SCAN, scanResponse.getPayloadLen(), (uint8_t*)scanResponse.getPayload());
return BLE_ERROR_NONE;
}
ble_error_t ArmGap::startAdvertising(const GapAdvertisingParams &params)
{
/* Make sure we support the advertising type */
if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) {
/* ToDo: This requires a proper security implementation, etc. */
return BLE_ERROR_NOT_IMPLEMENTED;
}
/* Check interval range */
if (params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) {
/* Min delay is slightly longer for unconnectable devices */
if ((params.getInterval() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) ||
(params.getInterval() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
} else {
if ((params.getInterval() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN) ||
(params.getInterval() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
}
/* Check timeout is zero for Connectable Directed */
if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && (params.getTimeout() != 0)) {
/* Timeout must be 0 with this type, although we'll never get here */
/* since this isn't implemented yet anyway */
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
/* Check timeout for other advertising types */
if ((params.getAdvertisingType() != GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) &&
(params.getTimeout() > GapAdvertisingParams::GAP_ADV_PARAMS_TIMEOUT_MAX)) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
DmAdvSetInterval(params.getInterval(), params.getInterval());
DmAdvStart(params.getAdvertisingType(), params.getTimeout());
state.advertising = 1;
return BLE_ERROR_NONE;
}
ble_error_t ArmGap::stopAdvertising(void)
{
DmAdvStop();
state.advertising = 0;
return BLE_ERROR_NONE;
}
void ArmGap::advertisingStopped(void)
{
/* If advertising stopped due to a call to stopAdvertising(), state.advertising will
* be '0.' Otherwise, advertising must have stopped due to a timeout
*/
if (state.advertising) {
processTimeoutEvent(Gap::TIMEOUT_SRC_ADVERTISING);
}
}
ble_error_t ArmGap::disconnect(DisconnectionReason_t reason)
{
DmConnClose(DM_CLIENT_ID_APP, m_connectionHandle, reason);
state.advertising = 0;
state.connected = 0;
return BLE_ERROR_NONE;
}
ble_error_t ArmGap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason)
{
DmConnClose(DM_CLIENT_ID_APP, connectionHandle, reason);
state.advertising = 0;
state.connected = 0;
return BLE_ERROR_NONE;
}
ble_error_t ArmGap::getPreferredConnectionParams(ConnectionParams_t *params)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t ArmGap::setPreferredConnectionParams(const ConnectionParams_t *params)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t ArmGap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams)
{
if (DmConnCheckIdle(handle) != 0) {
return BLE_STACK_BUSY;
}
hciConnSpec_t connSpec;
connSpec.connIntervalMin = newParams->minConnectionInterval;
connSpec.connIntervalMax = newParams->maxConnectionInterval;
connSpec.connLatency = newParams->slaveLatency;
connSpec.supTimeout = newParams->connectionSupervisionTimeout;
DmConnUpdate(handle, &connSpec);
return BLE_ERROR_NONE;
}
ble_error_t ArmGap::startRadioScan(const GapScanningParams &scanningParams)
{
DmScanSetInterval(scanningParams.getInterval(), scanningParams.getWindow());
uint8_t scanType = scanningParams.getActiveScanning() ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE;
uint32_t duration = (uint32_t)scanningParams.getTimeout() * 1000;
if (duration > 0xFFFF) {
// saturate to 16-bits
duration = 0xFFFF;
}
DmScanStart(DM_DISC_MODE_NONE, scanType, TRUE, duration);
return BLE_ERROR_NONE;
}
ble_error_t ArmGap::stopScan(void)
{
DmScanStop();
return BLE_ERROR_NONE;
}
void ArmGap::setConnectionHandle(uint16_t connectionHandle)
{
m_connectionHandle = connectionHandle;
}
uint16_t ArmGap::getConnectionHandle(void)
{
return m_connectionHandle;
}
ble_error_t ArmGap::setAddress(AddressType_t type, const Address_t address)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t ArmGap::getAddress(AddressType_t *typeP, Address_t address)
{
*typeP = m_type;
BdaCpy(address, HciGetBdAddr());
return BLE_ERROR_NONE;
}
ble_error_t ArmGap::setDeviceName(const uint8_t *deviceName)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t ArmGap::getDeviceName(uint8_t *deviceName, unsigned *lengthP)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t ArmGap::setAppearance(GapAdvertisingData::Appearance appearance)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t ArmGap::getAppearance(GapAdvertisingData::Appearance *appearanceP)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t ArmGap::setTxPower(int8_t txPower)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
void ArmGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP)
{
static const int8_t permittedTxValues[] = {
-18, -15, -12, -9, -6, -3, 0, 3
};
*valueArrayPP = permittedTxValues;
*countP = sizeof(permittedTxValues) / sizeof(int8_t);
}

View File

@ -0,0 +1,423 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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 "ArmGattServer.h"
#include "mbed.h"
#include "ArmGap.h"
#include "wsf_types.h"
#include "att_api.h"
typedef struct armChar_s {
uint16_t descLen;
armChar_s() {}
} armChar_t;
typedef struct armService_s armService_t;
struct armService_s {
uint16_t uuidLen;
armChar_t *chars;
attsGroup_t *attGroup;
armService_t *next;
armService_s() {}
};
static uint16_t currentHandle = 0x20;
static UUID cccUUID(BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
static const uint16_t cccSize = sizeof(uint16_t);
ArmGattServer &ArmGattServer::getInstance() {
static ArmGattServer m_instance;
return m_instance;
}
ble_error_t ArmGattServer::addService(GattService &service)
{
currentHandle = (currentHandle + 0xF) & ~0xF;
uint16_t startHandle = currentHandle;
armService_t *armSvc = new armService_t;
// Create WiCentric attribute group
armSvc->attGroup = new attsGroup_t;
// Determine the attribute list length
unsigned int attListLen = 1;
for (int i = 0; i < service.getCharacteristicCount(); i++) {
attListLen += 2;
GattCharacteristic *p_char = service.getCharacteristic(i);
if (p_char->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE)) {
// add a CCCD
attListLen++;
}
}
// Create WiCentric attribute list
armSvc->attGroup->pAttr = (attsAttr_t*)malloc(attListLen * sizeof(attsAttr_t));;
if (armSvc->attGroup->pAttr == NULL) {
return BLE_ERROR_BUFFER_OVERFLOW;
}
// Create characteristics
armSvc->chars = new armChar_t [service.getCharacteristicCount()];
attsAttr_t *currAtt = armSvc->attGroup->pAttr;
/* Service */
currAtt->pUuid = attPrimSvcUuid;
if (service.getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) {
armSvc->uuidLen = UUID::LENGTH_OF_LONG_UUID;
} else {
armSvc->uuidLen = sizeof(UUID::ShortUUIDBytes_t);
}
currAtt->pValue = (uint8_t*)malloc(armSvc->uuidLen);
memcpy(currAtt->pValue, service.getUUID().getBaseUUID(), armSvc->uuidLen);
currAtt->maxLen = armSvc->uuidLen;
currAtt->pLen = &armSvc->uuidLen;
currAtt->settings = 0;
currAtt->permissions = ATTS_PERMIT_READ;
currAtt++;
/* Add characteristics to the service */
for (int i = 0; i < service.getCharacteristicCount(); i++) {
GattCharacteristic *p_char = service.getCharacteristic(i);
/* Skip any incompletely defined, read-only characteristics. */
if ((p_char->getValueAttribute().getValuePtr() == NULL) &&
(p_char->getValueAttribute().getLength() == 0) &&
(p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) {
continue;
}
// Create Characteristic Attribute
currentHandle += 2;
currAtt->pUuid = attChUuid;
p_char->getValueAttribute().setHandle(currentHandle);
armSvc->chars[i].descLen = 1 + sizeof(currentHandle) + p_char->getValueAttribute().getUUID().getLen();
currAtt->pValue = (uint8_t*)malloc(armSvc->chars[i].descLen);
uint8_t *pValue = currAtt->pValue;
*pValue++ = p_char->getProperties();
memcpy(pValue, &currentHandle, sizeof(currentHandle));
pValue += sizeof(currentHandle);
memcpy(pValue, p_char->getValueAttribute().getUUID().getBaseUUID(), p_char->getValueAttribute().getUUID().getLen());
currAtt->pLen = &armSvc->chars[i].descLen;
currAtt->maxLen = armSvc->chars[i].descLen;
currAtt->settings = 0;
currAtt->permissions = ATTS_PERMIT_READ;
currAtt++;
// Create Value Attribute
currAtt->pUuid = p_char->getValueAttribute().getUUID().getBaseUUID();
currAtt->pValue = p_char->getValueAttribute().getValuePtr();
currAtt->pLen = p_char->getValueAttribute().getLengthPtr();
currAtt->maxLen = p_char->getValueAttribute().getMaxLength();
currAtt->settings = ATTS_SET_WRITE_CBACK | ATTS_SET_READ_CBACK;
if (p_char->getValueAttribute().getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) {
currAtt->settings |= ATTS_SET_UUID_128;
}
currAtt->permissions = 0;
if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ) { currAtt->permissions |= ATTS_PERMIT_READ; }
if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { currAtt->permissions |= ATTS_PERMIT_WRITE; }
currAtt++;
bool cccCreated = false;
for (int i = 0; i < p_char->getDescriptorCount(); i++) {
GattAttribute *p_att = p_char->getDescriptor(i);
currentHandle++;
currAtt->pUuid = p_att->getUUID().getBaseUUID();
currAtt->pValue = p_att->getValuePtr();
currAtt->pLen = p_att->getLengthPtr();
currAtt->maxLen = p_att->getMaxLength();
currAtt->settings = 0;
currAtt->permissions = 0;
if (p_att->getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) {
currAtt->settings |= ATTS_SET_UUID_128;
}
if (p_att->getUUID() == UUID(BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)) {
cccCreated = true;
currAtt->settings |= ATTS_SET_CCC;
currAtt->permissions |= ATTS_PERMIT_READ;
currAtt->permissions |= ATTS_PERMIT_WRITE;
if (cccCnt < MAX_CCC_CNT) {
cccSet[cccCnt].handle = currentHandle;
cccSet[cccCnt].valueRange = 0;
if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_NOTIFY;
}
if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) {
cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_INDICATE;
}
cccSet[cccCnt].secLevel = DM_SEC_LEVEL_NONE;
cccHandles[cccCnt] = p_char->getValueAttribute().getHandle();
cccCnt++;
} else {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
}
currAtt++;
}
if (!cccCreated && (p_char->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE))) {
/* There was not a CCCD included in the descriptors, but this
* characteristic is notifiable and/or indicatable. A CCCD is
* required so create one now.
*/
if (cccCnt >= MAX_CCC_CNT) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
currentHandle++;
currAtt->pUuid = cccUUID.getBaseUUID();
currAtt->pValue = (uint8_t*)&cccValues[cccCnt];
currAtt->pLen = (uint16_t*)&cccSize;
currAtt->maxLen = sizeof(uint16_t);
currAtt->settings = ATTS_SET_CCC;
currAtt->permissions = (ATTS_PERMIT_READ | ATTS_PERMIT_WRITE);
cccSet[cccCnt].handle = currentHandle;
cccSet[cccCnt].valueRange = 0;
if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_NOTIFY;
}
if (p_char->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) {
cccSet[cccCnt].valueRange |= ATT_CLIENT_CFG_INDICATE;
}
cccSet[cccCnt].secLevel = DM_SEC_LEVEL_NONE;
cccHandles[cccCnt] = p_char->getValueAttribute().getHandle();
cccCnt++;
currAtt++;
}
}
armSvc->attGroup->pNext = NULL;
armSvc->attGroup->readCback = attsReadCback;
armSvc->attGroup->writeCback = attsWriteCback;
armSvc->attGroup->startHandle = startHandle;
armSvc->attGroup->endHandle = currentHandle;
AttsAddGroup(armSvc->attGroup);
AttRegister(attCback);
AttsCccRegister(cccCnt, (attsCccSet_t*)cccSet, cccCback);
return BLE_ERROR_NONE;
}
ble_error_t ArmGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *const lengthP)
{
if (AttsGetAttr(attributeHandle, lengthP, &buffer) != ATT_SUCCESS) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
return BLE_ERROR_NONE;
}
ble_error_t ArmGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
{
// Check to see if this is a CCCD
uint8_t idx;
for (idx = 0; idx < cccCnt; idx++) {
if (attributeHandle == cccSet[idx].handle) {
if (connectionHandle == DM_CONN_ID_NONE) { // CCCDs are always 16 bits
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
*((uint16_t*)buffer) = AttsCccGet(connectionHandle, idx);
*lengthP = 2; // CCCDs are always 16 bits
return BLE_ERROR_NONE;
}
}
// This is not a CCCD. Use the non-connection specific update method.
return read(attributeHandle, buffer, lengthP);
}
ble_error_t ArmGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
{
uint16_t connectionHandle = ArmGap::getInstance().getConnectionHandle();
if (AttsSetAttr(attributeHandle, len, (uint8_t*)buffer) != ATT_SUCCESS) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
if (!localOnly) {
if (connectionHandle != DM_CONN_ID_NONE) {
// Check to see if this characteristic has a CCCD attribute
uint8_t idx;
for (idx = 0; idx < cccCnt; idx++) {
if (attributeHandle == cccHandles[idx]) {
break;
}
}
if (idx < cccCnt) {
// This characteristic has a CCCD attribute. Handle notifications and indications.
uint16_t cccEnabled = AttsCccEnabled(connectionHandle, idx);
if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) {
AttsHandleValueNtf(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
}
if (cccEnabled & ATT_CLIENT_CFG_INDICATE) {
AttsHandleValueInd(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
}
}
}
}
return BLE_ERROR_NONE;
}
ble_error_t ArmGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
{
// Check to see if this is a CCCD
uint8_t idx;
for (idx = 0; idx < cccCnt; idx++) {
if (attributeHandle == cccSet[idx].handle) {
if ((connectionHandle == DM_CONN_ID_NONE) || (len != 2)) { // CCCDs are always 16 bits
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
AttsCccSet(connectionHandle, idx, *((uint16_t*)buffer));
return BLE_ERROR_NONE;
}
}
// This is not a CCCD. Use the non-connection specific update method.
return write(attributeHandle, buffer, len, localOnly);
}
ble_error_t ArmGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP)
{
uint16_t connectionHandle = ArmGap::getInstance().getConnectionHandle();
if (connectionHandle != DM_CONN_ID_NONE) {
uint8_t idx;
for (idx = 0; idx < cccCnt; idx++) {
if (characteristic.getValueHandle() == cccHandles[idx]) {
uint16_t cccValue = AttsCccGet(connectionHandle, idx);
if (cccValue & ATT_CLIENT_CFG_NOTIFY) {
*enabledP = true;
} else {
*enabledP = false;
}
return BLE_ERROR_NONE;
}
}
}
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
ble_error_t ArmGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP)
{
if (connectionHandle != DM_CONN_ID_NONE) {
uint8_t idx;
for (idx = 0; idx < cccCnt; idx++) {
if (characteristic.getValueHandle() == cccHandles[idx]) {
uint16_t cccValue = AttsCccGet(connectionHandle, idx);
if (cccValue & ATT_CLIENT_CFG_NOTIFY) {
*enabledP = true;
} else {
*enabledP = false;
}
return BLE_ERROR_NONE;
}
}
}
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
void ArmGattServer::cccCback(attsCccEvt_t *pEvt)
{
if (pEvt->value & (ATT_CLIENT_CFG_NOTIFY | ATT_CLIENT_CFG_INDICATE)) {
getInstance().handleEvent(GattServerEvents::GATT_EVENT_UPDATES_ENABLED, pEvt->handle);
} else {
getInstance().handleEvent(GattServerEvents::GATT_EVENT_UPDATES_DISABLED, pEvt->handle);
}
}
void ArmGattServer::attCback(attEvt_t *pEvt)
{
if (pEvt->hdr.status == ATT_SUCCESS) {
getInstance().handleEvent(GattServerEvents::GATT_EVENT_DATA_SENT, pEvt->handle);
}
}
uint8_t ArmGattServer::attsReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, attsAttr_t *pAttr)
{
GattReadCallbackParams cbParams = {
.connHandle = connId,
.handle = handle,
.offset = offset,
.len = *pAttr->pLen,
.data = pAttr->pValue
};
getInstance().handleDataReadEvent(&cbParams);
return ATT_SUCCESS;
}
uint8_t ArmGattServer::attsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
{
uint8_t err;
/* TODO: offset is not handled properly */
if ((err = AttsSetAttr(handle, len, pValue)) != ATT_SUCCESS) {
return err;
}
GattWriteCallbackParams::WriteOp_t writeOp;
switch (operation) {
case ATT_PDU_WRITE_REQ:
writeOp = GattWriteCallbackParams::OP_WRITE_REQ;
break;
case ATT_PDU_WRITE_CMD:
writeOp = GattWriteCallbackParams::OP_WRITE_CMD;
break;
case ATT_PDU_SIGNED_WRITE_CMD:
writeOp = GattWriteCallbackParams::OP_SIGN_WRITE_CMD;
break;
case ATT_PDU_PREP_WRITE_REQ:
writeOp = GattWriteCallbackParams::OP_PREP_WRITE_REQ;
break;
case ATT_PDU_EXEC_WRITE_REQ:
writeOp = GattWriteCallbackParams::OP_EXEC_WRITE_REQ_NOW;
break;
default:
writeOp = GattWriteCallbackParams::OP_INVALID;
break;
}
GattWriteCallbackParams cbParams = {
.connHandle = connId,
.handle = handle,
.writeOp = writeOp,
.offset = offset,
.len = len,
.data = pValue
};
getInstance().handleDataWrittenEvent(&cbParams);
return ATT_SUCCESS;
}

View File

@ -0,0 +1,344 @@
# Change Log
## [v2.5.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.3) (2016-02-16)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.2...v2.5.3)
**Merged pull requests:**
- Fix for compilation errors with S110 softdevice in btle.cpp [\#109](https://github.com/ARMmbed/ble-nrf51822/pull/109) ([ddavidebor](https://github.com/ddavidebor))
## [v2.5.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.2) (2016-02-16)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.1...v2.5.2)
**Merged pull requests:**
- Sync develop against master [\#113](https://github.com/ARMmbed/ble-nrf51822/pull/113) ([pan-](https://github.com/pan-))
- Fix incorrect handles of characteristics descriptors. [\#112](https://github.com/ARMmbed/ble-nrf51822/pull/112) ([pan-](https://github.com/pan-))
## [v2.5.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.1) (2016-01-27)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.0...v2.5.1)
**Merged pull requests:**
- Remove Gap::state updates from this module [\#108](https://github.com/ARMmbed/ble-nrf51822/pull/108) ([andresag01](https://github.com/andresag01))
- merge version [\#106](https://github.com/ARMmbed/ble-nrf51822/pull/106) ([pan-](https://github.com/pan-))
## [v2.5.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.0) (2016-01-12)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.4.1...v2.5.0)
**Merged pull requests:**
- Fix access to enum member [\#105](https://github.com/ARMmbed/ble-nrf51822/pull/105) ([pan-](https://github.com/pan-))
- Hotfix dependency [\#104](https://github.com/ARMmbed/ble-nrf51822/pull/104) ([pan-](https://github.com/pan-))
- Finish implementation of getAddressesFromBondTable [\#103](https://github.com/ARMmbed/ble-nrf51822/pull/103) ([andresag01](https://github.com/andresag01))
## [v2.4.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.4.1) (2016-01-11)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.4.0...v2.4.1)
**Merged pull requests:**
- merge branch develop \(v2.4.0\) [\#100](https://github.com/ARMmbed/ble-nrf51822/pull/100) ([pan-](https://github.com/pan-))
## [v2.4.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.4.0) (2016-01-10)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.3.1...v2.4.0)
**Merged pull requests:**
- Add implementation of experimental whitelisting API [\#99](https://github.com/ARMmbed/ble-nrf51822/pull/99) ([andresag01](https://github.com/andresag01))
## [v2.3.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.3.1) (2016-01-07)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.3.0...v2.3.1)
**Merged pull requests:**
- Update yotta module dependencies [\#98](https://github.com/ARMmbed/ble-nrf51822/pull/98) ([pan-](https://github.com/pan-))
## [v2.3.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.3.0) (2015-12-23)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.10...v2.3.0)
**Merged pull requests:**
- Implementation of Characteristic descriptor discovery [\#74](https://github.com/ARMmbed/ble-nrf51822/pull/74) ([pan-](https://github.com/pan-))
## [v2.2.10](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.10) (2015-12-23)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.9...v2.2.10)
**Fixed bugs:**
- nRF5xn::init don't verify if errors have occurred during btle\_init [\#59](https://github.com/ARMmbed/ble-nrf51822/issues/59)
**Closed issues:**
- A call to shutdown does not clear the state of some components of BLE API [\#85](https://github.com/ARMmbed/ble-nrf51822/issues/85)
- Memory allocation issue on the NRF51DK board. [\#76](https://github.com/ARMmbed/ble-nrf51822/issues/76)
- Terrible handling of initLen / minLen and variable length characteristics. [\#56](https://github.com/ARMmbed/ble-nrf51822/issues/56)
**Merged pull requests:**
- Fix shutdown of Gap instance to avoid NULL refs [\#96](https://github.com/ARMmbed/ble-nrf51822/pull/96) ([andresag01](https://github.com/andresag01))
- Add check for return code of ble\_init [\#95](https://github.com/ARMmbed/ble-nrf51822/pull/95) ([andresag01](https://github.com/andresag01))
## [v2.2.9](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.9) (2015-12-18)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.8...v2.2.9)
**Closed issues:**
- Cannot open source input file "system\_nrf51.h" [\#52](https://github.com/ARMmbed/ble-nrf51822/issues/52)
**Merged pull requests:**
- Remove occurrence of deprecated appearance enum [\#92](https://github.com/ARMmbed/ble-nrf51822/pull/92) ([andresag01](https://github.com/andresag01))
## [v2.2.8](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.8) (2015-12-16)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.7...v2.2.8)
## [v2.2.7](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.7) (2015-12-15)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.6...v2.2.7)
**Merged pull requests:**
- Replace deprecated inclusions of mbed.h [\#89](https://github.com/ARMmbed/ble-nrf51822/pull/89) ([andresag01](https://github.com/andresag01))
- Improve shutdown to clear BLE API and not just SD [\#87](https://github.com/ARMmbed/ble-nrf51822/pull/87) ([andresag01](https://github.com/andresag01))
## [v2.2.6](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.6) (2015-12-15)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.5...v2.2.6)
**Merged pull requests:**
- follow the extraction of address related types from Gap.h into BLEProtocol.h [\#88](https://github.com/ARMmbed/ble-nrf51822/pull/88) ([rgrover](https://github.com/rgrover))
## [v2.2.5](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.5) (2015-12-11)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.3...v2.2.5)
**Merged pull requests:**
- Added SecurityManager::setLinkSecurity call for elevating security settings on a particular connection. [\#86](https://github.com/ARMmbed/ble-nrf51822/pull/86) ([marcuschangarm](https://github.com/marcuschangarm))
## [v2.2.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.3) (2015-12-10)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.2...v2.2.3)
## [v2.2.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.2) (2015-12-08)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.1...v2.2.2)
**Merged pull requests:**
- Add -Wno-unused-function to supress-warnings.cmake [\#83](https://github.com/ARMmbed/ble-nrf51822/pull/83) ([andresag01](https://github.com/andresag01))
## [v2.2.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.1) (2015-12-08)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.0...v2.2.1)
**Merged pull requests:**
- WIP: UUID endian change [\#82](https://github.com/ARMmbed/ble-nrf51822/pull/82) ([marcuschangarm](https://github.com/marcuschangarm))
## [v2.2.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.0) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.4...v2.2.0)
## [v2.1.4](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.4) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.3...v2.1.4)
## [v2.1.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.3) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.2...v2.1.3)
## [v2.1.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.2) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.1...v2.1.2)
**Merged pull requests:**
- Allow GattAttributes to have variable length [\#81](https://github.com/ARMmbed/ble-nrf51822/pull/81) ([andresag01](https://github.com/andresag01))
## [v2.1.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.1) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.0...v2.1.1)
**Merged pull requests:**
- Fixed endianness bug in nRF5xServiceDiscovery::processDiscoverUUIDResponse so it is consistent with BLE API. [\#80](https://github.com/ARMmbed/ble-nrf51822/pull/80) ([marcuschangarm](https://github.com/marcuschangarm))
- Fixed bug in nRF5xGap.setAddress where random adresses where not set properly. [\#79](https://github.com/ARMmbed/ble-nrf51822/pull/79) ([marcuschangarm](https://github.com/marcuschangarm))
- Separate concept of minlen and len for BLE chars [\#78](https://github.com/ARMmbed/ble-nrf51822/pull/78) ([andresag01](https://github.com/andresag01))
- Split nordic sdk into its own module [\#75](https://github.com/ARMmbed/ble-nrf51822/pull/75) ([LiyouZhou](https://github.com/LiyouZhou))
## [v2.1.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.0) (2015-11-27)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.8...v2.1.0)
**Merged pull requests:**
- Update to sdk 8.1 [\#77](https://github.com/ARMmbed/ble-nrf51822/pull/77) ([LiyouZhou](https://github.com/LiyouZhou))
## [v2.0.8](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.8) (2015-11-26)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.7...v2.0.8)
## [v2.0.7](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.7) (2015-11-26)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.6...v2.0.7)
**Closed issues:**
- test2000 [\#72](https://github.com/ARMmbed/ble-nrf51822/issues/72)
- test1000000 [\#71](https://github.com/ARMmbed/ble-nrf51822/issues/71)
- test4 [\#70](https://github.com/ARMmbed/ble-nrf51822/issues/70)
- test3 [\#69](https://github.com/ARMmbed/ble-nrf51822/issues/69)
- test2 [\#68](https://github.com/ARMmbed/ble-nrf51822/issues/68)
**Merged pull requests:**
- use Extern c around \#include to use nordic sdk headers implemented in C [\#73](https://github.com/ARMmbed/ble-nrf51822/pull/73) ([LiyouZhou](https://github.com/LiyouZhou))
## [v2.0.6](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.6) (2015-11-17)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.5...v2.0.6)
**Closed issues:**
- test [\#66](https://github.com/ARMmbed/ble-nrf51822/issues/66)
**Merged pull requests:**
- add Nordic's license agreement. [\#67](https://github.com/ARMmbed/ble-nrf51822/pull/67) ([rgrover](https://github.com/rgrover))
## [v2.0.5](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.5) (2015-11-16)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.4...v2.0.5)
**Merged pull requests:**
- Post radio notification callback through minar [\#65](https://github.com/ARMmbed/ble-nrf51822/pull/65) ([andresag01](https://github.com/andresag01))
## [v2.0.4](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.4) (2015-11-13)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.3...v2.0.4)
**Merged pull requests:**
- Fix assembly sequence to start bootloader in GCC [\#64](https://github.com/ARMmbed/ble-nrf51822/pull/64) ([andresag01](https://github.com/andresag01))
## [v2.0.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.3) (2015-11-09)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.2...v2.0.3)
**Merged pull requests:**
- Added watchdog header file from Nordic SDK 8.1 [\#62](https://github.com/ARMmbed/ble-nrf51822/pull/62) ([marcuschangarm](https://github.com/marcuschangarm))
## [v2.0.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.2) (2015-11-03)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/mbedos-release-15-11...v2.0.2)
## [mbedos-release-15-11](https://github.com/ARMmbed/ble-nrf51822/tree/mbedos-release-15-11) (2015-11-03)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.1...mbedos-release-15-11)
## [v2.0.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.1) (2015-11-02)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.0...v2.0.1)
**Merged pull requests:**
- Ensure that the initialization flags is set to false if the BLE stack is shutdown properly. [\#58](https://github.com/ARMmbed/ble-nrf51822/pull/58) ([pan-](https://github.com/pan-))
## [v2.0.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.0) (2015-11-02)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v1.1.0...v2.0.0)
**Closed issues:**
- Nordic SDK and SoftDevice [\#57](https://github.com/ARMmbed/ble-nrf51822/issues/57)
- shouldn't eab6631cb be merged into master? [\#54](https://github.com/ARMmbed/ble-nrf51822/issues/54)
**Merged pull requests:**
- Introduced changes for memory savings [\#55](https://github.com/ARMmbed/ble-nrf51822/pull/55) ([andresag01](https://github.com/andresag01))
## [v1.1.0](https://github.com/ARMmbed/ble-nrf51822/tree/v1.1.0) (2015-10-28)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v1.0.0...v1.1.0)
**Closed issues:**
- target dependencies in module.json [\#50](https://github.com/ARMmbed/ble-nrf51822/issues/50)
**Merged pull requests:**
- When connecting, if no scanning parameters are passed, use values from Gap parent. [\#53](https://github.com/ARMmbed/ble-nrf51822/pull/53) ([marcuschangarm](https://github.com/marcuschangarm))
## [v1.0.0](https://github.com/ARMmbed/ble-nrf51822/tree/v1.0.0) (2015-10-19)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/mbedos-techcon-oob2...v1.0.0)
## [mbedos-techcon-oob2](https://github.com/ARMmbed/ble-nrf51822/tree/mbedos-techcon-oob2) (2015-10-19)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.8...mbedos-techcon-oob2)
**Closed issues:**
- rename the bootloader files with \_fota in the name? [\#51](https://github.com/ARMmbed/ble-nrf51822/issues/51)
**Merged pull requests:**
- Update S110 detection macros, again [\#49](https://github.com/ARMmbed/ble-nrf51822/pull/49) ([jpbrucker](https://github.com/jpbrucker))
- Error check number of characteristics [\#48](https://github.com/ARMmbed/ble-nrf51822/pull/48) ([Timmmm](https://github.com/Timmmm))
## [v0.4.8](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.8) (2015-09-25)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.7...v0.4.8)
**Closed issues:**
- Error real cause loss in nRF5xGattServer.cpp [\#44](https://github.com/ARMmbed/ble-nrf51822/issues/44)
**Merged pull requests:**
- rgrover patch fixed [\#47](https://github.com/ARMmbed/ble-nrf51822/pull/47) ([fabiencomte](https://github.com/fabiencomte))
- Update S110 detection macros [\#43](https://github.com/ARMmbed/ble-nrf51822/pull/43) ([jpbrucker](https://github.com/jpbrucker))
- remove some unnecessary include paths [\#42](https://github.com/ARMmbed/ble-nrf51822/pull/42) ([autopulated](https://github.com/autopulated))
- Add FOTA bootloader image [\#41](https://github.com/ARMmbed/ble-nrf51822/pull/41) ([jpbrucker](https://github.com/jpbrucker))
## [v0.4.7](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.7) (2015-08-13)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.6...v0.4.7)
## [v0.4.6](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.6) (2015-08-11)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.5...v0.4.6)
**Closed issues:**
- remove duplication of global static variable BLE\_EVT\_BUFFER [\#39](https://github.com/ARMmbed/ble-nrf51822/issues/39)
- clearScanResponse\(\) [\#30](https://github.com/ARMmbed/ble-nrf51822/issues/30)
- Debug builds fail due to missing bsp.h [\#11](https://github.com/ARMmbed/ble-nrf51822/issues/11)
**Merged pull requests:**
- Disable GattClient features when using S110 SoftDevice [\#38](https://github.com/ARMmbed/ble-nrf51822/pull/38) ([jpbrucker](https://github.com/jpbrucker))
## [v0.4.5](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.5) (2015-08-10)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.4...v0.4.5)
## [v0.4.4](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.4) (2015-08-07)
[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.3...v0.4.4)
**Closed issues:**
- nrf51822 hangs after calling sd\_flash\_page\_erase\(\) [\#35](https://github.com/ARMmbed/ble-nrf51822/issues/35)
- nRF5xn::getVersion return \(Unknown\) with version 8 soft device [\#29](https://github.com/ARMmbed/ble-nrf51822/issues/29)
**Merged pull requests:**
- Changed Gap:: to GapAdvertisingParams:: because of change in BLE [\#34](https://github.com/ARMmbed/ble-nrf51822/pull/34) ([jslater8](https://github.com/jslater8))
- Select the clock source dynamically on SoftDevice initialisation [\#32](https://github.com/ARMmbed/ble-nrf51822/pull/32) ([jpbrucker](https://github.com/jpbrucker))
- Add S110 SoftDevice compatibility [\#28](https://github.com/ARMmbed/ble-nrf51822/pull/28) ([jpbrucker](https://github.com/jpbrucker))
## [v0.4.3](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.3) (2015-07-22)
**Closed issues:**
- Target polling failed [\#24](https://github.com/ARMmbed/ble-nrf51822/issues/24)
- support handling of HVX Events \(notifications and indications\). [\#22](https://github.com/ARMmbed/ble-nrf51822/issues/22)
- provide an implementation for GattServer::areUpdatesEnabled\(\) [\#21](https://github.com/ARMmbed/ble-nrf51822/issues/21)
- getValueHandle\(\) returns characteristicIndex instead of attribute-handle [\#20](https://github.com/ARMmbed/ble-nrf51822/issues/20)
- Clash With Definition And Enum Naming [\#16](https://github.com/ARMmbed/ble-nrf51822/issues/16)
- Errors in GCC build [\#14](https://github.com/ARMmbed/ble-nrf51822/issues/14)
- bring s110 support back [\#10](https://github.com/ARMmbed/ble-nrf51822/issues/10)
- Allow adding a User Description descriptor to a GattCharacteristic. [\#9](https://github.com/ARMmbed/ble-nrf51822/issues/9)
- device\_manager\_peripheral.c includes app\_trace.h [\#7](https://github.com/ARMmbed/ble-nrf51822/issues/7)
- linking esb\_gcc.a \(nrf51822 enhanced shock burst\) with mbed [\#5](https://github.com/ARMmbed/ble-nrf51822/issues/5)
- The app\_timer usage may conflict [\#2](https://github.com/ARMmbed/ble-nrf51822/issues/2)
- Nordic License [\#1](https://github.com/ARMmbed/ble-nrf51822/issues/1)
**Merged pull requests:**
- Develop [\#25](https://github.com/ARMmbed/ble-nrf51822/pull/25) ([zoujixing](https://github.com/zoujixing))
- Remove unnecessary 'compiler\_abstraction.h' to get rid of duplicate '… [\#23](https://github.com/ARMmbed/ble-nrf51822/pull/23) ([adfernandes](https://github.com/adfernandes))
- restructure for minimal yotta compatibility [\#15](https://github.com/ARMmbed/ble-nrf51822/pull/15) ([autopulated](https://github.com/autopulated))
- Fix various GCC compilation issues. [\#12](https://github.com/ARMmbed/ble-nrf51822/pull/12) ([adfernandes](https://github.com/adfernandes))
- Fix for GCC lost in SDK v8.0 update [\#8](https://github.com/ARMmbed/ble-nrf51822/pull/8) ([rosterloh](https://github.com/rosterloh))
- new target DELTA\_DFCM\_NNN40 with nrf51822 chip, config internal RC crystal. [\#6](https://github.com/ARMmbed/ble-nrf51822/pull/6) ([Marcomissyou](https://github.com/Marcomissyou))
- Updated return value for nRF51GattServer::updateValue. Will now report w... [\#4](https://github.com/ARMmbed/ble-nrf51822/pull/4) ([marcuschangarm](https://github.com/marcuschangarm))
- Added optional data and length fields to the return struct for authorize... [\#3](https://github.com/ARMmbed/ble-nrf51822/pull/3) ([marcuschangarm](https://github.com/marcuschangarm))
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

View File

@ -0,0 +1,6 @@
This module contains softdevice which comes with The Nordic Softdevice License Agreement,
a BSD-like licence for binary distributions, offered by Nordic for use in mbed. Some
other files come from the mbed SDK, and are licensed under Apache-2.0. 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. The Nordic Semiconductor Softdevice
License Agreement can be found in softdevice_nrf51822_licence_agreement.txt.

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.

View File

@ -0,0 +1,463 @@
:020000040003F7
:20C00000983C002005DD030017DD030019DD03000000000000000000000000000000000057
:20C0200000000000000000000000000069C1030000000000000000001DDD03001FDD0300D7
:20C0400021DD030021DD030021DD030021DD030021DD03000000000021DD030021DD0300D9
:20C0600021DD030021DD030021DD030021DD030021DD030021DD030021DD030021DD0300B8
:20C0800021DD030057D8030021DD030021DD03006DD8030021DD03004DF4030021DD0300DD
:20C0A00021DD030021DD03000000000000000000000000000000000000000000000000007E
:20C0C00000F002F800F040F80CA030C8083824182D18A246671EAB4654465D46AC4201D18E
:20C0E00000F032F87E460F3E0FCCB6460126334200D0FB1AA246AB463343184710370000C8
:20C1000030370000103A02D378C878C1FAD8520701D330C830C101D504680C6070470000D3
:20C120000023002400250026103A01D378C1FBD8520700D330C100D50B6070471FB5C04655
:20C14000C0461FBD10B510BD03F0E3FA1146FFF7F5FF00F0D3F803F0FBFA03B4FFF7F2FF19
:20C1600003BC03F0FFFA00000648704502D1EFF3098101E0EFF30881886902380078024A97
:20C1800010470000FDFFFFFF39D50300401E00BF00BF00BF00BF00BF00BF00BF00BF00BF28
:20C1A00000BF00BF00BFF1D170470000401E00BF00BF00BF00BF00BF00BF00BF00BF00BFB4
:20C1C00000BF00BF00BFF1D170470000401E00BF00BF00BF00BF00BF00BF00BF00BF00BF94
:20C1E00000BF00BF00BFF1D170470000056885F3088846680A4AEFF305839A42304602D183
:20C20000084CA6463047074C064D0646064FF0B4034C034D024E024FF0B404480047000005
:20C2200000000000FFFFFFFF00000021F9FFFFFF70B505460C46164602E00FCC0FC5103EEE
:20C24000102EFAD2082E02D303CC03C5083E042E07D301CC01C5361F03E021782970641C63
:20C260006D1C761EF9D270BD0A4610B50146664803F064F810BD10B502F078FC10BD10B5C6
:20C28000624C86B01ECC03946C460EC4002807D0684618DF002803D00022114603F04EF864
:20C2A0000F20800313DF002803D00022114603F045F8574B48225749092003F0A3F80028AB
:20C2C00003D00022114603F039F800200490059001206946087404A860DF002803D0002251
:20C2E000114603F02BF84C4803F0A8F8002803D00022114603F022F806B010BD08B547485A
:20C30000C169B12943D0002445480F2140698903884204D000221146104603F00FF8012068
:20C320000007006901218902884204D000221146104603F003F83B4800903B4B05220321A1
:20C34000002001F0BAFA002803D00022114602F0F5FF00F067FC00F0AAFC012500281AD09D
:20C3600000F0B4FC002803D00022114602F0E6FF20466840FFF783FF00F038F800F0CCFC74
:20C3800000280ED00022114602F0D8FF09E001240021C161B8E720466840FFF770FF00F002
:20C3A00025F803252D03002C04D1A86800F090FB002807D100F047FC002803D000221146D5
:20C3C00002F0BCFFA86800F083FB002806D000F06EFC002802D1A86800F041FCBFF34F8F12
:20C3E00013491248C860BFF34F8FFEE7094A10B548321421082002F00BFF002803D00022E2
:20C40000114602F09BFF10BDEFBEADDE8CF703006BF30300342B002077C20300000500404D
:20C4200000100010EFDC0300F42800200400FA0500ED00E070B5FC4C1E46A06815460229A3
:20C4400002D0042916D108E0052813D1A369002B10D03246294604200BE002280AD1F348B0
:20C46000406880470320A060A369002B02D0324629469847280003D00022114602F05EFF98
:20C4800070BD4CB5E84E0120307005200195009400F058FB4CBD10B5E34C2078002801D057
:20C4A000082010BD206901F0F4FA002803D00022114602F043FF0F2100228904206901F01E
:20C4C000ABFA040003D00022114602F037FF204610BDD54910B5D448243141610221816012
:20C4E000C168243002F059FD002803D00022114602F024FF10BDCC4910B5CB481C31416145
:20C50000022181600320000380680F218903081A4108C5481C3002F040FD002803D000223D
:20C52000114602F00BFF10BD704700B589B01822BF4902A8FFF77CFE06980799009001917A
:20C5400002A80FC800F0FEFA09B000BD00B5B64987B049886A461181032109038968069146
:20C56000B249012050394A6803928A680492C9680591069A0091019202A90EC900F0E2FA6E
:20C58000002007B000BD30B5A84CA748503C89B02430E16802F001FD002803D00022114679
:20C5A00002F0CCFEA048E2681C3041680023083002F0C3FC050012D1182102A802F0E6FFEA
:20C5C00000209949029049886A469181E1680691079A0091019203A90EC900F0B3FA284601
:20C5E00009B030BD00B5904987B049886A4611818E49032050394A6803928A680492C9683A
:20C600000591069A0091019202A90EC900F09AFA0020B6E73EB5864A6B46183207CA07C3A4
:20C62000814D00246C7029466C802431684602F068FC002801D0AC603EBD03207A4900038F
:20C6400080682431486024390A46526ACA610F218903091A490840187349764A1C31486068
:20C6600071480021103001F07BF9002803D00022114602F063FE0F2100228904286901F013
:20C68000CBF9002803D00022114602F057FE01206C60A86000203EBD63498861704770B59A
:20C6A000426862481468536891685038D26804604360C26081600078440701D5840705D130
:20C6C0009C0703D18C0701D1940701D0062070BD5B189A18544D0F239B02EA60994213D81A
:20C6E0005549564B514CC60709D08868181A90420AD3534820605348606053480FE08968F6
:20C70000591A4908914201D20C2070BD4F4921604F496160800701D54E4800E04E48A0607B
:20C72000A868012802D00826304670BDFFF7B3FE0600FAD12168E8688847F5E770B50500F7
:20C7400004D0287A800703D0102070BD0E2070BD354CA068032805D0042801D0052803D0CB
:20C76000082070BD0520A0606868E168860060688019884204D90020C04360600C2070BD5C
:20C78000FFF789FE0028FAD1A96832466368606902F0D3FB0028F2D1616889196160E268EB
:20C7A0009142ECD0092070BD10B51F4C08206168002900D010BDA1680429FBD11B4861786F
:20C7C000403802F021FC002802D00021617010BD0521A16010BDF8B5134C0746A068032899
:20C7E00004D0042804D008252846F8BD0420A0606068002801D00820F8BDFFF74CFE05000E
:20C80000FAD17868860060788119402901D90920F8BD064AB968403A1018324602F057FE82
:20C82000607880196070DFE7002800201C2D00209CF7030083C403000030000000C003006D
:20C84000D3C403002BC503004DC50300F7C4030029C50300E5C5030087C5030010B5894CF1
:20C86000A068052813D1E168606888420FD10620A060FFF710FE002808D16069E1684068FF
:20C8800002F0FCFB002801D10721A16010BD082010BD10B57B488168072901D0082010BD63
:20C8A000006901F0F6F8002803D00022114602F045FD75488068804710BD1CB506200195C2
:20C8C000009400F03FF91CBDF8B51C4617460D46064600F0C1F8002817D001200003854215
:20C8E00007D92346291B301B1A46FFF7EDFF00280BD13A462946304600F0B9F8002804D117
:20C900003A462946304600F0A7F8F8BDF0B589B0684600F015FA049800282AD001210903F7
:20C92000079A4018904226D9501A45081046049A0C468718024668001618001908900320DF
:20C9400000038068049988420DD261190846042200F08DF800280CD121460422084600F073
:20C9600086F8002805D1BA1B2B4630460899FFF7ABFF09B0F0BD049A079800F078F8F8E75C
:20C9800000B58DB004A800F0DBF9099800280DD0089800280CD008990B984018019000219D
:20C9A0000998009180080290684618DF0DB000BD0320000380680F218903091A4908ECE7FB
:20C9C00000B58DB004A800F0BBF909980028EDD00F210898890300280CD0089A0B98019158
:20C9E0008018029003220998009280080390684618DFDBE70320000380680A1A5208EEE7D2
:20CA000030B591B0684600F09BF90498002814D001210903079A4018904214D9501A43087B
:20CA20001046049A5C0082180019611803242403A468049DAC4202D20E2011B030BD121AB5
:20CA4000FFF742FFF9E703200CAB07C3049880080F900CA818DFF0E71FB5032301909008B3
:20CA6000039000930291684618DF04B010BD1FB5012301909008039000930291684618DF58
:20CA8000F3E70000002800201C2D002010B5BB480368012B02D1022900D10160100003D099
:20CAA0000022114602F04AFC10BD10B5B34C48DF002803D00022114602F040FC02F0FCFB82
:20CAC0002068022803D0032801D00428EFD110BD38B50068401C19D00024684600F058F96F
:20CAE00000980168012910D1818800290AD0C168032000038068002202F0CEFA0099898861
:20CB0000814201D1012400E00024204638BD10B504469A482021001D02F0B9F9002803D00E
:20CB20000022114602F00AFC9448002320222146001D02F01BF9002803D00022114602F053
:20CB4000FDFB10BD0FB4F8B5684600F021F96846818B069D0122894CFF238948002D13D090
:20CB6000012D17D0032D2BD00021022D37D02A46052D46D0042D4ED0062A01D10420206071
:20CB8000F8BC08BC04B0184781800A9983600260C16010E08180099D089949190A9D49195D
:20CBA000C160A52183600160089901610999856141610B99C16122607148FFF7A8FFDFE7B9
:20CBC00000990B6803608B888380C968C160AA21816008990161099941610A990BE0009D60
:20CBE0002E68A52E09D00660AE888680ED68C5600161836041618161DDE781800360C160C5
:20CC0000F6E700F085F9002803D00022114602F095FB0320B3E781800360C1600099896807
:20CC20008160C9E70EB557480090202001900120029002F001F8002804D150496846091D98
:20CC400002F023F80EBD10B5FFF7E4FC002805D100F02FFB0446FFF728FF204610BD70B58A
:20CC600011DF002803D00022114602F067FB464900200B68444C012180340A4682401A4206
:20CC800004D0C506ED0E0A46AA402260401C2028F3D303242403A06813DF002803D000226F
:20CCA000114602F04BFBA06802F0F2F970BD08B5684600F06DF800980168A52904D0806888
:20CCC000AA2801D0002008BD012008BD10B5FFF797FE002803D1FFF773FE00281BD064209C
:20CCE00001F0F2FDFFF712FE002803D00022114602F024FBFFF784FE002803D000221146DD
:20CD000002F01CFBFFF73CFE040003D00022114602F014FB204610BD00B589B018221B49CA
:20CD200002A8FFF785FA069807990090019102A80FC8FFF707FFFFF7B8FE002009B000BDB5
:20CD400010B50E4988B0044600232022091D684602F04FF80098206068468088A08003983A
:20CD6000E0600298A06004982061059860610698A0610798E06108B010BD00002C280020E6
:20CD8000282D00208DCA030000E100E0C0F70300014901607047000000FC030008280CD0DC
:20CDA00004DC002807D006280FD108E00B280AD00C280AD105E001207047022070470320C9
:20CDC000704704207047042901D0062070470520704770B515460A46032823D0042820D1FF
:20CDE000FE4C002906D0E088FD49884219D0132176DF10E0284602F0A3F9002803D00022F7
:20CE0000114602F09BFAE069A8420AD101220321F44801F003F8002803D00022114602F051
:20CE20008DFA70BD01211046FFF7B8FF02460121EEE7F0B5054608790E4685B081070CD07C
:20CE400003221146284600F0E9FF002803D00022114602F073FA05B0F0BDE04900901831D9
:20CE600002F047F9010011D1DC4CB168009AA06902F02DFB009802F097F9010006D1204647
:20CE80006946183002F09CF9010003D0284600F0AFFAE0E704200190009880080290A06902
:20CEA000039001A8FFF74AFC07000BD0092F10D0A06902F045F9010002D0284600F098FA04
:20CEC0003946E3E73079616940186061A069E061C1E7307961694118616160780028BAD073
:20CEE0006089401E0004000C6081B4D1284601F0E9F8002803D00022114602F01FFA20890D
:20CF00006081A8E710B50022114602F017FA10BD10B5B24C01202070E088B149884208D01B
:20CF2000132176DF002810D00022114602F006FA0BE0A078002808D074DF002803D0002282
:20CF4000114602F0FBF90020A07001F034FC002803D00022114602F0F1F9002010BD70B5E1
:20CF60000D68044601209D4A2B0002F002FC0A2B3043061320575C466012FFF76FFC0421FD
:20CF8000FFF70CFF024604212EE00022114602F0D5F970BDFFF7BCFF002803D0002211468A
:20CFA00002F0CCF9FFF775FC002808D170BDFFF7AFFF002803D00022114602F0BFF9FFF76D
:20CFC0007CFC70BD106188680078107170BD02201061886800780128F8D1FFF7E5FB02213F
:20CFE000FFF7DCFE02460221204600F017FF0028CBD170BD0320106170BD12692046012ACC
:20D0000006D0022A07D0032AF6D1FFF712FF70BD00F001FA70BD00F03BFA70BD50708888D5
:20D020001081508170BD00205070108170BD2046516901F010F8DAE710B5044669488EB0EB
:20D0400081796846817068490180342101A802F09DFA022001900021684641728472012131
:20D0600001820590002101A801F03FFA002803D00022114602F062F90EB010BDF0B5574C10
:20D080008BB0A07800283AD156481821183802F07DFA2046534CC078183C00250126002875
:20D0A00037D02746483700950195029510226946F81D039502F0DEF9002822D0F81D08909D
:20D0C00009976846067509A804906846067708A806900420FFF7B0FF25700220207204A813
:20D0E000E060282020823F486582183873DF002803D00022114602F021F9384886700BB045
:20D10000F0BD0520FFF798FF2670676025722582E9E70620FFF790FF257065602572E0E7E2
:20D1200070B52E4C01880022E588A6B017290AD01EDC11293FD008DC022977D0102902D123
:20D140008088E080A27026B070BD264C303426461836132951D01429F5D1C289638D002106
:20D160009A4200D1314600238088E21D82DF1BE0512970D00EDC18296CD01929E3D18079F5
:20D180000028E0D1A270E068401EE0604FD0FFF775FFD8E7522976D05529D4D18079002871
:20D1A000D1D11321284676DF0028CCD00022114602F0C4F8C7E78020694688803220E06054
:20D1C000012301AA06A92846AADF002803D00022114602F0B3F82078002807E038280020A2
:20D1E000FFFF0000602D00203015000001D1FFF745FF0020C043E080A5E70722C14910A839
:20D2000002F065F91022E11D0CA802F060F91C22314612A802F05BF90CA80A9012A8099039
:20D2200006ABB94A852128467FDFBDE70DE01822B64906A8FEF7FCFF0A980B9900900191F8
:20D2400006A80FC8FFF77EFC7DE70021284667DFAAE700E017E0817900299AD0807A042885
:20D2600003D0062801D0052893D1022909D0012069460872FF208330888102A92846A8DF82
:20D2800092E70220F4E700F08DF88DE710B5044601F0C2FA9B482146303800F09AFE2046D3
:20D2A000FFF73EFF10BD10B50022114602F046F810BD30B5944D87B00024203D2C7094483D
:20D2C0002C6102F0B3F800286AD19248FFF7E4F901F000FF002863D18A4800F059F900288C
:20D2E00001D10120E87011206946087207228AA102A87CDF002803D00022114602F01EF8B4
:20D3000000940C2168460194018018214180FF2184809131C1807ADF002803D0002211469A
:20D3200002F00CF804206946009408807C4801907C4802907348303800F00BFE002803D046
:20D340000022114601F0FAFF1C21684602F01EF9754801900120800302900094032168468C
:20D360000173C4810474714806900594684601F0FEF9002803D00022114601F0DFFF624910
:20D38000E12208784008400010400C30DF22104008700720487010208870FFF76FFE0020A3
:20D3A00007B030BD70B5584C614D203CE088A84201D1082070BDE178002914D05149012359
:20D3C00008223431A9DF0028F4D12A460C21E088A7DF5849884204D0082802D0891C88420E
:20D3E000E8D1002070BD00231A461946A9DF70BD10B50A46044603211046FFF7CFFC0246AE
:20D400000321204600F00AFD002803D00022114601F094FF10BD30B5054687B000200090AF
:20D4200001900290039038486A46203800791070364A0C3A1068926804906846069205900E
:20D4400008790C2806D003221BE00022114601F075FFA5E78C68204600F049F80190201D5E
:20D4600000F045F802902046083000F040F8039004A8FFF714F9002892D00121FFF78EFCB9
:20D4800002460121284600F0C9FC0028DDD187E7FEB50446087982070ED08207920F042385
:20D4A0009B1A0022154604E08E683554401CC0B2521C9A42F8D30871012000908868029048
:20D4C0000879800801906846FFF785F900280DD00221FFF763FC02460221204600F09EFCB8
:20D4E000002803D00022114601F028FFFEBD10B5044602F04DF80002E178000A09060843E0
:20D5000010BD0000902D002058280020E4F703008DD20300D3CD0300446675546172670031
:20D520005FCF0300A7D20300CD0C000005CF0300FFFF00000230000010B50C46002802D04D
:20D540000120086010BD2168002911D01C48421A814212D03C2A0DD23C303C3101220B78B9
:20D5600003701346491E401E521C3C2BF7D904E00E200BE03C2201F0AAFF00223C211048A9
:20D5800001F08AFD0E49891E08800020206010BD70B5054600223C21094801F07DFD084C21
:20D5A000A41E2188884201D00B2070BD3C220449284601F08CFF2088401C2080002070BD87
:20D5C000823F00208307FF22DB0E9A408907090E994000280BDA0007000F08388308FA484C
:20D5E0009B001B18D86990430843D86170478308F6489B001B1818689043084318607047AA
:20D6000070B50124F24960040860F24940108860F04940398860F04D6C602F20FEF7B6FDAC
:20D62000AC60EE4D00242F206C61FEF7AFFD2C7170BDF0B5E94F2821BC6841430D19396962
:20D640004A1C09D028224A431619AB68B268934204D8D21AB26069623861F0BD0A4602E066
:20D660000A46796A9B1B4E1C0BD028264E433719BE689E42F4D328264E433619B768FF1A1A
:20D68000B760AB60696228214A4311194862F0BD70B5D24C2269A5681346114606E0814212
:20D6A00007D00A46282671434919496A4E1CF6D170BD002EFCD08A420CD1282043435819EC
:20D6C000406A2061401C05D1C34B01209860002363616071282041434819282381685A4310
:20D6E000406A52195062421CE2D028225043401982685118816070BDF8B5B84C2569681CF9
:20D7000035D0B748002640686169401A07023F0A19E028204543A0682A189068B84214D8D0
:20D72000A3693F1A8619556A002B09D0116AD0699847002807D00022114601F0FFFD02E048
:20D74000D169106A8847681CE3D1A178E078814206D1401CC0B2E070022801D10020E07079
:20D760009E490006800D1C310E5000F0BAF9F8BDF8B50446994800270169009146785CE038
:20D780009648F100C2688D1851E0601C07D0934A28209268604321468018446A24E0287854
:20D7A000182141436A68401CC0B252182870A978884200D12F70894B516828209B6848434C
:20D7C000C0181368012B34D1037E002B31D19368C360D368036113694361526902627F4A52
:20D7E0005279002A00D0C7607C4BC2685B6996469C46D31A1A027B4B120A9A4202D20369C3
:20D80000D21808E0724663469A1A12020369120A934202D99A1A826000E08760C76001222E
:20D8200007610276921E42620846FFF702FF601CABD1287869788842A7D13046761EF6B202
:20D8400000289DD1654801690098814201D00120F8BD0020F8BD644900200860486088607F
:20D86000C860614940390860486045E7FEB50020C0435A4D02906869019068462E6900F07B
:20D8800035F9074600F04FF90446002F08D002AA0199009800F08FF90298FFF769FF06E050
:20D8A0000298FFF765FF002801D1002C02D0304600F0AAF900206871FEBDFFB59807002448
:20D8C00081B01E4615460F4600280BD1002E09D0FFF796FE41490A9888610F703246002042
:20D8E0008E6008E0072005B0F0BD28234343D4509B181C76401CB842F7DB28204743BB19C1
:20D90000032048700F461846CB6019461830002218232E465E43D3005B181C705C709D708A
:20D9200058603018521C032AF5DB0020C0433861BC70FC7001242D482405046003211420A9
:20D94000FFF740FE224880380460254C0198A06003211120FFF736FE606878610020C2E71A
:20D9600070B51E4CA568002D06D0002A06D0002804D00023247809E0082070BD072070BDBB
:20D9800028265E43AE59002E04D05B1CA342F7DB042070BD282401265C432E516419E261BF
:20D9A00061600360002070BD07494868C005C00D2CD010381CD50207120F083A9208920097
:20D9C0005118C96919E0000000ED00E000E400E080E100E040130140001001406028002054
:20D9E00000150140FFFF7F004011014080E200E08108B14A8900891809688007C00EC1400B
:20DA00000806800F012803D0032803D0022070470020704701207047FEB50446A74817469E
:20DA200082680D46002A0CD001788C4201D2052D01D20720FEBD2146282359435358012B7D
:20DA400001D00820FEBD8818406801281DD00026FFF7AAFFC00099490190C9684018694684
:20DA600000F018F9002812D0012144600160944949680830E2C091490198C9684118009877
:20DA8000487000F02EF80020FEBD2E46E0E70420FEBDF8B5894D0446A868002809D0297844
:20DAA0008C4201D30720F8BD282161434058012801D00820F8BDFFF777FFC600E86869465B
:20DAC000301800F0E7F8002809D0022112C0E86831180098487000F004F80020F8BD04206B
:20DAE000F8BD0120774900050860704710B5734900238A78CC78A24212D0521CD2B28A70D0
:20DB0000022A00D18B708A786C4B92001C339A580260486910180002000A4861012010BDA3
:20DB20000360002010BDF8B5644801690091457833E06248E900C0680E1834782AE01820A2
:20DB400060437168641C0818B178E4B2A14200D100240168022902D003291BD113E0574A00
:20DB600040682821926841438F18397E002911D0FFF78EFD002038760CE028277843C018B1
:20DB80000276406A03E04D4900228B680869471CF3D108617078A042D1D128466D1EEDB2D0
:20DBA0000028C6D1454801690098814201D00120F8BD0020F8BDF7B5404C0025A7682369E0
:20DBC0001EE028215943C9198E68864202D9301A886017E0801B751900268E600E764E6946
:20DBE0009C464B6AB646002E0AD0019E76193602360ACE6076460E6116684E626146116045
:20DC0000591CDED12361FEBDF8B52C4801694A1C3DD028225143826889188E6828494C681F
:20DC200047690079E11B0D022D0AED1C002815D10120254A00045060234A403A506021491D
:20DC4000400080310860214908602149012008602F20FEF79BFA194901200871B54200D208
:20DC60003546E81900021649000A4031086014494968001B091B0902090A0002C91C000A88
:20DC8000814203D901200F4940040860F8BDFFF7B7FCF8BD42788378521C934200D10022C2
:20DCA0000378934201D1002070470A6041684078182250430818704700E400E06028002090
:20DCC0000015014000E200E04013014000E100E00010014010B50446082904D000221146F9
:20DCE000104601F02BFB21686068884710BD1CB501910090024A0821684601F09DFA1CBD53
:20DD0000D5DC03000A48026803210A4302600948804709480047FEE7FEE7FEE7FEE7FEE797
:20DD2000FEE7000005480649064A074B70470000240500404DDD0300C1C003009830002007
:20DD4000983C00209834002098340020F8B500F035F82B4E002804D02A4870602A49F01300
:20DD600088612A480124018CC9B201290DD1818C09070AD1018D0906090F042905D1808D56
:20DD80000006000F01D1224884600027B461214D6F60A8058460686800280ED1C820FEF790
:20DDA00005FA1D487F1C8742F5D30020B06101208007846068680028FCD0F8BD1348018CB5
:20DDC000C9B2012917D1818C090714D1018D09060A0F03D1828D1206120F0ED0090F0129C2
:20DDE00003D1828D1206120F07D0032903D1808D0006000F01D0002070470120704700008E
:20DE000000050040DFFF07C0006C0040C00F00F000060040000100408813000030B585B071
:20DE2000002822D00388FE4CA34220D0FD4B1B78002B1CD0FB4B10255B1C1D7059700024C0
:20DE400001259A70032269460A820094019402940394028A0A808D708C8004A902910393E7
:20DE600000886946A6DF05B030BD0E20FBE70820F9E7F0B58BB0044602276846077300268B
:20DE800009968784C68408A80A900D46A18A208809AAA5DF002804D0E16A00291AD08847BE
:20DEA00018E06846008CC007C00F13D068460682208803A9A8DF002813D1A97E28461B30BA
:20DEC00001220B0001F055FC09430F1B202224263E284300FF20FE3069460882208803A94D
:20DEE000A8DF0BB0F0BD00960AE0062219E069460A71029022E0204690470020F1E700920D
:20DF00002B8B022BF3D2F0E700971DE003201AE0042018E0052016E0298B032905D20322BE
:20DF200008212046FFF77AFFDBE741780278080210436946888003D006200090A26ADAE784
:20DF40000720FAE7092000906946A26AD3E70322E7E730B585B00D46040038D0002D36D0EC
:20DF60006868002833D00020C043AF4B20800FCB049301AB07C3AD4869460880891C01A888
:20DF800063DF002822D1221D69460120A0DF00281CD168468078A071204600F0CEF8002886
:20DFA00014D1204600F055F900280FD12946204600F002F9002809D16868A062A868002804
:20DFC00000D0E06297490120087000204BE70E2049E73EB5002828D0002926D0826A002ABE
:20DFE00023D00A88102A21D0112A30D0502A1FD0512A1AD104460846891D0A78022A14D196
:20E000004A88238A9A4210D1807A04280DD006280BD0052809D0891C2046FFF72AFF002860
:20E0200003D0E16A002900D088473EBD898810E0CA8803899A42F8D1082200928A7F6B4605
:20E040001A7120310291826A694690473EBD0021C94301803EBDF0B585B00A4605002DD00F
:20E0600028886F4988422BD06E480078002827D06C4C1020641C2070072060700127A770F8
:20E080000321684601820026E11C104600F04CF801466846008A0918684601820096019680
:20E0A00002960396298A01808770868004A80394029028886946A6DF05B0F0BD0E20FBE7D3
:20E0C0000820F9E7F0B585B00A46050028D028885349884226D053480078002822D0514C3B
:20E0E0001120641C20700127684607820026611C104600F019F801466846008A0918684638
:20E1000001820096019602960396298A01808770868004A80394029028886946A6DFCBE782
:20E120000E20C9E70820C7E70870020A4A70020C8A70000EC8700420704730B58FB0054655
:20E140001C21684601F022FA694608780421084369460870002401940394049405940694E6
:20E16000A87908A9887031486946801C0884601C00070794000F0C77103048778A7FF920B4
:20E180000240921CE7200240012002438A77142109A801F0FBF908A8099007A80A906946D3
:20E1A0008C851420CC8508860D942B46A888083309AAA2DF0FB030BDF0B58FB00F4605465A
:20E1C0001C21684601F0E2F968460178022631430170002401940394049405940694A97917
:20E1E00008A8817011496846091D0184601C0107090F103168460794017700200146684618
:20E200004177817FF9200140891CE72001400120014368468177142109A801F0B7F907E086
:20E22000FFFF000088280020FCF703003015000008A8099007A80A9068468685C4850686B5
:20E240000D972B46A888203309AA6946A2DF0FB0F0BD30B58FB005461C21684601F096F9FD
:20E2600069460878082108431022104369460870002401940394049405940694A87908A962
:20E280008870144869460884601C00070794000F0C7710304877887FF9210840801CF72123
:20E2A000084010430121084369468877142109A801F06CF908A8099007A80A9069468C851A
:20E2C0001720CC8508860D942B46A888103309AAA2DF6FE731150000FFB583B0074600207F
:20E2E0000C9C8646267805463AE07868A90041180A88684682804988C1800022694601A8F7
:20E3000065DF002810D1684601780598814226D17046002801D0002200E002222078891824
:20E3200041181F2902D90C2007B0F0BD7146002908D1401CC0B2411C069B049A21701A54AF
:20E3400001208646217806980A18694601A865DF0028E9D1694620780978401820706D1CC0
:20E360003888A842C1DC7046002804D020780699801B401E88550020D6E7F8B51546069C10
:20E380001E46074602220094FFF7A6FF002806D133461022294638460094FFF79DFFF8BD07
:20E3A000F7B582B000260546167000681446002805D02846039900F0CAF8060008D168794D
:20E3C00000281ED02078039F001D1F2802D90C2005B0F0BD684679DF0028F9D1217803226A
:20E3E000481C20707A5421781922481C20707A542078C1196846008800F0A4F821784018A0
:20E400002070A8790223002810D02078039A411C2170135420780399471C012227700A54E5
:20E420002078AA79471C039927700A54A868002815D00021415620788C460246C01C03992E
:20E440001F28C4D8501C20708B5422780A23501C20708B5420786246431C23700A54A8899B
:20E46000002809D028460094062202210C30039BFFF783FF0600ABD1A88A002809D02846D9
:20E480000094072203211430039BFFF776FF06009ED1A88B002809D0284600941522142137
:20E4A0001C30039BFFF769FF060091D1686A002805D02246039900F07FF8060088D1A86A01
:20E4C000002805D02246039900F0B5F8060084D13020405D002806D022462846039900F0F6
:20E4E000DCF80600C7D1304672E770B50C4692B000216A46117007251171002809D0817927
:20E5000049070CD502A9FFF74BFF002808D102AE00E00026002C0ED0A079002802D028469D
:20E5200012B070BD01AA0AA92046FFF739FF0028F6D10AAA00E0002268460379017830463C
:20E5400072DFEDE70870000A487002207047F8B514780746A01C15460E461F2803D83879BF
:20E56000801C1F2801D90C20F8BD1D20001B80B26946864608803019801C7DDF0028F3D143
:20E580003868022805D168460088704501D8092107E038790821002801D0704501D96846F6
:20E5A0000088421C3255641CE2B2B1542978801C081828700020F8BDF8B50D461178064636
:20E5C000881D14461F2801D90C20F8BD33880720062BFAD31927FF01BB4202D94D4A9342D6
:20E5E000F3D17288062AF0D3BA4202D9494FBA42EBD1484FBB4203D0BA4201D09342E4D87E
:20E60000481C052220706A5420781222411C21702A54207841193088FFF794FF21784018C5
:20E62000C0B2207041197088FFF78CFF2178401820700020F8BD70B5054600790E46801CD6
:20E640001446C0B21178821C8A181F2A01D90C2070BD0A46491C401C2170B0542078FF224A
:20E66000411C21703254207881192888FFF76AFF21784018C0B22070AA88002A09D0A968AC
:20E68000002908D0801900F022FF2078297940182070002070BD072070BDF7B582B0029894
:20E6A0001446C06A0F46002832D0029800252030009028E00298C16A0C2068430E18217855
:20E6C00030794A1CC01C2270785421781622481C20707A542078C1193088FFF733FF217873
:20E6E0004018C0B22070B288002A09D0B16800290ED0C01900F0EBFE207831794018207087
:20E700006D1C0098EDB2007CA842D3D800205FE607205DE6FFFF000038B56749674A48883D
:20E7200090420FD04A78664C521CD2B24A70237B934208D3083175DF002803D0A1690029FF
:20E7400000D0884738BD00254D70217C002907D03B2176DF002803D0A169002900D0884728
:20E7600061690029EED068460095884738BD70B5054601461C225248FDF75AFD4E4C002647
:20E7800026702968002907D00822A01800F09FFE204608307ADF02E0474808307BDF0028C1
:20E7A00008D1401E608044486670464A0021001DFFF7D6F870BD10B53F484068FFF769F9D5
:20E7C00010BDF8B53C48103000F069F800263A4D3B4C002806D06169002919D001200090EB
:20E7E000684614E02878002804D0616900290FD00096F5E7687800280CD0A16800226868B8
:20E80000FFF70AF9002803D0A169002900D088472E70F8BD6168F1E7F8B5294C028800276B
:20E82000254DE689102A18D029464968112A21D0122A2DD0502A0FD1801D0288B2420BD1FF
:20E84000028B022A08D1C27E837E10021843C007C00F13D0FFF7B5FFF8BD81886980014667
:20E86000154808221631103000F031FE6F70002EF0D0F8BD0020C04368806F700846FFF7BB
:20E8800008F90028F5D0A1690029F2D08847F8BD811D09480822103000F019FEDAE7418827
:20E8A000054808300288914204D34088814201D8012070470020704790280020FFFF0000B6
:20E8C000CC2D002019E7030031B5054C04E0401E00902046FDF77AFC00980028F7D138BDC6
:20E8E000E703000018225043FE4A00218018017181604161012281610261C1607047FFB577
:20E9000081B0F94C049B039A054626691A4303200092002E03D1002A0ED001222261276919
:20E92000039A0126360792003B0000F022FF072707162940526127000222EFE770693269FC
:20E9400092B25043326933691204920C9BB2594329DF002812D102210FE0084628DF00286A
:20E960000CD10399002901D0032106E00499002916D12978042946D017E0216105B0F0BDAE
:20E980007069326992B25043326993B24B4301461846039A29DF0028F0D10499002901D0F4
:20E9A0000421EAE72978042920D00521E5E773693069366980B2434368681B189B18B6B2C7
:20E9C0004E43301880181946049A29DF0028E9D0D4E7306980B24843696880188A08696902
:20E9E00029DF0028CAD1009900290CD00621C4E77069316989B24843316989B200F0D9FD08
:20EA000028DF0028BAD10721B7E7F8B5B54918230A780F205A435418241DB3492278266970
:20EA2000CF68022A1BD001252D07042A2AD0052A5BD1286981B2304600F0BBFD0146A36877
:20EA400028699A1980B24843101A820860681818861928694B1C80B25843801B34E0B8023C
:20EA600062686169121A0918A3683018181801239B029A4202D2920829DF31E0FF220132BA
:20EA800029DF2DE0E268974914205043F4314018001D0BC8B04203D160685943814218D02E
:20EAA000022A16D0286981B2304600F082FD0146286980B24843301A820828694B1C80B208
:20EAC000584363689B19C01A83082046FFF717FF06E0286981B2304600F06BFDC01928DFED
:20EAE000002802D17F4901228A70F8BDF8B57D4C069E65780A2D1DD027787D19EDB20A2D5B
:20EB000001D30A3DEDB218277D432D192871AA6103C9EE60AB6069612861A1780020002978
:20EB200004D1FFF772FF112800D100206178491C6170F8BD0420F8BD38B5024669481823B1
:20EB400001785943081803690179022B0AD014246343644CF434E4588368009383691030F7
:20EB6000A04738BD604B14331C68F5E7F8B55D4B9978012914D100255B499D700A69082A77
:20EB800005D002280FD003280AD10D2006E0022807D00D7000F025FA002801D0FFF7CCFF37
:20EBA000F8BD0D61F6E74F48182403784E496343CC681818641C001DCC600378022B05D11F
:20EBC0004668A102B14201D3012700E00027052B01D1072A03D00021042B02D003E00121C1
:20EBE000FAE7072A03D00026042B02D007E00126FAE74068A302834201D3002A1AD0002000
:20EC0000314301433943C5D0374E28463561FFF793FF344C2078FFF765FEF5606078401E1E
:20EC200060702078401CC0B220700A28B2D30A382070AFE70120E3E770B500252A4C2948D3
:20EC4000E56025610570457085702E463046FFF749FE761C0A2EF9D3012212076560516952
:20EC600028461269491E92B25143E560A1601D49F4310D608D600D61CD601B4914310D6090
:20EC8000888001212170206170BDF8B5164A044610780E46002830D0002C30D0002E2ED058
:20ECA000206800282BD0012000076768016989B28F4228D8102F26D3A168002923D09568E2
:20ECC000794343694A19006980B243439A421AD801200007006980B2814212D901200007E1
:20ECE000006903E0E82D0020A828002080B2394600F05FFC002906D103E00820F8BD0E20B9
:20ED0000F8BDB80701D00720F8BDBD49486801281CD00F461421BB4A21C641438E18756092
:20ED2000236853506168B160A168F160A268616800235143012212075B1C14699BB2A4B214
:20ED40008C4205D21469A4B2091B02E00420F8BD00211469A4B265191469A4B28C42EBD985
:20ED6000BD60401C336178600020F8BDF8B50446A3481E46007815460F46002807D0002F3D
:20ED800007D0002C05D02068002817D103E00820F8BD0E20F8BD9B48016800290ED0C268E3
:20EDA000816840684A4310186268904206D9002D04D0A94202D3A819884201D90720F8BD90
:20EDC000384600F008F9002811D0304600F003F900280CD0606800F0FEF8002807D02B4637
:20EDE0003A46214602200096FFF780FEF8BD1020F8BDFFB5824881B000781F4616460D462B
:20EE0000002808D0002D08D00198002805D02868002817D103E00820B0E50E20AEE5794C91
:20EE2000206800280ED0E168A0686268414389186A68914206D9002E04D0B04202D3F119AD
:20EE4000814201D9072099E5019800F0C4F800281BD0384600F0BFF8002816D0686800F025
:20EE6000BAF8002811D068683246C119019800F02EFB00962868142148432458002203215B
:20EE80002846019BA047002078E5102076E5F8B505465B480F460078002805D0002D05D012
:20EEA0002868002821D103E00820F8BD0E20F8BD544C00262068002817D0A168E0684843CC
:20EEC00061684118686881420FD900F084F800280DD0296814225143091968684A68896834
:20EEE000801A00F066FB002903D00720F8BD1020F8BD3B460022294604200096FFF7F6FDB5
:20EF0000F8BD3F4A1278002A0DD000280DD000290BD00268002A08D0394A14321368002B3E
:20EF200005D004207047082070470E20704702230B600068106000207047F8B504463048AF
:20EF40001E46007817460D46002807D0002D07D0002C05D0206802281BD103E00820F8BDC3
:20EF60000E20F8BD264814300068002811D0084600F031F800280ED0304600F02CF800286C
:20EF800009D03B462A46214602200096FFF7AEFDF8BD0720F8BD1020F8BD08B5184A1278C8
:20EFA000002A05D0002805D00268022A11D103E0082008BD0E2008BD114A14321268002AD5
:20EFC00007D00B460022014604200092FFF78EFD08BD072008BD800701D000207047012068
:20EFE0007047084910B5F43949780020002906D0FFF70BFD002802D0112800D1002010BD48
:20F00000A8280020DC2E002070B500250C290ED304464318008941000919581A0A38C2B2BD
:20F020001748022A027002D30A318B4201D2092070BD144800F04BFA134914480A8882422E
:20F0400002D02388934217D14988814202D06088884211D10D4A0323521E20891B03A842DE
:20F060000AD9690009194989914203D09E896D1CB142F4D1002070BD0B2070BD00207047C6
:20F08000C4280020F02E002080100010FFFF000010B5FDF7ABF810BD10B50446002A02D054
:20F0A0001088002210E00A48FBE7030A00020343A05C584003061B0F43401803584083B2EB
:20F0C0001806C00C5840521C8A42EED310BD0000FFFF00004B48002101704C484A4A026039
:20F0E0008160C160016108224161426081610846704710B500291DD000220A60434A5368A8
:20F10000002B1BD0202817D85B1E5360D0682423401CD060106914684343E3180B60012366
:20F1200083409169401C19434007400F91611061002010BD0E2010BD0C2010BD042010BD8F
:20F14000F0B5324A0646916800292BD057691020791A4907490F14680B4624254D436519D6
:20F16000B54206D1012495698C4065400020956104E0491C4907490F8F42EED1491C4E07DC
:20F18000760F956901210C469C402B4623420AD19368002B07D05B1E936053685B1C53609D
:20F1A0003346F0E70420F0BD184A2423117C1268491E4907490F594320315050002070470B
:20F1C00070B500281AD0002918D0104AD368002B16D05B1ED360936824265B1C936053692A
:20F1E00015681C467343EE1820330660E858641C08606007400F5061002070BD0E2070BD84
:20F20000042070BDC5280020FC2E00201C30002030B5CB0008339DB293070024002B01D0E6
:20F22000072030BD3B4B9A605219DA605C701C7058809980002030BDF7B5364C0E466088D5
:20F24000814237D8344F00F069F822786078A188884201DA401C00E00020C0B2904202D155
:20F2600000F062F824E065786078884201DA401C00E00020607000F057F8BD4218D0A0688C
:20F28000EF000299C151009900290CD0002E0AD0608832464543E068281800F018F9A068B3
:20F2A0003818868002E00021381881800020FEBD0420FEBD0920FEBD0EB504E068468188A8
:20F2C000029A0098904702AA01A9684600F003F80028F3D00EBD70B50E4B05241D785E786C
:20F2E000AE4215D01D781C789E88B44201DA641C00E000241C705C88DE686C43A41904600F
:20F300009B68E800C418A4880C80185800241060204670BDCC280020FFFF000072B606484F
:20F320000168491C0160704703490868401E086000D162B670470000DC280020BFF34F8F11
:20F3400003490248C860BFF34F8FFEE70400FA0500ED00E010B5002904D000221146104619
:20F36000FFF7ECFF00F010F810BD10B50021024A0846FFF761FF10BD55F3030010B50846E6
:20F380001146FCF771FF10BDF8B5384C2078002837D02069002807D00026E068002805D0FB
:20F3A0000025002E04D013E00126F6E70125F8E7684651DF052806D0002806D000221146D2
:20F3C000FFF7BCFF04E0012602E0216900988847002D12D1608869460880A06861DF0528FA
:20F3E00006D0002806D000221146FFF7A7FF04E0012502E0E168A0688847002ED8D0002D15
:20F40000CFD0F8BD70B5002901D08C0701D0072070BD164C0125A16062801549636010DF46
:20F420000028F5D1257016202EDF70BD002803D00E49C860002070470E207047002803D0A8
:20F440000A490861002070470E20704710B507484068002807D08047002803D0002211463E
:20F46000FFF76CFF10BDFFF78FFF10BDE02800207DF30300034610B50B439B070FD1042A66
:20F480000DD308C810C9121FA342F8D018BA21BA884201D9012010BD0020C04310BD002AAC
:20F4A00003D0D30703D0521C07E0002010BD03780C78401C491C1B1B07D103780C78401C61
:20F4C000491C1B1B01D1921EF1D1184610BDF8B5042A2CD3830712D00B78491C0370401C25
:20F4E000521E83070BD00B78491C0370401C521E830704D00B78491C0370401C521E8B07F9
:20F500009B0F05D0C91ADF002023DE1B08C90AE0FCF78EFEF8BD1D4608C9FD401C46B440B8
:20F520002C4310C0121F042AF5D2F308C91A521EF0D40B78491C0370401C521EEAD40B78EC
:20F54000491C0370401C521EE4D409780170F8BD01E004C0091F0429FBD28B0701D50280F7
:20F56000801CC90700D00270704700290BD0C30702D00270401C491E022904D3830702D5EE
:20F580000280801C891EE3E70022EEE70022DFE70378C2781946437812061B0219438378A2
:20F5A000C0781B04194311430902090A000608437047002203098B422CD3030A8B4211D366
:20F5C00000239C464EE003460B433CD4002243088B4231D303098B421CD3030A8B4201D39D
:20F5E00094463FE0C3098B4201D3CB01C01A524183098B4201D38B01C01A524143098B422D
:20F6000001D34B01C01A524103098B4201D30B01C01A5241C3088B4201D3CB00C01A524193
:20F6200083088B4201D38B00C01A524143088B4201D34B00C01A5241411A00D201465241FB
:20F64000104670475DE0CA0F00D04942031000D34042534000229C4603098B422DD3030A47
:20F660008B4212D3FC22890112BA030A8B420CD3890192118B4208D3890192118B4204D305
:20F6800089013AD0921100E08909C3098B4201D3CB01C01A524183098B4201D38B01C01A88
:20F6A000524143098B4201D34B01C01A524103098B4201D30B01C01A5241C3088B4201D37F
:20F6C000CB00C01A524183088B4201D38B00C01A5241D9D243088B4201D34B00C01A52417F
:20F6E000411A00D20146634652415B10104601D34042002B00D54942704763465B1000D31A
:20F70000404201B50020C046C04602BD704770477047754600F022F8AE460500694653469B
:20F72000C008C000854618B020B5FEF7FBFA60BC00274908B6460026C0C5C0C5C0C5C0C525
:20F74000C0C5C0C5C0C5C0C5403D49008D4670470446C046C0462046FCF7FFFC004870479C
:20F760003830002001491820ABBEFEE726000200704730B47446641E2578641CAB4200D256
:20F780001D46635D5B00E31830BC184702000000000000000000000000000000040000009F
:20F7A000000000000000000000000000000000000000000035C4030000000000000000004D
:20F7C000020000000000000000000000000000000000000000000000030000000000000024
:20F7E0000000000005000000000000000000000000000000000000000000000023D1BCEA6A
:20F800005F782315DEEF1212000000002CF8030000280020F400000004C1030020F90300A1
:20F82000F4280020A413000020C103000000000000000000000000000000000000000000F1
:20F840000000000000000000000000000000000000000000000000000000000000000000A8
:20F8600000000000000000000000FFFF000000003200000000000000000000000000000058
:20F88000000000000000000000000000000000000000000000000000000000000000000068
:20F8A000000000000000000000000000000000000024F40000000000000000000000000030
:20F8C000000000000000000000000000000000000000000000000000000000000000000028
:20F8E000000000000000000000000000000000000000000000000000000000000000000008
:20F900000000000000000000000000000000000000000000000000000000000000000000E7
:20FC00000100000000000000FE0000000000000000000000000000000000000000000000E5
:020000041000EA
:0410140000C0030015
:040000050003C0C173
:00000001FF

View File

@ -0,0 +1,463 @@
:020000040003F7
:20C00000983C002005DD030017DD030019DD03000000000000000000000000000000000057
:20C0200000000000000000000000000069C1030000000000000000001DDD03001FDD0300D7
:20C0400021DD030021DD030021DD030021DD030021DD03000000000021DD030021DD0300D9
:20C0600021DD030021DD030021DD030021DD030021DD030021DD030021DD030021DD0300B8
:20C0800021DD030057D8030021DD030021DD03006DD8030021DD03004DF4030021DD0300DD
:20C0A00021DD030021DD03000000000000000000000000000000000000000000000000007E
:20C0C00000F002F800F040F80CA030C8083824182D18A246671EAB4654465D46AC4201D18E
:20C0E00000F032F87E460F3E0FCCB6460126334200D0FB1AA246AB463343184710370000C8
:20C1000030370000103A02D378C878C1FAD8520701D330C830C101D504680C6070470000D3
:20C120000023002400250026103A01D378C1FBD8520700D330C100D50B6070471FB5C04655
:20C14000C0461FBD10B510BD03F0E3FA1146FFF7F5FF00F0D3F803F0FBFA03B4FFF7F2FF19
:20C1600003BC03F0FFFA00000648704502D1EFF3098101E0EFF30881886902380078024A97
:20C1800010470000FDFFFFFF39D50300401E00BF00BF00BF00BF00BF00BF00BF00BF00BF28
:20C1A00000BF00BF00BFF1D170470000401E00BF00BF00BF00BF00BF00BF00BF00BF00BFB4
:20C1C00000BF00BF00BFF1D170470000401E00BF00BF00BF00BF00BF00BF00BF00BF00BF94
:20C1E00000BF00BF00BFF1D170470000056885F3088846680A4AEFF305839A42304602D183
:20C20000084CA6463047074C064D0646064FF0B4034C034D024E024FF0B404480047000005
:20C2200000000000FFFFFFFF00000021F9FFFFFF70B505460C46164602E00FCC0FC5103EEE
:20C24000102EFAD2082E02D303CC03C5083E042E07D301CC01C5361F03E021782970641C63
:20C260006D1C761EF9D270BD0A4610B50146664803F064F810BD10B502F078FC10BD10B5C6
:20C28000624C86B01ECC03946C460EC4002807D0684618DF002803D00022114603F04EF864
:20C2A0000F20800313DF002803D00022114603F045F8574B48225749092003F0A3F80028AB
:20C2C00003D00022114603F039F800200490059001206946087404A860DF002803D0002251
:20C2E000114603F02BF84C4803F0A8F8002803D00022114603F022F806B010BD08B547485A
:20C30000C169B12943D0002445480F2140698903884204D000221146104603F00FF8012068
:20C320000007006901218902884204D000221146104603F003F83B4800903B4B05220321A1
:20C34000002001F0BAFA002803D00022114602F0F5FF00F067FC00F0AAFC012500281AD09D
:20C3600000F0B4FC002803D00022114602F0E6FF20466840FFF783FF00F038F800F0CCFC74
:20C3800000280ED00022114602F0D8FF09E001240021C161B8E720466840FFF770FF00F002
:20C3A00025F803252D03002C04D1A86800F090FB002807D100F047FC002803D000221146D5
:20C3C00002F0BCFFA86800F083FB002806D000F06EFC002802D1A86800F041FCBFF34F8F12
:20C3E00013491248C860BFF34F8FFEE7094A10B548321421082002F00BFF002803D00022E2
:20C40000114602F09BFF10BDEFBEADDE8CF703006BF30300342B002077C20300000500404D
:20C4200000100010EFDC0300F42800200400FA0500ED00E070B5FC4C1E46A06815460229A3
:20C4400002D0042916D108E0052813D1A369002B10D03246294604200BE002280AD1F348B0
:20C46000406880470320A060A369002B02D0324629469847280003D00022114602F05EFF98
:20C4800070BD4CB5E84E0120307005200195009400F058FB4CBD10B5E34C2078002801D057
:20C4A000082010BD206901F0F4FA002803D00022114602F043FF0F2100228904206901F01E
:20C4C000ABFA040003D00022114602F037FF204610BDD54910B5D448243141610221816012
:20C4E000C168243002F059FD002803D00022114602F024FF10BDCC4910B5CB481C31416145
:20C50000022181600320000380680F218903081A4108C5481C3002F040FD002803D000223D
:20C52000114602F00BFF10BD704700B589B01822BF4902A8FFF77CFE06980799009001917A
:20C5400002A80FC800F0FEFA09B000BD00B5B64987B049886A461181032109038968069146
:20C56000B249012050394A6803928A680492C9680591069A0091019202A90EC900F0E2FA6E
:20C58000002007B000BD30B5A84CA748503C89B02430E16802F001FD002803D00022114679
:20C5A00002F0CCFEA048E2681C3041680023083002F0C3FC050012D1182102A802F0E6FFEA
:20C5C00000209949029049886A469181E1680691079A0091019203A90EC900F0B3FA284601
:20C5E00009B030BD00B5904987B049886A4611818E49032050394A6803928A680492C9683A
:20C600000591069A0091019202A90EC900F09AFA0020B6E73EB5864A6B46183207CA07C3A4
:20C62000814D00246C7029466C802431684602F068FC002801D0AC603EBD03207A4900038F
:20C6400080682431486024390A46526ACA610F218903091A490840187349764A1C31486068
:20C6600071480021103001F07BF9002803D00022114602F063FE0F2100228904286901F013
:20C68000CBF9002803D00022114602F057FE01206C60A86000203EBD63498861704770B59A
:20C6A000426862481468536891685038D26804604360C26081600078440701D5840705D130
:20C6C0009C0703D18C0701D1940701D0062070BD5B189A18544D0F239B02EA60994213D81A
:20C6E0005549564B514CC60709D08868181A90420AD3534820605348606053480FE08968F6
:20C70000591A4908914201D20C2070BD4F4921604F496160800701D54E4800E04E48A0607B
:20C72000A868012802D00826304670BDFFF7B3FE0600FAD12168E8688847F5E770B50500F7
:20C7400004D0287A800703D0102070BD0E2070BD354CA068032805D0042801D0052803D0CB
:20C76000082070BD0520A0606868E168860060688019884204D90020C04360600C2070BD5C
:20C78000FFF789FE0028FAD1A96832466368606902F0D3FB0028F2D1616889196160E268EB
:20C7A0009142ECD0092070BD10B51F4C08206168002900D010BDA1680429FBD11B4861786F
:20C7C000403802F021FC002802D00021617010BD0521A16010BDF8B5134C0746A068032899
:20C7E00004D0042804D008252846F8BD0420A0606068002801D00820F8BDFFF74CFE05000E
:20C80000FAD17868860060788119402901D90920F8BD064AB968403A1018324602F057FE82
:20C82000607880196070DFE7002800201C2D00209CF7030083C403000030000000C003006D
:20C84000D3C403002BC503004DC50300F7C4030029C50300E5C5030087C5030010B5894CF1
:20C86000A068052813D1E168606888420FD10620A060FFF710FE002808D16069E1684068FF
:20C8800002F0FCFB002801D10721A16010BD082010BD10B57B488168072901D0082010BD63
:20C8A000006901F0F6F8002803D00022114602F045FD75488068804710BD1CB506200195C2
:20C8C000009400F03FF91CBDF8B51C4617460D46064600F0C1F8002817D001200003854215
:20C8E00007D92346291B301B1A46FFF7EDFF00280BD13A462946304600F0B9F8002804D117
:20C900003A462946304600F0A7F8F8BDF0B589B0684600F015FA049800282AD001210903F7
:20C92000079A4018904226D9501A45081046049A0C468718024668001618001908900320DF
:20C9400000038068049988420DD261190846042200F08DF800280CD121460422084600F073
:20C9600086F8002805D1BA1B2B4630460899FFF7ABFF09B0F0BD049A079800F078F8F8E75C
:20C9800000B58DB004A800F0DBF9099800280DD0089800280CD008990B984018019000219D
:20C9A0000998009180080290684618DF0DB000BD0320000380680F218903091A4908ECE7FB
:20C9C00000B58DB004A800F0BBF909980028EDD00F210898890300280CD0089A0B98019158
:20C9E0008018029003220998009280080390684618DFDBE70320000380680A1A5208EEE7D2
:20CA000030B591B0684600F09BF90498002814D001210903079A4018904214D9501A43087B
:20CA20001046049A5C0082180019611803242403A468049DAC4202D20E2011B030BD121AB5
:20CA4000FFF742FFF9E703200CAB07C3049880080F900CA818DFF0E71FB5032301909008B3
:20CA6000039000930291684618DF04B010BD1FB5012301909008039000930291684618DF58
:20CA8000F3E70000002800201C2D002010B5BB480368012B02D1022900D10160100003D099
:20CAA0000022114602F04AFC10BD10B5B34C48DF002803D00022114602F040FC02F0FCFB82
:20CAC0002068022803D0032801D00428EFD110BD38B50068401C19D00024684600F058F96F
:20CAE00000980168012910D1818800290AD0C168032000038068002202F0CEFA0099898861
:20CB0000814201D1012400E00024204638BD10B504469A482021001D02F0B9F9002803D00E
:20CB20000022114602F00AFC9448002320222146001D02F01BF9002803D00022114602F053
:20CB4000FDFB10BD0FB4F8B5684600F021F96846818B069D0122894CFF238948002D13D090
:20CB6000012D17D0032D2BD00021022D37D02A46052D46D0042D4ED0062A01D10420206071
:20CB8000F8BC08BC04B0184781800A9983600260C16010E08180099D089949190A9D49195D
:20CBA000C160A52183600160089901610999856141610B99C16122607148FFF7A8FFDFE7B9
:20CBC00000990B6803608B888380C968C160AA21816008990161099941610A990BE0009D60
:20CBE0002E68A52E09D00660AE888680ED68C5600161836041618161DDE781800360C160C5
:20CC0000F6E700F085F9002803D00022114602F095FB0320B3E781800360C1600099896807
:20CC20008160C9E70EB557480090202001900120029002F001F8002804D150496846091D98
:20CC400002F023F80EBD10B5FFF7E4FC002805D100F02FFB0446FFF728FF204610BD70B58A
:20CC600011DF002803D00022114602F067FB464900200B68444C012180340A4682401A4206
:20CC800004D0C506ED0E0A46AA402260401C2028F3D303242403A06813DF002803D000226F
:20CCA000114602F04BFBA06802F0F2F970BD08B5684600F06DF800980168A52904D0806888
:20CCC000AA2801D0002008BD012008BD10B5FFF797FE002803D1FFF773FE00281BD064209C
:20CCE00001F0F2FDFFF712FE002803D00022114602F024FBFFF784FE002803D000221146DD
:20CD000002F01CFBFFF73CFE040003D00022114602F014FB204610BD00B589B018221B49CA
:20CD200002A8FFF785FA069807990090019102A80FC8FFF707FFFFF7B8FE002009B000BDB5
:20CD400010B50E4988B0044600232022091D684602F04FF80098206068468088A08003983A
:20CD6000E0600298A06004982061059860610698A0610798E06108B010BD00002C280020E6
:20CD8000282D00208DCA030000E100E0C0F70300014901607047000000FC030008280CD0DC
:20CDA00004DC002807D006280FD108E00B280AD00C280AD105E001207047022070470320C9
:20CDC000704704207047042901D0062070470520704770B515460A46032823D0042820D1FF
:20CDE000FE4C002906D0E088FD49884219D0132176DF10E0284602F0A3F9002803D00022F7
:20CE0000114602F09BFAE069A8420AD101220321F44801F003F8002803D00022114602F051
:20CE20008DFA70BD01211046FFF7B8FF02460121EEE7F0B5054608790E4685B081070CD07C
:20CE400003221146284600F0E9FF002803D00022114602F073FA05B0F0BDE04900901831D9
:20CE600002F047F9010011D1DC4CB168009AA06902F02DFB009802F097F9010006D1204647
:20CE80006946183002F09CF9010003D0284600F0AFFAE0E704200190009880080290A06902
:20CEA000039001A8FFF74AFC07000BD0092F10D0A06902F045F9010002D0284600F098FA04
:20CEC0003946E3E73079616940186061A069E061C1E7307961694118616160780028BAD073
:20CEE0006089401E0004000C6081B4D1284601F0E9F8002803D00022114602F01FFA20890D
:20CF00006081A8E710B50022114602F017FA10BD10B5B24C01202070E088B149884208D01B
:20CF2000132176DF002810D00022114602F006FA0BE0A078002808D074DF002803D0002282
:20CF4000114602F0FBF90020A07001F034FC002803D00022114602F0F1F9002010BD70B5E1
:20CF60000D68044601209D4A2B0002F002FC0A2B3043061320575C466012FFF76FFC0421FD
:20CF8000FFF70CFF024604212EE00022114602F0D5F970BDFFF7BCFF002803D0002211468A
:20CFA00002F0CCF9FFF775FC002808D170BDFFF7AFFF002803D00022114602F0BFF9FFF76D
:20CFC0007CFC70BD106188680078107170BD02201061886800780128F8D1FFF7E5FB02213F
:20CFE000FFF7DCFE02460221204600F017FF0028CBD170BD0320106170BD12692046012ACC
:20D0000006D0022A07D0032AF6D1FFF712FF70BD00F001FA70BD00F03BFA70BD50708888D5
:20D020001081508170BD00205070108170BD2046516901F010F8DAE710B5044669488EB0EB
:20D0400081796846817068490180342101A802F09DFA022001900021684641728472012131
:20D0600001820590002101A801F03FFA002803D00022114602F062F90EB010BDF0B5574C10
:20D080008BB0A07800283AD156481821183802F07DFA2046534CC078183C00250126002875
:20D0A00037D02746483700950195029510226946F81D039502F0DEF9002822D0F81D08909D
:20D0C00009976846067509A804906846067708A806900420FFF7B0FF25700220207204A813
:20D0E000E060282020823F486582183873DF002803D00022114602F021F9384886700BB045
:20D10000F0BD0520FFF798FF2670676025722582E9E70620FFF790FF257065602572E0E7E2
:20D1200070B52E4C01880022E588A6B017290AD01EDC11293FD008DC022977D0102902D123
:20D140008088E080A27026B070BD264C303426461836132951D01429F5D1C289638D002106
:20D160009A4200D1314600238088E21D82DF1BE0512970D00EDC18296CD01929E3D18079F5
:20D180000028E0D1A270E068401EE0604FD0FFF775FFD8E7522976D05529D4D18079002871
:20D1A000D1D11321284676DF0028CCD00022114602F0C4F8C7E78020694688803220E06054
:20D1C000012301AA06A92846AADF002803D00022114602F0B3F82078002807E038280020A2
:20D1E000FFFF0000602D00203015000001D1FFF745FF0020C043E080A5E70722C14910A839
:20D2000002F065F91022E11D0CA802F060F91C22314612A802F05BF90CA80A9012A8099039
:20D2200006ABB94A852128467FDFBDE70DE01822B64906A8FEF7FCFF0A980B9900900191F8
:20D2400006A80FC8FFF77EFC7DE70021284667DFAAE700E017E0817900299AD0807A042885
:20D2600003D0062801D0052893D1022909D0012069460872FF208330888102A92846A8DF82
:20D2800092E70220F4E700F08DF88DE710B5044601F0C2FA9B482146303800F09AFE2046D3
:20D2A000FFF73EFF10BD10B50022114602F046F810BD30B5944D87B00024203D2C7094483D
:20D2C0002C6102F0B3F800286AD19248FFF7E4F901F000FF002863D18A4800F059F900288C
:20D2E00001D10120E87011206946087207228AA102A87CDF002803D00022114602F01EF8B4
:20D3000000940C2168460194018018214180FF2184809131C1807ADF002803D0002211469A
:20D3200002F00CF804206946009408807C4801907C4802907348303800F00BFE002803D046
:20D340000022114601F0FAFF1C21684602F01EF9754801900120800302900094032168468C
:20D360000173C4810474714806900594684601F0FEF9002803D00022114601F0DFFF624910
:20D38000E12208784008400010400C30DF22104008700720487010208870FFF76FFE0020A3
:20D3A00007B030BD70B5584C614D203CE088A84201D1082070BDE178002914D05149012359
:20D3C00008223431A9DF0028F4D12A460C21E088A7DF5849884204D0082802D0891C88420E
:20D3E000E8D1002070BD00231A461946A9DF70BD10B50A46044603211046FFF7CFFC0246AE
:20D400000321204600F00AFD002803D00022114601F094FF10BD30B5054687B000200090AF
:20D4200001900290039038486A46203800791070364A0C3A1068926804906846069205900E
:20D4400008790C2806D003221BE00022114601F075FFA5E78C68204600F049F80190201D5E
:20D4600000F045F802902046083000F040F8039004A8FFF714F9002892D00121FFF78EFCB9
:20D4800002460121284600F0C9FC0028DDD187E7FEB50446087982070ED08207920F042385
:20D4A0009B1A0022154604E08E683554401CC0B2521C9A42F8D30871012000908868029048
:20D4C0000879800801906846FFF785F900280DD00221FFF763FC02460221204600F09EFCB8
:20D4E000002803D00022114601F028FFFEBD10B5044602F04DF80002E178000A09060843E0
:20D5000010BD0000902D002058280020E4F703008DD20300D3CD0300446675546172670031
:20D520005FCF0300A7D20300CD0C000005CF0300FFFF00000230000010B50C46002802D04D
:20D540000120086010BD2168002911D01C48421A814212D03C2A0DD23C303C3101220B78B9
:20D5600003701346491E401E521C3C2BF7D904E00E200BE03C2201F0AAFF00223C211048A9
:20D5800001F08AFD0E49891E08800020206010BD70B5054600223C21094801F07DFD084C21
:20D5A000A41E2188884201D00B2070BD3C220449284601F08CFF2088401C2080002070BD87
:20D5C000823F00208307FF22DB0E9A408907090E994000280BDA0007000F08388308FA484C
:20D5E0009B001B18D86990430843D86170478308F6489B001B1818689043084318607047AA
:20D6000070B50124F24960040860F24940108860F04940398860F04D6C602F20FEF7B6FDAC
:20D62000AC60EE4D00242F206C61FEF7AFFD2C7170BDF0B5E94F2821BC6841430D19396962
:20D640004A1C09D028224A431619AB68B268934204D8D21AB26069623861F0BD0A4602E066
:20D660000A46796A9B1B4E1C0BD028264E433719BE689E42F4D328264E433619B768FF1A1A
:20D68000B760AB60696228214A4311194862F0BD70B5D24C2269A5681346114606E0814212
:20D6A00007D00A46282671434919496A4E1CF6D170BD002EFCD08A420CD1282043435819EC
:20D6C000406A2061401C05D1C34B01209860002363616071282041434819282381685A4310
:20D6E000406A52195062421CE2D028225043401982685118816070BDF8B5B84C2569681CF9
:20D7000035D0B748002640686169401A07023F0A19E028204543A0682A189068B84214D8D0
:20D72000A3693F1A8619556A002B09D0116AD0699847002807D00022114601F0FFFD02E048
:20D74000D169106A8847681CE3D1A178E078814206D1401CC0B2E070022801D10020E07079
:20D760009E490006800D1C310E5000F0BAF9F8BDF8B50446994800270169009146785CE038
:20D780009648F100C2688D1851E0601C07D0934A28209268604321468018446A24E0287854
:20D7A000182141436A68401CC0B252182870A978884200D12F70894B516828209B6848434C
:20D7C000C0181368012B34D1037E002B31D19368C360D368036113694361526902627F4A52
:20D7E0005279002A00D0C7607C4BC2685B6996469C46D31A1A027B4B120A9A4202D20369C3
:20D80000D21808E0724663469A1A12020369120A934202D99A1A826000E08760C76001222E
:20D8200007610276921E42620846FFF702FF601CABD1287869788842A7D13046761EF6B202
:20D8400000289DD1654801690098814201D00120F8BD0020F8BD644900200860486088607F
:20D86000C860614940390860486045E7FEB50020C0435A4D02906869019068462E6900F07B
:20D8800035F9074600F04FF90446002F08D002AA0199009800F08FF90298FFF769FF06E050
:20D8A0000298FFF765FF002801D1002C02D0304600F0AAF900206871FEBDFFB59807002448
:20D8C00081B01E4615460F4600280BD1002E09D0FFF796FE41490A9888610F703246002042
:20D8E0008E6008E0072005B0F0BD28234343D4509B181C76401CB842F7DB28204743BB19C1
:20D90000032048700F461846CB6019461830002218232E465E43D3005B181C705C709D708A
:20D9200058603018521C032AF5DB0020C0433861BC70FC7001242D482405046003211420A9
:20D94000FFF740FE224880380460254C0198A06003211120FFF736FE606878610020C2E71A
:20D9600070B51E4CA568002D06D0002A06D0002804D00023247809E0082070BD072070BDBB
:20D9800028265E43AE59002E04D05B1CA342F7DB042070BD282401265C432E516419E261BF
:20D9A00061600360002070BD07494868C005C00D2CD010381CD50207120F083A9208920097
:20D9C0005118C96919E0000000ED00E000E400E080E100E040130140001001406028002054
:20D9E00000150140FFFF7F004011014080E200E08108B14A8900891809688007C00EC1400B
:20DA00000806800F012803D0032803D0022070470020704701207047FEB50446A74817469E
:20DA200082680D46002A0CD001788C4201D2052D01D20720FEBD2146282359435358012B7D
:20DA400001D00820FEBD8818406801281DD00026FFF7AAFFC00099490190C9684018694684
:20DA600000F018F9002812D0012144600160944949680830E2C091490198C9684118009877
:20DA8000487000F02EF80020FEBD2E46E0E70420FEBDF8B5894D0446A868002809D0297844
:20DAA0008C4201D30720F8BD282161434058012801D00820F8BDFFF777FFC600E86869465B
:20DAC000301800F0E7F8002809D0022112C0E86831180098487000F004F80020F8BD04206B
:20DAE000F8BD0120774900050860704710B5734900238A78CC78A24212D0521CD2B28A70D0
:20DB0000022A00D18B708A786C4B92001C339A580260486910180002000A4861012010BDA3
:20DB20000360002010BDF8B5644801690091457833E06248E900C0680E1834782AE01820A2
:20DB400060437168641C0818B178E4B2A14200D100240168022902D003291BD113E0574A00
:20DB600040682821926841438F18397E002911D0FFF78EFD002038760CE028277843C018B1
:20DB80000276406A03E04D4900228B680869471CF3D108617078A042D1D128466D1EEDB2D0
:20DBA0000028C6D1454801690098814201D00120F8BD0020F8BDF7B5404C0025A7682369E0
:20DBC0001EE028215943C9198E68864202D9301A886017E0801B751900268E600E764E6946
:20DBE0009C464B6AB646002E0AD0019E76193602360ACE6076460E6116684E626146116045
:20DC0000591CDED12361FEBDF8B52C4801694A1C3DD028225143826889188E6828494C681F
:20DC200047690079E11B0D022D0AED1C002815D10120254A00045060234A403A506021491D
:20DC4000400080310860214908602149012008602F20FEF79BFA194901200871B54200D208
:20DC60003546E81900021649000A4031086014494968001B091B0902090A0002C91C000A88
:20DC8000814203D901200F4940040860F8BDFFF7B7FCF8BD42788378521C934200D10022C2
:20DCA0000378934201D1002070470A6041684078182250430818704700E400E06028002090
:20DCC0000015014000E200E04013014000E100E00010014010B50446082904D000221146F9
:20DCE000104601F02BFB21686068884710BD1CB501910090024A0821684601F09DFA1CBD53
:20DD0000D5DC03000A48026803210A4302600948804709480047FEE7FEE7FEE7FEE7FEE797
:20DD2000FEE7000005480649064A074B70470000240500404DDD0300C1C003009830002007
:20DD4000983C00209834002098340020F8B500F035F82B4E002804D02A4870602A49F01300
:20DD600088612A480124018CC9B201290DD1818C09070AD1018D0906090F042905D1808D56
:20DD80000006000F01D1224884600027B461214D6F60A8058460686800280ED1C820FEF790
:20DDA00005FA1D487F1C8742F5D30020B06101208007846068680028FCD0F8BD1348018CB5
:20DDC000C9B2012917D1818C090714D1018D09060A0F03D1828D1206120F0ED0090F0129C2
:20DDE00003D1828D1206120F07D0032903D1808D0006000F01D0002070470120704700008E
:20DE000000050040DFFF07C0006C0040C00F00F000060040000100408813000030B585B071
:20DE2000002822D00388FE4CA34220D0FD4B1B78002B1CD0FB4B10255B1C1D7059700024C0
:20DE400001259A70032269460A820094019402940394028A0A808D708C8004A902910393E7
:20DE600000886946A6DF05B030BD0E20FBE70820F9E7F0B58BB0044602276846077300268B
:20DE800009968784C68408A80A900D46A18A208809AAA5DF002804D0E16A00291AD08847BE
:20DEA00018E06846008CC007C00F13D068460682208803A9A8DF002813D1A97E28461B30BA
:20DEC00001220B0001F055FC09430F1B202224263E284300FF20FE3069460882208803A94D
:20DEE000A8DF0BB0F0BD00960AE0062219E069460A71029022E0204690470020F1E700920D
:20DF00002B8B022BF3D2F0E700971DE003201AE0042018E0052016E0298B032905D20322BE
:20DF200008212046FFF77AFFDBE741780278080210436946888003D006200090A26ADAE784
:20DF40000720FAE7092000906946A26AD3E70322E7E730B585B00D46040038D0002D36D0EC
:20DF60006868002833D00020C043AF4B20800FCB049301AB07C3AD4869460880891C01A888
:20DF800063DF002822D1221D69460120A0DF00281CD168468078A071204600F0CEF8002886
:20DFA00014D1204600F055F900280FD12946204600F002F9002809D16868A062A868002804
:20DFC00000D0E06297490120087000204BE70E2049E73EB5002828D0002926D0826A002ABE
:20DFE00023D00A88102A21D0112A30D0502A1FD0512A1AD104460846891D0A78022A14D196
:20E000004A88238A9A4210D1807A04280DD006280BD0052809D0891C2046FFF72AFF002860
:20E0200003D0E16A002900D088473EBD898810E0CA8803899A42F8D1082200928A7F6B4605
:20E040001A7120310291826A694690473EBD0021C94301803EBDF0B585B00A4605002DD00F
:20E0600028886F4988422BD06E480078002827D06C4C1020641C2070072060700127A770F8
:20E080000321684601820026E11C104600F04CF801466846008A0918684601820096019680
:20E0A00002960396298A01808770868004A80394029028886946A6DF05B0F0BD0E20FBE7D3
:20E0C0000820F9E7F0B585B00A46050028D028885349884226D053480078002822D0514C3B
:20E0E0001120641C20700127684607820026611C104600F019F801466846008A0918684638
:20E1000001820096019602960396298A01808770868004A80394029028886946A6DFCBE782
:20E120000E20C9E70820C7E70870020A4A70020C8A70000EC8700420704730B58FB0054655
:20E140001C21684601F022FA694608780421084369460870002401940394049405940694E6
:20E16000A87908A9887031486946801C0884601C00070794000F0C77103048778A7FF920B4
:20E180000240921CE7200240012002438A77142109A801F0FBF908A8099007A80A906946D3
:20E1A0008C851420CC8508860D942B46A888083309AAA2DF0FB030BDF0B58FB00F4605465A
:20E1C0001C21684601F0E2F968460178022631430170002401940394049405940694A97917
:20E1E00008A8817011496846091D0184601C0107090F103168460794017700200146684618
:20E200004177817FF9200140891CE72001400120014368468177142109A801F0B7F907E086
:20E22000FFFF000088280020FCF703003015000008A8099007A80A9068468685C4850686B5
:20E240000D972B46A888203309AA6946A2DF0FB0F0BD30B58FB005461C21684601F096F9FD
:20E2600069460878082108431022104369460870002401940394049405940694A87908A962
:20E280008870144869460884601C00070794000F0C7710304877887FF9210840801CF72123
:20E2A000084010430121084369468877142109A801F06CF908A8099007A80A9069468C851A
:20E2C0001720CC8508860D942B46A888103309AAA2DF6FE731150000FFB583B0074600207F
:20E2E0000C9C8646267805463AE07868A90041180A88684682804988C1800022694601A8F7
:20E3000065DF002810D1684601780598814226D17046002801D0002200E002222078891824
:20E3200041181F2902D90C2007B0F0BD7146002908D1401CC0B2411C069B049A21701A54AF
:20E3400001208646217806980A18694601A865DF0028E9D1694620780978401820706D1CC0
:20E360003888A842C1DC7046002804D020780699801B401E88550020D6E7F8B51546069C10
:20E380001E46074602220094FFF7A6FF002806D133461022294638460094FFF79DFFF8BD07
:20E3A000F7B582B000260546167000681446002805D02846039900F0CAF8060008D168794D
:20E3C00000281ED02078039F001D1F2802D90C2005B0F0BD684679DF0028F9D1217803226A
:20E3E000481C20707A5421781922481C20707A542078C1196846008800F0A4F821784018A0
:20E400002070A8790223002810D02078039A411C2170135420780399471C012227700A54E5
:20E420002078AA79471C039927700A54A868002815D00021415620788C460246C01C03992E
:20E440001F28C4D8501C20708B5422780A23501C20708B5420786246431C23700A54A8899B
:20E46000002809D028460094062202210C30039BFFF783FF0600ABD1A88A002809D02846D9
:20E480000094072203211430039BFFF776FF06009ED1A88B002809D0284600941522142137
:20E4A0001C30039BFFF769FF060091D1686A002805D02246039900F07FF8060088D1A86A01
:20E4C000002805D02246039900F0B5F8060084D13020405D002806D022462846039900F0F6
:20E4E000DCF80600C7D1304672E770B50C4692B000216A46117007251171002809D0817927
:20E5000049070CD502A9FFF74BFF002808D102AE00E00026002C0ED0A079002802D028469D
:20E5200012B070BD01AA0AA92046FFF739FF0028F6D10AAA00E0002268460379017830463C
:20E5400072DFEDE70870000A487002207047F8B514780746A01C15460E461F2803D83879BF
:20E56000801C1F2801D90C20F8BD1D20001B80B26946864608803019801C7DDF0028F3D143
:20E580003868022805D168460088704501D8092107E038790821002801D0704501D96846F6
:20E5A0000088421C3255641CE2B2B1542978801C081828700020F8BDF8B50D461178064636
:20E5C000881D14461F2801D90C20F8BD33880720062BFAD31927FF01BB4202D94D4A9342D6
:20E5E000F3D17288062AF0D3BA4202D9494FBA42EBD1484FBB4203D0BA4201D09342E4D87E
:20E60000481C052220706A5420781222411C21702A54207841193088FFF794FF21784018C5
:20E62000C0B2207041197088FFF78CFF2178401820700020F8BD70B5054600790E46801CD6
:20E640001446C0B21178821C8A181F2A01D90C2070BD0A46491C401C2170B0542078FF224A
:20E66000411C21703254207881192888FFF76AFF21784018C0B22070AA88002A09D0A968AC
:20E68000002908D0801900F022FF2078297940182070002070BD072070BDF7B582B0029894
:20E6A0001446C06A0F46002832D0029800252030009028E00298C16A0C2068430E18217855
:20E6C00030794A1CC01C2270785421781622481C20707A542078C1193088FFF733FF217873
:20E6E0004018C0B22070B288002A09D0B16800290ED0C01900F0EBFE207831794018207087
:20E700006D1C0098EDB2007CA842D3D800205FE607205DE6FFFF000038B56749674A48883D
:20E7200090420FD04A78664C521CD2B24A70237B934208D3083175DF002803D0A1690029FF
:20E7400000D0884738BD00254D70217C002907D03B2176DF002803D0A169002900D0884728
:20E7600061690029EED068460095884738BD70B5054601461C225248FDF75AFD4E4C002647
:20E7800026702968002907D00822A01800F09FFE204608307ADF02E0474808307BDF0028C1
:20E7A00008D1401E608044486670464A0021001DFFF7D6F870BD10B53F484068FFF769F9D5
:20E7C00010BDF8B53C48103000F069F800263A4D3B4C002806D06169002919D001200090EB
:20E7E000684614E02878002804D0616900290FD00096F5E7687800280CD0A16800226868B8
:20E80000FFF70AF9002803D0A169002900D088472E70F8BD6168F1E7F8B5294C028800276B
:20E82000254DE689102A18D029464968112A21D0122A2DD0502A0FD1801D0288B2420BD1FF
:20E84000028B022A08D1C27E837E10021843C007C00F13D0FFF7B5FFF8BD81886980014667
:20E86000154808221631103000F031FE6F70002EF0D0F8BD0020C04368806F700846FFF7BB
:20E8800008F90028F5D0A1690029F2D08847F8BD811D09480822103000F019FEDAE7418827
:20E8A000054808300288914204D34088814201D8012070470020704790280020FFFF0000B6
:20E8C000CC2D002019E7030031B5054C04E0401E00902046FDF77AFC00980028F7D138BDC6
:20E8E000E703000018225043FE4A00218018017181604161012281610261C1607047FFB577
:20E9000081B0F94C049B039A054626691A4303200092002E03D1002A0ED001222261276919
:20E92000039A0126360792003B0000F022FF072707162940526127000222EFE770693269FC
:20E9400092B25043326933691204920C9BB2594329DF002812D102210FE0084628DF00286A
:20E960000CD10399002901D0032106E00499002916D12978042946D017E0216105B0F0BDAE
:20E980007069326992B25043326993B24B4301461846039A29DF0028F0D10499002901D0F4
:20E9A0000421EAE72978042920D00521E5E773693069366980B2434368681B189B18B6B2C7
:20E9C0004E43301880181946049A29DF0028E9D0D4E7306980B24843696880188A08696902
:20E9E00029DF0028CAD1009900290CD00621C4E77069316989B24843316989B200F0D9FD08
:20EA000028DF0028BAD10721B7E7F8B5B54918230A780F205A435418241DB3492278266970
:20EA2000CF68022A1BD001252D07042A2AD0052A5BD1286981B2304600F0BBFD0146A36877
:20EA400028699A1980B24843101A820860681818861928694B1C80B25843801B34E0B8023C
:20EA600062686169121A0918A3683018181801239B029A4202D2920829DF31E0FF220132BA
:20EA800029DF2DE0E268974914205043F4314018001D0BC8B04203D160685943814218D02E
:20EAA000022A16D0286981B2304600F082FD0146286980B24843301A820828694B1C80B208
:20EAC000584363689B19C01A83082046FFF717FF06E0286981B2304600F06BFDC01928DFED
:20EAE000002802D17F4901228A70F8BDF8B57D4C069E65780A2D1DD027787D19EDB20A2D5B
:20EB000001D30A3DEDB218277D432D192871AA6103C9EE60AB6069612861A1780020002978
:20EB200004D1FFF772FF112800D100206178491C6170F8BD0420F8BD38B5024669481823B1
:20EB400001785943081803690179022B0AD014246343644CF434E4588368009383691030F7
:20EB6000A04738BD604B14331C68F5E7F8B55D4B9978012914D100255B499D700A69082A77
:20EB800005D002280FD003280AD10D2006E0022807D00D7000F025FA002801D0FFF7CCFF37
:20EBA000F8BD0D61F6E74F48182403784E496343CC681818641C001DCC600378022B05D11F
:20EBC0004668A102B14201D3012700E00027052B01D1072A03D00021042B02D003E00121C1
:20EBE000FAE7072A03D00026042B02D007E00126FAE74068A302834201D3002A1AD0002000
:20EC0000314301433943C5D0374E28463561FFF793FF344C2078FFF765FEF5606078401E1E
:20EC200060702078401CC0B220700A28B2D30A382070AFE70120E3E770B500252A4C2948D3
:20EC4000E56025610570457085702E463046FFF749FE761C0A2EF9D3012212076560516952
:20EC600028461269491E92B25143E560A1601D49F4310D608D600D61CD601B4914310D6090
:20EC8000888001212170206170BDF8B5164A044610780E46002830D0002C30D0002E2ED058
:20ECA000206800282BD0012000076768016989B28F4228D8102F26D3A168002923D09568E2
:20ECC000794343694A19006980B243439A421AD801200007006980B2814212D901200007E1
:20ECE000006903E0E82D0020A828002080B2394600F05FFC002906D103E00820F8BD0E20B9
:20ED0000F8BDB80701D00720F8BDBD49486801281CD00F461421BB4A21C641438E18756092
:20ED2000236853506168B160A168F160A268616800235143012212075B1C14699BB2A4B214
:20ED40008C4205D21469A4B2091B02E00420F8BD00211469A4B265191469A4B28C42EBD985
:20ED6000BD60401C336178600020F8BDF8B50446A3481E46007815460F46002807D0002F3D
:20ED800007D0002C05D02068002817D103E00820F8BD0E20F8BD9B48016800290ED0C268E3
:20EDA000816840684A4310186268904206D9002D04D0A94202D3A819884201D90720F8BD90
:20EDC000384600F008F9002811D0304600F003F900280CD0606800F0FEF8002807D02B4637
:20EDE0003A46214602200096FFF780FEF8BD1020F8BDFFB5824881B000781F4616460D462B
:20EE0000002808D0002D08D00198002805D02868002817D103E00820B0E50E20AEE5794C91
:20EE2000206800280ED0E168A0686268414389186A68914206D9002E04D0B04202D3F119AD
:20EE4000814201D9072099E5019800F0C4F800281BD0384600F0BFF8002816D0686800F025
:20EE6000BAF8002811D068683246C119019800F02EFB00962868142148432458002203215B
:20EE80002846019BA047002078E5102076E5F8B505465B480F460078002805D0002D05D012
:20EEA0002868002821D103E00820F8BD0E20F8BD544C00262068002817D0A168E0684843CC
:20EEC00061684118686881420FD900F084F800280DD0296814225143091968684A68896834
:20EEE000801A00F066FB002903D00720F8BD1020F8BD3B460022294604200096FFF7F6FDB5
:20EF0000F8BD3F4A1278002A0DD000280DD000290BD00268002A08D0394A14321368002B3E
:20EF200005D004207047082070470E20704702230B600068106000207047F8B504463048AF
:20EF40001E46007817460D46002807D0002D07D0002C05D0206802281BD103E00820F8BDC3
:20EF60000E20F8BD264814300068002811D0084600F031F800280ED0304600F02CF800286C
:20EF800009D03B462A46214602200096FFF7AEFDF8BD0720F8BD1020F8BD08B5184A1278C8
:20EFA000002A05D0002805D00268022A11D103E0082008BD0E2008BD114A14321268002AD5
:20EFC00007D00B460022014604200092FFF78EFD08BD072008BD800701D000207047012068
:20EFE0007047084910B5F43949780020002906D0FFF70BFD002802D0112800D1002010BD48
:20F00000A8280020DC2E002070B500250C290ED304464318008941000919581A0A38C2B2BD
:20F020001748022A027002D30A318B4201D2092070BD144800F04BFA134914480A8882422E
:20F0400002D02388934217D14988814202D06088884211D10D4A0323521E20891B03A842DE
:20F060000AD9690009194989914203D09E896D1CB142F4D1002070BD0B2070BD00207047C6
:20F08000C4280020F02E002080100010FFFF000010B5FDF7ABF810BD10B50446002A02D054
:20F0A0001088002210E00A48FBE7030A00020343A05C584003061B0F43401803584083B2EB
:20F0C0001806C00C5840521C8A42EED310BD0000FFFF00004B48002101704C484A4A026039
:20F0E0008160C160016108224161426081610846704710B500291DD000220A60434A5368A8
:20F10000002B1BD0202817D85B1E5360D0682423401CD060106914684343E3180B60012366
:20F1200083409169401C19434007400F91611061002010BD0E2010BD0C2010BD042010BD8F
:20F14000F0B5324A0646916800292BD057691020791A4907490F14680B4624254D436519D6
:20F16000B54206D1012495698C4065400020956104E0491C4907490F8F42EED1491C4E07DC
:20F18000760F956901210C469C402B4623420AD19368002B07D05B1E936053685B1C53609D
:20F1A0003346F0E70420F0BD184A2423117C1268491E4907490F594320315050002070470B
:20F1C00070B500281AD0002918D0104AD368002B16D05B1ED360936824265B1C936053692A
:20F1E00015681C467343EE1820330660E858641C08606007400F5061002070BD0E2070BD84
:20F20000042070BDC5280020FC2E00201C30002030B5CB0008339DB293070024002B01D0E6
:20F22000072030BD3B4B9A605219DA605C701C7058809980002030BDF7B5364C0E466088D5
:20F24000814237D8344F00F069F822786078A188884201DA401C00E00020C0B2904202D155
:20F2600000F062F824E065786078884201DA401C00E00020607000F057F8BD4218D0A0688C
:20F28000EF000299C151009900290CD0002E0AD0608832464543E068281800F018F9A068B3
:20F2A0003818868002E00021381881800020FEBD0420FEBD0920FEBD0EB504E068468188A8
:20F2C000029A0098904702AA01A9684600F003F80028F3D00EBD70B50E4B05241D785E786C
:20F2E000AE4215D01D781C789E88B44201DA641C00E000241C705C88DE686C43A41904600F
:20F300009B68E800C418A4880C80185800241060204670BDCC280020FFFF000072B606484F
:20F320000168491C0160704703490868401E086000D162B670470000DC280020BFF34F8F11
:20F3400003490248C860BFF34F8FFEE70400FA0500ED00E010B5002904D000221146104619
:20F36000FFF7ECFF00F010F810BD10B50021024A0846FFF761FF10BD55F3030010B50846E6
:20F380001146FCF771FF10BDF8B5384C2078002837D02069002807D00026E068002805D0FB
:20F3A0000025002E04D013E00126F6E70125F8E7684651DF052806D0002806D000221146D2
:20F3C000FFF7BCFF04E0012602E0216900988847002D12D1608869460880A06861DF0528FA
:20F3E00006D0002806D000221146FFF7A7FF04E0012502E0E168A0688847002ED8D0002D15
:20F40000CFD0F8BD70B5002901D08C0701D0072070BD164C0125A16062801549636010DF46
:20F420000028F5D1257016202EDF70BD002803D00E49C860002070470E207047002803D0A8
:20F440000A490861002070470E20704710B507484068002807D08047002803D0002211463E
:20F46000FFF76CFF10BDFFF78FFF10BDE02800207DF30300034610B50B439B070FD1042A66
:20F480000DD308C810C9121FA342F8D018BA21BA884201D9012010BD0020C04310BD002AAC
:20F4A00003D0D30703D0521C07E0002010BD03780C78401C491C1B1B07D103780C78401C61
:20F4C000491C1B1B01D1921EF1D1184610BDF8B5042A2CD3830712D00B78491C0370401C25
:20F4E000521E83070BD00B78491C0370401C521E830704D00B78491C0370401C521E8B07F9
:20F500009B0F05D0C91ADF002023DE1B08C90AE0FCF78EFEF8BD1D4608C9FD401C46B440B8
:20F520002C4310C0121F042AF5D2F308C91A521EF0D40B78491C0370401C521EEAD40B78EC
:20F54000491C0370401C521EE4D409780170F8BD01E004C0091F0429FBD28B0701D50280F7
:20F56000801CC90700D00270704700290BD0C30702D00270401C491E022904D3830702D5EE
:20F580000280801C891EE3E70022EEE70022DFE70378C2781946437812061B0219438378A2
:20F5A000C0781B04194311430902090A000608437047002203098B422CD3030A8B4211D366
:20F5C00000239C464EE003460B433CD4002243088B4231D303098B421CD3030A8B4201D39D
:20F5E00094463FE0C3098B4201D3CB01C01A524183098B4201D38B01C01A524143098B422D
:20F6000001D34B01C01A524103098B4201D30B01C01A5241C3088B4201D3CB00C01A524193
:20F6200083088B4201D38B00C01A524143088B4201D34B00C01A5241411A00D201465241FB
:20F64000104670475DE0CA0F00D04942031000D34042534000229C4603098B422DD3030A47
:20F660008B4212D3FC22890112BA030A8B420CD3890192118B4208D3890192118B4204D305
:20F6800089013AD0921100E08909C3098B4201D3CB01C01A524183098B4201D38B01C01A88
:20F6A000524143098B4201D34B01C01A524103098B4201D30B01C01A5241C3088B4201D37F
:20F6C000CB00C01A524183088B4201D38B00C01A5241D9D243088B4201D34B00C01A52417F
:20F6E000411A00D20146634652415B10104601D34042002B00D54942704763465B1000D31A
:20F70000404201B50020C046C04602BD704770477047754600F022F8AE460500694653469B
:20F72000C008C000854618B020B5FEF7FBFA60BC00274908B6460026C0C5C0C5C0C5C0C525
:20F74000C0C5C0C5C0C5C0C5403D49008D4670470446C046C0462046FCF7FFFC004870479C
:20F760003830002001491820ABBEFEE726000200704730B47446641E2578641CAB4200D256
:20F780001D46635D5B00E31830BC184702000000000000000000000000000000040000009F
:20F7A000000000000000000000000000000000000000000035C4030000000000000000004D
:20F7C000020000000000000000000000000000000000000000000000030000000000000024
:20F7E0000000000005000000000000000000000000000000000000000000000023D1BCEA6A
:20F800005F782315DEEF1212000000002CF8030000280020F400000004C1030020F90300A1
:20F82000F4280020A413000020C103000000000000000000000000000000000000000000F1
:20F840000000000000000000000000000000000000000000000000000000000000000000A8
:20F8600000000000000000000000FFFF000000003200000000000000000000000000000058
:20F88000000000000000000000000000000000000000000000000000000000000000000068
:20F8A000000000000000000000000000000000000024F40000000000000000000000000030
:20F8C000000000000000000000000000000000000000000000000000000000000000000028
:20F8E000000000000000000000000000000000000000000000000000000000000000000008
:20F900000000000000000000000000000000000000000000000000000000000000000000E7
:20FC00000100000000000000FE0000000000000000000000000000000000000000000000E5
:020000041000EA
:0410140000C0030015
:040000050003C0C173
:00000001FF

View File

@ -0,0 +1,30 @@
/*
* S110/S120/S130 License Agreement
*
* Copyright (c) 2015, Nordic Semiconductor ASA, All rights reserved.
*
* Redistribution. Redistribution and use in binary form, without modification,
* are permitted provided that the following conditions are met:
*
* • Redistributions must reproduce the above copyright notice and the following
* disclaimer in the documentation and/or other materials provided with the
* distribution.
* • Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* • No reverse engineering, decompilation, or disassembly of this software is
* permitted.
*
* DISCLAIMER.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* /

View File

@ -0,0 +1,36 @@
{
"name": "ble-nrf51822",
"version": "2.7.1",
"description": "Nordic stack and drivers for the mbed BLE API.",
"keywords": [
"Bluetooth",
"BLE",
"mbed",
"mbed-official"
],
"author": "Rohit Grover",
"repository": {
"url": "git@github.com:ARMmbed/ble-nRF51822.git",
"type": "git"
},
"homepage": "https://developer.mbed.org/teams/Nordic-Semiconductor/",
"licenses": [
{
"url": "https://spdx.org/licenses/Apache-2.0",
"type": "Apache-2.0"
},
{
"type": "LicenseRef-softdevice_nrf51822_licence_agreement.txt"
}
],
"dependencies": {
"ble": "^2.6.0",
"nrf51-sdk": "^2.4.0"
},
"extraIncludes": [
"source/btle",
"source/btle/custom",
"source/common"
],
"targetDependencies": {}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

View File

@ -0,0 +1,78 @@
# Change Log
## [v2.2.1](https://github.com/ARMmbed/nrf51-sdk/tree/v2.2.1) (2016-01-27)
[Full Changelog](https://github.com/ARMmbed/nrf51-sdk/compare/v2.2.0...v2.2.1)
**Closed issues:**
- It's not possible to generate a debug build with nrf51-sdk 1.0.1 [\#11](https://github.com/ARMmbed/nrf51-sdk/issues/11)
**Merged pull requests:**
- Optimise to omit frame pointer even in a debug build [\#19](https://github.com/ARMmbed/nrf51-sdk/pull/19) ([LiyouZhou](https://github.com/LiyouZhou))
## [v2.2.0](https://github.com/ARMmbed/nrf51-sdk/tree/v2.2.0) (2016-01-11)
[Full Changelog](https://github.com/ARMmbed/nrf51-sdk/compare/v2.1.0...v2.2.0)
**Closed issues:**
- Update bootloader branch to sdk V10 [\#14](https://github.com/ARMmbed/nrf51-sdk/issues/14)
**Merged pull requests:**
- Add missing implementations for peer\_manager. [\#18](https://github.com/ARMmbed/nrf51-sdk/pull/18) ([pan-](https://github.com/pan-))
- Expose function in DM to calculate BLE hash [\#17](https://github.com/ARMmbed/nrf51-sdk/pull/17) ([andresag01](https://github.com/andresag01))
## [v2.1.0](https://github.com/ARMmbed/nrf51-sdk/tree/v2.1.0) (2016-01-08)
[Full Changelog](https://github.com/ARMmbed/nrf51-sdk/compare/v2.0.0...v2.1.0)
**Merged pull requests:**
- Add files from peer manager from nRF51 SDK 10.0.0 [\#15](https://github.com/ARMmbed/nrf51-sdk/pull/15) ([andresag01](https://github.com/andresag01))
## [v2.0.0](https://github.com/ARMmbed/nrf51-sdk/tree/v2.0.0) (2016-01-07)
[Full Changelog](https://github.com/ARMmbed/nrf51-sdk/compare/v1.0.1...v2.0.0)
**Closed issues:**
- nrf51-sdk generates warnings for old style declarations [\#10](https://github.com/ARMmbed/nrf51-sdk/issues/10)
**Merged pull requests:**
- Nordic sdk 10.0.0 [\#13](https://github.com/ARMmbed/nrf51-sdk/pull/13) ([LiyouZhou](https://github.com/LiyouZhou))
- Add ifdef to include correct mbed.h file in mbedOS [\#9](https://github.com/ARMmbed/nrf51-sdk/pull/9) ([andresag01](https://github.com/andresag01))
- Update files to Nordic sdk 9.0.0 [\#8](https://github.com/ARMmbed/nrf51-sdk/pull/8) ([LiyouZhou](https://github.com/LiyouZhou))
## [v1.0.1](https://github.com/ARMmbed/nrf51-sdk/tree/v1.0.1) (2015-12-10)
[Full Changelog](https://github.com/ARMmbed/nrf51-sdk/compare/v1.0.0...v1.0.1)
**Closed issues:**
- Need the ability to do version bump [\#1](https://github.com/ARMmbed/nrf51-sdk/issues/1)
**Merged pull requests:**
- Add GCC diagnostics to suppress unused-parameter warnings [\#7](https://github.com/ARMmbed/nrf51-sdk/pull/7) ([andresag01](https://github.com/andresag01))
## [v1.0.0](https://github.com/ARMmbed/nrf51-sdk/tree/v1.0.0) (2015-12-02)
[Full Changelog](https://github.com/ARMmbed/nrf51-sdk/compare/v0.0.1...v1.0.0)
**Closed issues:**
- Need to keep previous improvements while moving to nrf51-sdk [\#2](https://github.com/ARMmbed/nrf51-sdk/issues/2)
**Merged pull requests:**
- supress warnings for the sources in nRF51 SDK [\#6](https://github.com/ARMmbed/nrf51-sdk/pull/6) ([rgrover](https://github.com/rgrover))
## [v0.0.1](https://github.com/ARMmbed/nrf51-sdk/tree/v0.0.1) (2015-12-01)
[Full Changelog](https://github.com/ARMmbed/nrf51-sdk/compare/v8.1.0...v0.0.1)
**Merged pull requests:**
- Migrate changes from ble nrf51822 [\#4](https://github.com/ARMmbed/nrf51-sdk/pull/4) ([LiyouZhou](https://github.com/LiyouZhou))
## [v8.1.0](https://github.com/ARMmbed/nrf51-sdk/tree/v8.1.0) (2015-11-17)
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

View File

@ -0,0 +1,6 @@
Many of the files in this module have been inherited from the Nordic SDK for
nRF51822; they come with a BSD-like license offered by Nordic for use in mbed.
Some other files come from the mbed SDK, and are licensed under Apache-2.0.
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.
The BSD-like Nordic license can be found in BSD-3clause-Nordic.txt

View File

@ -0,0 +1,32 @@
# nrf51-sdk
Module to contain files provided by the nordic nRF51 SDK. The latest version of this module uses files from Nordic SDK 10.0.0. The files are extracted from [here](https://developer.nordicsemi.com/nRF5_SDK/nRF51_SDK_v10.x.x/nRF51_SDK_10.0.0_dc26b5e.zip).
## Changes made to Nordic files
The files are kept the same as much as possible to the Nordic SDK. Modifications are made in order to integrate with mbed.
- ble/common/ble_conn_state.c: Preprocessor tests regarding S110, S120 or S130 macro should be replace by TARGET_MCU_NRF51_XXK_SXXX tests
- `ble.h` in `source/nordic_sdk/components/softdevice/s130/headers/ble.h` has to be renamed `nrf_ble.h`. All files which include this file should be updated accordingly.
## Porting new versions of Nordic SDK
A list of files currently requierd by mbed is maintained in [script/required_files.txt](https://github.com/ARMmbed/nrf51-sdk/blob/master/script/required_files.txt). [A python script](https://github.com/ARMmbed/nrf51-sdk/blob/master/script/pick_nrf51_files.py) is written to help porting from nordic sdk releases. **required_files.txt** is parsed to find a list of filenames. The script searches for these filenames in the sdk folder, and copy then into the yotta module mirroring the folder structure in the sdk. **extraIncludes** is automatically added to module.json to allow direct inclusion of noridc headers with just the filename.
### Script usage
```
python pick_nrf51_files.py [options] <full-noridc-sdk-path> <nrf51-sdk-yotta-module-path>
options: --purge : to delete all existing files and start again
--dry-run : to list the files to be copied but not actually copy them
```
There are files in the sdk with the same filename but in different folder. This is dealt with by excluding certain directories. The excluded directories are listed in [pick_nrf51_files.py](https://github.com/ARMmbed/nrf51-sdk/blob/master/script/pick_nrf51_files.py).
After running the script, the changes in [the previous section](#changes-made-to-nordic-files) will have to be applied manually again.
Folder structure or even file name can change between releases of the nordic sdk, hence a degree of manual adjustment is needed when porting.
## Using Noridc Headers
The nordic sdk is written in C and yotta modules support C++. If you are trying to include Nordic files in a cpp program, you need to use the `extern "C"` keyword around the includes.
```c
extern "C" {
#include "softdevice_handler.h"
}
```

View File

@ -0,0 +1,51 @@
{
"name": "nrf51-sdk",
"version": "2.4.0",
"description": "Module to contain files provided by the nordic nRF51 SDK",
"keywords": [
"nordic",
"nrf51",
"sdk"
],
"author": "",
"repository": {
"url": "git@github.com:ARMmbed/nrf51-sdk.git",
"type": "git"
},
"license": "nordic",
"targetDependencies": {
"mbed-classic": {
"mbed-classic": "~0.0.1"
},
"mbed-os": {
"mbed-drivers": "*"
}
},
"extraIncludes": [
"source/nordic_sdk/components/ble/ble_radio_notification",
"source/nordic_sdk/components/ble/ble_services/ble_dfu",
"source/nordic_sdk/components/ble/common",
"source/nordic_sdk/components/ble/device_manager",
"source/nordic_sdk/components/ble/device_manager/config",
"source/nordic_sdk/components/ble/peer_manager",
"source/nordic_sdk/components/device",
"source/nordic_sdk/components/drivers_nrf/ble_flash",
"source/nordic_sdk/components/drivers_nrf/delay",
"source/nordic_sdk/components/drivers_nrf/hal",
"source/nordic_sdk/components/drivers_nrf/pstorage",
"source/nordic_sdk/components/drivers_nrf/pstorage/config",
"source/nordic_sdk/components/libraries/bootloader_dfu",
"source/nordic_sdk/components/libraries/bootloader_dfu/hci_transport",
"source/nordic_sdk/components/libraries/crc16",
"source/nordic_sdk/components/libraries/hci",
"source/nordic_sdk/components/libraries/scheduler",
"source/nordic_sdk/components/libraries/timer",
"source/nordic_sdk/components/libraries/util",
"source/nordic_sdk/components/libraries/fds",
"source/nordic_sdk/components/libraries/fstorage",
"source/nordic_sdk/components/libraries/experimental_section_vars",
"source/nordic_sdk/components/softdevice/common/softdevice_handler",
"source/nordic_sdk/components/softdevice/s130/headers",
"source/nordic_sdk/components/toolchain"
]
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

View File

@ -0,0 +1,141 @@
#!/usr/bin/env python
# Copyright (c) 2015-2016 ARM Limited
# SPDX-License-Identifier: Apache-2.0
#
# 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.
import os, shutil, json, pprint, sys
from collections import OrderedDict
help_text = """
Usage: python {} [options] <full-noridc-sdk-path> <nrf51-sdk-yotta-module-path>
options: --purge : to delete all existing files and start again
--dry-run : to list the files to be copied but not actually copy them
""".format(os.path.basename(__file__))
# exclude path to avoid confusion over files of the same name
exclude_path = ["examples", "SVD", "s110", "s120", "s210", "s310", "nrf_soc_nosd", "serialization/connectivity",
'components/libraries/hci/config', 'components/libraries/bootloader_dfu/ble_transport']
def find(name, path):
paths = []
for root, dirs, files in os.walk(path):
if True not in [x in root for x in exclude_path]:
if name in files:
paths.append(os.path.join(root, name))
if len(paths) == 0:
print "-"*30
print "Warning! No {} found!!!!".format(name)
print "-"*30
return None
elif len(paths) > 1:
print "-"*30
print "Warning! More than one {} found!!!!".format(name)
print paths
print "-"*30
return None
else:
return paths[0]
def find_dir(dir_name, path):
paths = []
for root, dirs, files in os.walk(path):
if dir_name in root:
for fn in files:
paths.append(os.path.join(root, fn))
return paths
if __name__ == "__main__":
# define source and destination of copy
arg_valid = True
if len(sys.argv) not in [3, 4]:
arg_valid = False
else:
src_folder = sys.argv[-2]
yt_module_dir = sys.argv[-1]
for d in [src_folder, yt_module_dir]:
if not os.path.isdir(d):
arg_valid = False
print src_folder, "is not a folder"
purge = ("--purge" in sys.argv)
dry_run = ("--dry-run" in sys.argv)
if not arg_valid:
print help_text
sys.exit(1)
dst_folder = os.path.join(yt_module_dir, "source/nordic_sdk")
# build a file_list from required_files.txt
file_list = []
with open("required_files.txt", "r") as fd:
for line in fd:
line = line.strip()
if line.startswith("D "):
directory = line.split(" ")[-1]
file_list += find_dir(directory, src_folder)
elif not line.startswith("#") and line != '':
fn = os.path.basename(line).strip()
fn = find(fn, src_folder)
file_list.append(fn)
# remove everything from the destination folder
if purge and not dry_run and os.path.exists(dst_folder):
shutil.rmtree(dst_folder)
# copy files
extra_includes = []
for src in file_list:
if src:
rel_dst = os.path.relpath(src, src_folder)
dst = os.path.join(dst_folder, rel_dst)
print src, "->", dst
directory = os.path.dirname(dst)
if not os.path.exists(directory):
print "Creating directory:", directory
if not dry_run:
os.makedirs(directory)
if not os.path.isfile(dst):
print "Copying file", dst
if not dry_run:
shutil.copyfile(src, dst)
# build a list of extra includes to be added to module.json
if dst.endswith(".h"):
inc_rel_path = os.path.relpath(dst, yt_module_dir)
inc_dir_path = os.path.dirname(inc_rel_path)
if inc_dir_path not in extra_includes:
extra_includes.append(inc_dir_path)
# write extraIncludes in the module.json file
mod_json = os.path.join(yt_module_dir, "module.json")
print "-"*30
print "Writing extra_includes to {}".format(mod_json)
print "-"*30
for n in sorted(extra_includes):
print n
if not dry_run:
with open(mod_json, 'r+') as fd:
jobj = json.loads(fd.read(), object_pairs_hook=OrderedDict)
jobj['extraIncludes'] = sorted(extra_includes)
jdump = json.dumps(jobj, indent=2, separators=(',', ': '))
fd.seek(0)
fd.write(jdump)
fd.write("\n")
fd.truncate()

View File

@ -0,0 +1,38 @@
# Copyright (c) 2015-2016 ARM Limited
# SPDX-License-Identifier: Apache-2.0
#
# 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.
import os
with open("copyright_header.txt", "r") as fd:
header = fd.read()
path = "../source/nordic_sdk"
for root, dirs, files in os.walk(path):
for fn in [os.path.join(root, x) for x in files]:
with open(fn, "r+") as fd:
print "+"*35
print fn
s = fd.read()
start = s.find("/*")
end = s.find("*/")
copyright_str = s[start:end+2]
if "copyright (c)" not in copyright_str.lower():
s = header + "\n\n" + s
elif copyright_str is not header:
s = s.replace(copyright_str, header)
fd.seek(0)
fd.write(s)
fd.truncate()

View File

@ -0,0 +1,136 @@
# from cmsis-core-nrf51822:
cmsis-core-nrf51822/compiler_abstraction.h
cmsis-core-nrf51822/nrf.h
cmsis-core-nrf51822/nrf51.h
cmsis-core-nrf51822/nrf51_bitfields.h
cmsis-core-nrf51822/nrf_delay.h
cmsis-core-nrf51822/system_nrf51.h
source/system_nrf51.c
# from ble-nrf51822
source/nordic-sdk/components/ble/ble_radio_notification/ble_radio_notification.c
source/nordic-sdk/components/ble/ble_radio_notification/ble_radio_notification.h
source/nordic-sdk/components/ble/ble_services/ble_dfu/ble_dfu.c
source/nordic-sdk/components/ble/ble_services/ble_dfu/ble_dfu.h
source/nordic-sdk/components/ble/common/ble_advdata.c
source/nordic-sdk/components/ble/common/ble_advdata.h
source/nordic-sdk/components/ble/common/ble_advdata_parser.c
source/nordic-sdk/components/ble/common/ble_advdata_parser.h
source/nordic-sdk/components/ble/peer_manager/id_manager.h
source/nordic-sdk/components/ble/peer_manager/id_manager.c
source/nordic-sdk/components/ble/peer_manager/peer_manager_types.h
source/nordic-sdk/components/ble/peer_manager/ble_gatt_db.h
source/nordic-sdk/components/ble/peer_manager/ble_conn_state.h
source/nordic-sdk/components/ble/peer_manager/sdk_mapped_flags.h
source/nordic-sdk/components/ble/peer_manager/peer_database.h
# source/nordic-sdk/components/ble/common/ble_conn_params.cpp the file is called
source/nordic-sdk/components/ble/common/ble_conn_params.c
source/nordic-sdk/components/ble/common/ble_conn_params.h
source/nordic-sdk/components/ble/common/ble_date_time.h
source/nordic-sdk/components/ble/common/ble_sensor_location.h
source/nordic-sdk/components/ble/common/ble_srv_common.c
source/nordic-sdk/components/ble/common/ble_srv_common.h
source/nordic-sdk/components/ble/device_manager/config/device_manager_cnfg.h
source/nordic-sdk/components/ble/device_manager/device_manager.h
source/nordic-sdk/components/ble/device_manager/device_manager_peripheral.c
source/nordic-sdk/components/drivers_nrf/ble_flash/ble_flash.c
source/nordic-sdk/components/drivers_nrf/ble_flash/ble_flash.h
source/nordic-sdk/components/drivers_nrf/hal/compiler_abstraction.h
source/nordic-sdk/components/drivers_nrf/hal/nrf.h
source/nordic-sdk/components/drivers_nrf/hal/nrf51.h
source/nordic-sdk/components/drivers_nrf/hal/nrf51_bitfields.h
source/nordic-sdk/components/drivers_nrf/hal/nrf51_deprecated.h
source/nordic-sdk/components/drivers_nrf/hal/nrf_delay.c
source/nordic-sdk/components/drivers_nrf/hal/nrf_ecb.c
source/nordic-sdk/components/drivers_nrf/hal/nrf_ecb.h
source/nordic-sdk/components/drivers_nrf/hal/nrf_gpio.h
source/nordic-sdk/components/drivers_nrf/hal/nrf_gpiote.h
source/nordic-sdk/components/drivers_nrf/hal/nrf_nvmc.c
source/nordic-sdk/components/drivers_nrf/hal/nrf_nvmc.h
source/nordic-sdk/components/drivers_nrf/hal/nrf_temp.h
source/nordic-sdk/components/drivers_nrf/pstorage/config/pstorage_platform.h
source/nordic-sdk/components/drivers_nrf/pstorage/pstorage.c
source/nordic-sdk/components/drivers_nrf/pstorage/pstorage.h
source/nordic-sdk/components/libraries/bootloader_dfu/bootloader.h
source/nordic-sdk/components/libraries/bootloader_dfu/bootloader_types.h
source/nordic-sdk/components/libraries/bootloader_dfu/bootloader_util.h
# source/nordic-sdk/components/libraries/bootloader_dfu/bootloader_util_arm.c new file is called:
source/nordic-sdk/components/libraries/bootloader_dfu/bootloader_util.c
source/nordic-sdk/components/libraries/bootloader_dfu/dfu.h
source/nordic-sdk/components/libraries/bootloader_dfu/dfu_bank_internal.h
source/nordic-sdk/components/libraries/bootloader_dfu/dfu_ble_svc.h
source/nordic-sdk/components/libraries/bootloader_dfu/dfu_ble_svc_internal.h
source/nordic-sdk/components/libraries/bootloader_dfu/dfu_init.h
source/nordic-sdk/components/libraries/bootloader_dfu/dfu_init_template.c
source/nordic-sdk/components/libraries/bootloader_dfu/dfu_transport.h
source/nordic-sdk/components/libraries/bootloader_dfu/dfu_types.h
source/nordic-sdk/components/libraries/bootloader_dfu/experimental/dfu_app_handler.c
source/nordic-sdk/components/libraries/bootloader_dfu/experimental/dfu_app_handler.h
source/nordic-sdk/components/libraries/bootloader_dfu/hci_transport/hci_mem_pool_internal.h
source/nordic-sdk/components/libraries/crc16/crc16.c
source/nordic-sdk/components/libraries/hci/hci_mem_pool.c
source/nordic-sdk/components/libraries/hci/hci_mem_pool.h
source/nordic-sdk/components/libraries/scheduler/app_scheduler.c
source/nordic-sdk/components/libraries/util/app_error.c
source/nordic-sdk/components/libraries/util/app_util_platform.c
source/nordic-sdk/components/libraries/util/app_util_platform.h
source/nordic-sdk/components/libraries/util/common.h
source/nordic-sdk/components/libraries/util/nordic_common.h
source/nordic-sdk/components/libraries/util/nrf_assert.c
source/nordic-sdk/components/libraries/util/nrf_assert.h
source/nordic-sdk/components/libraries/util/sdk_common.h
source/nordic-sdk/components/libraries/util/sdk_errors.h
source/nordic-sdk/components/libraries/util/sdk_os.h
source/nordic-sdk/components/softdevice/common/softdevice_handler/ant_stack_handler_types.h
source/nordic-sdk/components/softdevice/common/softdevice_handler/ble_stack_handler_types.h
source/nordic-sdk/components/softdevice/common/softdevice_handler/softdevice_handler.c
source/nordic-sdk/components/softdevice/common/softdevice_handler/softdevice_handler.h
source/nordic-sdk/components/softdevice/common/softdevice_handler/softdevice_handler_appsh.c
source/nordic-sdk/components/softdevice/common/softdevice_handler/softdevice_handler_appsh.h
# source/nordic-sdk/components/softdevice/s130/doc/ble_api.dox uncertain of the origin of this file
source/nordic-sdk/components/softdevice/s130/include/ble.h
source/nordic-sdk/components/softdevice/s130/include/ble_err.h
source/nordic-sdk/components/softdevice/s130/include/ble_gap.h
source/nordic-sdk/components/softdevice/s130/include/ble_gatt.h
source/nordic-sdk/components/softdevice/s130/include/ble_gattc.h
source/nordic-sdk/components/softdevice/s130/include/ble_gatts.h
source/nordic-sdk/components/softdevice/s130/include/ble_hci.h
source/nordic-sdk/components/softdevice/s130/include/ble_l2cap.h
source/nordic-sdk/components/softdevice/s130/include/ble_ranges.h
source/nordic-sdk/components/softdevice/s130/include/ble_types.h
source/nordic-sdk/components/softdevice/s130/include/nrf_error.h
source/nordic-sdk/components/softdevice/s130/include/nrf_error_sdm.h
source/nordic-sdk/components/softdevice/s130/include/nrf_error_soc.h
source/nordic-sdk/components/softdevice/s130/include/nrf_mbr.h
source/nordic-sdk/components/softdevice/s130/include/nrf_sdm.h
source/nordic-sdk/components/softdevice/s130/include/nrf_soc.h
source/nordic-sdk/components/softdevice/s130/include/nrf_svc.h
source/nordic-sdk/components/softdevice/s130/include/softdevice_assert.h
source/nordic-sdk/components/drivers_nrf/hal/nrf_wdt.h
source/nordic-sdk/components/ble/common/ble_conn_state.c
source/nordic-sdk/components/ble/peer_manager/peer_data.c
source/nordic-sdk/components/ble/peer_manager/peer_data.h
source/nordic-sdk/components/ble/peer_manager/peer_data_storage.c
source/nordic-sdk/components/ble/peer_manager/peer_data_storage.h
source/nordic-sdk/components/ble/peer_manager/peer_database.c
source/nordic-sdk/components/ble/peer_manager/peer_id.c
source/nordic-sdk/components/ble/peer_manager/peer_id.h
source/nordic-sdk/components/ble/peer_manager/pm_buffer.c
source/nordic-sdk/components/ble/peer_manager/pm_buffer.h
source/nordic-sdk/components/ble/peer_manager/pm_mutex.c
source/nordic-sdk/components/ble/peer_manager/pm_mutex.h
source/nordic-sdk/components/libraries/experimental_section_vars/
source/nordic-sdk/components/libraries/fds/
source/nordic-sdk/components/libraries/fstorage/
source/nordic-sdk/components/libraries/util/sdk_mapped_flags.c
# from mbed-hal-nrf51822-mcu
mbed-hal-nrf51822-mcu/lib/nordic_sdk/components/libraries/crc16/crc16.h
mbed-hal-nrf51822-mcu/lib/nordic_sdk/components/libraries/scheduler/app_scheduler.h
mbed-hal-nrf51822-mcu/lib/nordic_sdk/components/libraries/util/app_error.h
mbed-hal-nrf51822-mcu/lib/nordic_sdk/components/libraries/util/app_util.h
# included from ble_conn_params.c
app_timer.h

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ble_radio_notification.h"
#include <stdlib.h>
static bool m_radio_active = false; /**< Current radio state. */
static ble_radio_notification_evt_handler_t m_evt_handler = NULL; /**< Application event handler for handling Radio Notification events. */
void SWI1_IRQHandler(void)
{
m_radio_active = !m_radio_active;
if (m_evt_handler != NULL)
{
m_evt_handler(m_radio_active);
}
}
uint32_t ble_radio_notification_init(nrf_app_irq_priority_t irq_priority,
nrf_radio_notification_distance_t distance,
ble_radio_notification_evt_handler_t evt_handler)
{
uint32_t err_code;
m_evt_handler = evt_handler;
// Initialize Radio Notification software interrupt
err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = sd_nvic_SetPriority(SWI1_IRQn, irq_priority);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Configure the event
return sd_radio_notification_cfg_set(NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, distance);
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup ble_radio_notification Radio Notification Event Handler
* @{
* @ingroup ble_sdk_lib
* @brief Module for propagating Radio Notification events to the application.
*/
#ifndef BLE_RADIO_NOTIFICATION_H__
#define BLE_RADIO_NOTIFICATION_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_soc.h"
/**@brief Application radio notification event handler type. */
typedef void (*ble_radio_notification_evt_handler_t) (bool radio_active);
/**@brief Function for initializing the Radio Notification module.
*
* @param[in] irq_priority Interrupt priority for the Radio Notification interrupt handler.
* @param[in] distance The time from an Active event until the radio is activated.
* @param[in] evt_handler Handler to be executed when a radio notification event has been
* received.
*
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
*/
uint32_t ble_radio_notification_init(nrf_app_irq_priority_t irq_priority,
nrf_radio_notification_distance_t distance,
ble_radio_notification_evt_handler_t evt_handler);
#endif // BLE_RADIO_NOTIFICATION_H__
/** @} */

View File

@ -0,0 +1,686 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ble_dfu.h"
#include "nrf_error.h"
#include "ble_types.h"
#include "ble_gatts.h"
#include "app_util.h"
#include "ble_srv_common.h"
#include "nordic_common.h"
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#define MAX_DFU_PKT_LEN 20 /**< Maximum length (in bytes) of the DFU Packet characteristic. */
#define PKT_START_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Start DFU Request. */
#define PKT_INIT_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Init DFU Request. */
#define PKT_RCPT_NOTIF_REQ_LEN 3 /**< Length (in bytes) of the Packet Receipt Notification Request. */
#define MAX_PKTS_RCPT_NOTIF_LEN 6 /**< Maximum length (in bytes) of the Packets Receipt Notification. */
#define MAX_RESPONSE_LEN 7 /**< Maximum length (in bytes) of the response to a Control Point command. */
#define MAX_NOTIF_BUFFER_LEN MAX(MAX_PKTS_RCPT_NOTIF_LEN, MAX_RESPONSE_LEN) /**< Maximum length (in bytes) of the buffer needed by DFU Service while sending notifications to peer. */
enum
{
OP_CODE_START_DFU = 1, /**< Value of the Op code field for 'Start DFU' command.*/
OP_CODE_RECEIVE_INIT = 2, /**< Value of the Op code field for 'Initialize DFU parameters' command.*/
OP_CODE_RECEIVE_FW = 3, /**< Value of the Op code field for 'Receive firmware image' command.*/
OP_CODE_VALIDATE = 4, /**< Value of the Op code field for 'Validate firmware' command.*/
OP_CODE_ACTIVATE_N_RESET = 5, /**< Value of the Op code field for 'Activate & Reset' command.*/
OP_CODE_SYS_RESET = 6, /**< Value of the Op code field for 'Reset System' command.*/
OP_CODE_IMAGE_SIZE_REQ = 7, /**< Value of the Op code field for 'Report received image size' command.*/
OP_CODE_PKT_RCPT_NOTIF_REQ = 8, /**< Value of the Op code field for 'Request packet receipt notification.*/
OP_CODE_RESPONSE = 16, /**< Value of the Op code field for 'Response.*/
OP_CODE_PKT_RCPT_NOTIF = 17 /**< Value of the Op code field for 'Packets Receipt Notification'.*/
};
static bool m_is_dfu_service_initialized = false; /**< Variable to check if the DFU service was initialized by the application.*/
static uint8_t m_notif_buffer[MAX_NOTIF_BUFFER_LEN]; /**< Buffer used for sending notifications to peer. */
/**@brief Function for adding DFU Packet characteristic to the BLE Stack.
*
* @param[in] p_dfu DFU Service structure.
*
* @return NRF_SUCCESS on success. Otherwise an error code.
*/
static uint32_t dfu_pkt_char_add(ble_dfu_t * const p_dfu)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.write_wo_resp = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
char_uuid.type = p_dfu->uuid_type;
char_uuid.uuid = BLE_DFU_PKT_CHAR_UUID;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = 0;
attr_char_value.init_offs = 0;
attr_char_value.max_len = MAX_DFU_PKT_LEN;
attr_char_value.p_value = NULL;
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
&char_md,
&attr_char_value,
&p_dfu->dfu_pkt_handles);
}
/**@brief Function for adding DFU Revision characteristic to the BLE Stack.
*
* @param[in] p_dfu DFU Service structure.
*
* @return NRF_SUCCESS on success. Otherwise an error code.
*/
static uint32_t dfu_rev_char_add(ble_dfu_t * const p_dfu, ble_dfu_init_t const * const p_dfu_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
char_uuid.type = p_dfu->uuid_type;
char_uuid.uuid = BLE_DFU_REV_CHAR_UUID;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint16_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof(uint16_t);
attr_char_value.p_value = (uint8_t *)&p_dfu_init->revision;
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
&char_md,
&attr_char_value,
&p_dfu->dfu_rev_handles);
}
/**@brief Function for adding DFU Control Point characteristic to the BLE Stack.
*
* @param[in] p_dfu DFU Service structure.
*
* @return NRF_SUCCESS on success. Otherwise an error code.
*/
static uint32_t dfu_ctrl_pt_add(ble_dfu_t * const p_dfu)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.write = 1;
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
char_uuid.type = p_dfu->uuid_type;
char_uuid.uuid = BLE_DFU_CTRL_PT_UUID;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 1;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = 0;
attr_char_value.init_offs = 0;
attr_char_value.max_len = BLE_L2CAP_MTU_DEF;
attr_char_value.p_value = NULL;
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
&char_md,
&attr_char_value,
&p_dfu->dfu_ctrl_pt_handles);
}
/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the S110 SoftDevice.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_connect(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
p_dfu->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for checking if the CCCD of DFU Control point is configured for Notification.
*
* @details This function checks if the CCCD of DFU Control Point characteristic is configured
* for Notification by the DFU Controller.
*
* @param[in] p_dfu DFU Service structure.
*
* @return True if the CCCD of DFU Control Point characteristic is configured for Notification.
* False otherwise.
*/
static bool is_cccd_configured(ble_dfu_t * p_dfu)
{
// Check if the CCCDs are configured.
uint8_t cccd_val_buf[BLE_CCCD_VALUE_LEN];
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = BLE_CCCD_VALUE_LEN;
gatts_value.offset = 0;
gatts_value.p_value = cccd_val_buf;
// Check the CCCD Value of DFU Control Point.
uint32_t err_code = sd_ble_gatts_value_get(p_dfu->conn_handle,
p_dfu->dfu_ctrl_pt_handles.cccd_handle,
&gatts_value);
if (err_code != NRF_SUCCESS)
{
if (p_dfu->error_handler != NULL)
{
p_dfu->error_handler(err_code);
}
return false;
}
return ble_srv_is_notification_enabled(cccd_val_buf);
}
/**@brief Function for handling a Write event on the Control Point characteristic.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_write_evt Pointer to the write event received from BLE stack.
*
* @return NRF_SUCCESS on successful processing of control point write. Otherwise an error code.
*/
static uint32_t on_ctrl_pt_write(ble_dfu_t * p_dfu, ble_gatts_evt_write_t * p_ble_write_evt)
{
ble_gatts_rw_authorize_reply_params_t write_authorize_reply;
write_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
if (!is_cccd_configured(p_dfu))
{
// Send an error response to the peer indicating that the CCCD is improperly configured.
write_authorize_reply.params.write.gatt_status =
BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
return (sd_ble_gatts_rw_authorize_reply(p_dfu->conn_handle, &write_authorize_reply));
}
else
{
uint32_t err_code;
write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
err_code = (sd_ble_gatts_rw_authorize_reply(p_dfu->conn_handle, &write_authorize_reply));
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
ble_dfu_evt_t ble_dfu_evt;
switch (p_ble_write_evt->data[0])
{
case OP_CODE_START_DFU:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_START;
if (p_ble_write_evt->len < PKT_START_DFU_PARAM_LEN)
{
return ble_dfu_response_send(p_dfu,
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
BLE_DFU_RESP_VAL_OPER_FAILED);
}
ble_dfu_evt.evt.ble_dfu_pkt_write.len = 1;
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = &(p_ble_write_evt->data[1]);
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_RECEIVE_INIT:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_RECEIVE_INIT_DATA;
if (p_ble_write_evt->len < PKT_INIT_DFU_PARAM_LEN)
{
return ble_dfu_response_send(p_dfu,
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
BLE_DFU_RESP_VAL_OPER_FAILED);
}
ble_dfu_evt.evt.ble_dfu_pkt_write.len = 1;
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = &(p_ble_write_evt->data[1]);
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_RECEIVE_FW:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_RECEIVE_APP_DATA;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_VALIDATE:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_VALIDATE;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_ACTIVATE_N_RESET:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_ACTIVATE_N_RESET;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_SYS_RESET:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_SYS_RESET;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_PKT_RCPT_NOTIF_REQ:
if (p_ble_write_evt->len < PKT_RCPT_NOTIF_REQ_LEN)
{
return (ble_dfu_response_send(p_dfu,
BLE_DFU_PKT_RCPT_REQ_PROCEDURE,
BLE_DFU_RESP_VAL_NOT_SUPPORTED));
}
ble_dfu_evt.evt.pkt_rcpt_notif_req.num_of_pkts =
uint16_decode(&(p_ble_write_evt->data[1]));
if (ble_dfu_evt.evt.pkt_rcpt_notif_req.num_of_pkts == 0)
{
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PKT_RCPT_NOTIF_DISABLED;
}
else
{
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PKT_RCPT_NOTIF_ENABLED;
}
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_IMAGE_SIZE_REQ:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_BYTES_RECEIVED_SEND;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
default:
// Unsupported op code.
return ble_dfu_response_send(p_dfu,
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
BLE_DFU_RESP_VAL_NOT_SUPPORTED);
}
return NRF_SUCCESS;
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event from the S110
* Stack.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_rw_authorize_req(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_rw_authorize_request_t * p_authorize_request;
p_authorize_request = &(p_ble_evt->evt.gatts_evt.params.authorize_request);
if (
(p_authorize_request->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
&&
(p_authorize_request->request.write.handle == p_dfu->dfu_ctrl_pt_handles.value_handle)
&&
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ)
&&
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
&&
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
)
{
uint32_t err_code;
err_code = on_ctrl_pt_write(p_dfu, &(p_authorize_request->request.write));
if (err_code != NRF_SUCCESS && p_dfu->error_handler != NULL)
{
p_dfu->error_handler(err_code);
}
}
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the S110 SoftDevice.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_write(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
if (p_ble_evt->evt.gatts_evt.params.write.handle == p_dfu->dfu_pkt_handles.value_handle)
{
// DFU Packet written
ble_dfu_evt_t ble_dfu_evt;
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PACKET_WRITE;
ble_dfu_evt.evt.ble_dfu_pkt_write.len = p_ble_evt->evt.gatts_evt.params.write.len;
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = p_ble_evt->evt.gatts_evt.params.write.data;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
}
}
/**@brief Function for handling the BLE_GAP_EVT_DISCONNECTED event from the S110 SoftDevice.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_disconnect(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
p_dfu->conn_handle = BLE_CONN_HANDLE_INVALID;
}
uint32_t ble_dfu_init(ble_dfu_t * p_dfu, ble_dfu_init_t * p_dfu_init)
{
if ((p_dfu == NULL) || (p_dfu_init == NULL) || (p_dfu_init->evt_handler == NULL))
{
return NRF_ERROR_NULL;
}
p_dfu->conn_handle = BLE_CONN_HANDLE_INVALID;
ble_uuid_t service_uuid;
uint32_t err_code;
const ble_uuid128_t base_uuid128 =
{
{
0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00
}
};
service_uuid.uuid = BLE_DFU_SERVICE_UUID;
err_code = sd_ble_uuid_vs_add(&base_uuid128, &(service_uuid.type));
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&service_uuid,
&(p_dfu->service_handle));
if (err_code != NRF_SUCCESS)
{
return err_code;
}
p_dfu->uuid_type = service_uuid.type;
err_code = dfu_pkt_char_add(p_dfu);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = dfu_ctrl_pt_add(p_dfu);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = dfu_rev_char_add(p_dfu, p_dfu_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
p_dfu->evt_handler = p_dfu_init->evt_handler;
if (p_dfu_init->error_handler != NULL)
{
p_dfu->error_handler = p_dfu_init->error_handler;
}
m_is_dfu_service_initialized = true;
return NRF_SUCCESS;
}
void ble_dfu_on_ble_evt(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
if ((p_dfu == NULL) || (p_ble_evt == NULL))
{
return;
}
if (p_dfu->evt_handler != NULL)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_dfu, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_dfu, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_dfu, p_ble_evt);
break;
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
on_rw_authorize_req(p_dfu, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
}
uint32_t ble_dfu_bytes_rcvd_report(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd)
{
if (p_dfu == NULL)
{
return NRF_ERROR_NULL;
}
if ((p_dfu->conn_handle == BLE_CONN_HANDLE_INVALID) || !m_is_dfu_service_initialized)
{
return NRF_ERROR_INVALID_STATE;
}
ble_gatts_hvx_params_t hvx_params;
uint16_t index = 0;
// Encode the Op Code.
m_notif_buffer[index++] = OP_CODE_RESPONSE;
// Encode the Reqest Op Code.
m_notif_buffer[index++] = OP_CODE_IMAGE_SIZE_REQ;
// Encode the Response Value.
m_notif_buffer[index++] = (uint8_t)BLE_DFU_RESP_VAL_SUCCESS;
index += uint32_encode(num_of_firmware_bytes_rcvd, &m_notif_buffer[index]);
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_dfu->dfu_ctrl_pt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &index;
hvx_params.p_data = m_notif_buffer;
return sd_ble_gatts_hvx(p_dfu->conn_handle, &hvx_params);
}
uint32_t ble_dfu_pkts_rcpt_notify(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd)
{
if (p_dfu == NULL)
{
return NRF_ERROR_NULL;
}
if ((p_dfu->conn_handle == BLE_CONN_HANDLE_INVALID) || !m_is_dfu_service_initialized)
{
return NRF_ERROR_INVALID_STATE;
}
ble_gatts_hvx_params_t hvx_params;
uint16_t index = 0;
m_notif_buffer[index++] = OP_CODE_PKT_RCPT_NOTIF;
index += uint32_encode(num_of_firmware_bytes_rcvd, &m_notif_buffer[index]);
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_dfu->dfu_ctrl_pt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &index;
hvx_params.p_data = m_notif_buffer;
return sd_ble_gatts_hvx(p_dfu->conn_handle, &hvx_params);
}
uint32_t ble_dfu_response_send(ble_dfu_t * p_dfu,
ble_dfu_procedure_t dfu_proc,
ble_dfu_resp_val_t resp_val)
{
if (p_dfu == NULL)
{
return NRF_ERROR_NULL;
}
if ((p_dfu->conn_handle == BLE_CONN_HANDLE_INVALID) || !m_is_dfu_service_initialized)
{
return NRF_ERROR_INVALID_STATE;
}
ble_gatts_hvx_params_t hvx_params;
uint16_t index = 0;
m_notif_buffer[index++] = OP_CODE_RESPONSE;
// Encode the Request Op code
m_notif_buffer[index++] = (uint8_t)dfu_proc;
// Encode the Response Value.
m_notif_buffer[index++] = (uint8_t)resp_val;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_dfu->dfu_ctrl_pt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &index;
hvx_params.p_data = m_notif_buffer;
return sd_ble_gatts_hvx(p_dfu->conn_handle, &hvx_params);
}

View File

@ -0,0 +1,259 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup ble_sdk_srv_dfu Device Firmware Update Service
* @{
* @ingroup ble_sdk_srv
* @brief Device Firmware Update Service
*
* @details The Device Firmware Update (DFU) service is a GATT based service that can be used for
* performing firmware updates over BLE. Note that this implementation uses vendor
* specific UUIDs for service and characteristics and is intended to demonstrate the
* firmware updates over BLE. Refer @ref bledfu_transport_bleservice and @ref
* bledfu_transport_bleprofile for more information on the service and profile respectively.
*/
#ifndef BLE_DFU_H__
#define BLE_DFU_H__
#include <stdint.h>
#include "ble_gatts.h"
#include "ble_gap.h"
#include "nrf_ble.h"
#include "ble_srv_common.h"
#define BLE_DFU_SERVICE_UUID 0x1530 /**< The UUID of the DFU Service. */
#define BLE_DFU_PKT_CHAR_UUID 0x1532 /**< The UUID of the DFU Packet Characteristic. */
#define BLE_DFU_CTRL_PT_UUID 0x1531 /**< The UUID of the DFU Control Point. */
#define BLE_DFU_STATUS_REP_UUID 0x1533 /**< The UUID of the DFU Status Report Characteristic. */
#define BLE_DFU_REV_CHAR_UUID 0x1534 /**< The UUID of the DFU Revision Characteristic. */
/**@brief DFU Event type.
*
* @details This enumeration contains the types of events that will be received from the DFU Service.
*/
typedef enum
{
BLE_DFU_START, /**< The event indicating that the peer wants the application to prepare for a new firmware update. */
BLE_DFU_RECEIVE_INIT_DATA, /**< The event indicating that the peer wants the application to prepare to receive init parameters. */
BLE_DFU_RECEIVE_APP_DATA, /**< The event indicating that the peer wants the application to prepare to receive the new firmware image. */
BLE_DFU_VALIDATE, /**< The event indicating that the peer wants the application to validate the newly received firmware image. */
BLE_DFU_ACTIVATE_N_RESET, /**< The event indicating that the peer wants the application to undergo activate new firmware and restart with new valid application */
BLE_DFU_SYS_RESET, /**< The event indicating that the peer wants the application to undergo a reset and start the currently valid application image.*/
BLE_DFU_PKT_RCPT_NOTIF_ENABLED, /**< The event indicating that the peer has enabled packet receipt notifications. It is the responsibility of the application to call @ref ble_dfu_pkts_rcpt_notify each time the number of packets indicated by num_of_pkts field in @ref ble_dfu_evt_t is received.*/
BLE_DFU_PKT_RCPT_NOTIF_DISABLED, /**< The event indicating that the peer has disabled the packet receipt notifications.*/
BLE_DFU_PACKET_WRITE, /**< The event indicating that the peer has written a value to the 'DFU Packet' characteristic. The data received from the peer will be present in the @ref BLE_DFU_PACKET_WRITE element contained within @ref ble_dfu_evt_t.*/
BLE_DFU_BYTES_RECEIVED_SEND /**< The event indicating that the peer is requesting for the number of bytes of firmware data last received by the application. It is the responsibility of the application to call @ref ble_dfu_pkts_rcpt_notify in response to this event. */
} ble_dfu_evt_type_t;
/**@brief DFU Procedure type.
*
* @details This enumeration contains the types of DFU procedures.
*/
typedef enum
{
BLE_DFU_START_PROCEDURE = 1, /**< DFU Start procedure.*/
BLE_DFU_INIT_PROCEDURE = 2, /**< DFU Initialization procedure.*/
BLE_DFU_RECEIVE_APP_PROCEDURE = 3, /**< Firmware receiving procedure.*/
BLE_DFU_VALIDATE_PROCEDURE = 4, /**< Firmware image validation procedure .*/
BLE_DFU_PKT_RCPT_REQ_PROCEDURE = 8 /**< Packet receipt notification request procedure. */
} ble_dfu_procedure_t;
/**@brief DFU Response value type.
*/
typedef enum
{
BLE_DFU_RESP_VAL_SUCCESS = 1, /**< Success.*/
BLE_DFU_RESP_VAL_INVALID_STATE, /**< Invalid state.*/
BLE_DFU_RESP_VAL_NOT_SUPPORTED, /**< Operation not supported.*/
BLE_DFU_RESP_VAL_DATA_SIZE, /**< Data size exceeds limit.*/
BLE_DFU_RESP_VAL_CRC_ERROR, /**< CRC Error.*/
BLE_DFU_RESP_VAL_OPER_FAILED /**< Operation failed.*/
} ble_dfu_resp_val_t;
/**@brief DFU Packet structure.
*
* @details This structure contains the value of the DFU Packet characteristic as written by the
* peer and the length of the value written. It will be filled by the DFU Service when the
* peer writes to the DFU Packet characteristic.
*/
typedef struct
{
uint8_t * p_data; /**< Pointer to the received packet. This will point to a word aligned memory location.*/
uint8_t len; /**< Length of the packet received. */
} ble_dfu_pkt_write_t;
/**@brief Packet receipt notification request structure.
*
* @details This structure contains the contents of the packet receipt notification request
* sent by the DFU Controller.
*/
typedef struct
{
uint16_t num_of_pkts; /**< The number of packets of firmware data to be received by application before sending the next Packet Receipt Notification to the peer. */
} ble_pkt_rcpt_notif_req_t;
/**@brief DFU Event structure.
*
* @details This structure contains the event generated by the DFU Service based on the data
* received from the peer.
*/
typedef struct
{
ble_dfu_evt_type_t ble_dfu_evt_type; /**< Type of the event.*/
union
{
ble_dfu_pkt_write_t ble_dfu_pkt_write; /**< The DFU packet received. This field is when the @ref ble_dfu_evt_type field is set to @ref BLE_DFU_PACKET_WRITE.*/
ble_pkt_rcpt_notif_req_t pkt_rcpt_notif_req; /**< Packet receipt notification request. This field is when the @ref ble_dfu_evt_type field is set to @ref BLE_DFU_PKT_RCPT_NOTIF_ENABLED.*/
} evt;
} ble_dfu_evt_t;
// Forward declaration of the ble_dfu_t type.
typedef struct ble_dfu_s ble_dfu_t;
/**@brief DFU Service event handler type. */
typedef void (*ble_dfu_evt_handler_t) (ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt);
/**@brief DFU service structure.
*
* @details This structure contains status information related to the service.
*/
struct ble_dfu_s
{
uint16_t conn_handle; /**< Handle of the current connection (as provided by the S110 SoftDevice). This will be BLE_CONN_HANDLE_INVALID when not in a connection. */
uint16_t revision; /**< Handle of DFU Service (as provided by the S110 SoftDevice). */
uint16_t service_handle; /**< Handle of DFU Service (as provided by the S110 SoftDevice). */
uint8_t uuid_type; /**< UUID type assigned for DFU Service by the S110 SoftDevice. */
ble_gatts_char_handles_t dfu_pkt_handles; /**< Handles related to the DFU Packet characteristic. */
ble_gatts_char_handles_t dfu_ctrl_pt_handles; /**< Handles related to the DFU Control Point characteristic. */
ble_gatts_char_handles_t dfu_status_rep_handles; /**< Handles related to the DFU Status Report characteristic. */
ble_gatts_char_handles_t dfu_rev_handles; /**< Handles related to the DFU Revision characteristic. */
ble_dfu_evt_handler_t evt_handler; /**< The event handler to be called when an event is to be sent to the application.*/
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
};
/**@brief DFU service initialization structure.
*
* @details This structure contains the initialization information for the DFU Service. The
* application needs to fill this structure and pass it to the DFU Service using the
* @ref ble_dfu_init function.
*/
typedef struct
{
uint16_t revision; /**< Revision number to be exposed by the DFU service. */
ble_dfu_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Device Firmware Update Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
} ble_dfu_init_t;
/**@brief Function for handling a BLE event.
*
* @details The DFU service expects the application to call this function each time an event
* is received from the S110 SoftDevice. This function processes the event, if it is
* relevant for the DFU service and calls the DFU event handler of the application if
* necessary.
*
* @param[in] p_dfu Pointer to the DFU service structure.
* @param[in] p_ble_evt Pointer to the event received from S110 SoftDevice.
*/
void ble_dfu_on_ble_evt(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt);
/**@brief Function for initializing the DFU service.
*
* @param[out] p_dfu Device Firmware Update service structure. This structure will have to be
* supplied by the application. It will be initialized by this function,
* and will later be used to identify the service instance.
* @param[in] p_dfu_init Information needed to initialize the service.
*
* @return NRF_SUCCESS if the DFU service and its characteristics were successfully added to the
* S110 SoftDevice. Otherwise an error code.
* This function returns NRF_ERROR_NULL if the value of evt_handler in p_dfu_init
* structure provided is NULL or if the pointers supplied as input are NULL.
*/
uint32_t ble_dfu_init(ble_dfu_t * p_dfu, ble_dfu_init_t * p_dfu_init);
/**@brief Function for sending response to a control point command.
*
* @details This function will encode a DFU Control Point response using the given input
* parameters and will send a notification of the same to the peer.
*
* @param[in] p_dfu Pointer to the DFU service structure.
* @param[in] dfu_proc Procedure for which this response is to be sent.
* @param[in] resp_val Response value.
*
* @return NRF_SUCCESS if the DFU Service has successfully requested the S110 SoftDevice to
* send the notification. Otherwise an error code.
* This function returns NRF_ERROR_INVALID_STATE if the device is not connected to a
* peer or if the DFU service is not initialized or if the notification of the DFU
* Status Report characteristic was not enabled by the peer. It returns NRF_ERROR_NULL
* if the pointer p_dfu is NULL.
*/
uint32_t ble_dfu_response_send(ble_dfu_t * p_dfu,
ble_dfu_procedure_t dfu_proc,
ble_dfu_resp_val_t resp_val);
/**@brief Function for notifying the peer about the number of bytes of firmware data received.
*
* @param[in] p_dfu Pointer to the DFU service structure.
* @param[in] num_of_firmware_bytes_rcvd Number of bytes.
*
* @return NRF_SUCCESS if the DFU Service has successfully requested the S110 SoftDevice to send
* the notification. Otherwise an error code.
* This function returns NRF_ERROR_INVALID_STATE if the device is not connected to a
* peer or if the DFU service is not initialized or if the notification of the DFU
* Status Report characteristic was not enabled by the peer. It returns NRF_ERROR_NULL
* if the pointer p_dfu is NULL.
*/
uint32_t ble_dfu_bytes_rcvd_report(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd);
/**@brief Function for sending Packet Receipt Notification to the peer.
*
* This function will encode the number of bytes received as input parameter into a
* notification of the control point characteristic and send it to the peer.
*
* @param[in] p_dfu Pointer to the DFU service structure.
* @param[in] num_of_firmware_bytes_rcvd Number of bytes of firmware image received.
*
* @return NRF_SUCCESS if the DFU Service has successfully requested the S110 SoftDevice to send
* the notification. Otherwise an error code.
* This function returns NRF_ERROR_INVALID_STATE if the device is not connected to a
* peer or if the DFU service is not initialized or if the notification of the DFU
* Status Report characteristic was not enabled by the peer. It returns NRF_ERROR_NULL
* if the pointer p_dfu is NULL.
*/
uint32_t ble_dfu_pkts_rcpt_notify(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd);
#endif // BLE_DFU_H__
/** @} */

View File

@ -0,0 +1,861 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ble_advdata.h"
#include "nordic_common.h"
#include "nrf_error.h"
#include "ble_gap.h"
#include "ble_srv_common.h"
#include "app_util.h"
// NOTE: For now, Security Manager Out of Band Flags (OOB) are omitted from the advertising data.
// Types of LE Bluetooth Device Address AD type
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_PUBLIC 0UL
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_RANDOM 1UL
static uint32_t tk_value_encode(ble_advdata_tk_value_t * p_tk_value,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
int8_t i;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_TK_VALUE_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode LE Role.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_TK_VALUE_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
for (i = AD_TYPE_TK_VALUE_DATA_SIZE - 1; i >= 0; i--, (*p_offset)++)
{
p_encoded_data[*p_offset] = p_tk_value->tk[i];
}
return NRF_SUCCESS;
}
static uint32_t le_role_encode(ble_advdata_le_role_t le_role,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_LE_ROLE_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode LE Role.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_LE_ROLE_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_LE_ROLE;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
switch(le_role)
{
case BLE_ADVDATA_ROLE_ONLY_PERIPH:
p_encoded_data[*p_offset] = 0;
break;
case BLE_ADVDATA_ROLE_ONLY_CENTRAL:
p_encoded_data[*p_offset] = 1;
break;
case BLE_ADVDATA_ROLE_BOTH_PERIPH_PREFERRED:
p_encoded_data[*p_offset] = 2;
break;
case BLE_ADVDATA_ROLE_BOTH_CENTRAL_PREFERRED:
p_encoded_data[*p_offset] = 3;
break;
default:
return NRF_ERROR_INVALID_PARAM;
}
*p_offset += AD_TYPE_LE_ROLE_DATA_SIZE;
return NRF_SUCCESS;
}
static uint32_t ble_device_addr_encode(uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
ble_gap_addr_t device_addr;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_BLE_DEVICE_ADDR_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Get BLE address
err_code = sd_ble_gap_address_get(&device_addr);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Encode LE Bluetooth Device Address
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE +
AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
memcpy(&p_encoded_data[*p_offset], &device_addr.addr[0], BLE_GAP_ADDR_LEN);
*p_offset += BLE_GAP_ADDR_LEN;
if(BLE_GAP_ADDR_TYPE_PUBLIC == device_addr.addr_type)
{
p_encoded_data[*p_offset] = AD_TYPE_BLE_DEVICE_ADDR_TYPE_PUBLIC;
}
else
{
p_encoded_data[*p_offset] = AD_TYPE_BLE_DEVICE_ADDR_TYPE_RANDOM;
}
*p_offset += AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE;
return NRF_SUCCESS;
}
static uint32_t name_encode(const ble_advdata_t * p_advdata,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
uint16_t rem_adv_data_len;
uint16_t actual_length;
uint8_t adv_data_format;
// Validate parameters
if((BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) && (0 == p_advdata->short_name_len))
{
return NRF_ERROR_INVALID_PARAM;
}
// Check for buffer overflow.
if ( (((*p_offset) + ADV_AD_DATA_OFFSET) > max_size) ||
( (BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) &&
(((*p_offset) + ADV_AD_DATA_OFFSET + p_advdata->short_name_len) > max_size)))
{
return NRF_ERROR_DATA_SIZE;
}
rem_adv_data_len = max_size - (*p_offset) - ADV_AD_DATA_OFFSET;
actual_length = rem_adv_data_len;
// Get GAP device name and length
err_code = sd_ble_gap_device_name_get(&p_encoded_data[(*p_offset) + ADV_AD_DATA_OFFSET],
&actual_length);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Check if device intend to use short name and it can fit available data size.
if ((p_advdata->name_type == BLE_ADVDATA_FULL_NAME) && (actual_length <= rem_adv_data_len))
{
// Complete device name can fit, setting Complete Name in Adv Data.
adv_data_format = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
}
else
{
// Else short name needs to be used. Or application has requested use of short name.
adv_data_format = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME;
// If application has set a preference on the short name size, it needs to be considered,
// else fit what can be fit.
if ((BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) &&
(p_advdata->short_name_len <= rem_adv_data_len))
{
// Short name fits available size.
actual_length = p_advdata->short_name_len;
}
// Else whatever can fit the data buffer will be packed.
else
{
actual_length = rem_adv_data_len;
}
}
// There is only 1 byte intended to encode length which is (actual_length + ADV_AD_TYPE_FIELD_SIZE)
if(actual_length > (0x00FF - ADV_AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Complete name field in encoded data.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + actual_length);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = adv_data_format;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
*p_offset += actual_length;
return NRF_SUCCESS;
}
static uint32_t appearance_encode(uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
uint16_t appearance;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_APPEARANCE_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Get GAP appearance field.
err_code = sd_ble_gap_appearance_get(&appearance);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Encode Length, AD Type and Appearance.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_APPEARANCE_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_APPEARANCE;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
*p_offset += uint16_encode(appearance, &p_encoded_data[*p_offset]);
return NRF_SUCCESS;
}
static uint32_t flags_encode(int8_t flags,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_FLAGS_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode flags.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_FLAGS_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_FLAGS;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
p_encoded_data[*p_offset] = flags;
*p_offset += AD_TYPE_FLAGS_DATA_SIZE;
return NRF_SUCCESS;
}
static uint32_t sec_mgr_oob_flags_encode(uint8_t oob_flags,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_OOB_FLAGS_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode flags.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_OOB_FLAGS_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
p_encoded_data[*p_offset] = oob_flags;
*p_offset += AD_TYPE_OOB_FLAGS_DATA_SIZE;
return NRF_SUCCESS;
}
static uint32_t tx_power_level_encode(int8_t tx_power_level,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_TX_POWER_LEVEL_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode TX Power Level.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE +
AD_TYPE_TX_POWER_LEVEL_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_TX_POWER_LEVEL;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
p_encoded_data[*p_offset] = tx_power_level;
*p_offset += AD_TYPE_TX_POWER_LEVEL_DATA_SIZE;
return NRF_SUCCESS;
}
static uint32_t uuid_list_sized_encode(const ble_advdata_uuid_list_t * p_uuid_list,
uint8_t adv_type,
uint8_t uuid_size,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
int i;
bool is_heading_written = false;
uint16_t start_pos = *p_offset;
uint16_t length;
for (i = 0; i < p_uuid_list->uuid_cnt; i++)
{
uint32_t err_code;
uint8_t encoded_size;
ble_uuid_t uuid = p_uuid_list->p_uuids[i];
// Find encoded uuid size.
err_code = sd_ble_uuid_encode(&uuid, &encoded_size, NULL);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Check size.
if (encoded_size == uuid_size)
{
uint8_t heading_bytes = (is_heading_written) ? 0 : ADV_AD_DATA_OFFSET;
// Check for buffer overflow
if (((*p_offset) + encoded_size + heading_bytes) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
if (!is_heading_written)
{
// Write AD structure heading.
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = adv_type;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
is_heading_written = true;
}
// Write UUID.
err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &p_encoded_data[*p_offset]);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
*p_offset += encoded_size;
}
}
if (is_heading_written)
{
// Write length.
length = (*p_offset) - (start_pos + ADV_LENGTH_FIELD_SIZE);
// There is only 1 byte intended to encode length
if(length > 0x00FF)
{
return NRF_ERROR_DATA_SIZE;
}
p_encoded_data[start_pos] = (uint8_t)length;
}
return NRF_SUCCESS;
}
static uint32_t uuid_list_encode(const ble_advdata_uuid_list_t * p_uuid_list,
uint8_t adv_type_16,
uint8_t adv_type_128,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
// Encode 16 bit UUIDs.
err_code = uuid_list_sized_encode(p_uuid_list,
adv_type_16,
sizeof(uint16_le_t),
p_encoded_data,
p_offset,
max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Encode 128 bit UUIDs.
err_code = uuid_list_sized_encode(p_uuid_list,
adv_type_128,
sizeof(ble_uuid128_t),
p_encoded_data,
p_offset,
max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
return NRF_SUCCESS;
}
static uint32_t conn_int_check(const ble_advdata_conn_int_t *p_conn_int)
{
// Check Minimum Connection Interval.
if ((p_conn_int->min_conn_interval < 0x0006) ||
(
(p_conn_int->min_conn_interval > 0x0c80) &&
(p_conn_int->min_conn_interval != 0xffff)
)
)
{
return NRF_ERROR_INVALID_PARAM;
}
// Check Maximum Connection Interval.
if ((p_conn_int->max_conn_interval < 0x0006) ||
(
(p_conn_int->max_conn_interval > 0x0c80) &&
(p_conn_int->max_conn_interval != 0xffff)
)
)
{
return NRF_ERROR_INVALID_PARAM;
}
// Make sure Minimum Connection Interval is not bigger than Maximum Connection Interval.
if ((p_conn_int->min_conn_interval != 0xffff) &&
(p_conn_int->max_conn_interval != 0xffff) &&
(p_conn_int->min_conn_interval > p_conn_int->max_conn_interval)
)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
static uint32_t conn_int_encode(const ble_advdata_conn_int_t * p_conn_int,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_CONN_INT_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Check parameters.
err_code = conn_int_check(p_conn_int);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_CONN_INT_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
// Encode Minimum and Maximum Connection Intervals.
*p_offset += uint16_encode(p_conn_int->min_conn_interval, &p_encoded_data[*p_offset]);
*p_offset += uint16_encode(p_conn_int->max_conn_interval, &p_encoded_data[*p_offset]);
return NRF_SUCCESS;
}
static uint32_t manuf_specific_data_encode(const ble_advdata_manuf_data_t * p_manuf_sp_data,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t data_size = AD_TYPE_MANUF_SPEC_DATA_ID_SIZE + p_manuf_sp_data->data.size;
// Check for buffer overflow.
if (((*p_offset) + ADV_AD_DATA_OFFSET + data_size) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// There is only 1 byte intended to encode length which is (data_size + ADV_AD_TYPE_FIELD_SIZE)
if(data_size > (0x00FF - ADV_AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + data_size);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
// Encode Company Identifier.
*p_offset += uint16_encode(p_manuf_sp_data->company_identifier, &p_encoded_data[*p_offset]);
// Encode additional manufacturer specific data.
if (p_manuf_sp_data->data.size > 0)
{
if (p_manuf_sp_data->data.p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
memcpy(&p_encoded_data[*p_offset], p_manuf_sp_data->data.p_data, p_manuf_sp_data->data.size);
*p_offset += p_manuf_sp_data->data.size;
}
return NRF_SUCCESS;
}
// Implemented only for 16-bit UUIDs
static uint32_t service_data_encode(const ble_advdata_t * p_advdata,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint8_t i;
// Check parameter consistency.
if (p_advdata->p_service_data_array == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
for (i = 0; i < p_advdata->service_data_count; i++)
{
ble_advdata_service_data_t * p_service_data;
uint32_t data_size;
p_service_data = &p_advdata->p_service_data_array[i];
// For now implemented only for 16-bit UUIDs
data_size = AD_TYPE_SERV_DATA_16BIT_UUID_SIZE + p_service_data->data.size;
// There is only 1 byte intended to encode length which is (data_size + ADV_AD_TYPE_FIELD_SIZE)
if(data_size > (0x00FF - ADV_AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + data_size);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SERVICE_DATA;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
// Encode service 16-bit UUID.
*p_offset += uint16_encode(p_service_data->service_uuid, &p_encoded_data[*p_offset]);
// Encode additional service data.
if (p_service_data->data.size > 0)
{
if (p_service_data->data.p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
memcpy(&p_encoded_data[*p_offset], p_service_data->data.p_data, p_service_data->data.size);
*p_offset += p_service_data->data.size;
}
}
return NRF_SUCCESS;
}
uint32_t adv_data_encode(ble_advdata_t const * const p_advdata,
uint8_t * const p_encoded_data,
uint16_t * const p_len)
{
uint32_t err_code = NRF_SUCCESS;
uint16_t max_size = *p_len;
*p_len = 0;
//Encode Security Manager OOB Flags
if (p_advdata->p_sec_mgr_oob_flags != NULL)
{
err_code = sec_mgr_oob_flags_encode(*p_advdata->p_sec_mgr_oob_flags,
p_encoded_data,
p_len,
max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode Security Manager TK value
if (NULL != p_advdata->p_tk_value)
{
err_code = tk_value_encode(p_advdata->p_tk_value, p_encoded_data, p_len, max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode LE Role
if (BLE_ADVDATA_ROLE_NOT_PRESENT != p_advdata->le_role)
{
err_code = le_role_encode(p_advdata->le_role, p_encoded_data, p_len, max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode LE Bluetooth Device Address
if (p_advdata->include_ble_device_addr)
{
err_code = ble_device_addr_encode(p_encoded_data, p_len, max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode appearance.
if (p_advdata->include_appearance)
{
err_code = appearance_encode(p_encoded_data, p_len, max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
//Encode Flags
if(p_advdata->flags != 0 )
{
err_code = flags_encode(p_advdata->flags, p_encoded_data, p_len, max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode TX power level.
if (p_advdata->p_tx_power_level != NULL)
{
err_code = tx_power_level_encode(*p_advdata->p_tx_power_level,
p_encoded_data,
p_len,
max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode 'more available' uuid list.
if (p_advdata->uuids_more_available.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_more_available,
BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE,
BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE,
p_encoded_data,
p_len,
max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode 'complete' uuid list.
if (p_advdata->uuids_complete.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_complete,
BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,
BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE,
p_encoded_data,
p_len,
max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode 'solicited service' uuid list.
if (p_advdata->uuids_solicited.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_solicited,
BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT,
BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT,
p_encoded_data,
p_len,
max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode Slave Connection Interval Range.
if (p_advdata->p_slave_conn_int != NULL)
{
err_code = conn_int_encode(p_advdata->p_slave_conn_int, p_encoded_data, p_len, max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode Manufacturer Specific Data.
if (p_advdata->p_manuf_specific_data != NULL)
{
err_code = manuf_specific_data_encode(p_advdata->p_manuf_specific_data,
p_encoded_data,
p_len,
max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode Service Data.
if (p_advdata->service_data_count > 0)
{
err_code = service_data_encode(p_advdata, p_encoded_data, p_len, max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Encode name. WARNING: it is encoded last on purpose since too long device name is truncated.
if (p_advdata->name_type != BLE_ADVDATA_NO_NAME)
{
err_code = name_encode(p_advdata, p_encoded_data, p_len, max_size);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
return err_code;
}
static uint32_t advdata_check(const ble_advdata_t * p_advdata)
{
// Flags must be included in advertising data, and the BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED flag must be set.
if (
((p_advdata->flags & BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) == 0)
)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
static uint32_t srdata_check(const ble_advdata_t * p_srdata)
{
// Flags shall not be included in the scan response data.
if (p_srdata->flags)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
uint32_t ble_advdata_set(const ble_advdata_t * p_advdata, const ble_advdata_t * p_srdata)
{
uint32_t err_code;
uint16_t len_advdata = BLE_GAP_ADV_MAX_SIZE;
uint16_t len_srdata = BLE_GAP_ADV_MAX_SIZE;
uint8_t encoded_advdata[BLE_GAP_ADV_MAX_SIZE];
uint8_t encoded_srdata[BLE_GAP_ADV_MAX_SIZE];
uint8_t * p_encoded_advdata;
uint8_t * p_encoded_srdata;
// Encode advertising data (if supplied).
if (p_advdata != NULL)
{
err_code = advdata_check(p_advdata);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = adv_data_encode(p_advdata, encoded_advdata, &len_advdata);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
p_encoded_advdata = encoded_advdata;
}
else
{
p_encoded_advdata = NULL;
len_advdata = 0;
}
// Encode scan response data (if supplied).
if (p_srdata != NULL)
{
err_code = srdata_check(p_srdata);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = adv_data_encode(p_srdata, encoded_srdata, &len_srdata);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
p_encoded_srdata = encoded_srdata;
}
else
{
p_encoded_srdata = NULL;
len_srdata = 0;
}
// Pass encoded advertising data and/or scan response data to the stack.
return sd_ble_gap_adv_data_set(p_encoded_advdata, len_advdata, p_encoded_srdata, len_srdata);
}

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup ble_sdk_lib_advdata Advertising and Scan Response Data Encoder
* @{
* @ingroup ble_sdk_lib
* @brief Functions for encoding data in the Advertising and Scan Response Data format,
* and for passing the data to the stack.
*/
#ifndef BLE_ADVDATA_H__
#define BLE_ADVDATA_H__
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "nrf_ble.h"
#include "app_util.h"
#define ADV_LENGTH_FIELD_SIZE 1UL /**< Advertising Data and Scan Response format contains 1 octet for the length. */
#define ADV_AD_TYPE_FIELD_SIZE 1UL /**< Advertising Data and Scan Response format contains 1 octet for the AD type. */
#define ADV_AD_DATA_OFFSET (ADV_LENGTH_FIELD_SIZE + \
ADV_AD_TYPE_FIELD_SIZE) /**< Offset for the AD data field of the Advertising Data and Scan Response format. */
#define AD_TYPE_TK_VALUE_DATA_SIZE (sizeof(ble_advdata_tk_value_t)) /**< Data size (in octets) of the Security Manager TK value AD type. */
#define AD_TYPE_TK_VALUE_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_TK_VALUE_DATA_SIZE) /**< Size (in octets) of the Security Manager TK value AD type. */
#define AD_TYPE_LE_ROLE_DATA_SIZE 1UL /**< Data size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_LE_ROLE_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_LE_ROLE_DATA_SIZE) /**< Size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE 1UL /**< Data size (in octets) of the Address type of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE (BLE_GAP_ADDR_LEN + \
AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE) /**< Data size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_BLE_DEVICE_ADDR_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE) /**< Size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_APPEARANCE_DATA_SIZE 2UL /**< Data size (in octets) of the Appearance AD type. */
#define AD_TYPE_APPEARANCE_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_APPEARANCE_DATA_SIZE) /**< Size (in octets) of the Appearance AD type. */
#define AD_TYPE_FLAGS_DATA_SIZE 1UL /**< Data size (in octets) of the Flags AD type. */
#define AD_TYPE_FLAGS_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_FLAGS_DATA_SIZE) /**< Size (in octets) of the Flags AD type. */
#define AD_TYPE_TX_POWER_LEVEL_DATA_SIZE 1UL /**< Data size (in octets) of the TX Power Level AD type. */
#define AD_TYPE_TX_POWER_LEVEL_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_TX_POWER_LEVEL_DATA_SIZE) /**< Size (in octets) of the TX Power Level AD type. */
#define AD_TYPE_CONN_INT_DATA_SIZE 4UL /**< Data size (in octets) of the Slave Connection Interval Range AD type. */
#define AD_TYPE_CONN_INT_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_CONN_INT_DATA_SIZE) /**< Data size (in octets) of the Slave Connection Interval Range AD type. */
#define AD_TYPE_MANUF_SPEC_DATA_ID_SIZE 2UL /**< Size (in octets) of the Company Identifier Code, which is a part of the Manufacturer Specific Data AD type. */
#define AD_TYPE_SERV_DATA_16BIT_UUID_SIZE 2UL /**< Size (in octets) of the 16-bit UUID, which is a part of the Service Data AD type. */
#define AD_TYPE_OOB_FLAGS_DATA_SIZE 1UL /**< Data size (in octets) of the Security Manager OOB Flags AD type. */
#define AD_TYPE_OOB_FLAGS_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_OOB_FLAGS_DATA_SIZE) /**< Size (in octets) of the Security Manager OOB Flags AD type. */
#define AD_TYPE_SEC_MGR_OOB_FLAG_SET 1U /**< Security Manager OOB Flag set. Flag selection is done using _POS defines */
#define AD_TYPE_SEC_MGR_OOB_FLAG_CLEAR 0U /**< Security Manager OOB Flag clear. Flag selection is done using _POS defines */
#define AD_TYPE_SEC_MGR_OOB_FLAG_OOB_DATA_PRESENT_POS 0UL /**< Security Manager OOB Data Present Flag position. */
#define AD_TYPE_SEC_MGR_OOB_FLAG_OOB_LE_SUPPORTED_POS 1UL /**< Security Manager OOB Low Energy Supported Flag position. */
#define AD_TYPE_SEC_MGR_OOB_FLAG_SIM_LE_AND_EP_POS 2UL /**< Security Manager OOB Simultaneous LE and BR/EDR to Same Device Capable Flag position. */
#define AD_TYPE_SEC_MGR_OOB_ADDRESS_TYPE_PUBLIC 0UL /**< Security Manager OOB Public Address type. */
#define AD_TYPE_SEC_MGR_OOB_ADDRESS_TYPE_RANDOM 1UL /**< Security Manager OOB Random Address type. */
#define AD_TYPE_SEC_MGR_OOB_FLAG_ADDRESS_TYPE_POS 3UL /**< Security Manager OOB Address type Flag (0 = Public Address, 1 = Random Address) position. */
/**@brief Security Manager TK value. */
typedef struct
{
uint8_t tk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing TK value. */
} ble_advdata_tk_value_t;
/**@brief Advertising data LE Role types. This enumeration contains the options available for the LE role inside
* the advertising data. */
typedef enum
{
BLE_ADVDATA_ROLE_NOT_PRESENT = 0, /**< LE Role AD structure not present. */
BLE_ADVDATA_ROLE_ONLY_PERIPH, /**< Only Peripheral Role supported. */
BLE_ADVDATA_ROLE_ONLY_CENTRAL, /**< Only Central Role supported. */
BLE_ADVDATA_ROLE_BOTH_PERIPH_PREFERRED, /**< Peripheral and Central Role supported. Peripheral Role preferred for connection establishment. */
BLE_ADVDATA_ROLE_BOTH_CENTRAL_PREFERRED /**< Peripheral and Central Role supported. Central Role preferred for connection establishment */
} ble_advdata_le_role_t;
/**@brief Advertising data name type. This enumeration contains the options available for the device name inside
* the advertising data. */
typedef enum
{
BLE_ADVDATA_NO_NAME, /**< Include no device name in advertising data. */
BLE_ADVDATA_SHORT_NAME, /**< Include short device name in advertising data. */
BLE_ADVDATA_FULL_NAME /**< Include full device name in advertising data. */
} ble_advdata_name_type_t;
/**@brief UUID list type. */
typedef struct
{
uint16_t uuid_cnt; /**< Number of UUID entries. */
ble_uuid_t * p_uuids; /**< Pointer to UUID array entries. */
} ble_advdata_uuid_list_t;
/**@brief Connection interval range structure. */
typedef struct
{
uint16_t min_conn_interval; /**< Minimum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). */
uint16_t max_conn_interval; /**< Maximum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). The value 0xFFFF indicates no specific maximum. */
} ble_advdata_conn_int_t;
/**@brief Manufacturer specific data structure. */
typedef struct
{
uint16_t company_identifier; /**< Company identifier code. */
uint8_array_t data; /**< Additional manufacturer specific data. */
} ble_advdata_manuf_data_t;
/**@brief Service data structure. */
typedef struct
{
uint16_t service_uuid; /**< Service UUID. */
uint8_array_t data; /**< Additional service data. */
} ble_advdata_service_data_t;
/**@brief Advertising data structure. This structure contains all options and data needed for encoding and
* setting the advertising data. */
typedef struct
{
ble_advdata_name_type_t name_type; /**< Type of device name. */
uint8_t short_name_len; /**< Length of short device name (if short type is specified). */
bool include_appearance; /**< Determines if Appearance shall be included. */
uint8_t flags; /**< Advertising data Flags field. */
int8_t * p_tx_power_level; /**< TX Power Level field. */
ble_advdata_uuid_list_t uuids_more_available; /**< List of UUIDs in the 'More Available' list. */
ble_advdata_uuid_list_t uuids_complete; /**< List of UUIDs in the 'Complete' list. */
ble_advdata_uuid_list_t uuids_solicited; /**< List of solicited UUIDs. */
ble_advdata_conn_int_t * p_slave_conn_int; /**< Slave Connection Interval Range. */
ble_advdata_manuf_data_t * p_manuf_specific_data; /**< Manufacturer specific data. */
ble_advdata_service_data_t * p_service_data_array; /**< Array of Service data structures. */
uint8_t service_data_count; /**< Number of Service data structures. */
bool include_ble_device_addr; /**< Determines if LE Bluetooth Device Address shall be included. */
ble_advdata_le_role_t le_role; /**< LE Role field. Included when different from @ref BLE_ADVDATA_ROLE_NOT_PRESENT.*/
ble_advdata_tk_value_t * p_tk_value; /**< Security Manager TK value field. Included when different from NULL.*/
uint8_t * p_sec_mgr_oob_flags; /**< Security Manager Out Of Band Flags field. Included when different from NULL.*/
} ble_advdata_t;
/**@brief Function for encoding data in the Advertising and Scan Response data format
* (AD structures).
*
* @details This function encodes data into the Advertising and Scan Response data format
* (AD structures) based on the selections in the supplied structures. This function can be used to
* create a payload of Advertising packet or Scan Response packet, or a payload of NFC
* message intended for initiating the Out-of-Band pairing.
*
* @param[in] p_advdata Pointer to the structure for specifying the content of encoded data.
* @param[out] p_encoded_data Pointer to the buffer where encoded data will be returned.
* @param[in,out] p_len \c in: Size of \p p_encoded_data buffer.
* \c out: Length of encoded data.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_INVALID_PARAM If the operation failed because a wrong parameter was provided in \p p_advdata.
* @retval NRF_ERROR_DATA_SIZE If the operation failed because not all the requested data could fit into the
* provided buffer or some encoded AD structure is too long and its
* length cannot be encoded with one octet.
*
* @warning This API may override the application's request to use the long name and use a short name
* instead. This truncation will occur in case the long name does not fit the provided buffer size.
* The application can specify a preferred short name length if truncation is required.
* For example, if the complete device name is ABCD_HRMonitor, the application can specify the short name
* length to be 8, so that the short device name appears as ABCD_HRM instead of ABCD_HRMo or ABCD_HRMoni
* if the available size for the short name is 9 or 12 respectively, to have a more appropriate short name.
* However, it should be noted that this is just a preference that the application can specify, and
* if the preference is too large to fit in the provided buffer, the name can be truncated further.
*/
uint32_t adv_data_encode(ble_advdata_t const * const p_advdata,
uint8_t * const p_encoded_data,
uint16_t * const p_len);
/**@brief Function for encoding and setting the advertising data and/or scan response data.
*
* @details This function encodes advertising data and/or scan response data based on the selections
* in the supplied structures, and passes the encoded data to the stack.
*
* @param[in] p_advdata Structure for specifying the content of the advertising data.
* Set to NULL if advertising data is not to be set.
* @param[in] p_srdata Structure for specifying the content of the scan response data.
* Set to NULL if scan response data is not to be set.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_INVALID_PARAM If the operation failed because a wrong parameter was provided in \p p_advdata.
* @retval NRF_ERROR_DATA_SIZE If the operation failed because not all the requested data could fit into the
* advertising packet. The maximum size of the advertisement packet
* is @ref BLE_GAP_ADV_MAX_SIZE.
*
* @warning This API may override the application's request to use the long name and use a short name
* instead. This truncation will occur in case the long name does not fit the provided buffer size.
* The application can specify a preferred short name length if truncation is required.
* For example, if the complete device name is ABCD_HRMonitor, the application can specify the short name
* length to be 8, so that the short device name appears as ABCD_HRM instead of ABCD_HRMo or ABCD_HRMoni
* if the available size for the short name is 9 or 12 respectively, to have a more appropriate short name.
* However, it should be noted that this is just a preference that the application can specify, and
* if the preference is too large to fit in the provided buffer, the name can be truncated further.
*/
uint32_t ble_advdata_set(const ble_advdata_t * p_advdata, const ble_advdata_t * p_srdata);
#endif // BLE_ADVDATA_H__
/** @} */

View File

@ -0,0 +1,386 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ble_conn_params.h"
#include <stdlib.h>
#include "nordic_common.h"
#include "ble_hci.h"
#include "ble_srv_common.h"
#include "app_util.h"
#ifdef USE_APP_TIMER
#include "app_timer.h"
#else
#ifdef YOTTA_CFG_MBED_OS
#include "mbed-drivers/mbed.h"
#else
#include "mbed.h"
#endif
#endif
static ble_conn_params_init_t m_conn_params_config; /**< Configuration as specified by the application. */
static ble_gap_conn_params_t m_preferred_conn_params; /**< Connection parameters preferred by the application. */
static uint8_t m_update_count; /**< Number of Connection Parameter Update messages that has currently been sent. */
static uint16_t m_conn_handle; /**< Current connection handle. */
static ble_gap_conn_params_t m_current_conn_params; /**< Connection parameters received in the most recent Connect event. */
#ifdef USE_APP_TIMER
static app_timer_id_t m_conn_params_timer_id; /**< Connection parameters timer. */
#else
static Ticker m_conn_params_timer;
#endif
static bool m_change_param = false;
static bool is_conn_params_ok(ble_gap_conn_params_t * p_conn_params)
{
// Check if interval is within the acceptable range.
// NOTE: Using max_conn_interval in the received event data because this contains
// the client's connection interval.
if (
(p_conn_params->max_conn_interval >= m_preferred_conn_params.min_conn_interval)
&&
(p_conn_params->max_conn_interval <= m_preferred_conn_params.max_conn_interval)
)
{
return true;
}
else
{
return false;
}
}
#ifdef USE_APP_TIMER
static void update_timeout_handler(void * p_context)
{
UNUSED_PARAMETER(p_context);
#else /* #if !USE_APP_TIMER */
static void update_timeout_handler(void)
{
m_conn_params_timer.detach(); /* this is supposed to be a single-shot timer callback */
#endif /* #if !USE_APP_TIMER */
if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
{
// Check if we have reached the maximum number of attempts
m_update_count++;
if (m_update_count <= m_conn_params_config.max_conn_params_update_count)
{
uint32_t err_code;
// Parameters are not ok, send connection parameters update request.
err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params);
if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
{
m_conn_params_config.error_handler(err_code);
}
}
else
{
m_update_count = 0;
// Negotiation failed, disconnect automatically if this has been configured
if (m_conn_params_config.disconnect_on_fail)
{
uint32_t err_code;
err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
{
m_conn_params_config.error_handler(err_code);
}
}
// Notify the application that the procedure has failed
if (m_conn_params_config.evt_handler != NULL)
{
ble_conn_params_evt_t evt;
evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
m_conn_params_config.evt_handler(&evt);
}
}
}
}
uint32_t ble_conn_params_init(const ble_conn_params_init_t * p_init)
{
uint32_t err_code;
m_conn_params_config = *p_init;
m_change_param = false;
if (p_init->p_conn_params != NULL)
{
m_preferred_conn_params = *p_init->p_conn_params;
// Set the connection params in stack
err_code = sd_ble_gap_ppcp_set(&m_preferred_conn_params);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
else
{
// Fetch the connection params from stack
err_code = sd_ble_gap_ppcp_get(&m_preferred_conn_params);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
m_conn_handle = BLE_CONN_HANDLE_INVALID;
m_update_count = 0;
#ifdef USE_APP_TIMER
return app_timer_create(&m_conn_params_timer_id,
APP_TIMER_MODE_SINGLE_SHOT,
update_timeout_handler);
#else
return NRF_SUCCESS;
#endif
}
uint32_t ble_conn_params_stop(void)
{
#ifdef USE_APP_TIMER
return app_timer_stop(m_conn_params_timer_id);
#else /* #if !USE_APP_TIMER */
m_conn_params_timer.detach();
return NRF_SUCCESS;
#endif /* #if !USE_APP_TIMER */
}
static void conn_params_negotiation(void)
{
// Start negotiation if the received connection parameters are not acceptable
if (!is_conn_params_ok(&m_current_conn_params))
{
#ifdef USE_APP_TIMER
uint32_t err_code;
#endif
uint32_t timeout_ticks;
if (m_change_param)
{
// Notify the application that the procedure has failed
if (m_conn_params_config.evt_handler != NULL)
{
ble_conn_params_evt_t evt;
evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
m_conn_params_config.evt_handler(&evt);
}
}
else
{
if (m_update_count == 0)
{
// First connection parameter update
timeout_ticks = m_conn_params_config.first_conn_params_update_delay;
}
else
{
timeout_ticks = m_conn_params_config.next_conn_params_update_delay;
}
#ifdef USE_APP_TIMER
err_code = app_timer_start(m_conn_params_timer_id, timeout_ticks, NULL);
if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
{
m_conn_params_config.error_handler(err_code);
}
#else
m_conn_params_timer.attach(update_timeout_handler, timeout_ticks / 32768);
#endif
}
}
else
{
// Notify the application that the procedure has succeded
if (m_conn_params_config.evt_handler != NULL)
{
ble_conn_params_evt_t evt;
evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
m_conn_params_config.evt_handler(&evt);
}
}
m_change_param = false;
}
static void on_connect(ble_evt_t * p_ble_evt)
{
// Save connection parameters
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
m_current_conn_params = p_ble_evt->evt.gap_evt.params.connected.conn_params;
m_update_count = 0; // Connection parameter negotiation should re-start every connection
// Check if we shall handle negotiation on connect
if (m_conn_params_config.start_on_notify_cccd_handle == BLE_GATT_HANDLE_INVALID)
{
conn_params_negotiation();
}
}
static void on_disconnect(ble_evt_t * p_ble_evt)
{
#ifdef USE_APP_TIMER
uint32_t err_code;
#endif
m_conn_handle = BLE_CONN_HANDLE_INVALID;
// Stop timer if running
m_update_count = 0; // Connection parameters updates should happen during every connection
#ifdef USE_APP_TIMER
err_code = app_timer_stop(m_conn_params_timer_id);
if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
{
m_conn_params_config.error_handler(err_code);
}
#else
m_conn_params_timer.detach();
#endif
}
static void on_write(ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
// Check if this the correct CCCD
if (
(p_evt_write->handle == m_conn_params_config.start_on_notify_cccd_handle)
&&
(p_evt_write->len == 2)
)
{
// Check if this is a 'start notification'
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
// Do connection parameter negotiation if necessary
conn_params_negotiation();
}
else
{
#ifdef USE_APP_TIMER
uint32_t err_code;
// Stop timer if running
err_code = app_timer_stop(m_conn_params_timer_id);
if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
{
m_conn_params_config.error_handler(err_code);
}
#else /* #if !USE_APP_TIMER */
m_conn_params_timer.detach();
#endif /* #if !USE_APP_TIMER */
}
}
}
static void on_conn_params_update(ble_evt_t * p_ble_evt)
{
// Copy the parameters
m_current_conn_params = p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params;
conn_params_negotiation();
}
void ble_conn_params_on_ble_evt(ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_ble_evt);
break;
case BLE_GAP_EVT_CONN_PARAM_UPDATE:
on_conn_params_update(p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
uint32_t ble_conn_params_change_conn_params(ble_gap_conn_params_t * new_params)
{
uint32_t err_code;
m_preferred_conn_params = *new_params;
// Set the connection params in stack
err_code = sd_ble_gap_ppcp_set(&m_preferred_conn_params);
if (err_code == NRF_SUCCESS)
{
if (!is_conn_params_ok(&m_current_conn_params))
{
m_change_param = true;
err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params);
m_update_count = 1;
}
else
{
// Notify the application that the procedure has succeded
if (m_conn_params_config.evt_handler != NULL)
{
ble_conn_params_evt_t evt;
evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
m_conn_params_config.evt_handler(&evt);
}
err_code = NRF_SUCCESS;
}
}
return err_code;
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup ble_sdk_lib_conn_params Connection Parameters Negotiation
* @{
* @ingroup ble_sdk_lib
* @brief Module for initiating and executing a connection parameters negotiation procedure.
*/
#ifndef BLE_CONN_PARAMS_H__
#define BLE_CONN_PARAMS_H__
#include <stdint.h>
#include "nrf_ble.h"
#include "ble_srv_common.h"
/**@brief Connection Parameters Module event type. */
typedef enum
{
BLE_CONN_PARAMS_EVT_FAILED , /**< Negotiation procedure failed. */
BLE_CONN_PARAMS_EVT_SUCCEEDED /**< Negotiation procedure succeeded. */
} ble_conn_params_evt_type_t;
/**@brief Connection Parameters Module event. */
typedef struct
{
ble_conn_params_evt_type_t evt_type; /**< Type of event. */
} ble_conn_params_evt_t;
/**@brief Connection Parameters Module event handler type. */
typedef void (*ble_conn_params_evt_handler_t) (ble_conn_params_evt_t * p_evt);
/**@brief Connection Parameters Module init structure. This contains all options and data needed for
* initialization of the connection parameters negotiation module. */
typedef struct
{
ble_gap_conn_params_t * p_conn_params; /**< Pointer to the connection parameters desired by the application. When calling ble_conn_params_init, if this parameter is set to NULL, the connection parameters will be fetched from host. */
uint32_t first_conn_params_update_delay; /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (in number of timer ticks). */
uint32_t next_conn_params_update_delay; /**< Time between each call to sd_ble_gap_conn_param_update after the first (in number of timer ticks). Recommended value 30 seconds as per BLUETOOTH SPECIFICATION Version 4.0. */
uint8_t max_conn_params_update_count; /**< Number of attempts before giving up the negotiation. */
uint16_t start_on_notify_cccd_handle; /**< If procedure is to be started when notification is started, set this to the handle of the corresponding CCCD. Set to BLE_GATT_HANDLE_INVALID if procedure is to be started on connect event. */
bool disconnect_on_fail; /**< Set to TRUE if a failed connection parameters update shall cause an automatic disconnection, set to FALSE otherwise. */
ble_conn_params_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Connection Parameters. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
} ble_conn_params_init_t;
/**@brief Function for initializing the Connection Parameters module.
*
* @note If the negotiation procedure should be triggered when notification/indication of
* any characteristic is enabled by the peer, then this function must be called after
* having initialized the services.
*
* @param[in] p_init This contains information needed to initialize this module.
*
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
*/
uint32_t ble_conn_params_init(const ble_conn_params_init_t * p_init);
/**@brief Function for stopping the Connection Parameters module.
*
* @details This function is intended to be used by the application to clean up the connection
* parameters update module. This will stop the connection parameters update timer if
* running, thereby preventing any impending connection parameters update procedure. This
* function must be called by the application when it needs to clean itself up (for
* example, before disabling the bluetooth SoftDevice) so that an unwanted timer expiry
* event can be avoided.
*
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
*/
uint32_t ble_conn_params_stop(void);
/**@brief Function for changing the current connection parameters to a new set.
*
* @details Use this function to change the connection parameters to a new set of parameter
* (ie different from the ones given at init of the module).
* This function is usefull for scenario where most of the time the application
* needs a relatively big connection interval, and just sometimes, for a temporary
* period requires shorter connection interval, for example to transfer a higher
* amount of data.
* If the given parameters does not match the current connection's parameters
* this function initiates a new negotiation.
*
* @param[in] new_params This contains the new connections parameters to setup.
*
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
*/
uint32_t ble_conn_params_change_conn_params(ble_gap_conn_params_t *new_params);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack that are of interest to this module.
*
* @param[in] p_ble_evt The event received from the BLE stack.
*/
void ble_conn_params_on_ble_evt(ble_evt_t * p_ble_evt);
#endif // BLE_CONN_PARAMS_H__
/** @} */

View File

@ -0,0 +1,414 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ble_conn_state.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrf_ble.h"
#include "sdk_mapped_flags.h"
#include "app_error.h"
#if defined(__CC_ARM)
#pragma push
#pragma anon_unions
#elif defined(__ICCARM__)
#pragma language=extended
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#endif
#define BLE_CONN_STATE_N_DEFAULT_FLAGS 5 /**< The number of flags kept for each connection, excluding user flags. */
#define BLE_CONN_STATE_N_FLAGS (BLE_CONN_STATE_N_DEFAULT_FLAGS + BLE_CONN_STATE_N_USER_FLAGS) /**< The number of flags kept for each connection, including user flags. */
/**@brief Structure containing all the flag collections maintained by the Connection State module.
*/
typedef struct
{
sdk_mapped_flags_t valid_flags; /**< Flags indicating which connection handles are valid. */
sdk_mapped_flags_t connected_flags; /**< Flags indicating which connections are connected, since disconnected connection handles will not immediately be invalidated. */
sdk_mapped_flags_t central_flags; /**< Flags indicating in which connections the local device is the central. */
sdk_mapped_flags_t encrypted_flags; /**< Flags indicating which connections are encrypted. */
sdk_mapped_flags_t mitm_protected_flags; /**< Flags indicating which connections have encryption with protection from man-in-the-middle attacks. */
sdk_mapped_flags_t user_flags[BLE_CONN_STATE_N_USER_FLAGS]; /**< Flags that can be reserved by the user. The flags will be cleared when a connection is invalidated, otherwise, the user is wholly responsible for the flag states. */
} ble_conn_state_flag_collections_t;
/**@brief Structure containing the internal state of the Connection State module.
*/
typedef struct
{
uint16_t acquired_flags; /**< Bitmap for keeping track of which user flags have been acquired. */
uint16_t valid_conn_handles[SDK_MAPPED_FLAGS_N_KEYS]; /**< List of connection handles used as keys for the sdk_mapped_flags module. */
union
{
ble_conn_state_flag_collections_t flags; /**< Flag collections kept by the Connection State module. */
sdk_mapped_flags_t flag_array[BLE_CONN_STATE_N_FLAGS]; /**< Flag collections as array to allow use of @ref sdk_mapped_flags_bulk_update_by_key() when setting all flags. */
};
} ble_conn_state_t;
#if defined(__CC_ARM)
#pragma pop
#elif defined(__ICCARM__)
/* leave anonymous unions enabled */
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#endif
static ble_conn_state_t m_bcs = {0}; /**< Instantiation of the internal state. */
/**@brief Function for resetting all internal memory to the values it had at initialization.
*/
void bcs_internal_state_reset(void)
{
memset( &m_bcs, 0, sizeof(ble_conn_state_t) );
}
/**@brief Function for activating a connection record.
*
* @param p_record The record to activate.
* @param conn_handle The connection handle to copy into the record.
* @param role The role of the connection.
*
* @return whether the record was activated successfully.
*/
static bool record_activate(uint16_t conn_handle)
{
uint16_t available_index = sdk_mapped_flags_first_key_index_get(~m_bcs.flags.valid_flags);
if (available_index != SDK_MAPPED_FLAGS_INVALID_INDEX)
{
m_bcs.valid_conn_handles[available_index] = conn_handle;
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.connected_flags,
conn_handle,
1);
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.valid_flags,
conn_handle,
1);
return true;
}
return false;
}
/**@brief Function for marking a connection record as invalid and resetting the values.
*
* @param p_record The record to invalidate.
*/
static void record_invalidate(uint16_t conn_handle)
{
sdk_mapped_flags_bulk_update_by_key(m_bcs.valid_conn_handles,
m_bcs.flag_array,
BLE_CONN_STATE_N_FLAGS,
conn_handle,
0);
}
/**@brief Function for marking a connection as disconnected. See @ref BLE_CONN_STATUS_DISCONNECTED.
*
* @param p_record The record of the connection to set as disconnected.
*/
static void record_set_disconnected(uint16_t conn_handle)
{
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.connected_flags,
conn_handle,
0);
}
/**@brief Function for invalidating records with a @ref BLE_CONN_STATUS_DISCONNECTED
* connection status
*/
static void record_purge_disconnected()
{
sdk_mapped_flags_key_list_t disconnected_list;
disconnected_list = sdk_mapped_flags_key_list_get(
m_bcs.valid_conn_handles,
(~m_bcs.flags.connected_flags) & (m_bcs.flags.valid_flags));
for (int i = 0; i < disconnected_list.len; i++)
{
record_invalidate(disconnected_list.flag_keys[i]);
}
}
/**@brief Function for checking if a user flag has been acquired.
*
* @param[in] flag_id Which flag to check.
*
* @return Whether the flag has been acquired.
*/
static bool user_flag_is_acquired(ble_conn_state_user_flag_id_t flag_id)
{
return ((m_bcs.acquired_flags & (1 << flag_id)) != 0);
}
/**@brief Function for marking a user flag as acquired.
*
* @param[in] flag_id Which flag to mark.
*/
static void user_flag_acquire(ble_conn_state_user_flag_id_t flag_id)
{
m_bcs.acquired_flags |= (1 << flag_id);
}
void ble_conn_state_init(void)
{
bcs_internal_state_reset();
}
void ble_conn_state_on_ble_evt(ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
record_purge_disconnected();
if ( !record_activate(p_ble_evt->evt.gap_evt.conn_handle) )
{
// No more records available. Should not happen.
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
}
else
{
#if defined(TARGET_MCU_NRF51_16K_S110) || defined(TARGET_MCU_NRF51_32K_S110)
bool is_central = false;
#elif defined(TARGET_MCU_NRF51_16K_S120) || defined(TARGET_MCU_NRF51_32K_S120)
bool is_central = true;
#else
bool is_central =
(p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_CENTRAL);
#endif
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.central_flags,
p_ble_evt->evt.gap_evt.conn_handle,
is_central);
}
break;
case BLE_GAP_EVT_DISCONNECTED:
record_set_disconnected(p_ble_evt->evt.gap_evt.conn_handle);
break;
case BLE_GAP_EVT_CONN_SEC_UPDATE:
sdk_mapped_flags_update_by_key(
m_bcs.valid_conn_handles,
&m_bcs.flags.encrypted_flags,
p_ble_evt->evt.gap_evt.conn_handle,
(p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv > 1));
sdk_mapped_flags_update_by_key(
m_bcs.valid_conn_handles,
&m_bcs.flags.mitm_protected_flags,
p_ble_evt->evt.gap_evt.conn_handle,
(p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv > 2));
break;
}
}
bool ble_conn_state_valid(uint16_t conn_handle)
{
return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.valid_flags,
conn_handle);
}
uint8_t ble_conn_state_role(uint16_t conn_handle)
{
uint8_t role = BLE_GAP_ROLE_INVALID;
if ( sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, m_bcs.flags.valid_flags, conn_handle) )
{
bool central = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.central_flags,
conn_handle);
role = central ? BLE_GAP_ROLE_CENTRAL : BLE_GAP_ROLE_PERIPH;
}
return role;
}
ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle)
{
ble_conn_state_status_t conn_status = BLE_CONN_STATUS_INVALID;
bool valid = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.valid_flags,
conn_handle);
if (valid)
{
bool connected = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.connected_flags,
conn_handle);
conn_status = connected ? BLE_CONN_STATUS_CONNECTED : BLE_CONN_STATUS_DISCONNECTED;
}
return conn_status;
}
bool ble_conn_state_encrypted(uint16_t conn_handle)
{
return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.encrypted_flags,
conn_handle);
}
bool ble_conn_state_mitm_protected(uint16_t conn_handle)
{
return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.mitm_protected_flags,
conn_handle);
}
uint32_t ble_conn_state_n_connections(void)
{
return sdk_mapped_flags_n_flags_set(m_bcs.flags.connected_flags);
}
uint32_t ble_conn_state_n_centrals(void)
{
return sdk_mapped_flags_n_flags_set((m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags));
}
uint32_t ble_conn_state_n_peripherals(void)
{
return sdk_mapped_flags_n_flags_set((~m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags));
}
sdk_mapped_flags_key_list_t ble_conn_state_conn_handles(void)
{
return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles, m_bcs.flags.valid_flags);
}
sdk_mapped_flags_key_list_t ble_conn_state_central_handles(void)
{
return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles,
(m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags));
}
sdk_mapped_flags_key_list_t ble_conn_state_periph_handles(void)
{
return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles,
(~m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags));
}
ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void)
{
for (ble_conn_state_user_flag_id_t i = BLE_CONN_STATE_USER_FLAG0;
i < BLE_CONN_STATE_N_USER_FLAGS;
i++)
{
if ( !user_flag_is_acquired(i) )
{
user_flag_acquire(i);
return i;
}
}
return BLE_CONN_STATE_USER_FLAG_INVALID;
}
bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id)
{
if (user_flag_is_acquired(flag_id))
{
return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.user_flags[flag_id],
conn_handle);
}
else
{
return false;
}
}
void ble_conn_state_user_flag_set(uint16_t conn_handle,
ble_conn_state_user_flag_id_t flag_id,
bool value)
{
if (user_flag_is_acquired(flag_id))
{
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.user_flags[flag_id],
conn_handle,
value);
}
}
sdk_mapped_flags_t ble_conn_state_user_flag_collection(ble_conn_state_user_flag_id_t flag_id)
{
if ( user_flag_is_acquired(flag_id) )
{
return m_bcs.flags.user_flags[flag_id];
}
else
{
return 0;
}
}

View File

@ -0,0 +1,287 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
*
* @defgroup ble_conn_state Connection state
* @ingroup ble_sdk_lib
* @{
* @brief Module for storing data on BLE connections.
*
* @details This module stores certain states for each connection, which can be queried by
* connection handle. The module uses BLE events to keep the states updated.
*
* In addition to the preprogrammed states, this module can also keep track of a number of
* binary user states, or <i>user flags</i>. These are reset to 0 for new connections, but
* otherwise not touched by this module.
*
* This module uses the @ref sdk_mapped_flags module, with connection handles as keys and
* the connection states as flags.
*
* @note A connection handle is not immediately invalidated when it is disconnected. Certain states,
* such as the role, can still be queried until the next time a new connection is established
* to any device.
*
* To function properly, this module must be provided with BLE events from the SoftDevice
* through the @ref ble_conn_state_on_ble_evt() function. This module should be the first
* to receive BLE events if they are dispatched to multiple modules.
*/
#ifndef BLE_CONN_STATE_H__
#define BLE_CONN_STATE_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_ble.h"
#include "sdk_mapped_flags.h"
/**@brief Connection handle statuses.
*/
typedef enum
{
BLE_CONN_STATUS_INVALID, /**< The connection handle is invalid. */
BLE_CONN_STATUS_DISCONNECTED, /**< The connection handle refers to a connection that has been disconnected, but not yet invalidated. */
BLE_CONN_STATUS_CONNECTED, /**< The connection handle refers to an active connection. */
} ble_conn_state_status_t;
#define BLE_CONN_STATE_N_USER_FLAGS 16 /**< The number of available user flags. */
/**@brief One ID for each user flag collection.
*
* @details These IDs are used to identify user flag collections in the API calls.
*/
typedef enum
{
BLE_CONN_STATE_USER_FLAG0 = 0,
BLE_CONN_STATE_USER_FLAG1,
BLE_CONN_STATE_USER_FLAG2,
BLE_CONN_STATE_USER_FLAG3,
BLE_CONN_STATE_USER_FLAG4,
BLE_CONN_STATE_USER_FLAG5,
BLE_CONN_STATE_USER_FLAG6,
BLE_CONN_STATE_USER_FLAG7,
BLE_CONN_STATE_USER_FLAG8,
BLE_CONN_STATE_USER_FLAG9,
BLE_CONN_STATE_USER_FLAG10,
BLE_CONN_STATE_USER_FLAG11,
BLE_CONN_STATE_USER_FLAG12,
BLE_CONN_STATE_USER_FLAG13,
BLE_CONN_STATE_USER_FLAG14,
BLE_CONN_STATE_USER_FLAG15,
BLE_CONN_STATE_USER_FLAG_INVALID,
} ble_conn_state_user_flag_id_t;
/**
* @defgroup ble_conn_state_functions BLE connection state functions
* @{
*/
/**@brief Function for initializing or resetting the module.
*
* @details This function sets all states to their default, removing all records of connection handles.
*/
void ble_conn_state_init(void);
/**@brief Function for providing BLE SoftDevice events to the connection state module.
*
* @param[in] p_ble_evt The SoftDevice event.
*/
void ble_conn_state_on_ble_evt(ble_evt_t * p_ble_evt);
/**@brief Function for querying whether a connection handle represents a valid connection.
*
* @details A connection might be valid and have a BLE_CONN_STATUS_DISCONNECTED status.
* Those connections are invalidated after a new connection occurs.
*
* @param[in] conn_handle Handle of the connection.
*
* @retval true If conn_handle represents a valid connection, thus a connection for which
we have a record.
* @retval false If conn_handle is @ref BLE_GAP_ROLE_INVALID, or if it has never been recorded.
*/
bool ble_conn_state_valid(uint16_t conn_handle);
/**@brief Function for querying the role of the local device in a connection.
*
* @param[in] conn_handle Handle of the connection to get the role for.
*
* @return The role of the local device in the connection (see @ref BLE_GAP_ROLES).
* If conn_handle is not valid, the function returns BLE_GAP_ROLE_INVALID.
*/
uint8_t ble_conn_state_role(uint16_t conn_handle);
/**@brief Function for querying the status of a connection.
*
* @param[in] conn_handle Handle of the connection.
*
* @return The status of the connection.
* If conn_handle is not valid, the function returns BLE_CONN_STATE_INVALID.
*/
ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle);
/**@brief Function for querying whether a connection is encrypted.
*
* @param[in] conn_handle Handle of connection to get the encryption state for.
*
* @retval true If the connection is encrypted.
* @retval false If the connection is not encrypted or conn_handle is invalid.
*/
bool ble_conn_state_encrypted(uint16_t conn_handle);
/**@brief Function for querying whether a connection encryption is protected from Man in the Middle
* attacks.
*
* @param[in] conn_handle Handle of connection to get the MITM state for.
*
* @retval true If the connection is encrypted with MITM protection.
* @retval false If the connection is not encrypted, or encryption is not MITM protected, or
* conn_handle is invalid.
*/
bool ble_conn_state_mitm_protected(uint16_t conn_handle);
/**@brief Function for querying the total number of connections.
*
* @return The total number of valid connections for which the module has a record.
*/
uint32_t ble_conn_state_n_connections(void);
/**@brief Function for querying the total number of connections in which the role of the local
* device is @ref BLE_GAP_ROLE_CENTRAL.
*
* @return The number of connections in which the role of the local device is
* @ref BLE_GAP_ROLE_CENTRAL.
*/
uint32_t ble_conn_state_n_centrals(void);
/**@brief Function for querying the total number of connections in which the role of the local
* device is @ref BLE_GAP_ROLE_PERIPH.
*
* @return The number of connections in which the role of the local device is
* @ref BLE_GAP_ROLE_PERIPH.
*/
uint32_t ble_conn_state_n_peripherals(void);
/**@brief Function for obtaining a list of all connection handles for which the module has a record.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record.
*/
sdk_mapped_flags_key_list_t ble_conn_state_conn_handles(void);
/**@brief Function for obtaining a list of connection handles in which the role of the local
* device is @ref BLE_GAP_ROLE_CENTRAL.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record and in which
* the role of local device is @ref BLE_GAP_ROLE_CENTRAL.
*/
sdk_mapped_flags_key_list_t ble_conn_state_central_handles(void);
/**@brief Function for obtaining the handle for the connection in which the role of the local device
* is @ref BLE_GAP_ROLE_PERIPH.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record and in which
* the role of local device is @ref BLE_GAP_ROLE_PERIPH.
*/
sdk_mapped_flags_key_list_t ble_conn_state_periph_handles(void);
/**@brief Function for obtaining exclusive access to one of the user flag collections.
*
* @details The acquired collection contains one flag for each connection. These flags can be set
* and read individually for each connection.
*
* The state of user flags will not be modified by the connection state module, except to
* set it to 0 for a connection when that connection is invalidated.
*
* @return The ID of the acquired flag, or BLE_CONN_STATE_USER_FLAG_INVALID if none are available.
*/
ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void);
/**@brief Function for reading the value of a user flag.
*
* @param[in] conn_handle Handle of connection to get the flag state for.
* @param[in] flag_id Which flag to get the state for.
*
* @return The state of the flag. If conn_handle is invalid, the function returns false.
*/
bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id);
/**@brief Function for setting the value of a user flag.
*
* @param[in] conn_handle Handle of connection to set the flag state for.
* @param[in] flag_id Which flag to set the state for.
* @param[in] value Value to set the flag state to.
*/
void ble_conn_state_user_flag_set(uint16_t conn_handle,
ble_conn_state_user_flag_id_t flag_id,
bool value);
/**@brief Function for getting the state of a user flag for all connection handles.
*
* @details The returned collection can be used with the @ref sdk_mapped_flags API. The returned
* collection is a copy, so modifying it has no effect on the conn_state module.
*
* @param[in] flag_id Which flag to get states for.
*
* @return The collection of flag states. The collection is always all zeros when the flag_id is
* unregistered.
*/
sdk_mapped_flags_t ble_conn_state_user_flag_collection(ble_conn_state_user_flag_id_t flag_id);
/** @} */
/** @} */
#endif /* BLE_CONN_STATE_H__ */

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
/** @file
* @brief Contains definition of ble_date_time structure.
*/
/** @file
*
* @defgroup ble_sdk_srv_date_time BLE Date Time characteristic type
* @{
* @ingroup ble_sdk_lib
* @brief Definition of ble_date_time_t type.
*/
#ifndef BLE_DATE_TIME_H__
#define BLE_DATE_TIME_H__
#include <stdint.h>
/**@brief Date and Time structure. */
typedef struct
{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hours;
uint8_t minutes;
uint8_t seconds;
} ble_date_time_t;
static __INLINE uint8_t ble_date_time_encode(const ble_date_time_t * p_date_time,
uint8_t * p_encoded_data)
{
uint8_t len = uint16_encode(p_date_time->year, p_encoded_data);
p_encoded_data[len++] = p_date_time->month;
p_encoded_data[len++] = p_date_time->day;
p_encoded_data[len++] = p_date_time->hours;
p_encoded_data[len++] = p_date_time->minutes;
p_encoded_data[len++] = p_date_time->seconds;
return len;
}
static __INLINE uint8_t ble_date_time_decode(ble_date_time_t * p_date_time,
const uint8_t * p_encoded_data)
{
uint8_t len = sizeof(uint16_t);
p_date_time->year = uint16_decode(p_encoded_data);
p_date_time->month = p_encoded_data[len++];
p_date_time->day = p_encoded_data[len++];
p_date_time->hours = p_encoded_data[len++];
p_date_time->minutes = p_encoded_data[len++];
p_date_time->seconds = p_encoded_data[len++];
return len;
}
#endif // BLE_DATE_TIME_H__
/** @} */

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef BLE_GATT_DB_H__
#define BLE_GATT_DB_H__
#include "stdint.h"
#include "nrf_ble.h"
#include "ble_gattc.h"
#define BLE_GATT_DB_MAX_CHARS 4 /**< The maximum number of characteristics present in a service record. */
/**@brief Structure for holding the characteristic and the handle of its CCCD present on a server.
*/
typedef struct
{
ble_gattc_char_t characteristic; /**< Structure containing information about the characteristic. */
uint16_t cccd_handle; /**< CCCD Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if a CCCD is not present at the server. */
} ble_gatt_db_char_t;
/**@brief Structure for holding information about the service and the characteristics present on a
* server.
*/
typedef struct
{
ble_uuid_t srv_uuid; /**< UUID of the service. */
uint8_t char_count; /**< Number of characteristics present in the service. */
ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */
ble_gatt_db_char_t charateristics[BLE_GATT_DB_MAX_CHARS]; /**< Array of information related to the characteristics present in the service. This list can extend further than one. */
} ble_gatt_db_srv_t;
#endif /* BLE_GATT_DB_H__ */

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_SENSOR_LOCATION_H__
#define BLE_SENSOR_LOCATION_H__
typedef enum {
BLE_SENSOR_LOCATION_OTHER = 0 , /**<-- Other */
BLE_SENSOR_LOCATION_TOP_OF_SHOE = 1 , /**<-- Top of shoe */
BLE_SENSOR_LOCATION_IN_SHOE = 2 , /**<-- In shoe */
BLE_SENSOR_LOCATION_HIP = 3 , /**<-- Hip */
BLE_SENSOR_LOCATION_FRONT_WHEEL = 4 , /**<-- Front Wheel */
BLE_SENSOR_LOCATION_LEFT_CRANK = 5 , /**<-- Left Crank */
BLE_SENSOR_LOCATION_RIGHT_CRANK = 6 , /**<-- Right Crank */
BLE_SENSOR_LOCATION_LEFT_PEDAL = 7 , /**<-- Left Pedal */
BLE_SENSOR_LOCATION_RIGHT_PEDAL = 8 , /**<-- Right Pedal */
BLE_SENSOR_LOCATION_FRONT_HUB = 9 , /**<-- Front Hub */
BLE_SENSOR_LOCATION_REAR_DROPOUT = 10, /**<-- Rear Dropout */
BLE_SENSOR_LOCATION_CHAINSTAY = 11, /**<-- Chainstay */
BLE_SENSOR_LOCATION_REAR_WHEEL = 12, /**<-- Rear Wheel */
BLE_SENSOR_LOCATION_REAR_HUB = 13, /**<-- Rear Hub */
}ble_sensor_location_t;
#define BLE_NB_MAX_SENSOR_LOCATIONS 14
#endif // BLE_SENSOR_LOCATION_H__

View File

@ -0,0 +1,217 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_srv_common.h"
#include <string.h>
#include "nordic_common.h"
#include "app_error.h"
#include "nrf_ble.h"
uint8_t ble_srv_report_ref_encode(uint8_t * p_encoded_buffer,
const ble_srv_report_ref_t * p_report_ref)
{
uint8_t len = 0;
p_encoded_buffer[len++] = p_report_ref->report_id;
p_encoded_buffer[len++] = p_report_ref->report_type;
APP_ERROR_CHECK_BOOL(len == BLE_SRV_ENCODED_REPORT_REF_LEN);
return len;
}
void ble_srv_ascii_to_utf8(ble_srv_utf8_str_t * p_utf8, char * p_ascii)
{
p_utf8->length = (uint16_t)strlen(p_ascii);
p_utf8->p_str = (uint8_t *)p_ascii;
}
/**@brief Function for setting security requirements of a characteristic.
*
* @param[in] level required security level.
* @param[out] p_perm Characteristic security requirements.
*
* @return encoded security level and security mode.
*/
static inline void set_security_req(security_req_t level, ble_gap_conn_sec_mode_t * p_perm)
{
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(p_perm);
switch (level)
{
case SEC_NO_ACCESS:
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(p_perm);
break;
case SEC_OPEN:
BLE_GAP_CONN_SEC_MODE_SET_OPEN(p_perm);
break;
case SEC_JUST_WORKS:
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(p_perm);
break;
case SEC_MITM:
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(p_perm);
break;
case SEC_SIGNED:
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(p_perm);
break;
case SEC_SIGNED_MITM:
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(p_perm);
break;
}
return;
}
uint32_t characteristic_add(uint16_t service_handle,
ble_add_char_params_t * p_char_props,
ble_gatts_char_handles_t * p_char_handle)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
ble_gatts_attr_md_t user_descr_attr_md;
ble_gatts_attr_md_t cccd_md;
if (p_char_props->uuid_type == 0)
{
char_uuid.type = BLE_UUID_TYPE_BLE;
}
else
{
char_uuid.type = p_char_props->uuid_type;
}
char_uuid.uuid = p_char_props->uuid;
memset(&attr_md, 0, sizeof(ble_gatts_attr_md_t));
set_security_req(p_char_props->read_access, &attr_md.read_perm);
set_security_req(p_char_props->write_access, & attr_md.write_perm);
attr_md.rd_auth = (p_char_props->is_defered_read ? 1 : 0);
attr_md.wr_auth = (p_char_props->is_defered_write ? 1 : 0);
attr_md.vlen = (p_char_props->is_var_len ? 1 : 0);
attr_md.vloc = (p_char_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
memset(&char_md, 0, sizeof(ble_gatts_char_md_t));
if ((p_char_props->char_props.notify == 1)||(p_char_props->char_props.indicate == 1))
{
memset(&cccd_md, 0, sizeof(cccd_md));
set_security_req(p_char_props->cccd_write_access, &cccd_md.write_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
char_md.p_cccd_md = &cccd_md;
}
char_md.char_props = p_char_props->char_props;
memset(&attr_char_value, 0, sizeof(ble_gatts_attr_t));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.max_len = p_char_props->max_len;
if (p_char_props->p_init_value != NULL)
{
attr_char_value.init_len = p_char_props->init_len;
attr_char_value.p_value = p_char_props->p_init_value;
}
if (p_char_props->p_user_descr != NULL)
{
memset(&user_descr_attr_md, 0, sizeof(ble_gatts_attr_md_t));
char_md.char_user_desc_max_size = p_char_props->p_user_descr->max_size;
char_md.char_user_desc_size = p_char_props->p_user_descr->size;
char_md.p_char_user_desc = p_char_props->p_user_descr->p_char_user_desc;
char_md.p_user_desc_md = &user_descr_attr_md;
set_security_req(p_char_props->p_user_descr->read_access, &user_descr_attr_md.read_perm);
set_security_req(p_char_props->p_user_descr->write_access, &user_descr_attr_md.write_perm);
user_descr_attr_md.rd_auth = (p_char_props->p_user_descr->is_defered_read ? 1 : 0);
user_descr_attr_md.wr_auth = (p_char_props->p_user_descr->is_defered_write ? 1 : 0);
user_descr_attr_md.vlen = (p_char_props->p_user_descr->is_var_len ? 1 : 0);
user_descr_attr_md.vloc = (p_char_props->p_user_descr->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
}
if (p_char_props->p_presentation_format != NULL)
{
char_md.p_char_pf = p_char_props->p_presentation_format;
}
return sd_ble_gatts_characteristic_add(service_handle,
&char_md,
&attr_char_value,
p_char_handle);
}
uint32_t descriptor_add(uint16_t char_handle,
ble_add_descr_params_t * p_descr_props,
uint16_t * p_descr_handle)
{
ble_gatts_attr_t descr_params;
ble_uuid_t desc_uuid;
ble_gatts_attr_md_t attr_md;
memset(&descr_params, 0, sizeof(descr_params));
if (p_descr_props->uuid_type == 0)
{
desc_uuid.type = BLE_UUID_TYPE_BLE;
}
else
{
desc_uuid.type = p_descr_props->uuid_type;
}
desc_uuid.uuid = p_descr_props->uuid;
descr_params.p_uuid = &desc_uuid;
set_security_req(p_descr_props->read_access, &attr_md.read_perm);
set_security_req(p_descr_props->write_access,&attr_md.write_perm);
attr_md.rd_auth = (p_descr_props->is_defered_read ? 1 : 0);
attr_md.wr_auth = (p_descr_props->is_defered_write ? 1 : 0);
attr_md.vlen = (p_descr_props->is_var_len ? 1 : 0);
attr_md.vloc = (p_descr_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
descr_params.p_attr_md = &attr_md;
descr_params.init_len = p_descr_props->init_len;
descr_params.init_offs = p_descr_props->init_offs;
descr_params.max_len = p_descr_props->max_len;
descr_params.p_value = p_descr_props->p_value;
return sd_ble_gatts_descriptor_add(char_handle, &descr_params, p_descr_handle);
}

View File

@ -0,0 +1,368 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_common Common service definitions
* @{
* @ingroup ble_sdk_srv
* @brief Constants, type definitions, and functions that are common to all services.
*/
#ifndef BLE_SRV_COMMON_H__
#define BLE_SRV_COMMON_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble_types.h"
#include "app_util.h"
#include "nrf_ble.h"
#include "ble_gap.h"
#include "ble_gatt.h"
/** @defgroup UUID_SERVICES Service UUID definitions
* @{ */
#define BLE_UUID_ALERT_NOTIFICATION_SERVICE 0x1811 /**< Alert Notification service UUID. */
#define BLE_UUID_BATTERY_SERVICE 0x180F /**< Battery service UUID. */
#define BLE_UUID_BLOOD_PRESSURE_SERVICE 0x1810 /**< Blood Pressure service UUID. */
#define BLE_UUID_CURRENT_TIME_SERVICE 0x1805 /**< Current Time service UUID. */
#define BLE_UUID_CYCLING_SPEED_AND_CADENCE 0x1816 /**< Cycling Speed and Cadence service UUID. */
#define BLE_UUID_LOCATION_AND_NAVIGATION_SERVICE 0x1819 /**< Location and Navigation service UUID. */
#define BLE_UUID_DEVICE_INFORMATION_SERVICE 0x180A /**< Device Information service UUID. */
#define BLE_UUID_GLUCOSE_SERVICE 0x1808 /**< Glucose service UUID. */
#define BLE_UUID_HEALTH_THERMOMETER_SERVICE 0x1809 /**< Health Thermometer service UUID. */
#define BLE_UUID_HEART_RATE_SERVICE 0x180D /**< Heart Rate service UUID. */
#define BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE 0x1812 /**< Human Interface Device service UUID. */
#define BLE_UUID_IMMEDIATE_ALERT_SERVICE 0x1802 /**< Immediate Alert service UUID. */
#define BLE_UUID_LINK_LOSS_SERVICE 0x1803 /**< Link Loss service UUID. */
#define BLE_UUID_NEXT_DST_CHANGE_SERVICE 0x1807 /**< Next Dst Change service UUID. */
#define BLE_UUID_PHONE_ALERT_STATUS_SERVICE 0x180E /**< Phone Alert Status service UUID. */
#define BLE_UUID_REFERENCE_TIME_UPDATE_SERVICE 0x1806 /**< Reference Time Update service UUID. */
#define BLE_UUID_RUNNING_SPEED_AND_CADENCE 0x1814 /**< Running Speed and Cadence service UUID. */
#define BLE_UUID_SCAN_PARAMETERS_SERVICE 0x1813 /**< Scan Parameters service UUID. */
#define BLE_UUID_TX_POWER_SERVICE 0x1804 /**< TX Power service UUID. */
#define BLE_UUID_IPSP_SERVICE 0x1820 /**< Internet Protocol Support service UUID. */
/** @} */
/** @defgroup UUID_CHARACTERISTICS Characteristic UUID definitions
* @{ */
#define BLE_UUID_BATTERY_LEVEL_STATE_CHAR 0x2A1B /**< Battery Level State characteristic UUID. */
#define BLE_UUID_BATTERY_POWER_STATE_CHAR 0x2A1A /**< Battery Power State characteristic UUID. */
#define BLE_UUID_REMOVABLE_CHAR 0x2A3A /**< Removable characteristic UUID. */
#define BLE_UUID_SERVICE_REQUIRED_CHAR 0x2A3B /**< Service Required characteristic UUID. */
#define BLE_UUID_ALERT_CATEGORY_ID_CHAR 0x2A43 /**< Alert Category Id characteristic UUID. */
#define BLE_UUID_ALERT_CATEGORY_ID_BIT_MASK_CHAR 0x2A42 /**< Alert Category Id Bit Mask characteristic UUID. */
#define BLE_UUID_ALERT_LEVEL_CHAR 0x2A06 /**< Alert Level characteristic UUID. */
#define BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR 0x2A44 /**< Alert Notification Control Point characteristic UUID. */
#define BLE_UUID_ALERT_STATUS_CHAR 0x2A3F /**< Alert Status characteristic UUID. */
#define BLE_UUID_BATTERY_LEVEL_CHAR 0x2A19 /**< Battery Level characteristic UUID. */
#define BLE_UUID_BLOOD_PRESSURE_FEATURE_CHAR 0x2A49 /**< Blood Pressure Feature characteristic UUID. */
#define BLE_UUID_BLOOD_PRESSURE_MEASUREMENT_CHAR 0x2A35 /**< Blood Pressure Measurement characteristic UUID. */
#define BLE_UUID_BODY_SENSOR_LOCATION_CHAR 0x2A38 /**< Body Sensor Location characteristic UUID. */
#define BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR 0x2A22 /**< Boot Keyboard Input Report characteristic UUID. */
#define BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR 0x2A32 /**< Boot Keyboard Output Report characteristic UUID. */
#define BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR 0x2A33 /**< Boot Mouse Input Report characteristic UUID. */
#define BLE_UUID_CURRENT_TIME_CHAR 0x2A2B /**< Current Time characteristic UUID. */
#define BLE_UUID_DATE_TIME_CHAR 0x2A08 /**< Date Time characteristic UUID. */
#define BLE_UUID_DAY_DATE_TIME_CHAR 0x2A0A /**< Day Date Time characteristic UUID. */
#define BLE_UUID_DAY_OF_WEEK_CHAR 0x2A09 /**< Day Of Week characteristic UUID. */
#define BLE_UUID_DST_OFFSET_CHAR 0x2A0D /**< Dst Offset characteristic UUID. */
#define BLE_UUID_EXACT_TIME_256_CHAR 0x2A0C /**< Exact Time 256 characteristic UUID. */
#define BLE_UUID_FIRMWARE_REVISION_STRING_CHAR 0x2A26 /**< Firmware Revision String characteristic UUID. */
#define BLE_UUID_GLUCOSE_FEATURE_CHAR 0x2A51 /**< Glucose Feature characteristic UUID. */
#define BLE_UUID_GLUCOSE_MEASUREMENT_CHAR 0x2A18 /**< Glucose Measurement characteristic UUID. */
#define BLE_UUID_GLUCOSE_MEASUREMENT_CONTEXT_CHAR 0x2A34 /**< Glucose Measurement Context characteristic UUID. */
#define BLE_UUID_HARDWARE_REVISION_STRING_CHAR 0x2A27 /**< Hardware Revision String characteristic UUID. */
#define BLE_UUID_HEART_RATE_CONTROL_POINT_CHAR 0x2A39 /**< Heart Rate Control Point characteristic UUID. */
#define BLE_UUID_HEART_RATE_MEASUREMENT_CHAR 0x2A37 /**< Heart Rate Measurement characteristic UUID. */
#define BLE_UUID_HID_CONTROL_POINT_CHAR 0x2A4C /**< Hid Control Point characteristic UUID. */
#define BLE_UUID_HID_INFORMATION_CHAR 0x2A4A /**< Hid Information characteristic UUID. */
#define BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR 0x2A2A /**< IEEE Regulatory Certification Data List characteristic UUID. */
#define BLE_UUID_INTERMEDIATE_CUFF_PRESSURE_CHAR 0x2A36 /**< Intermediate Cuff Pressure characteristic UUID. */
#define BLE_UUID_INTERMEDIATE_TEMPERATURE_CHAR 0x2A1E /**< Intermediate Temperature characteristic UUID. */
#define BLE_UUID_LOCAL_TIME_INFORMATION_CHAR 0x2A0F /**< Local Time Information characteristic UUID. */
#define BLE_UUID_MANUFACTURER_NAME_STRING_CHAR 0x2A29 /**< Manufacturer Name String characteristic UUID. */
#define BLE_UUID_MEASUREMENT_INTERVAL_CHAR 0x2A21 /**< Measurement Interval characteristic UUID. */
#define BLE_UUID_MODEL_NUMBER_STRING_CHAR 0x2A24 /**< Model Number String characteristic UUID. */
#define BLE_UUID_UNREAD_ALERT_CHAR 0x2A45 /**< Unread Alert characteristic UUID. */
#define BLE_UUID_NEW_ALERT_CHAR 0x2A46 /**< New Alert characteristic UUID. */
#define BLE_UUID_PNP_ID_CHAR 0x2A50 /**< PNP Id characteristic UUID. */
#define BLE_UUID_PROTOCOL_MODE_CHAR 0x2A4E /**< Protocol Mode characteristic UUID. */
#define BLE_UUID_RECORD_ACCESS_CONTROL_POINT_CHAR 0x2A52 /**< Record Access Control Point characteristic UUID. */
#define BLE_UUID_REFERENCE_TIME_INFORMATION_CHAR 0x2A14 /**< Reference Time Information characteristic UUID. */
#define BLE_UUID_REPORT_CHAR 0x2A4D /**< Report characteristic UUID. */
#define BLE_UUID_REPORT_MAP_CHAR 0x2A4B /**< Report Map characteristic UUID. */
#define BLE_UUID_RINGER_CONTROL_POINT_CHAR 0x2A40 /**< Ringer Control Point characteristic UUID. */
#define BLE_UUID_RINGER_SETTING_CHAR 0x2A41 /**< Ringer Setting characteristic UUID. */
#define BLE_UUID_SCAN_INTERVAL_WINDOW_CHAR 0x2A4F /**< Scan Interval Window characteristic UUID. */
#define BLE_UUID_SCAN_REFRESH_CHAR 0x2A31 /**< Scan Refresh characteristic UUID. */
#define BLE_UUID_SERIAL_NUMBER_STRING_CHAR 0x2A25 /**< Serial Number String characteristic UUID. */
#define BLE_UUID_SOFTWARE_REVISION_STRING_CHAR 0x2A28 /**< Software Revision String characteristic UUID. */
#define BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR 0x2A47 /**< Supported New Alert Category characteristic UUID. */
#define BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR 0x2A48 /**< Supported Unread Alert Category characteristic UUID. */
#define BLE_UUID_SYSTEM_ID_CHAR 0x2A23 /**< System Id characteristic UUID. */
#define BLE_UUID_TEMPERATURE_MEASUREMENT_CHAR 0x2A1C /**< Temperature Measurement characteristic UUID. */
#define BLE_UUID_TEMPERATURE_TYPE_CHAR 0x2A1D /**< Temperature Type characteristic UUID. */
#define BLE_UUID_TIME_ACCURACY_CHAR 0x2A12 /**< Time Accuracy characteristic UUID. */
#define BLE_UUID_TIME_SOURCE_CHAR 0x2A13 /**< Time Source characteristic UUID. */
#define BLE_UUID_TIME_UPDATE_CONTROL_POINT_CHAR 0x2A16 /**< Time Update Control Point characteristic UUID. */
#define BLE_UUID_TIME_UPDATE_STATE_CHAR 0x2A17 /**< Time Update State characteristic UUID. */
#define BLE_UUID_TIME_WITH_DST_CHAR 0x2A11 /**< Time With Dst characteristic UUID. */
#define BLE_UUID_TIME_ZONE_CHAR 0x2A0E /**< Time Zone characteristic UUID. */
#define BLE_UUID_TX_POWER_LEVEL_CHAR 0x2A07 /**< TX Power Level characteristic UUID. */
#define BLE_UUID_CSC_FEATURE_CHAR 0x2A5C /**< Cycling Speed and Cadence Feature characteristic UUID. */
#define BLE_UUID_CSC_MEASUREMENT_CHAR 0x2A5B /**< Cycling Speed and Cadence Measurement characteristic UUID. */
#define BLE_UUID_RSC_FEATURE_CHAR 0x2A54 /**< Running Speed and Cadence Feature characteristic UUID. */
#define BLE_UUID_SC_CTRLPT_CHAR 0x2A55 /**< Speed and Cadence Control Point UUID. */
#define BLE_UUID_RSC_MEASUREMENT_CHAR 0x2A53 /**< Running Speed and Cadence Measurement characteristic UUID. */
#define BLE_UUID_SENSOR_LOCATION_CHAR 0x2A5D /**< Sensor Location characteristic UUID. */
#define BLE_UUID_EXTERNAL_REPORT_REF_DESCR 0x2907 /**< External Report Reference descriptor UUID. */
#define BLE_UUID_REPORT_REF_DESCR 0x2908 /**< Report Reference descriptor UUID. */
#define BLE_UUID_LN_FEATURE_CHAR 0x2A6A /**< Location Navigation Service, Feature characteristic UUID. */
#define BLE_UUID_LN_POSITION_QUALITY_CHAR 0x2A69 /**< Location Navigation Service, Position quality UUID. */
#define BLE_UUID_LN_LOCATION_AND_SPEED_CHAR 0x2A67 /**< Location Navigation Service, Location and Speed characteristic UUID. */
#define BLE_UUID_LN_NAVIGATION_CHAR 0x2A68 /**< Location Navigation Service, Navigation characteristic UUID. */
#define BLE_UUID_LN_CONTROL_POINT_CHAR 0x2A6B /**< Location Navigation Service, Control point characteristic UUID. */
/** @} */
/** @defgroup ALERT_LEVEL_VALUES Definitions for the Alert Level characteristic values
* @{ */
#define BLE_CHAR_ALERT_LEVEL_NO_ALERT 0x00 /**< No Alert. */
#define BLE_CHAR_ALERT_LEVEL_MILD_ALERT 0x01 /**< Mild Alert. */
#define BLE_CHAR_ALERT_LEVEL_HIGH_ALERT 0x02 /**< High Alert. */
/** @} */
#define BLE_SRV_ENCODED_REPORT_REF_LEN 2 /**< The length of an encoded Report Reference Descriptor. */
#define BLE_CCCD_VALUE_LEN 2 /**< The length of a CCCD value. */
/**@brief Type definition for error handler function that will be called in case of an error in
* a service or a service library module. */
typedef void (*ble_srv_error_handler_t) (uint32_t nrf_error);
/**@brief Value of a Report Reference descriptor.
*
* @details This is mapping information that maps the parent characteristic to the Report ID(s) and
* Report Type(s) defined within a Report Map characteristic.
*/
typedef struct
{
uint8_t report_id; /**< Non-zero value if there is more than one instance of the same Report Type */
uint8_t report_type; /**< Type of Report characteristic (see @ref BLE_HIDS_REPORT_TYPE) */
} ble_srv_report_ref_t;
/**@brief UTF-8 string data type.
*
* @note The type can only hold a pointer to the string data (i.e. not the actual data).
*/
typedef struct
{
uint16_t length; /**< String length. */
uint8_t * p_str; /**< String data. */
} ble_srv_utf8_str_t;
/**@brief Security settings structure.
* @details This structure contains the security options needed during initialization of the
* service.
*/
typedef struct
{
ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
} ble_srv_security_mode_t;
/**@brief Security settings structure.
* @details This structure contains the security options needed during initialization of the
* service. It can be used when the characteristics contains a CCCD.
*/
typedef struct
{
ble_gap_conn_sec_mode_t cccd_write_perm; /**< Write permissions for Client Characteristic Configuration Descriptor. */
ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
} ble_srv_cccd_security_mode_t;
/**@brief Function for decoding a CCCD value, and then testing if notification is
* enabled.
*
* @param[in] p_encoded_data Buffer where the encoded CCCD is stored.
*
* @retval TRUE If notification is enabled.
* @retval FALSE Otherwise.
*/
static __INLINE bool ble_srv_is_notification_enabled(uint8_t * p_encoded_data)
{
uint16_t cccd_value = uint16_decode(p_encoded_data);
return ((cccd_value & BLE_GATT_HVX_NOTIFICATION) != 0);
}
/**@brief Function for decoding a CCCD value, and then testing if indication is
* enabled.
*
* @param[in] p_encoded_data Buffer where the encoded CCCD is stored.
*
* @retval TRUE If indication is enabled.
* @retval FALSE Otherwise.
*/
static __INLINE bool ble_srv_is_indication_enabled(uint8_t * p_encoded_data)
{
uint16_t cccd_value = uint16_decode(p_encoded_data);
return ((cccd_value & BLE_GATT_HVX_INDICATION) != 0);
}
/**@brief Function for encoding a Report Reference Descriptor.
*
* @param[in] p_encoded_buffer The buffer of the encoded data.
* @param[in] p_report_ref Report Reference value to be encoded.
*
* @return Length of the encoded data.
*/
uint8_t ble_srv_report_ref_encode(uint8_t * p_encoded_buffer,
const ble_srv_report_ref_t * p_report_ref);
/**@brief Function for making a UTF-8 structure refer to an ASCII string.
*
* @param[out] p_utf8 UTF-8 structure to be set.
* @param[in] p_ascii ASCII string to be referred to.
*/
void ble_srv_ascii_to_utf8(ble_srv_utf8_str_t * p_utf8, char * p_ascii);
/**@brief Security Access enumeration.
* @details This enumeration gives the possible requirements for accessing a characteristic value.
*/
typedef enum
{
SEC_NO_ACCESS = 0, /**< Not possible to access. */
SEC_OPEN = 1, /**< Access open. */
SEC_JUST_WORKS = 2, /**< Access possible with 'Just Works' security at least. */
SEC_MITM = 3, /**< Access possible with 'MITM' security at least. */
SEC_SIGNED = 4, /**< Access possible with 'signed' security at least. */
SEC_SIGNED_MITM = 5 /**< Access possible with 'signed and MITM' security at least. */
}security_req_t;
/**@brief Characteristic User Descriptor parameters.
* @details This structure contains the parameters for User Descriptor.
*/
typedef struct
{
uint16_t max_size; /**< Maximum size of the user descriptor*/
uint16_t size; /**< Size of the user descriptor*/
uint8_t *p_char_user_desc; /**< User descriptor content, pointer to a UTF-8 encoded string (non-NULL terminated)*/
bool is_var_len; /**< Indicates if the user descriptor has variable length.*/
ble_gatt_char_props_t char_props; /**< user descriptor properties.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
security_req_t read_access; /**< Security requirement for reading the user descriptor.*/
security_req_t write_access; /**< Security requirement for writing the user descriptor.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
}ble_add_char_user_desc_t;
/**@brief Add characteristic parameters structure.
* @details This structure contains the parameters needed to use the @ref characteristic_add function.
*/
typedef struct
{
uint16_t uuid; /**< Characteristic UUID (16 bits UUIDs).*/
uint8_t uuid_type; /**< Base UUID. If 0, the Bluetooth SIG UUID will be used. Otherwise, this should be a value returned by @ref sd_ble_uuid_vs_add when adding the base UUID.*/
uint16_t max_len; /**< Maximum length of the characteristic value.*/
uint16_t init_len; /**< Initial length of the characteristic value.*/
uint8_t * p_init_value; /**< Initial encoded value of the characteristic.*/
bool is_var_len; /**< Indicates if the characteristic value has variable length.*/
ble_gatt_char_props_t char_props; /**< Characteristic properties.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
security_req_t read_access; /**< Security requirement for reading the characteristic value.*/
security_req_t write_access; /**< Security requirement for writing the characteristic value.*/
security_req_t cccd_write_access; /**< Security requirement for writing the characteristic's CCCD.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
ble_add_char_user_desc_t *p_user_descr; /**< Pointer to user descriptor if needed*/
ble_gatts_char_pf_t *p_presentation_format; /**< Pointer to characteristic format if needed*/
} ble_add_char_params_t;
/**@brief Add descriptor parameters structure.
* @details This structure contains the parameters needed to use the @ref descriptor_add function.
*/
typedef struct
{
uint16_t uuid; /**< descriptor UUID (16 bits UUIDs).*/
uint8_t uuid_type; /**< Base UUID. If 0, the Bluetooth SIG UUID will be used. Otherwise, this should be a value returned by @ref sd_ble_uuid_vs_add when adding the base UUID.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
bool is_var_len; /**< Indicates if the descriptor value has variable length.*/
security_req_t read_access; /**< Security requirement for reading the descriptor value.*/
security_req_t write_access; /**< Security requirement for writing the descriptor value.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
uint16_t init_len; /**< Initial descriptor value length in bytes. */
uint16_t init_offs; /**< Initial descriptor value offset in bytes. If different from zero, the first init_offs bytes of the attribute value will be left uninitialized. */
uint16_t max_len; /**< Maximum descriptor value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */
uint8_t* p_value; /**< Pointer to the value of the descriptor*/
} ble_add_descr_params_t;
/**@brief Function for adding a characteristic to a given service.
*
* If no pointer is given for the initial value,
* the initial length parameter will be ignored and the initial length will be 0.
*
* @param[in] service_handle Handle of the service to which the characteristic is to be added.
* @param[in] p_char_props Information needed to add the characteristic.
* @param[out] p_char_handle Handle of the added characteristic.
*
* @retval NRF_SUCCESS If the characteristic was added successfully. Otherwise, an error code is returned.
*/
uint32_t characteristic_add(uint16_t service_handle,
ble_add_char_params_t * p_char_props,
ble_gatts_char_handles_t * p_char_handle);
/**@brief Function for adding a characteristic's descriptor to a given characteristic.
*
* @param[in] char_handle Handle of the characteristic to which the descriptor is to be added, if @ref BLE_GATT_HANDLE_INVALID is used, it will be placed sequentially.
* @param[in] p_descr_props Information needed to add the descriptor.
* @param[out] p_descr_handle Handle of the added descriptor.
*
* @retval NRF_SUCCESS If the characteristic was added successfully. Otherwise, an error code is returned.
*/
uint32_t descriptor_add(uint16_t char_handle,
ble_add_descr_params_t * p_descr_props,
uint16_t * p_descr_handle);
#endif // BLE_SRV_COMMON_H__
/** @} */

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file device_manager_cnfg.h
*
* @cond
* @defgroup device_manager_cnfg Device Manager Configuration
* @ingroup device_manager
* @{
*
* @brief Defines application specific configuration for Device Manager.
*
* @details All configurations that are specific to application have been defined
* here. Application should configuration that best suits its requirements.
*/
#ifndef DEVICE_MANAGER_CNFG_H__
#define DEVICE_MANAGER_CNFG_H__
/**
* @defgroup device_manager_inst Device Manager Instances
* @{
*/
/**
* @brief Maximum applications that Device Manager can support.
*
* @details Maximum application that the Device Manager can support.
* Currently only one application can be supported.
* Minimum value : 1
* Maximum value : 1
* Dependencies : None.
*/
#define DEVICE_MANAGER_MAX_APPLICATIONS 1
/**
* @brief Maximum connections that Device Manager should simultaneously manage.
*
* @details Maximum connections that Device Manager should simultaneously manage.
* Minimum value : 1
* Maximum value : Maximum links supported by SoftDevice.
* Dependencies : None.
*/
#define DEVICE_MANAGER_MAX_CONNECTIONS 1
/**
* @brief Maximum bonds that Device Manager should manage.
*
* @details Maximum bonds that Device Manager should manage.
* Minimum value : 1
* Maximum value : 254.
* Dependencies : None.
* @note In case of GAP Peripheral role, the Device Manager will accept bonding procedure
* requests from peers even if this limit is reached, but bonding information will not
* be stored. In such cases, application will be notified with DM_DEVICE_CONTEXT_FULL
* as event result at the completion of the security procedure.
*/
#define DEVICE_MANAGER_MAX_BONDS 2
/**
* @brief Maximum Characteristic Client Descriptors used for GATT Server.
*
* @details Maximum Characteristic Client Descriptors used for GATT Server.
* Minimum value : 1
* Maximum value : 254.
* Dependencies : None.
*/
#define DM_GATT_CCCD_COUNT 2
/**
* @brief Size of application context.
*
* @details Size of application context that Device Manager should manage for each bonded device.
* Size had to be a multiple of word size.
* Minimum value : 4.
* Maximum value : 256.
* Dependencies : Needed only if Application Context saving is used by the application.
* @note If set to zero, its an indication that application context is not required to be managed
* by the module.
*/
#define DEVICE_MANAGER_APP_CONTEXT_SIZE 0
/* @} */
/* @} */
/** @endcond */
#endif // DEVICE_MANAGER_CNFG_H__

View File

@ -0,0 +1,909 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file device_manager.h
*
* @defgroup device_manager Device Manager
* @ingroup ble_sdk_lib
* @{
* @brief Device Manager Application Interface Abstraction.
*
* @details The Device Manager module manages Active and Bonded Peers. Management of peer includes
* book keeping of contextual information like the Security Keys, GATT
* configuration and any application specific information.
*
* Active Peers are devices which are connected, and may or may not be bonded.
* Bonded Peers are devices which are bonded, and may or may not be Active (Connected).
* Active Bonded Peer refers to a device which is connected and bonded.
*
* Paired Devices refers to peer devices that are connected and have necessary context
* establishment/exchange for the current connection session. On disconnect,
* all contextual information is flushed. For example, SMP Information Exchanged during
* pairing and GATT Configuration is not retained on disconnection.
*
* Note that this module allows management of contextual information but
* does not provide an interface for connection management. Therefore, entering connectible
* mode, connection establishment, or disconnection of a link with peer is not in scope
* of this module.
*
* For bonded peers, the contextual information is required to be retained on disconnection
* and power cycling. Persistent storage of contextual information is handled by the
* module. This module categorizes the contextual information into 3 categories:
* - <b>Bonding Information</b>
* Bond information is the information exchanged between local and peer device to
* establish a bond. It also includes peer identification information,
* like the peer address or the IRK or both. From here on this category of information
* is referred to as Device Context.
* - <b>Service/Protocol Information</b>
* Service/Protocol information is the information retained for the peer to save on one-time
* procedures like the GATT Service Discovery procedures and Service Configurations.
* It allows devices to resume data exchange on subsequent reconnection without having
* to perform initial set-up procedures each time. From here on this category is
* referred to as Service Context.
* - <b>Application Information</b>
* Application information is the context that the application would like to associate with
* each of the bonded device. For example, if the application chooses to rank its peers
* in order to manage them better, the rank information could be treated as
* Application Information. This storage space is provided to save the application from
* maintaining a mapping table with each Device Instance and Application Information.
* However, if the application have no use for this, it is possible to not
* use or employ this at compile time. From here on this category of information is
* referred to as Application Context.
*/
#ifndef DEVICE_MANAGER_H__
#define DEVICE_MANAGER_H__
#include <stdint.h>
#include <stdbool.h>
#include "sdk_common.h"
#include "nrf_ble.h"
#include "ble_gap.h"
#include "device_manager_cnfg.h"
/**
* @defgroup dm_service_cntext_types Service/Protocol Types
*
* @brief Describes the possible types of Service/Protocol Contexts for a bonded/peer device.
*
* @details Possible Service/Protocol context per peer device. The Device Manager provides the
* functionality of persistently storing the Service/Protocol context and can automatically
* load them when needed.
* For example system attributes for a GATT Server. Based on the nature of the application,
* not all service types may be needed. The application can specify
* only the service/protocol context it wants to use at the time of registration.
* @{
*/
#define DM_PROTOCOL_CNTXT_NONE 0x00 /**< No Service Context, this implies the application does not want to associate any service/protocol context with the peer device */
#define DM_PROTOCOL_CNTXT_GATT_SRVR_ID 0x01 /**< GATT Server Service Context, this implies the application does associate GATT Server with the peer device and this information will be loaded when needed for a bonded device */
#define DM_PROTOCOL_CNTXT_GATT_CLI_ID 0x02 /**< GATT Client Service Context, this implies the application does associate GATT Client with the peer device and this information will be loaded when needed for a bonded device */
#define DM_PROTOCOL_CNTXT_ALL \
(DM_PROTOCOL_CNTXT_GATT_SRVR_ID | DM_PROTOCOL_CNTXT_GATT_CLI_ID) /**< All Service/Protocol Context, this implies that the application wants to associate all Service/Protocol Information with the bonded device. This is configurable based on system requirements. If the application has only one type of service, this define could be altered to reflect the same. */
/** @} */
/**
* @defgroup dm_events Device Manager Events
*
* @brief This section describes the device manager events that are notified to the application.
*
* @details The Device Manager notifies the application of various asynchronous events using the
* asynchronous event notification callback. All events has been categorized into:
* a. General.
* b. Link Status.
* c. Context Management.
*
* In the callback, these events are notified along with handle that uniquely identifies:
* application instance, active instance (if applicable), device instance
* bonding instance, (if applicable) and service instance.
* Not all events are pertaining to an active connection, for example a context deletion event could occur even if the peer
* is not connected. Also, general category of events may not be pertaining to any specific peer.
* See also \ref dm_event_cb_t and \ref dm_register.
* @{
*/
/**
* @defgroup general_events General Events
*
* @brief General or miscellaneous events.
*
* @details This category of events are general events not pertaining to a peer or context.
*
* @{
*/
#define DM_EVT_RFU 0x00 /**< Reserved for future use, is never notified. */
#define DM_EVT_ERROR 0x01 /**< Device Manager Event Error. */
/** @} */
/**
* @defgroup link_status_events Link Status Events
*
* @brief Link Status Events.
*
* @details This category of events notify the application of the link status. Event result associated
* with the event is provided along with the event in the callback to provide more details of
* whether a procedure succeeded or failed and assist the application in decision making of
* how to proceed. For example if a DM_DEVICE_CONNECT_IND is indicated with NRF_SUCCESS
* result, the application may want to proceed with discovering and association with
* service of the peer. However, if indicated with a failure result, the application may
* want to take an alternate action such as reattempting to connect or go into a
* sleep mode.
*
* @{
*/
#define DM_EVT_CONNECTION 0x11 /**< Indicates that link with the peer is established. */
#define DM_EVT_DISCONNECTION 0x12 /**< Indicates that link with peer is torn down. */
#define DM_EVT_SECURITY_SETUP 0x13 /**< Security procedure for link started indication */
#define DM_EVT_SECURITY_SETUP_COMPLETE 0x14 /**< Security procedure for link completion indication. */
#define DM_EVT_LINK_SECURED 0x15 /**< Indicates that link with the peer is secured. For bonded devices, subsequent reconnections with bonded peer will result only in this event when the link is secured and setup procedures will not occur unless the bonding information is either lost or deleted on either or both sides. */
#define DM_EVT_SECURITY_SETUP_REFRESH 0x16 /**< Indicates that the security on the link was re-established. */
/** @} */
/**
* @defgroup context_mgmt_events Context Management Events
*
* @brief Context Management Events.
*
* @details These events notify the application of the status of context loading and storing.
*
* @{
*/
#define DM_EVT_DEVICE_CONTEXT_LOADED 0x21 /**< Indicates that device context for a peer is loaded. */
#define DM_EVT_DEVICE_CONTEXT_STORED 0x22 /**< Indicates that device context is stored persistently. */
#define DM_EVT_DEVICE_CONTEXT_DELETED 0x23 /**< Indicates that device context is deleted. */
#define DM_EVT_SERVICE_CONTEXT_LOADED 0x31 /**< Indicates that service context for a peer is loaded. */
#define DM_EVT_SERVICE_CONTEXT_STORED 0x32 /**< Indicates that service context is stored persistently. */
#define DM_EVT_SERVICE_CONTEXT_DELETED 0x33 /**< Indicates that service context is deleted. */
#define DM_EVT_APPL_CONTEXT_LOADED 0x41 /**< Indicates that application context for a peer is loaded. */
#define DM_EVT_APPL_CONTEXT_STORED 0x42 /**< Indicates that application context is stored persistently. */
#define DM_EVT_APPL_CONTEXT_DELETED 0x43 /**< Indicates that application context is deleted. */
/** @} */
/** @} */
#define DM_INVALID_ID 0xFF /**< Invalid instance idenitifer. */
/**
* @defgroup dm_data_structure Device Manager Data Types
*
* @brief This section describes all the data types exposed by the module to the application.
* @{
*/
/**
* @brief Application Instance.
*
* @details Application instance uniquely identifies an application. The identifier is allocated by
* the device manager when application registers with the module. The application is
* expected to identify itself with this instance identifier when initiating subsequent
* requests. Application should use the utility API \ref dm_application_instance_set in
* order to set its application instance in dm_handle_t needed for all subsequent APIs.
* See also \ref dm_register.
*/
typedef uint8_t dm_application_instance_t;
/**
* @brief Connection Instance.
*
* @details Identifies connection instance for an active device. This instance is allocated by the
* device manager when a connection is established and is notified with DM_EVT_CONNECTION
* with the event result NRF_SUCCESS.
*/
typedef uint8_t dm_connection_instance_t;
/**
* @brief Device Instance.
*
* @details Uniquely identifies a bonded peer device. The peer device may or may not be connected.
* In case of the central: The bonded device instance to identify the peer is allocated when bonding procedure is initiated by the central using dm_security_setup_req.
* In case of the peripheral: When the bonding procedure is successful, the DM_EVT_SECURITY_SETUP_COMPLETE event with success event result, is received.
* In case the module cannot add more bonded devices, no instance is allocated, this is indicated by an appropriate error code for the API/event as the case may be. Application can choose to disconnect the link.
*/
typedef uint8_t dm_device_instance_t;
/**
* @brief Service Instance.
*
* @details Uniquely identifies a peer device. The peer device may or may not be connected. This
* instance is allocated by the device manager when a device is bonded and is notified
* when security procedures have been initiated.
* Security Procedures initiation is notified with DM_SECURITY_SETUP_IND with
* success event result. In case the event result indicates that the module cannot add more
* bonded devices, no instance is allocated. Application can chose to disconnect the link.
*/
typedef uint8_t dm_service_instance_t;
/**
* @brief Service/Protocol Type Identifier.
*
* @details Uniquely identifies a service or a protocol type. Service/Protocol Type identification
* is needed as each service/protocol can have its own contextual data.
* This allows the peer to access more than one service at a time. \ref dm_service_cntext_types describes the
* list of services/protocols supported.
*/
typedef uint8_t service_type_t;
/**@brief Device Manager Master identification and encryption information. */
typedef struct dm_enc_key
{
ble_gap_enc_info_t enc_info; /**< GAP encryption information. */
ble_gap_master_id_t master_id; /**< Master identification. */
} dm_enc_key_t;
/** @brief Device Manager identity and address information. */
typedef struct dm_id_key
{
ble_gap_irk_t id_info; /**< Identity information. */
ble_gap_addr_t id_addr_info; /**< Identity address information. */
} dm_id_key_t;
/** @brief Device Manager signing information. */
typedef struct dm_sign_key
{
ble_gap_sign_info_t sign_key; /**< GAP signing information. */
} dm_sign_key_t;
/** @brief Security keys. */
typedef struct dm_sec_keyset
{
union
{
dm_enc_key_t * p_enc_key; /**< Pointer to Device Manager encryption information structure. */
} enc_key;
dm_id_key_t * p_id_key; /**< Identity key, or NULL. */
dm_sign_key_t * p_sign_key; /**< Signing key, or NULL. */
} dm_sec_keys_t;
/** @brief Device Manager security key set. */
typedef struct
{
dm_sec_keys_t keys_periph; /**< Keys distributed by the device in the Peripheral role. */
dm_sec_keys_t keys_central; /**< Keys distributed by the device in the Central role. */
} dm_sec_keyset_t;
/**
* @brief Device Handle used for unique identification of each peer.
*
* @details This data type is used to uniquely identify each peer device. A peer device could be
* active and/or bonded. Therefore an instance for active and bonded is provided.
* However, the application is expected to treat this is an opaque structure and use this for
* all API interactions once stored on appropriate events.
* See \ref dm_events.
*/
typedef struct device_handle
{
dm_application_instance_t appl_id; /**< Identifies the application instances for the device that is being managed. */
dm_connection_instance_t connection_id; /**< Identifies the active connection instance. */
dm_device_instance_t device_id; /**< Identifies peer instance in the data base. */
dm_service_instance_t service_id; /**< Service instance identifier. */
} dm_handle_t;
/**
* @brief Definition of Data Context.
*
* @details Defines contextual data format, it consists of context data length and pointer to data.
*/
typedef struct
{
uint32_t flags; /**< Additional flags identifying data. */
uint32_t len; /**< Length of data. */
uint8_t * p_data; /**< Pointer to contextual data, a copy is made of the data. */
} dm_context_t;
/**
* @brief Device Context.
*
* @details Defines "device context" type for a device managed by device manager.
*/
typedef dm_context_t dm_device_context_t;
/**
* @brief Service Context.
*
* @details Service context data for a service identified by the 'service_type' field.
*/
typedef struct
{
service_type_t service_type; /**< Identifies the service/protocol to which the context data is related. */
dm_context_t context_data; /**< Contains length and pointer to context data */
} dm_service_context_t;
/**
* @brief Application context.
*
* @details The application context can be used by the application to map any application level
* information that is to be mapped with a particular peer.
* For bonded peers, this information will be stored by the bond manager persistently.
* Note that the device manager treats this information as an
* opaque block of bytes.
* Necessary APIs to get and set this context for a peer have been provided.
*/
typedef dm_context_t dm_application_context_t;
/**
* @brief Event parameters.
*
* @details Defines event parameters for each of the events notified by the module.
*/
typedef union
{
ble_gap_evt_t * p_gap_param; /**< All events that are triggered in device manager as a result of GAP events, like connection, disconnection and security procedures are accompanied with GAP parameters. */
dm_application_context_t * p_app_context; /**< All events that are associated with application context procedures of store, load, and deletion have this as event parameter. */
dm_service_context_t * p_service_context; /**< All events that are associated with service context procedures of store, load and deletion have this as event parameter. */
dm_device_context_t * p_device_context; /**< All events that are associated with device context procedures of store, load and deletion have this as event parameter. */
} dm_event_param_t;
/**
* @brief Asynchronous events details notified to the application by the module.
*
* @details Defines event type along with event parameters notified to the application by the
* module.
*/
typedef struct
{
uint8_t event_id; /**< Identifies the event. See \ref dm_events for details on event types and their significance. */
dm_event_param_t event_param; /**< Event parameters. Can be NULL if the event does not have any parameters. */
uint16_t event_paramlen; /**< Length of the event parameters, is zero if the event does not have any parameters. */
} dm_event_t;
/**
* @brief Event notification callback registered by application with the module.
*
* @details Event notification callback registered by application with the module when registering
* the module using \ref dm_register API.
*
* @param[in] p_handle Identifies the peer for which the event is being notified.
* @param[in] p_event Identifies the event, any associated parameters and parameter length.
* See \ref dm_events for details on event types and their significance.
* @param[in,out] event_result Provide additional information on the event.
* In addition to SDK error codes there is also a return value
* indicating if maximum number of connections has been reached when connecting or bonding.
*
* @retval NRF_SUCCESS on success, or a failure to indicate if it could handle the event
* successfully. There is no action taken in case application returns a failure.
*/
typedef ret_code_t (*dm_event_cb_t)(dm_handle_t const * p_handle,
dm_event_t const * p_event,
ret_code_t event_result);
/**
* @brief Initialization Parameters.
*
* @details Indicates the application parameters. Currently this only encompasses clearing
* all persistent data.
*/
typedef struct
{
bool clear_persistent_data; /**< Set to true in case the module should clear all persistent data. */
} dm_init_param_t;
/**
* @brief Application Registration Parameters.
*
* @details Parameters needed by the module when registering with it.
*/
typedef struct
{
dm_event_cb_t evt_handler; /**< Event Handler to be registered. It will receive asynchronous notification from the module, see \ref dm_events for asynchronous events. */
uint8_t service_type; /**< Bit mask identifying services that the application intends to support for all peers. */
ble_gap_sec_params_t sec_param; /**< Security parameters to be used for the application. */
} dm_application_param_t;
/**
* @brief Defines possible security status/states.
*
* @details Defines possible security status/states of a link when requested by application using
* the \ref dm_security_status_req.
*/
typedef enum
{
NOT_ENCRYPTED, /**< The link is not secured. */
ENCRYPTION_IN_PROGRESS, /**< Link security is being established.*/
ENCRYPTED /**< The link is secure.*/
} dm_security_status_t;
/** @} */
/**
* @defgroup dm_api Device Module APIs
*
* @brief This section describes APIs exposed by the module.
*
* @details This section describes APIs exposed by the module. The APIs have been categorized to provide
* better and specific look up for developers. Categories are:
* - Set up APIs.
* - Context Management APIs.
* - Utility APIs.
*
* MSCs describe usage of these APIs.
* See @ref dm_msc.
* @{
*/
/**
* @defgroup dm_setup_api Device Module Set-up APIs
*
* @brief Initialization & registration APIs that are pre-requisite for all other module procedures.
* @details This section describes the Module Initialization and Registration APIs needed to be set up by
* the application before device manager can start managing devices and device contexts
* for the application.
*
* @{
*/
/**
* @brief Module Initialization Routine.
*
* @details Function for initializing the module. Must called before any other APIs of the module are used.
*
* @param[in] p_init_param Initialization parameters.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
*
* @note It is mandatory that pstorage is initialized before initializing this module.
*/
ret_code_t dm_init(dm_init_param_t const * p_init_param);
/**
* @brief Function for registering the application.
*
* @details This routine is used by the application to register for asynchronous events with the
* device manager. During registration the application also indicates the services that it
* intends to support on this instance. It is possible to register multiple times with the
* device manager. At least one instance shall be registered with the device manager after
* the module has been initialized.
* Maximum number of application instances device manager can support is determined
* by DM_MAX_APPLICATIONS.
*
* All applications must be registered before initiating or accepting connections from the peer.
*
* @param[in] p_appl_param Application parameters.
* @param[out] p_appl_instance Application Instance Identifier in case registration is successful.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization.
* @retval NRF_ERROR_NO_MEM If module cannot support more applications.
*
* @note Currently only one application instance is supported by the module.
*/
ret_code_t dm_register(dm_application_instance_t * p_appl_instance,
dm_application_param_t const * p_appl_param);
/**
* @brief Function for handling BLE events.
*
* @details BLE Event Handler for the module. This routine should be called from BLE stack event
* dispatcher for the module to work as expected.
*
* @param[in] p_ble_evt BLE stack event being dispatched to the function.
*
*/
void dm_ble_evt_handler(ble_evt_t * p_ble_evt);
/** @} */
/**
* @defgroup dm_security_api APIs to set up or read status of security on a link.
*
* @brief This section describes APIs to set up Security. These APIs require that the peer is
* connected before the procedures can be requested.
*
* @details This group allows application to request security procedures
* or get the status of the security on a link.
* @{
*/
/**
* @brief Function for requesting setting up security on a link.
*
* @details This API initiates security procedures with a peer device.
* @note For the GAP Central role, in case peer is not bonded, request to bond/pair is
* initiated. If it is bonded, the link is re-encrypted using the existing bond information.
* For the GAP peripheral role, a Slave security request is sent.
* @details If a pairing procedure is initiated successfully, application is notified of
* @ref DM_EVT_SECURITY_SETUP_COMPLETE. A result indicating success or failure is notified along with the event.
* In case the link is re-encrypted using existing bond information, @ref DM_EVT_LINK_SECURED is
* notified to the application.
*
* @param[in] p_handle Identifies the link on which security is desired.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application
* or if the peer is not connected when this procedure is requested.
*/
ret_code_t dm_security_setup_req(dm_handle_t * p_handle);
/**
* @brief Function for reading the status of the security on a link.
*
* @details This API allows application to query status of security on a link.
*
* @param[in] p_handle Identifies the link on which security is desired.
* @param[out] p_status Pointer where security status is provided to the application.
* See \ref dm_security_status_t for possible statuses that can be expected.
*
* @retval NRF_SUCCESS Or appropriate error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle or p_status is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified by the handle provided by the application
* or if peer is not connected when this procedure is requested.
*/
ret_code_t dm_security_status_req(dm_handle_t const * p_handle, dm_security_status_t * p_status);
/**
* @brief Function for creating the whitelist.
*
* @details This API allows application to create whitelist based on bonded peer devices in module
* data base.
*
* @param[in] p_handle Identifies the application requesting whitelist creation.
* @param[in,out] p_whitelist Pointer where created whitelist is provided to the application.
*
* @note 'addr_count' and 'irk_count' fields of the structure should be populated with the maximum
* number of devices that the application wishes to request in the whitelist.
* If the number of bonded devices is less than requested, the fields are updated with that number of devices.
* If the number of devices are more than requested, the module will populate the list
* with devices in the order the bond was established with the peer devices. Also, if this routine is
* called when a connection exists with one or more peer devices,
* those connected devices are not added to the whitelist.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle or p_whitelist is NULL.
*/
ret_code_t dm_whitelist_create(dm_application_instance_t const * p_handle,
ble_gap_whitelist_t * p_whitelist);
/** @} */
/**
* @defgroup dm_cntxt_mgmt_api Context Management APIs
*
* @brief Utility APIs offered by the device manager to get information about the peer if and
* when needed.
*
* @details This group of API allow the application to access information that is not required to be
* maintained by the application but may be needed. Hence it is possible to get the
* information from the module instead of mapping all the information with a device
* context.
* @{
*/
ret_code_t dm_device_add(dm_handle_t * p_handle,
dm_device_context_t const * p_context);
/**
* @brief Function for deleting a peer device context and all related information from the database.
*
* @details Delete peer device context and all related information from database. If
* this API returns NRF_SUCCESS, DM_EVT_DEVICE_CONTEXT_DELETED event is notified to the
* application. Event result notified along with the event indicates success or failure
* of this procedure.
*
* @param[in] p_handle Identifies the peer device to be deleted.
*
* @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE In the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified the handle provided by the application.
*
* @note Deleting device context results in deleting service and application context for the
* bonded device. The respective events DM_EVT_SERVICE_CONTEXT_DELETED and
* DM_EVT_APPL_CONTEXT_DELETED are not notified to the application.
*/
ret_code_t dm_device_delete(dm_handle_t const * p_handle);
/**
* @brief Function for deleting all peer device context and all related information from the database.
*
* @details Delete peer device context and all related information from database. If
* this API returns NRF_SUCCESS, DM_EVT_DEVICE_CONTEXT_DELETED event is notified to the
* application for each device that is deleted from the data base. Event result
* notified along with the event indicates success or failure of this procedure.
*
* @param[in] p_handle Identifies application instance that is requesting
* the deletion of all bonded devices.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified the handle provided by the application.
*
* @note Deleting device context results in deleting both service and application context for the
* bonded device. The respective events DM_EVT_SERVICE_CONTEXT_DELETED and
* DM_EVT_APPL_CONTEXT_DELETED are not notified to the application.
*/
ret_code_t dm_device_delete_all(dm_application_instance_t const * p_handle);
/**
* @brief Function for setting Service Context for a peer device identified by 'p_handle' parameter.
*
* @details This API allows application to Set Service Context for a peer device identified by the
* 'p_handle' parameter. This API is useful when the Service Context cannot be requested
* from the SoftDevice, but needs to be assembled by the application or an another module.
* (or when service context is exchanged in an out of band way.)
* This API could also be used to trigger a storing of service context into persistent
* memory. If this is desired, a NULL pointer could be passed to the p_context.
*
* @param[in] p_handle Identifies peer device for which the procedure is requested.
* @param[in] p_context Service context being set. The context information includes length of
* data and pointer to the contextual data being set. The memory pointed to by
* the pointer to data is assumed to be resident when API is being called and
* can be freed or reused once the set procedure is complete. Set procedure
* completion is indicated by the event \ref DM_EVT_SERVICE_CONTEXT_STORED.
* The Event result is notified along with the event and indicates success or failure of
* this procedure.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
*/
ret_code_t dm_service_context_set(dm_handle_t const * p_handle,
dm_service_context_t const * p_context);
/**
* @brief Function for getting Service Context for a peer device identified by 'p_handle' parameter.
*
* @details Get Service Context for a peer device identified by the 'p_handle' parameter. If
* this API returns NRF_SUCCESS, DM_EVT_SERVICE_CONTEXT_LOADED event is notified to the
* application. The event result is notified along with the event indicates success or failure
* of this procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
* @param[in] p_context Application context being requested. The context information includes length
* of the data and a pointer to the data. Note that requesting a 'get'
* of application does not need to provide memory, the pointer to data will be
* pointing to service data and hence no data movement is involved.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE In case API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
*/
ret_code_t dm_service_context_get(dm_handle_t const * p_handle,
dm_service_context_t * p_context);
/**
* @brief Function for deleting a Service Context for a peer device identified by the 'p_handle' parameter.
*
* @details This API allows application to delete a Service Context identified for a peer device
* identified by the 'p_handle' parameter. If this API returns NRF_SUCCESS,
* DM_EVT_SERVICE_CONTEXT_DELETED event is notified to the application.
* Event result is notified along with the event and indicates success or failure of this
* procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
*/
ret_code_t dm_service_context_delete(dm_handle_t const * p_handle);
/**
* @brief Function for setting Application Context for a peer device identified by the 'p_handle' parameter.
*
* @details This application allows the setting of the application context for the peer device identified by
* the 'p_handle'. Application context is stored persistently by the module and can be
* requested by the application at any time using the \ref dm_application_context_get
* API. Note that this procedure is permitted only for bonded devices. If the
* device is not bonded, application context cannot be set. However, it is not mandatory
* that the bonded device is connected when requesting this procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
*
* @param[in] p_context Application context being set. The context information includes length of the
* data and pointer to the contextual data being set. The memory pointed to by
* the data pointer is assumed to be resident when API is being called and
* can be freed or reused once the set procedure is complete. Set procedure
* completion is notified by the event \ref DM_EVT_APPL_CONTEXT_STORED.
* The event result is notified along with the event and indicates success or
* failure of this procedure.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_context is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified the handle provided by the application.
*
* @note The API returns FEATURE_NOT_ENABLED in case DEVICE_MANAGER_APP_CONTEXT_SIZE is set to zero.
*/
ret_code_t dm_application_context_set(dm_handle_t const * p_handle,
dm_application_context_t const * p_context);
/**
* @brief Function for getting Application Context for a peer device identified by the 'p_handle' parameter.
*
* @details Get Application Context for a peer device identified by the 'p_handle' parameter. If
* this API returns NRF_SUCCESS, DM_EVT_APPL_CONTEXT_LOADED event is notified to the
* application. Event result notified along with the event indicates success or failure
* of this procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
* @param[in] p_context Application context being requested. The context information includes
* length of data and pointer to the contextual data is provided.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_context is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
* @retval DM_NO_APP_CONTEXT If no application context was set that can be fetched.
*
* @note The API returns FEATURE_NOT_ENABLED in case DEVICE_MANAGER_APP_CONTEXT_SIZE is set to
* zero.
*/
ret_code_t dm_application_context_get(dm_handle_t const * p_handle,
dm_application_context_t * p_context);
/**
* @brief Function for deleting Application Context for a peer device identified by the 'p_handle' parameter.
*
* @details Delete Application Context for a peer device identified by the 'p_handle' parameter. If
* this API returns NRF_SUCCESS, DM_EVT_APPL_CONTEXT_DELETED event is notified to the
* application. The event result notified along with the event and indicates success or failure
* of this procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If the p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified the handle provided by the application.
* @retval DM_NO_APP_CONTEXT If no application context was set that can be deleted.
*
* @note The API returns FEATURE_NOT_ENABLED if the DEVICE_MANAGER_APP_CONTEXT_SIZE is set to zero.
*/
ret_code_t dm_application_context_delete(dm_handle_t const * p_handle);
/** @} */
/**
* @defgroup utility_api Utility APIs
* @{
* @brief This section describes the utility APIs offered by the module.
*
* @details APIs defined in this section are utility or assisting/helper APIs.
*/
/**
* @brief Function for Setting/Copying Application instance to Device Manager handle.
*
* @param[in] p_appl_instance Application instance to be set.
* @param[out] p_handle Device Manager handle for which the instance is to be copied.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_addr is NULL.
*/
ret_code_t dm_application_instance_set(dm_application_instance_t const * p_appl_instance,
dm_handle_t * p_handle);
/**
* @brief Function for getting a peer's device address.
*
* @param[in] p_handle Identifies the peer device whose address is requested. Can not be NULL.
* @param[out] p_addr Pointer where address is to be copied. Can not be NULL.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_addr is NULL.
* @retval NRF_ERROR_NOT_FOUND If the peer could not be identified.
*/
ret_code_t dm_peer_addr_get(dm_handle_t const * p_handle,
ble_gap_addr_t * p_addr);
/**
* @brief Function for setting/updating a peer's device address.
*
* @param[in] p_handle Identifies the peer device whose address is requested to be set/updated.
* @param[out] p_addr Address to be set/updated.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_addr is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
* @retval NRF_ERROR_INVALID_PARAM If this procedure is requested while connected to the peer or if the address
* type was set to BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE.
*
* @note Setting or updating a peer's device address is permitted
* only for a peer that is bonded and disconnected.
* @note Updated address is reflected only after DM_EVT_DEVICE_CONTEXT_STORED is notified to the
* application for this bonded device instance. In order to avoid abnormal behaviour, it is
* recommended to not invite/initiate connections on the updated address unless this event
* has been notified.
*/
ret_code_t dm_peer_addr_set(dm_handle_t const * p_handle,
ble_gap_addr_t const * p_addr);
/**
* @brief Function for initializing Device Manager handle.
*
* @param[in] p_handle Device Manager handle to be initialized.
*
* @retval NRF_SUCCESS On success.
* @retval NRF_ERROR_NULL If p_handle is NULL.
*
* @note This routine is permitted before initialization of the module.
*/
ret_code_t dm_handle_initialize(dm_handle_t * p_handle);
/**
* @brief Function for getting distributed keys for a device.
*
* @param[in] p_handle Device Manager handle identifying the peer.
* @param[out] p_key_dist Pointer to distributed keys.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If the p_handle and/or p_key_dist pointer is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
*/
ret_code_t dm_distributed_keys_get(dm_handle_t const * p_handle,
dm_sec_keyset_t * p_key_dist);
/**
* @brief Function for getting the corresponding dm_handle_t based on the connection handle.
*
* @param[in] conn_handle Connection handle as provided by the SoftDevice.
* @param[in,out] p_handle Pointer to the p_handle containg the application instance for the
* registered application. If the application instance is valid then
* the p_handle will be filled with requested data.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_NULL If the p_handle pointer is NULL.
* @retval NRF_ERROR_NOT_FOUND If no p_handle is found for the provided connection handle.
*/
ret_code_t dm_handle_get(uint16_t conn_handle, dm_handle_t * p_handle);
/** @} */
/** @} */
/** @} */
#endif // DEVICE_MANAGER_H__

View File

@ -0,0 +1,751 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "id_manager.h"
#include <string.h>
#include "nrf_soc.h"
#include "ble_gap.h"
#include "ble_conn_state.h"
#include "peer_manager_types.h"
#include "peer_database.h"
#include "nordic_common.h"
#define IM_MAX_CONN_HANDLES 8
#define IM_NO_INVALID_CONN_HANDLES 0xFF
#define MAX_REGISTRANTS 3
#define WHITELIST_MAX_COUNT MAX(BLE_GAP_WHITELIST_ADDR_MAX_COUNT, \
BLE_GAP_WHITELIST_IRK_MAX_COUNT)
#define IM_ADDR_CLEARTEXT_LENGTH 3
#define IM_ADDR_CIPHERTEXT_LENGTH 3
#define MODULE_INITIALIZED (m_im.n_registrants > 0)
#define VERIFY_MODULE_INITIALIZED() \
do \
{ \
if (!MODULE_INITIALIZED) \
{ \
return NRF_ERROR_INVALID_STATE; \
} \
} while(0)
#define VERIFY_PARAM_NOT_NULL(param) \
do \
{ \
if (param == NULL) \
{ \
return NRF_ERROR_NULL; \
} \
} while(0)
typedef struct
{
pm_peer_id_t peer_id;
uint16_t conn_handle;
ble_gap_addr_t peer_address;
} im_connection_t;
typedef struct
{
im_evt_handler_t evt_handlers[MAX_REGISTRANTS];
uint8_t n_registrants;
im_connection_t connections[8];
pm_peer_id_t whitelist_peer_ids[BLE_GAP_WHITELIST_IRK_MAX_COUNT];
ble_gap_irk_t whitelist_irks[BLE_GAP_WHITELIST_IRK_MAX_COUNT];
ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
uint8_t n_whitelist_peer_ids;
ble_conn_state_user_flag_id_t conn_state_user_flag_id;
} im_t;
static im_t m_im = {.n_registrants = 0};
static void internal_state_reset()
{
memset(&m_im, 0, sizeof(im_t));
m_im.n_registrants = 0;
m_im.n_whitelist_peer_ids = 0;
m_im.conn_state_user_flag_id = BLE_CONN_STATE_USER_FLAG_INVALID;
for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
{
m_im.connections[i].conn_handle = BLE_CONN_HANDLE_INVALID;
}
}
/**@brief Function for sending an event to all registered event handlers.
*
* @param[in] p_event The event to distribute.
*/
static void evt_send(im_evt_t * p_event)
{
for (uint32_t i = 0; i < m_im.n_registrants; i++)
{
m_im.evt_handlers[i](p_event);
}
}
/**@brief Function finding a free position in m_im.connections.
*
* @detail All connection handles in the m_im.connections array are checked against the connection
* state module. The index of the first one that is not a connection handle for a current
* connection is returned. This position in the array can safely be used for a new connection.
*
* @return Either the index of a free position in the array or IM_NO_INVALID_CONN_HANDLES if no free
position exists.
*/
uint8_t get_free_connection()
{
for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
{
// Query the connection state module to check if the connection handle does not belong to a
// valid connection.
if (!ble_conn_state_user_flag_get(m_im.connections[i].conn_handle, m_im.conn_state_user_flag_id))
{
return i;
}
}
// If all connection handles belong to a valid connection, return IM_NO_INVALID_CONN_HANDLES.
return IM_NO_INVALID_CONN_HANDLES;
}
/**@brief Function finding a particular connection handle m_im.connections.
*
* @param[in] conn_handle The handle to find.
*
* @return Either the index of the conn_handle in the array or IM_NO_INVALID_CONN_HANDLES if the
* handle was not found.
*/
uint8_t get_connection_by_conn_handle(uint16_t conn_handle)
{
if (ble_conn_state_user_flag_get(conn_handle, m_im.conn_state_user_flag_id))
{
for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
{
if (m_im.connections[i].conn_handle == conn_handle)
{
return i;
}
}
}
// If all connection handles belong to a valid connection, return IM_NO_INVALID_CONN_HANDLES.
return IM_NO_INVALID_CONN_HANDLES;
}
/**@brief Function for registering a new connection instance.
*
* @param[in] conn_handle The handle of the new connection.
* @param[in] p_ble_addr The address used to connect.
*
* @return Either the index of the new connection in the array or IM_NO_INVALID_CONN_HANDLES if no
* free position exists.
*/
uint8_t new_connection(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr)
{
uint8_t conn_index = IM_NO_INVALID_CONN_HANDLES;
if ((p_ble_addr != NULL) && (conn_handle != BLE_CONN_HANDLE_INVALID))
{
ble_conn_state_user_flag_set(conn_handle, m_im.conn_state_user_flag_id, true);
conn_index = get_connection_by_conn_handle(conn_handle);
if (conn_index == IM_NO_INVALID_CONN_HANDLES)
{
conn_index = get_free_connection();
}
if (conn_index != IM_NO_INVALID_CONN_HANDLES)
{
m_im.connections[conn_index].conn_handle = conn_handle;
m_im.connections[conn_index].peer_id = PM_PEER_ID_INVALID;
m_im.connections[conn_index].peer_address = *p_ble_addr;
}
}
return conn_index;
}
/**@brief Function checking the validity of an IRK
*
* @detail An all-zero IRK is not valid. This function will check if a given IRK is valid.
*
* @param[in] irk The IRK for which the validity is going to be checked.
*
* @retval true The IRK is valid.
* @retval false The IRK is invalid.
*/
bool is_valid_irk(ble_gap_irk_t const * irk)
{
for (uint32_t i = 0; i < BLE_GAP_SEC_KEY_LEN; i++)
{
if (irk->irk[i] != 0)
{
return true;
}
}
return false;
}
/**@brief Function for comparing two addresses to determine if they are identical
*
* @note The address type need to be identical, as well as every bit in the address itself.
*
* @param[in] p_addr1 The first address to be compared.
* @param[in] p_addr2 The second address to be compared.
*
* @retval true The addresses are identical.
* @retval false The addresses are not identical.
*/
bool addr_compare(ble_gap_addr_t const * p_addr1, ble_gap_addr_t const * p_addr2)
{
if ((p_addr1 == NULL) || (p_addr2 == NULL))
{
return false;
}
// Check that the addr type is identical, return false if it is not
if (p_addr1->addr_type != p_addr2->addr_type)
{
return false;
}
// Check if the addr bytes are is identical
return (memcmp(p_addr1->addr, p_addr2->addr, BLE_GAP_ADDR_LEN) == 0);
}
void im_ble_evt_handler(ble_evt_t * ble_evt)
{
ret_code_t err_code;
switch (ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
{
pm_peer_id_t bonded_matching_peer_id = PM_PEER_ID_INVALID;
if (ble_evt->evt.gap_evt.params.connected.irk_match == 1)
{
// The peer was matched using a whitelist.
bonded_matching_peer_id
= m_im.whitelist_peer_ids[ble_evt->evt.gap_evt.params.connected.irk_match_idx];
}
else if ( ble_evt->evt.gap_evt.params.connected.peer_addr.addr_type
!= BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE)
{
/* Search the database for bonding data matching the one that triggered the event.
* Public and static addresses can be matched on address alone, while resolvable
* random addresses can be resolved agains known IRKs. Non-resolvable random addresses
* are never matching because they are not longterm form of identification.
*/
pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
while ( (compared_peer_id != PM_PEER_ID_INVALID)
&& (bonded_matching_peer_id == PM_PEER_ID_INVALID))
{
pm_peer_data_flash_t compared_data;
switch (ble_evt->evt.gap_evt.params.connected.peer_addr.addr_type)
{
case BLE_GAP_ADDR_TYPE_PUBLIC:
/* fall-through */
case BLE_GAP_ADDR_TYPE_RANDOM_STATIC:
err_code = pdb_read_buf_get(compared_peer_id,
PM_PEER_DATA_ID_BONDING,
&compared_data,
NULL);
if ((err_code == NRF_SUCCESS) &&
addr_compare(&ble_evt->evt.gap_evt.params.connected.peer_addr,
&compared_data.data.p_bonding_data->peer_id.id_addr_info)
)
{
bonded_matching_peer_id = compared_peer_id;
}
break;
case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE:
err_code = pdb_read_buf_get(compared_peer_id,
PM_PEER_DATA_ID_BONDING,
&compared_data,
NULL);
if (err_code == NRF_SUCCESS &&
im_address_resolve(&ble_evt->evt.gap_evt.params.connected.peer_addr,
&compared_data.data.p_bonding_data->peer_id.id_info)
)
{
bonded_matching_peer_id = compared_peer_id;
}
break;
case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE:
// Should not happen.
break;
default:
break;
}
compared_peer_id = pdb_next_peer_id_get(compared_peer_id);
}
}
new_connection(ble_evt->evt.gap_evt.conn_handle, &ble_evt->evt.gap_evt.params.connected.peer_addr);
if (bonded_matching_peer_id != PM_PEER_ID_INVALID)
{
im_new_peer_id(ble_evt->evt.gap_evt.conn_handle, bonded_matching_peer_id);
// Send a bonded peer event
im_evt_t im_evt;
im_evt.conn_handle = ble_evt->evt.gap_evt.conn_handle;
im_evt.evt_id = IM_EVT_BONDED_PEER_CONNECTED;
evt_send(&im_evt);
}
}
}
}
/**@brief Function to compare two sets of bonding data to check if they belong to the same device.
* @note Invalid irks will never match even though they are identical.
*
* @param[in] p_bonding_data1 First bonding data for comparison
* @param[in] p_bonding_data2 Second bonding data for comparison
*
* @return True if the input matches, false if it does not.
*/
bool is_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data1,
pm_peer_data_bonding_t const * p_bonding_data2)
{
bool valid_irk = is_valid_irk(&p_bonding_data1->peer_id.id_info);
bool duplicate_irk = valid_irk &&
(memcmp(p_bonding_data1->peer_id.id_info.irk,
p_bonding_data2->peer_id.id_info.irk,
BLE_GAP_SEC_KEY_LEN) == 0
);
bool duplicate_addr = addr_compare(&p_bonding_data1->peer_id.id_addr_info,
&p_bonding_data2->peer_id.id_addr_info
);
return duplicate_irk || duplicate_addr;
}
/**@brief Event handler for events from the peer_database module.
*
* @param[in] p_event The event that has happend with peer id and flags.
*/
static void pdb_evt_handler(pdb_evt_t const * p_event)
{
ret_code_t err_code;
if ((p_event != NULL) && (p_event->evt_id == PDB_EVT_WRITE_BUF_STORED))
{
// If new data about peer id has been stored it is compared to other peers peer ids in
// search of duplicates.
if (p_event->data_id == PM_PEER_DATA_ID_BONDING)
{
pm_peer_data_flash_t written_data;
err_code = pdb_read_buf_get(p_event->peer_id, PM_PEER_DATA_ID_BONDING, &written_data, NULL);
if (err_code == NRF_SUCCESS)
{
pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
while (compared_peer_id != PM_PEER_ID_INVALID)
{
pm_peer_data_flash_t compared_data;
err_code = pdb_read_buf_get(compared_peer_id,
PM_PEER_DATA_ID_BONDING,
&compared_data,
NULL);
if ( err_code == NRF_SUCCESS &&
p_event->peer_id != compared_peer_id &&
is_duplicate_bonding_data(written_data.data.p_bonding_data,
compared_data.data.p_bonding_data)
)
{
im_evt_t im_evt;
im_evt.conn_handle = im_conn_handle_get(p_event->peer_id);
im_evt.evt_id = IM_EVT_DUPLICATE_ID;
im_evt.params.duplicate_id.peer_id_1 = p_event->peer_id;
im_evt.params.duplicate_id.peer_id_2 = compared_peer_id;
evt_send(&im_evt);
}
compared_peer_id = pdb_next_peer_id_get(compared_peer_id);
}
}
}
}
}
ret_code_t im_register(im_evt_handler_t evt_handler)
{
VERIFY_PARAM_NOT_NULL(evt_handler);
ret_code_t err_code = NRF_SUCCESS;
if (!MODULE_INITIALIZED)
{
internal_state_reset();
m_im.conn_state_user_flag_id = ble_conn_state_user_flag_acquire();
if (m_im.conn_state_user_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
{
err_code = NRF_ERROR_NO_MEM;
}
else
{
err_code = pdb_register(pdb_evt_handler);
}
}
if (err_code == NRF_SUCCESS)
{
if ((m_im.n_registrants < MAX_REGISTRANTS))
{
m_im.evt_handlers[m_im.n_registrants++] = evt_handler;
}
else
{
err_code = NRF_ERROR_NO_MEM;
}
}
return err_code;
}
pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle)
{
uint8_t conn_index = get_connection_by_conn_handle(conn_handle);
if (MODULE_INITIALIZED && (conn_index != IM_NO_INVALID_CONN_HANDLES))
{
return m_im.connections[conn_index].peer_id;
}
return PM_PEER_ID_INVALID;
}
ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_ble_addr);
uint8_t conn_index = get_connection_by_conn_handle(conn_handle);
if (conn_index != IM_NO_INVALID_CONN_HANDLES)
{
*p_ble_addr = m_im.connections[conn_index].peer_address;
return NRF_SUCCESS;
}
return NRF_ERROR_NOT_FOUND;
}
/**@brief Function for comparing two master ids
* @note Two invalid master IDs will not match.
*
* @param[in] p_master_id1 First master id for comparison
* @param[in] p_master_id2 Second master id for comparison
*
* @return True if the input matches, false if it does not.
*/
bool master_id_compare(ble_gap_master_id_t const * p_master_id1,
ble_gap_master_id_t const * p_master_id2)
{
if(!im_master_id_is_valid(p_master_id1))
{
return false;
}
if (p_master_id1->ediv != p_master_id2->ediv)
{
return false;
}
return (memcmp(p_master_id1->rand, p_master_id2->rand, BLE_GAP_SEC_RAND_LEN) == 0);
}
pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t * p_master_id)
{
ret_code_t err_code;
// For each stored peer, check if the master_id match p_master_id
pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
while (compared_peer_id != PM_PEER_ID_INVALID)
{
pm_peer_data_flash_t compared_data;
ble_gap_master_id_t const * p_compared_master_id;
err_code = pdb_read_buf_get(compared_peer_id, PM_PEER_DATA_ID_BONDING, &compared_data, NULL);
if (err_code == NRF_SUCCESS)
{
p_compared_master_id = &compared_data.data.p_bonding_data->own_ltk.master_id;
if (compared_data.data.p_bonding_data->own_role == BLE_GAP_ROLE_CENTRAL)
{
p_compared_master_id = &compared_data.data.p_bonding_data->peer_ltk.master_id;
}
if (master_id_compare(p_master_id, p_compared_master_id))
{
// If a matching master_id is found return the peer_id
return compared_peer_id;
}
}
compared_peer_id = pdb_next_peer_id_get(compared_peer_id);
}
// If no matching master_id is found return the PM_PEER_ID_INVALID
return PM_PEER_ID_INVALID;
}
pm_peer_id_t im_peer_id_get_by_irk_match_idx(uint8_t irk_match_idx)
{
// Verify that the requested idx is within the list
if (irk_match_idx < m_im.n_whitelist_peer_ids)
{
// Return the peer_id from the white list
return m_im.whitelist_peer_ids[irk_match_idx];
}
else
{
// Return PM_PEER_ID_INVALID to indicate that there was no peer with the requested idx
return PM_PEER_ID_INVALID;
}
}
uint16_t im_conn_handle_get(pm_peer_id_t peer_id)
{
for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
{
if (peer_id == m_im.connections[i].peer_id)
{
return m_im.connections[i].conn_handle;
}
}
return BLE_CONN_HANDLE_INVALID;
}
bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id)
{
if (p_master_id->ediv != 0)
{
return true;
}
for (uint32_t i = 0; i < BLE_GAP_SEC_RAND_LEN; i++)
{
if (p_master_id->rand[i] != 0)
{
return true;
}
}
return false;
}
void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id)
{
uint8_t conn_index = get_connection_by_conn_handle(conn_handle);
if (conn_index != IM_NO_INVALID_CONN_HANDLES)
{
m_im.connections[conn_index].peer_id = peer_id;
}
}
ret_code_t im_wlist_create(pm_peer_id_t * p_peer_ids,
uint8_t n_peer_ids,
ble_gap_whitelist_t * p_whitelist)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_whitelist);
ret_code_t err_code;
p_whitelist->addr_count = 0;
p_whitelist->irk_count = 0;
m_im.n_whitelist_peer_ids = 0;
for (uint32_t peer_index = 0; peer_index < n_peer_ids; peer_index++)
{
bool peer_connected = false;
for (uint32_t conn_index = 0; conn_index < IM_MAX_CONN_HANDLES; conn_index++)
{
if (p_peer_ids[peer_index] == m_im.connections[conn_index].peer_id &&
ble_conn_state_user_flag_get(m_im.connections[conn_index].conn_handle, m_im.conn_state_user_flag_id)
)
{
peer_connected = true;
break;
}
}
if (!peer_connected)
{
pm_peer_data_flash_t peer_data;
err_code = pdb_read_buf_get(p_peer_ids[peer_index], PM_PEER_DATA_ID_BONDING, &peer_data, NULL);
if (err_code == NRF_ERROR_INVALID_PARAM || err_code == NRF_ERROR_NOT_FOUND)
{
return NRF_ERROR_INVALID_PARAM;
}
if (p_whitelist->pp_addrs != NULL &&
peer_data.data.p_bonding_data->peer_id.id_addr_info.addr_type
!= BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE &&
peer_data.data.p_bonding_data->peer_id.id_addr_info.addr_type
!= BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE
)
{
memcpy(m_im.whitelist_addrs[peer_index].addr,
peer_data.data.p_bonding_data->peer_id.id_addr_info.addr,
BLE_GAP_ADDR_LEN
);
m_im.whitelist_addrs[peer_index].addr_type =
peer_data.data.p_bonding_data->peer_id.id_addr_info.addr_type;
p_whitelist->pp_addrs[peer_index] = &m_im.whitelist_addrs[peer_index];
p_whitelist->addr_count++;
}
if (p_whitelist->pp_irks != NULL &&
is_valid_irk(&(peer_data.data.p_bonding_data->peer_id.id_info))
)
{
memcpy(m_im.whitelist_irks[peer_index].irk,
peer_data.data.p_bonding_data->peer_id.id_info.irk,
BLE_GAP_SEC_KEY_LEN
);
p_whitelist->pp_irks[peer_index] = &m_im.whitelist_irks[peer_index];
p_whitelist->irk_count++;
m_im.whitelist_peer_ids[peer_index] = p_peer_ids[peer_index];
m_im.n_whitelist_peer_ids++;
}
}
}
return NRF_SUCCESS;
}
ret_code_t im_wlist_set(ble_gap_whitelist_t * p_whitelist)
{
pm_peer_id_t new_whitelist_peer_ids[BLE_GAP_WHITELIST_IRK_MAX_COUNT];
uint32_t n_new_whitelist_peer_ids = 0;
VERIFY_PARAM_NOT_NULL(p_whitelist);
for (uint32_t i = 0; i < BLE_GAP_WHITELIST_IRK_MAX_COUNT; i++)
{
new_whitelist_peer_ids[i] = PM_PEER_ID_INVALID;
}
pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
while (compared_peer_id != PM_PEER_ID_INVALID)
{
pm_peer_data_flash_t compared_data;
pdb_read_buf_get(compared_peer_id, PM_PEER_DATA_ID_BONDING, &compared_data, NULL);
for (uint32_t i = 0; i < p_whitelist->irk_count; i++)
{
bool valid_irk = is_valid_irk(&compared_data.data.p_bonding_data->peer_id.id_info);
bool duplicate_irk = valid_irk &&
(memcmp(p_whitelist->pp_irks[i]->irk,
compared_data.data.p_bonding_data->peer_id.id_info.irk,
BLE_GAP_SEC_KEY_LEN) == 0
);
if (duplicate_irk)
{
new_whitelist_peer_ids[i] = compared_peer_id;
n_new_whitelist_peer_ids++;
}
}
compared_peer_id = pdb_next_peer_id_get(compared_peer_id);
}
if (n_new_whitelist_peer_ids != p_whitelist->irk_count)
{
return NRF_ERROR_NOT_FOUND;
}
else
{
for (uint32_t i = 0; i < n_new_whitelist_peer_ids; i++)
{
m_im.whitelist_peer_ids[i] = new_whitelist_peer_ids[i];
}
m_im.n_whitelist_peer_ids = n_new_whitelist_peer_ids;
return NRF_SUCCESS;
}
}
/**@brief Function for calculating the ah() hash function described in Bluetooth core specification
* 4.2 section 3.H.2.2.2.
*
* @detail BLE uses a hash function to calculate the first half of a resolvable address
* from the second half of the address and an irk. This function will use the ECB
* periferal to hash these data acording to the Bluetooth core specification.
*
* @note The ECB expect little endian input and output.
* This function expect big endian and will reverse the data as necessary.
*
* @param[in] p_k The key used in the hash function.
* For address resolution this is should be the irk.
* The array must have a length of 16.
* @param[in] p_r The rand used in the hash function. For generating a new address
* this would be a random number. For resolving a resolvable address
* this would be the last half of the address being resolved.
* The array must have a length of 3.
* @param[out] p_local_hash The result of the hash operation. For address resolution this
* will match the first half of the address being resolved if and only
* if the irk used in the hash function is the same one used to generate
* the address.
* The array must have a length of 16.
*/
void ah(uint8_t const * p_k, uint8_t const * p_r, uint8_t * p_local_hash)
{
nrf_ecb_hal_data_t ecb_hal_data;
for (uint32_t i = 0; i < SOC_ECB_KEY_LENGTH; i++)
{
ecb_hal_data.key[i] = p_k[SOC_ECB_KEY_LENGTH - 1 - i];
}
memset(ecb_hal_data.cleartext, 0, SOC_ECB_KEY_LENGTH - IM_ADDR_CLEARTEXT_LENGTH);
for (uint32_t i = 0; i < IM_ADDR_CLEARTEXT_LENGTH; i++)
{
ecb_hal_data.cleartext[SOC_ECB_KEY_LENGTH - 1 - i] = p_r[i];
}
sd_ecb_block_encrypt(&ecb_hal_data);
for (uint32_t i = 0; i < IM_ADDR_CIPHERTEXT_LENGTH; i++)
{
p_local_hash[i] = ecb_hal_data.ciphertext[SOC_ECB_KEY_LENGTH - 1 - i];
}
}
bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
{
if (p_addr->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
{
return false;
}
uint8_t hash[IM_ADDR_CIPHERTEXT_LENGTH];
uint8_t local_hash[IM_ADDR_CIPHERTEXT_LENGTH];
uint8_t prand[IM_ADDR_CLEARTEXT_LENGTH];
memcpy(hash, p_addr->addr, IM_ADDR_CIPHERTEXT_LENGTH);
memcpy(prand, &p_addr->addr[IM_ADDR_CIPHERTEXT_LENGTH], IM_ADDR_CLEARTEXT_LENGTH);
ah(p_irk->irk, prand, local_hash);
return (memcmp(hash, local_hash, IM_ADDR_CIPHERTEXT_LENGTH) == 0);
}

View File

@ -0,0 +1,266 @@
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef PEER_ID_MANAGER_H__
#define PEER_ID_MANAGER_H__
#include "stdint.h"
#include "sdk_errors.h"
#include "nrf_ble.h"
#include "ble_gap.h"
#include "peer_manager_types.h"
/**
* @defgroup id_manager ID Manager
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. A module for keeping track of peer identities
* (IRK and peer address).
*/
/**@brief Events that can come from the ID Manager module.
*/
typedef enum
{
IM_EVT_DUPLICATE_ID, /**< The ID Manager module has detected that two stored peers represent the same peer. */
IM_EVT_BONDED_PEER_CONNECTED, /**< A connected peer has been identified as one of the bonded peers. This can happen immediately on connection, or at a later time. */
} im_evt_id_t;
typedef struct
{
im_evt_id_t evt_id;
uint16_t conn_handle;
union
{
struct
{
pm_peer_id_t peer_id_1;
pm_peer_id_t peer_id_2;
} duplicate_id;
} params;
} im_evt_t;
/**@brief Event handler for events from the ID Manager module.
*
* @param[in] p_event The event that has happened.
*/
typedef void (*im_evt_handler_t)(im_evt_t const * p_event);
/**@brief Function for registering for events from the ID Manager module.
*
* @note This will also initialize the module if needed.
*
* @param[in] evt_handler Callback for events from the ID Manager module.
*
* @retval NRF_SUCCESS Registration was successful.
* @retval NRF_ERROR_NO_MEM No more registrations possible.
* @retval NRF_ERROR_NULL evt_handler was NULL.
*/
ret_code_t im_register(im_evt_handler_t evt_handler);
/**@brief Function for dispatching SoftDevice events to the ID Manager module.
*
* @param[in] p_ble_evt The SoftDevice event.
*/
void im_ble_evt_handler(ble_evt_t * p_ble_evt);
/**@brief Function for getting the corresponding peer ID from a connection handle.
*
* @param[in] conn_handle The connection handle.
*
* @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
*/
pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle);
/**@brief Function for getting the corresponding peer ID from a master ID (EDIV and rand).
*
* @param[in] p_master_id The master ID.
*
* @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
*/
pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t * p_master_id);
/**@brief Function for getting the corresponding peer ID from an IRK match index, see @ref
* ble_gap_evt_connected_t.
*
* @param[in] irk_match_idx The IRK match index.
*
* @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
*/
pm_peer_id_t im_peer_id_get_by_irk_match_idx(uint8_t irk_match_idx);
/**@brief Function for getting the corresponding connection handle from a peer ID.
*
* @param[in] peer_id The peer ID.
*
* @return The corresponding connection handle, or @ref BLE_CONN_HANDLE_INVALID if none could be
* resolved.
*/
uint16_t im_conn_handle_get(pm_peer_id_t peer_id);
/**@brief Function for getting the BLE address used by the peer when connecting.
*
* @param[in] conn_handle The connection handle.
* @param[out] p_ble_addr The BLE address used by the peer when the connection specified by
* conn_handle was established.
*
* @retval NRF_SUCCESS The address was found and copied.
* @retval NRF_ERROR_INVALID_STATE Module not initialized.
* @retval BLE_ERROR_CONN_HANDLE_INVALID conn_handle does not refer to an active connection.
* @retval NRF_ERROR_NULL p_ble_addr was NULL.
*/
ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr);
/**@brief Function for checking whether a master ID is valid or invalid
*
* @param[in] p_master_id The master ID.
*
* @retval true The master id is valid.
* @retval true The master id is invalid (i.e. all zeros).
*/
bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id);
/**@brief Function for reporting that a new peer ID has been allocated for a specified connection.
*
* @param[in] conn_handle The connection.
* @param[in] peer_id The new peer ID.
*/
void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id);
/**
* @brief Function for informing this module of what whitelist will be used.
*
* @details This function is meant to be used when the app wants to use a custom whitelist.
* When using peer manager, this function must be used if a custom whitelist is used.
*
* @note When using a whitelist, always use the whitelist created/set by the most recent
* call to @ref im_wlist_create or to this function, whichever happened most recently.
* @note Do not call this function while scanning with another whitelist.
* @note Do not add any irks to the whitelist that are not present in the bonding data of a peer in
* the peer database.
*
* @param[in] p_whitelist The whitelist.
*
* @retval NRF_SUCCESS Whitelist successfully set.
* @retval NRF_ERROR_NULL p_whitelist was NULL.
* @retval NRF_ERROR_NOT_FOUND One or more of the whitelists irks was not found in the peer_database.
*/
ret_code_t im_wlist_set(ble_gap_whitelist_t * p_whitelist);
/**
* @brief Function for constructing a whitelist for use when advertising.
*
* @note When advertising with whitelist, always use the whitelist created/set by the most recent
* call to this function or to @ref im_wlist_set, whichever happened most recently.
* @note Do not call this function while advertising with another whitelist.
*
* @param[in] p_peer_ids The ids of the peers to be added to the whitelist.
* @param[in] n_peer_ids The number of peer ids in p_peer_ids.
* @param[in,out] p_whitelist The constructed whitelist. Note that p_adv_whitelist->pp_addrs
* must be NULL or point to an array with size @ref
* BLE_GAP_WHITELIST_ADDR_MAX_COUNT and p_adv_whitelist->pp_irks
* must be NULL or point to an array with size @ref
* BLE_GAP_WHITELIST_IRK_MAX_COUNT.
*
* @retval NRF_SUCCESS Whitelist successfully created.
* @retval NRF_ERROR_NULL p_whitelist was NULL.
*/
ret_code_t im_wlist_create(pm_peer_id_t * p_peer_ids,
uint8_t n_peer_ids,
ble_gap_whitelist_t * p_whitelist);
/**
* @brief Function for resolving a resolvable address with an identity resolution key (IRK).
*
* @details This function will use the ECB peripheral to resolve a resolvable address.
* This can be used to resolve the identity of a device distributing a random
* resolvable address based on any IRKs you have received earlier. If an address is
* resolved by an IRK, the device disributing the address must also know the IRK.
*
* @param[in] p_addr A random resolvable address.
* @param[in] p_irk An identity resolution key (IRK).
*
* @retval true The irk used matched the one used to create the address.
* @retval false The irk used did not match the one used to create the address, or an argument was
* NULL.
*/
bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk);
/**@brief Function for calculating the ah() hash function described in Bluetooth core specification
* 4.2 section 3.H.2.2.2.
*
* @detail BLE uses a hash function to calculate the first half of a resolvable address
* from the second half of the address and an irk. This function will use the ECB
* periferal to hash these data acording to the Bluetooth core specification.
*
* @note The ECB expect little endian input and output.
* This function expect big endian and will reverse the data as necessary.
*
* @param[in] p_k The key used in the hash function.
* For address resolution this is should be the irk.
* The array must have a length of 16.
* @param[in] p_r The rand used in the hash function. For generating a new address
* this would be a random number. For resolving a resolvable address
* this would be the last half of the address being resolved.
* The array must have a length of 3.
* @param[out] p_local_hash The result of the hash operation. For address resolution this
* will match the first half of the address being resolved if and only
* if the irk used in the hash function is the same one used to generate
* the address.
* The array must have a length of 16.
*
* @note ====IMPORTANT====
* This is a special modification to the original nRF51 SDK required by the mbed BLE API
* to be able to generate BLE private resolvable addresses. This function is used by
* the BLE API implementation for nRF5xSecurityManager::getAddressFromBondTable() in the
* ble-nrf51822 yotta module.
* =================
*/
void ah(uint8_t const * p_k, uint8_t const * p_r, uint8_t * p_local_hash);
/** @} */
#endif /* PEER_ID_MANAGER_H__ */

Some files were not shown because too many files have changed in this diff Show More