Merge pull request #324 from pan-/fix_ble_import

Import missing files in BLE.
Mihail Stoyanov 2016-06-13 17:07:22 +01:00 committed by GitHub
commit 128efd50b3
136 changed files with 32677 additions and 0 deletions

2
bluetooth/ble/.gitignore vendored Normal file
View File

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

393
bluetooth/ble/CHANGELOG.md Normal file
View File

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

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.

2
bluetooth/ble/LICENSE Normal file
View File

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

28
bluetooth/ble/README.md Normal file
View File

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

View File

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

2418
bluetooth/ble/ble.doxyfile Normal file

File diff suppressed because it is too large Load Diff

1569
bluetooth/ble/ble/BLE.h Normal file

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

1919
bluetooth/ble/ble/Gap.h Normal file

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

331
bluetooth/ble/ble/UUID.h Normal file
View File

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

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,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__

45
bluetooth/ble/module.json Normal file
View File

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

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,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,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,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,166 @@
/*
* 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 "peer_data.h"
#include <stdint.h>
#include <string.h>
#include "peer_manager_types.h"
#include "fds.h"
void peer_data_parts_get(pm_peer_data_const_t const * p_peer_data, fds_record_chunk_t * p_chunks, uint16_t * p_n_chunks)
{
if (p_n_chunks == NULL)
{
}
else if ((p_peer_data == NULL) || (p_chunks == NULL))
{
*p_n_chunks = 0;
}
else
{
switch (p_peer_data->data_type)
{
case PM_PEER_DATA_ID_BONDING:
p_chunks[0].p_data = p_peer_data->data.p_bonding_data;
p_chunks[0].length_words = p_peer_data->length_words;
*p_n_chunks = 1;
break;
case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
p_chunks[0].p_data = p_peer_data->data.p_service_changed_pending;
p_chunks[0].length_words = p_peer_data->length_words;
*p_n_chunks = 1;
break;
case PM_PEER_DATA_ID_GATT_LOCAL:
p_chunks[0].p_data = p_peer_data->data.p_local_gatt_db;
p_chunks[0].length_words = PM_N_WORDS(PM_LOCAL_DB_LEN_OVERHEAD_BYTES);
p_chunks[1].p_data = p_peer_data->data.p_local_gatt_db->p_data;
p_chunks[1].length_words = p_peer_data->length_words - p_chunks[0].length_words;
*p_n_chunks = 2;
break;
case PM_PEER_DATA_ID_GATT_REMOTE:
p_chunks[0].p_data = p_peer_data->data.p_remote_gatt_db;
p_chunks[0].length_words = PM_N_WORDS(PM_REMOTE_DB_LEN_OVERHEAD_BYTES);
p_chunks[1].p_data = p_peer_data->data.p_remote_gatt_db->p_data;
p_chunks[1].length_words = p_peer_data->length_words - p_chunks[0].length_words;
*p_n_chunks = 2;
break;
case PM_PEER_DATA_ID_APPLICATION:
p_chunks[0].p_data = p_peer_data->data.p_application_data;
p_chunks[0].length_words = p_peer_data->length_words;
*p_n_chunks = 1;
break;
default:
*p_n_chunks = 0;
break;
}
}
}
ret_code_t peer_data_deserialize(pm_peer_data_flash_t const * p_in_data, pm_peer_data_t * p_out_data)
{
if ((p_in_data == NULL) || (p_out_data == NULL))
{
return NRF_ERROR_NULL;
}
else
{
if (p_out_data->length_words < p_in_data->length_words)
{
p_out_data->length_words = p_in_data->length_words;
return NRF_ERROR_NO_MEM;
}
p_out_data->length_words = p_in_data->length_words;
p_out_data->data_type = p_in_data->data_type;
switch (p_in_data->data_type)
{
case PM_PEER_DATA_ID_BONDING:
*p_out_data->data.p_bonding_data = *p_in_data->data.p_bonding_data;
break;
case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
*p_out_data->data.p_service_changed_pending = *p_in_data->data.p_service_changed_pending;
break;
case PM_PEER_DATA_ID_GATT_LOCAL:
if (p_out_data->data.p_local_gatt_db->p_data == NULL)
{
return NRF_ERROR_NULL;
}
if (p_out_data->data.p_local_gatt_db->len < p_in_data->data.p_local_gatt_db->len)
{
p_out_data->data.p_local_gatt_db->len = p_in_data->data.p_local_gatt_db->len;
return NRF_ERROR_NO_MEM;
}
else
{
p_out_data->data.p_local_gatt_db->flags = p_in_data->data.p_local_gatt_db->flags;
p_out_data->data.p_local_gatt_db->len = p_in_data->data.p_local_gatt_db->len;
memcpy(p_out_data->data.p_local_gatt_db->p_data,
p_in_data->data.p_local_gatt_db->p_data,
p_in_data->data.p_local_gatt_db->len);
}
break;
case PM_PEER_DATA_ID_GATT_REMOTE:
if (p_out_data->data.p_remote_gatt_db->p_data == NULL)
{
return NRF_ERROR_NULL;
}
if (p_out_data->data.p_remote_gatt_db->service_count < p_in_data->data.p_remote_gatt_db->service_count)
{
p_out_data->data.p_remote_gatt_db->service_count = p_in_data->data.p_remote_gatt_db->service_count;
return NRF_ERROR_NO_MEM;
}
else
{
p_out_data->data.p_remote_gatt_db->service_count = p_in_data->data.p_remote_gatt_db->service_count;
memcpy(p_out_data->data.p_remote_gatt_db->p_data,
p_in_data->data.p_remote_gatt_db->p_data,
p_in_data->data.p_remote_gatt_db->service_count * sizeof(ble_gatt_db_srv_t));
}
break;
case PM_PEER_DATA_ID_APPLICATION:
memcpy(p_out_data->data.p_application_data,
p_in_data->data.p_application_data,
p_in_data->length_words * 4);
break;
default:
break;
}
}
return NRF_SUCCESS;
}

View File

@ -0,0 +1,73 @@
/*
* 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_DATA_H__
#define PEER_DATA_H__
#include <stdint.h>
#include "peer_manager_types.h"
#include "fds.h"
/**
* @defgroup peer_data Peer Data
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. This module defines the structure of the data
* that is managed by the @ref peer_manager. It also provides functions for parsing the data.
*/
/**@brief Function for enumerating the separate (non-contiguous) parts of the peer data.
*
* @param[in] p_peer_data The peer data to enumerate.
* @param[out] p_chunks The resulting chunks. This must be an array of at least 2 elements.
* @param[out] p_n_chunks The number of chunks. If this is 0, something went wrong.
*/
void peer_data_parts_get(pm_peer_data_const_t const * p_peer_data, fds_record_chunk_t * p_chunks, uint16_t * p_n_chunks);
/**@brief Function for converting @ref pm_peer_data_flash_t into @ref pm_peer_data_t.
*
* @param[in] p_in_data The source data.
* @param[out] p_out_data The target data structure.
*
* @retval NRF_SUCCESS Successful conversion.
* @retval NRF_ERROR_NULL A parameter was NULL.
* @retval NRF_ERROR_NO_MEM A buffer was not large enough.
*/
ret_code_t peer_data_deserialize(pm_peer_data_flash_t const * p_in_data, pm_peer_data_t * p_out_data);
/** @} */
#endif /* PEER_DATA_H__ */

View File

@ -0,0 +1,688 @@
/*
* 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 "peer_data_storage.h"
#include <stdint.h>
#include <string.h>
#include "sdk_errors.h"
#include "peer_manager_types.h"
#include "peer_id.h"
#include "peer_data.h"
#include "fds.h"
#define MAX_REGISTRANTS 6 /**< The number of user that can register with the module. */
#define MODULE_INITIALIZED (m_pds.n_registrants > 0) /**< Expression which is true when the module is initialized. */
/**@brief Macro for verifying that the module is initialized. It will cause the function to return
* @ref NRF_ERROR_INVALID_STATE if not.
*/
#define VERIFY_MODULE_INITIALIZED() \
do \
{ \
if (!MODULE_INITIALIZED) \
{ \
return NRF_ERROR_INVALID_STATE; \
} \
} while(0)
/**@brief Macro for verifying that the module is initialized. It will cause the function to return
* if not.
*/
#define VERIFY_MODULE_INITIALIZED_VOID() \
do \
{ \
if (!MODULE_INITIALIZED) \
{ \
return; \
} \
} while(0)
/**@brief Macro for verifying that the param is not NULL. It will cause the function to return
* if not.
*
* @param[in] param The variable to check if is NULL.
*/
#define VERIFY_PARAM_NOT_NULL(param) \
do \
{ \
if (param == NULL) \
{ \
return NRF_ERROR_NULL; \
} \
} while(0)
/**@brief Macro for verifying that param is not zero. It will cause the function to return
* if not.
*
* @param[in] param The variable to check if is zero.
*/
#define VERIFY_PARAM_NOT_ZERO(param) \
do \
{ \
if (param == 0) \
{ \
return NRF_ERROR_NULL; \
} \
} while(0)
/**@brief Macro for verifying that the peer id is within a valid range
*
* @param[in] id The peer data id to check.
*/
#define VERIFY_PEER_ID_IN_RANGE(id) \
do \
{ \
if ((id >= PM_PEER_ID_N_AVAILABLE_IDS)) \
{ \
return NRF_ERROR_INVALID_PARAM; \
} \
} while (0)
/**@brief Macro for verifying that the peer data id is withing a valid range
*
* @param[in] id The peer data id to check.
*/
#define VERIFY_PEER_DATA_ID_IN_RANGE(id) \
do \
{ \
if (!PM_PEER_DATA_ID_IS_VALID(id)) \
{ \
return NRF_ERROR_INVALID_PARAM; \
} \
} while (0)
#define PEER_IDS_INITIALIZE() \
do \
{ \
if (!m_pds.peer_ids_initialized) \
{ \
peer_ids_init(); \
} \
} while (0)
typedef struct
{
bool peer_ids_initialized;
pds_evt_handler_t evt_handlers[MAX_REGISTRANTS];
uint8_t n_registrants;
} pds_t;
static pds_t m_pds = {.n_registrants = 0};
static void internal_state_reset(pds_t * p_pds)
{
memset(p_pds, 0, sizeof(pds_t));
}
/**@brief Function for dispatching outbound events to all registered event handlers.
*
* @param[in] p_event The event to dispatch.
*/
static void pds_evt_send(pds_evt_t * p_event)
{
for (int i = 0; i < m_pds.n_registrants; i++)
{
m_pds.evt_handlers[i](p_event);
}
}
/**@brief Function to convert peer id to instance id
*
* @param[in] peer_id Peer id to convert to instance id
*
* @return Value as instance id
*/
static fds_instance_id_t convert_peer_id_to_instance_id(pm_peer_id_t peer_id)
{
return (fds_instance_id_t)(peer_id + peer_id_to_instance_id);
}
/**@brief Function to convert peer data id to type id
*
* @param[in] peer_data_id Peer data id to convert to type_id
*
* @return Value as type id
*/
static fds_type_id_t convert_peer_data_id_to_type_id(pm_peer_data_id_t peer_data_id)
{
return (fds_type_id_t)peer_data_id + (fds_type_id_t)peer_data_id_to_type_id;
}
/**@brief Function to convert peer data id to type id
*
* @param[in] peer_data_id Peer data id to convert to type_id
*
* @return Value as type id
*/
static pm_peer_id_t convert_instance_id_to_peer_id(fds_instance_id_t instance_id)
{
return (pm_peer_id_t)(instance_id + instance_id_to_peer_id);
}
/**@brief Function to type id to peer data id
*
* @param[in] type_id Type id to convert to peer data id
*
* @return Value as peer data id
*/
static pm_peer_data_id_t convert_type_id_to_peer_data_id(fds_type_id_t type_id)
{
return (pm_peer_data_id_t)(type_id + instance_id_to_peer_id);
}
static ret_code_t find_fds_item(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
fds_record_desc_t * const p_desc)
{
fds_find_token_t find_tok;
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
// pp_record verified outside
fds_type_id_t type_id = convert_peer_data_id_to_type_id(data_id);
fds_instance_id_t instance_id = convert_peer_id_to_instance_id(peer_id);
return fds_find(type_id, instance_id, p_desc, &find_tok);
}
static void peer_ids_init()
{
fds_record_t record;
fds_record_desc_t record_desc;
fds_find_token_t find_tok;
fds_type_id_t const type_id = convert_peer_data_id_to_type_id(PM_PEER_DATA_ID_BONDING);
pm_peer_id_t peer_id;
if (!m_pds.peer_ids_initialized)
{
while(fds_find_by_type(type_id, &record_desc, &find_tok) == NRF_SUCCESS)
{
fds_open(&record_desc, &record);
fds_close(&record_desc);
peer_id = convert_instance_id_to_peer_id(record.header.ic.instance);
peer_id_allocate(peer_id);
}
m_pds.peer_ids_initialized = true;
}
}
//uint32_t size_pad_to_mult_of_four(uint32_t unpadded_size)
//{
// return (unpadded_size + 3) & 3;
//}
static void fds_evt_handler(ret_code_t result,
fds_cmd_id_t cmd,
fds_record_id_t record_id,
fds_record_key_t record_key
/*fds_record_t const * const p_record*/)
{
pds_evt_t evt;
switch(cmd)
{
case FDS_CMD_INIT:
break;
case FDS_CMD_UPDATE:
case FDS_CMD_WRITE:
evt.peer_id = convert_instance_id_to_peer_id(record_key.instance);
evt.evt_id = (result == NRF_SUCCESS) ? PDS_EVT_STORED : PDS_EVT_ERROR_STORE;
evt.data_id = convert_type_id_to_peer_data_id(record_key.type);
evt.store_token = record_id;
pds_evt_send(&evt);
break;
case FDS_CMD_CLEAR:
evt.peer_id = convert_instance_id_to_peer_id(record_key.instance);
evt.evt_id = (result == NRF_SUCCESS) ? PDS_EVT_CLEARED : PDS_EVT_ERROR_CLEAR;
evt.data_id = convert_type_id_to_peer_data_id(record_key.type);
evt.store_token = record_id;
pds_evt_send(&evt);
break;
case FDS_CMD_CLEAR_INST:
{
if ((record_key.type == FDS_TYPE_ID_INVALID) &&
(record_key.instance != FDS_TYPE_ID_INVALID))
{
pm_peer_id_t peer_id = convert_instance_id_to_peer_id(record_key.instance);
evt.peer_id = peer_id;
evt.data_id = PM_PEER_DATA_ID_INVALID;
if (result == NRF_SUCCESS)
{
evt.evt_id = PDS_EVT_PEER_ID_CLEAR;
peer_id_free(peer_id);
}
else
{
evt.evt_id = PDS_EVT_ERROR_PEER_ID_CLEAR;
}
}
else
{
// TODO: Not supported yet (clear many without clearing peer_id)
}
pds_evt_send(&evt);
}
break;
case FDS_CMD_GC:
evt.peer_id = convert_instance_id_to_peer_id(record_key.instance);
evt.evt_id = PDS_EVT_COMPRESSED;
evt.data_id = convert_type_id_to_peer_data_id(record_key.type);
evt.store_token = record_id;
pds_evt_send(&evt);
break;
default:
break;
}
}
ret_code_t pds_register(pds_evt_handler_t evt_handler)
{
if (m_pds.n_registrants >= MAX_REGISTRANTS)
{
return NRF_ERROR_NO_MEM;
}
VERIFY_PARAM_NOT_NULL(evt_handler);
if (!MODULE_INITIALIZED)
{
ret_code_t retval;
internal_state_reset(&m_pds);
peer_id_init();
fds_cb_t cb = fds_evt_handler;
retval = fds_register(cb);
if(retval != NRF_SUCCESS)
{
return retval;
}
retval = fds_init();
if(retval != NRF_SUCCESS)
{
return retval;
}
}
m_pds.evt_handlers[m_pds.n_registrants] = evt_handler;
m_pds.n_registrants += 1;
return NRF_SUCCESS;
}
ret_code_t pds_peer_data_read_ptr_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_flash_t * p_data,
pm_store_token_t * p_token)
{
ret_code_t retval;
fds_record_t record;
fds_record_desc_t record_desc;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
retval = find_fds_item(peer_id, data_id, &record_desc);
if (retval != NRF_SUCCESS)
{
return retval;
}
// Shouldn't fail, unless record is cleared.
fds_open(&record_desc, &record);
// No need to keep it open, since we are not reading.
fds_close(&record_desc);
//NRF_LOG_PRINTF("Found item with peer_id: %d, data_id: %d, Address: %p\r\n", record.p_data);
if (p_data != NULL)
{
p_data->data_type = data_id;
p_data->length_words = record.header.tl.length_words;
p_data->data.p_application_data = (uint8_t const*)record.p_data;
}
if (p_token != NULL)
{
*p_token = (uint32_t)record.header.id;
}
return retval;
}
ret_code_t pds_peer_data_lock(pm_store_token_t store_token)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_ZERO(store_token);
// TODO: Not implemented yet in fds
return NRF_SUCCESS;
}
ret_code_t pds_peer_data_verify(pm_store_token_t store_token)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_ZERO(store_token);
// TODO: Not implemented yet in fds
return NRF_SUCCESS;
}
ret_code_t pds_peer_data_read(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_t * p_data,
fds_length_t * p_len_words)
{
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
VERIFY_PARAM_NOT_NULL(p_len_words);
VERIFY_PARAM_NOT_NULL(p_data);
ret_code_t err_code;
pm_peer_data_flash_t peer_data_flash;
err_code = pds_peer_data_read_ptr_get(peer_id, data_id, &peer_data_flash, NULL);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
if ((*p_len_words) == 0)
{
(*p_len_words) = peer_data_flash.length_words;
return NRF_SUCCESS;
}
else if ((*p_len_words) < peer_data_flash.length_words)
{
return NRF_ERROR_NO_MEM;
}
VERIFY_PARAM_NOT_NULL(p_data->data.p_application_data);
err_code = peer_data_deserialize(&peer_data_flash, p_data);
return err_code;
}
ret_code_t pds_peer_data_write_prepare(pm_peer_data_const_t const * p_peer_data,
pm_prepare_token_t * p_prepare_token)
{
ret_code_t retval;
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_peer_data);
VERIFY_PARAM_NOT_NULL(p_prepare_token);
VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_type);
retval = fds_reserve((fds_write_token_t*)p_prepare_token, p_peer_data->length_words);
return retval;
}
ret_code_t pds_peer_data_write_prepare_cancel(pm_prepare_token_t prepare_token)
{
ret_code_t retval;
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_ZERO(prepare_token);
retval = fds_reserve_cancel((fds_write_token_t*)&prepare_token);
return retval;
}
ret_code_t pds_peer_data_write_prepared(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_prepare_token_t prepare_token,
pm_store_token_t * p_store_token)
{
ret_code_t retval;
fds_record_desc_t record_desc;
fds_record_key_t record_key;
fds_record_chunk_t chunks[2];
uint16_t n_chunks;
VERIFY_MODULE_INITIALIZED();
//VERIFY_PARAM_NOT_ZERO(prepare_token);
VERIFY_PARAM_NOT_NULL(p_peer_data);
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_type);
// Fill in the keys.
record_key.type = convert_peer_data_id_to_type_id(p_peer_data->data_type);
record_key.instance = convert_peer_id_to_instance_id(peer_id);
// Create chunks.
peer_data_parts_get(p_peer_data, chunks, &n_chunks);
retval = fds_write_reserved((fds_write_token_t*)&prepare_token, &record_desc,
record_key, n_chunks, chunks);
if ((retval == NRF_SUCCESS) && (p_store_token != NULL))
{
fds_record_id_from_desc(&record_desc, (fds_record_id_t*)p_store_token);
}
return retval;
}
ret_code_t pds_peer_data_write(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_store_token_t * p_store_token)
{
ret_code_t retval;
fds_record_desc_t record_desc;
fds_record_key_t record_key;
fds_record_chunk_t chunks[2];
uint16_t n_chunks;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_type);
// Fill in the keys.
record_key.type = convert_peer_data_id_to_type_id(p_peer_data->data_type);
record_key.instance = convert_peer_id_to_instance_id(peer_id);
// Create chunks
peer_data_parts_get(p_peer_data, chunks, &n_chunks);
// Request write
retval = fds_write(&record_desc, record_key, n_chunks, chunks);
if ((retval == NRF_SUCCESS) && (p_store_token != NULL))
{
fds_record_id_from_desc(&record_desc, (fds_record_id_t*)p_store_token);
}
return retval;
}
ret_code_t pds_peer_data_update(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_store_token_t old_token,
pm_store_token_t * p_store_token)
{
ret_code_t retval;
fds_record_desc_t record_desc;
fds_record_key_t record_key;
fds_record_chunk_t chunks[2];
uint16_t n_chunks;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_type);
VERIFY_PARAM_NOT_NULL(p_peer_data);
record_key.type = convert_peer_data_id_to_type_id(p_peer_data->data_type);
record_key.instance = convert_peer_id_to_instance_id(peer_id);
// Create chunks
peer_data_parts_get(p_peer_data, chunks, &n_chunks);
fds_descriptor_from_rec_id(&record_desc, (fds_record_id_t)old_token);
retval = fds_update(&record_desc, record_key, n_chunks, chunks);
if ((retval == NRF_SUCCESS) && (p_store_token != NULL))
{
fds_record_id_from_desc(&record_desc, (fds_record_id_t*)p_store_token);
}
return retval;
}
ret_code_t pds_peer_data_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
ret_code_t retval;
fds_type_id_t type_id;
fds_instance_id_t instance_id;
fds_record_desc_t record_desc;
fds_find_token_t find_tok;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
type_id = convert_peer_data_id_to_type_id(data_id);
instance_id = convert_peer_id_to_instance_id(peer_id);
retval = fds_find(type_id, instance_id, &record_desc, &find_tok);
if(retval != NRF_SUCCESS)
{
return retval;
}
retval = fds_clear(&record_desc);
return retval;
}
pm_peer_id_t pds_peer_id_allocate(void)
{
if (!MODULE_INITIALIZED)
{
return PM_PEER_ID_INVALID;
}
PEER_IDS_INITIALIZE();
return peer_id_allocate(PM_PEER_ID_INVALID);
}
ret_code_t pds_peer_id_free(pm_peer_id_t peer_id)
{
ret_code_t retval;
fds_instance_id_t instance_id;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
PEER_IDS_INITIALIZE();
instance_id = convert_peer_id_to_instance_id(peer_id);
retval = fds_clear_by_instance(instance_id);
return retval;
}
bool pds_peer_id_is_allocated(pm_peer_id_t peer_id)
{
if (!MODULE_INITIALIZED)
{
return false;
}
PEER_IDS_INITIALIZE();
return peer_id_is_allocated(peer_id);
}
pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id)
{
if (!MODULE_INITIALIZED)
{
return PM_PEER_ID_INVALID;
}
PEER_IDS_INITIALIZE();
return peer_id_next_id_get(prev_peer_id);
}
uint32_t pds_n_peers(void)
{
if (!MODULE_INITIALIZED)
{
return 0;
}
PEER_IDS_INITIALIZE();
return peer_id_n_ids();
}

View File

@ -0,0 +1,370 @@
/*
* 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_DATA_STORAGE_H__
#define PEER_DATA_STORAGE_H__
#include "stdint.h"
#include "sdk_errors.h"
#include "ble_gap.h"
#include "peer_manager_types.h"
#include "fds.h"
/**
* @defgroup peer_data_storage Peer Data Storage
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. This module provides a Peer Manager-specific API
* to the persistent storage.
*/
#define PDS_PREPARE_TOKEN_INVALID 0
#define PDS_STORE_TOKEN_INVALID 0
typedef enum
{
peer_id_to_instance_id = 16384,
instance_id_to_peer_id = -peer_id_to_instance_id,
peer_data_id_to_type_id = 32768,
type_id_to_peer_data_id = -peer_data_id_to_type_id,
} pds_convert_t;
/**@brief The types of events that can come from the peer_data_storage module.
*/
typedef enum
{
PDS_EVT_STORED, /**< The specified data has been successfully stored. */
PDS_EVT_CLEARED, /**< The specified data has been successfully cleared. */
PDS_EVT_PEER_ID_CLEAR, /**< The peer id has been successfully cleared. */
PDS_EVT_ERROR_STORE, /**< The specified data could not be stored. */
PDS_EVT_ERROR_CLEAR, /**< The specified data could not be cleared. */
PDS_EVT_ERROR_PEER_ID_CLEAR, /**< The peer id has been successfully cleared. */
PDS_EVT_COMPRESSED, /**< A compress procedure has finished successfully. */
} pds_evt_id_t;
/**@brief Events that can come from the peer_data_storage module.
*/
typedef struct
{
pds_evt_id_t evt_id; /**< The type of event. */
pm_peer_id_t peer_id; /**< The peer the event pertains to. */
pm_peer_data_id_t data_id; /**< The data the event pertains to. */
pm_store_token_t store_token;
} pds_evt_t;
/**@brief Event handler for events from the peer_data_storage module.
*
* @param[in] event The event that has happened.
* @param[in] peer_id The id of the peer the event pertains to.
* @param[in] flags The data the event pertains to.
*/
typedef void (*pds_evt_handler_t)(pds_evt_t const * p_event);
/**@brief Function for registering for events from the peer database.
*
* @note This function will initialize the module if it is not already initialized.
*
* @param[in] evt_handler Event handler to register.
*
* @retval NRF_SUCCESS Registration successful.
* @retval NRF_ERROR_NO_MEM No more event handlers can be registered.
* @retval NRF_ERROR_NULL evt_handler was NULL.
* @retval NRF_ERROR_INVALID_PARAM Unexpected return code from @ref pm_buffer_init.
* @retval NRF_ERROR_INVALID_STATE FDS has not been initalized.
*/
ret_code_t pds_register(pds_evt_handler_t evt_handler);
#if 0
/**@brief Function for initializing Peer Data storage and registering a
* callback for its events.
*
* @param[in] evt_handler Event handler to register.
*
* @retval NRF_SUCCESS Registration successful.
* @retval NRF_ERROR_NO_MEM No more event handlers can be registered.
* @retval NRF_ERROR_NULL evt_handler was NULL.
* @retval NRF_ERROR_INVALID_STATE FDS has not completed initialization.
*/
ret_code_t pds_init(pds_evt_handler_t evt_handler);
#endif
/**@brief Function for retrieving a direct pointer to peer data in persistent storage.
*
* @param[in] peer_id The id of the peer whose data to read.
* @param[in] data_id Which data to get.
* @param[out] p_data The peer data pointer.
* @param[out] p_token Token that can be used to lock data in flash and check data validity.
*
* @retval NRF_SUCCESS The pointer was successfully retrieved.
* @retval NRF_ERROR_INVALID_PARAM Invalid data_id.
* @retval NRF_ERROR_NULL p_data was NULL.
* @retval NRF_ERROR_NOT_FOUND The requested data was not found in persistent storage.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_read_ptr_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_flash_t * p_data,
pm_store_token_t * p_token);
/**@brief Function to lock the flash data (to defer compression from invalidating data)
*
* @param[in] store_token The token representing the item to lock
*
*/
ret_code_t pds_peer_data_lock(pm_store_token_t store_token);
/**@brief Function to verify flash data integrity
*
* @param[in] store_token The token representing the item to lock
*
* @retval NRF_SUCCESS The data integrity is valid.
* @retval NRF_ERROR_NULL The token is invalid.
* @retval NRF_ERROR_INVALID_DATA The data integrity is not valid.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_verify(pm_store_token_t store_token);
/**@brief Function for retrieving peer data from persistent storage by making a copy
*
* @param[in] peer_id The id of the peer whose data to read.
* @param[in] data_id Which piece of data to read.
* @param[out] p_data Pointer to the peer data.
* @param[in,out] p_len_words Length available to copy to (in words).
* If set to NULL, then no copy will be made and the
* length will be reflected in p_len_words after the call returns.
*
* @retval NRF_SUCCESS The read was successful.
* @retval NRF_ERROR_INVALID_PARAM Invalid data_id.
* @retval NRF_ERROR_NULL data contained a NULL pointer.
* @retval NRF_ERROR_NOT_FOUND The requested data was not found in persistent storage.
* @retval NRF_ERROR_NO_MEM The length of stored data too large to copy out
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_read(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_t * p_data,
fds_length_t * p_len_words);
/**@brief Function for preparing persistent storage for a write.
*
* @details If this call succeeds, space is reserved in persistent storage, so the write will fit.
*
* @note If space has already been prepared for this peer_id/data_id pair, no new space will be
* reserved, unless the previous reservation had too small size.
*
* @param[in] p_peer_data Data to prepare for. The data needs not be ready, but length and type
* values must.
* @param[out] p_prepare_token A token identifying the prepared memory area.
*
* @retval NRF_SUCCESS The call was successful.
* @retval NRF_ERROR_INVALID_PARAM Invalid data ID.
* @retval NRF_ERROR_INVALID_LENGTH Data length above the maximum allowed.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_write_prepare(pm_peer_data_const_t const * p_peer_data,
pm_prepare_token_t * p_prepare_token);
/**@brief Function for undoing a previous call to @ref pds_peer_data_write_prepare.
*
* @param[in] prepare_token A token identifying the prepared memory area to cancel.
*
* @retval NRF_SUCCESS The call was successful.
* @retval NRF_ERROR_NOT_FOUND Invalid peer ID and/or prepare token.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_write_prepare_cancel(pm_prepare_token_t prepare_token);
/**@brief Function for writing prepared (reserved) peer data to persistent storage.
*
* @details Writing happens asynchronously. Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE
* event.
*
* @param[in] peer_id The id of the peer the data pertains to.
* @param[in] p_peer_data The peer data.
* @param[in] prepare_token A token identifying the prepared memory area to write into. If
* the prepare token is invalid, e.g. PDS_PREPARE_TOKEN_INVALID, the
* prepare/write sequence will happen atomically.
* @param[out] p_store_token A token identifying this particular store operation. The token can be
* used to identify events pertaining to this operation.
*
* @retval NRF_SUCCESS The write was initiated successfully.
* @retval NRF_ERROR_INVALID_PARAM Invalid data ID or store_flags.
* @retval NRF_ERROR_INVALID_LENGTH Length of data longer than in prepare call.
* @retval NRF_ERROR_NULL data contained a NULL pointer.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage. This can only happen
* if p_prepare_token is NULL.
* @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any
* more requests
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_write_prepared(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_prepare_token_t prepare_token,
pm_store_token_t * p_store_token);
/**@brief Function for writing peer data to persistent storage.
*
* @details Writing happens asynchronously. Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE
* event.
*
* @param[in] peer_id The id of the peer the data pertains to.
* @param[in] p_peer_data The peer data.
* @param[out] p_store_token A token identifying this particular store operation. The token can be
* used to identify events pertaining to this operation.
*
* @retval NRF_SUCCESS The write was initiated successfully.
* @retval NRF_ERROR_INVALID_PARAM Invalid data ID or store_flags.
* @retval NRF_ERROR_NULL Data contained a NULL pointer.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage. This can only happen
* if p_prepare_token is NULL.
* @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any
* more requests
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_write(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_store_token_t * p_store_token);
/**@brief Function for updating currently stored peer data to a new version
*
* @details Updating happens asynchronously.
* Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE for the store token
* and a @ref PDS_EVT_ERROR_CLEAR or @ref PDS_EVT_ERROR_CLEAR for the old token
*
* @param[in] peer_id The peer which the data is associated to.
* @param[in] peer_data New data.
* @param[in] old_token Store token for the old data.
* @param[out] p_store_token Store token for the new data.
*
* @retval NRF_SUCESS The update was initiated successfully
* @retval NRF_ERROR_NOT_FOUND The old store token was invalid.
* @retval NRF_ERROR_NULL Data contained a NULL pointer.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage.
* @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any
* more requests
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_update(pm_peer_id_t peer_id,
pm_peer_data_const_t const * peer_data,
pm_store_token_t old_token,
pm_store_token_t * p_store_token);
/**@brief Function for clearing peer data from persistent storage.
*
* @details Clearing happens asynchronously. Expect a @ref PDS_EVT_CLEARED or @ref PDS_EVT_ERROR_CLEAR
* event.
*
* @param[in] peer_id The id of the peer the data pertains to.
* @param[in] data_id Which data to clear.
*
* @retval NRF_SUCCESS The clear was initiated successfully.
* @retval NRF_ERROR_INVALID_PARAM Data ID or was invalid.
* @retval NRF_ERROR_NOT_FOUND Nothing to clear for this peer ID.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
/**@brief Function for claiming an unused peer ID.
*
* @return The first unused peer ID.
* @retval PM_PEER_ID_INVALID If no peer ID is available or module is not initialized.
*/
pm_peer_id_t pds_peer_id_allocate(void);
/**@brief Function for freeing a peer ID and clearing all data associated with it in persistent
* storage.
*
* @param[in] peer_id Peer ID to free.
*
* @retval NRF_SUCCESS The clear was initiated successfully
* @retval NRF_ERROR_BUSY Another peer_id clear was already requested or fds queue full
*/
ret_code_t pds_peer_id_free(pm_peer_id_t peer_id);
/**@brief Function for finding out whether a peer ID is in use.
*
* @param[in] peer_id The peer ID to inquire about.
*
* @retval true peer_id is in use.
* @retval false peer_id is free, or the module is not initialized.
*/
bool pds_peer_id_is_allocated(pm_peer_id_t peer_id);
/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
* used to loop through all used peer IDs.
*
* @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
* peer ID.
*
* @param[in] prev_peer_id The previous peer ID.
*
* @return The next peer ID.
* @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
* @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module
* is not initialized.
*/
pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id);
/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
* in persistent storage.
*
* @return The number of valid peer IDs, or 0 if module is not initialized.
*/
uint32_t pds_n_peers(void);
/** @} */
#endif /* PEER_DATA_STORAGE_H__ */

View File

@ -0,0 +1,768 @@
/*
* 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 "peer_database.h"
#include <string.h>
#include "peer_manager_types.h"
#include "peer_data_storage.h"
#include "pm_buffer.h"
#define MAX_REGISTRANTS 6 /**< The number of user that can register with the module. */
#define MODULE_INITIALIZED (m_pdb.n_registrants > 0) /**< Expression which is true when the module is initialized. */
#define N_WRITE_BUFFERS 8 /**< The number of write buffers available. */
#define N_WRITE_BUFFER_RECORDS (N_WRITE_BUFFERS) /**< The number of write buffer records. */
/**@brief Macro for verifying that the module is initialized. It will cause the function to return
* @ref NRF_ERROR_INVALID_STATE if not.
*/
#define VERIFY_MODULE_INITIALIZED() \
do \
{ \
if (!MODULE_INITIALIZED) \
{ \
return NRF_ERROR_INVALID_STATE; \
} \
} while(0)
/**@brief Macro for verifying that the module is initialized. It will cause the function to return
* if not.
*/
#define VERIFY_MODULE_INITIALIZED_VOID()\
do \
{ \
if (!MODULE_INITIALIZED) \
{ \
return; \
} \
} while(0)
/**@brief Macro for verifying that the module is initialized. It will cause the function to return
* if not.
*
* @param[in] param The variable to check if is NULL.
*/
#define VERIFY_PARAM_NOT_NULL(param) \
do \
{ \
if (param == NULL) \
{ \
return NRF_ERROR_NULL; \
} \
} while(0)
typedef struct
{
pm_peer_id_t peer_id;
pm_peer_data_id_t data_id;
uint8_t buffer_block_id;
uint8_t store_busy : 1;
uint8_t store_flash_full : 1;
uint8_t store_requested : 1;
uint32_t n_bufs;
pm_prepare_token_t prepare_token;
pm_store_token_t store_token;
} pdb_buffer_record_t;
typedef struct
{
pdb_evt_handler_t evt_handlers[MAX_REGISTRANTS];
uint8_t n_registrants;
pm_buffer_t write_buffer;
pdb_buffer_record_t write_buffer_records[N_WRITE_BUFFER_RECORDS];
uint32_t n_writes;
} pdb_t;
static pdb_t m_pdb = {.n_registrants = 0};
/**@brief Function for invalidating a record of a write buffer allocation.
*
* @param[in] p_record The record to invalidate.
*/
static void write_buffer_record_invalidate(pdb_buffer_record_t * p_record)
{
p_record->peer_id = PM_PEER_ID_INVALID;
p_record->data_id = PM_PEER_DATA_ID_INVALID;
p_record->buffer_block_id = BUFFER_INVALID_ID;
p_record->store_busy = false;
p_record->store_flash_full = false;
p_record->store_requested = false;
p_record->n_bufs = 0;
p_record->prepare_token = PDS_PREPARE_TOKEN_INVALID;
p_record->store_token = PDS_STORE_TOKEN_INVALID;
}
/**@brief Function for finding a record of a write buffer allocation.
*
* @param[in] peer_id The peer ID in the record.
* @param[in] data_id The data ID in the record.
*
* @return A pointer to the matching record, or NULL if none was found.
*/
static pdb_buffer_record_t * write_buffer_record_find(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id)
{
for (int i = 0; i < N_WRITE_BUFFER_RECORDS; i++)
{
if ((m_pdb.write_buffer_records[i].peer_id == peer_id)
&& (m_pdb.write_buffer_records[i].data_id == data_id))
{
return &m_pdb.write_buffer_records[i];
}
}
return NULL;
}
/**@brief Function for finding an available record for write buffer allocation.
*
* @return A pointer to the available record, or NULL if none was found.
*/
static pdb_buffer_record_t * write_buffer_record_find_unused(void)
{
return write_buffer_record_find(PM_PEER_ID_INVALID, PM_PEER_DATA_ID_INVALID);
}
/**@brief Function for gracefully deactivating a write buffer record.
*
* @details This function will first release any buffers, then invalidate the record.
*
* @param[inout] p_write_buffer_record The record to release.
*
* @return A pointer to the matching record, or NULL if none was found.
*/
static void write_buffer_record_release(pdb_buffer_record_t * p_write_buffer_record)
{
for (int i = 0; i < p_write_buffer_record->n_bufs; i++)
{
pm_buffer_release(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id + i);
}
write_buffer_record_invalidate(p_write_buffer_record);
}
static void write_buffer_record_get(pdb_buffer_record_t ** pp_write_buffer_record, pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
if (pp_write_buffer_record == NULL)
{
return;
}
*pp_write_buffer_record = write_buffer_record_find_unused();
if (*pp_write_buffer_record == NULL)
{
// This also means the buffer is full.
return;
}
(*pp_write_buffer_record)->peer_id = peer_id;
(*pp_write_buffer_record)->data_id = data_id;
}
/**@brief Function for dispatching outbound events to all registered event handlers.
*
* @param[in] p_event The event to dispatch.
*/
static void pdb_evt_send(pdb_evt_t * p_event)
{
for (int i = 0; i < m_pdb.n_registrants; i++)
{
m_pdb.evt_handlers[i](p_event);
}
}
/**@brief Function for resetting the internal state of the Peer Database module.
*
* @param[out] p_event The event to dispatch.
*/
static void internal_state_reset(pdb_t * pdb)
{
memset(pdb, 0, sizeof(pdb_t));
for (int i = 0; i < N_WRITE_BUFFER_RECORDS; i++)
{
write_buffer_record_invalidate(&pdb->write_buffer_records[i]);
}
}
/**@brief Function for handling events from the Peer Data Storage module.
*
* @param[in] p_event The event to handle.
*/
static void pds_evt_handler(pds_evt_t const * p_event)
{
ret_code_t err_code;
pdb_buffer_record_t * p_write_buffer_record;
bool retry_flash_full = false;
pdb_evt_t event =
{
.peer_id = p_event->peer_id,
.data_id = p_event->data_id,
};
p_write_buffer_record = write_buffer_record_find(p_event->peer_id, p_event->data_id);
switch (p_event->evt_id)
{
case PDS_EVT_STORED:
if ( (p_write_buffer_record != NULL)
//&& (p_write_buffer_record->store_token == p_event->store_token)
&& (p_write_buffer_record->store_requested))
{
write_buffer_record_release(p_write_buffer_record);
event.evt_id = PDB_EVT_WRITE_BUF_STORED;
pdb_evt_send(&event);
}
else
{
event.evt_id = PDB_EVT_RAW_STORED;
pdb_evt_send(&event);
}
break;
case PDS_EVT_ERROR_STORE:
if ( (p_write_buffer_record != NULL)
&& (p_write_buffer_record->store_token == p_event->store_token)
&& (p_write_buffer_record->store_requested))
{
// Retry if internal buffer.
m_pdb.n_writes++;
p_write_buffer_record->store_requested = false;
p_write_buffer_record->store_busy = true;
}
else
{
event.evt_id = PDB_EVT_RAW_STORE_FAILED;
pdb_evt_send(&event);
}
break;
case PDS_EVT_CLEARED:
event.evt_id = PDB_EVT_CLEARED;
pdb_evt_send(&event);
break;
case PDS_EVT_ERROR_CLEAR:
event.evt_id = PDB_EVT_CLEAR_FAILED;
pdb_evt_send(&event);
break;
case PDS_EVT_COMPRESSED:
retry_flash_full = true;
event.evt_id = PDB_EVT_COMPRESSED;
pdb_evt_send(&event);
break;
default:
break;
}
if (m_pdb.n_writes > 0)
{
for (int i = 0; i < N_WRITE_BUFFER_RECORDS; i++)
{
if ((m_pdb.write_buffer_records[i].store_busy)
|| (m_pdb.write_buffer_records[i].store_flash_full && retry_flash_full))
{
err_code = pdb_write_buf_store(m_pdb.write_buffer_records[i].peer_id,
m_pdb.write_buffer_records[i].data_id);
if (err_code != NRF_SUCCESS)
{
event.peer_id = m_pdb.write_buffer_records[i].peer_id;
event.data_id = m_pdb.write_buffer_records[i].data_id;
if (err_code == NRF_ERROR_NO_MEM)
{
event.evt_id = PDB_EVT_ERROR_NO_MEM;
}
else
{
event.evt_id = PDB_EVT_ERROR_UNEXPECTED;
}
pdb_evt_send(&event);
break;
}
}
}
}
}
ret_code_t pdb_register(pdb_evt_handler_t evt_handler)
{
if (m_pdb.n_registrants >= MAX_REGISTRANTS)
{
return NRF_ERROR_NO_MEM;
}
VERIFY_PARAM_NOT_NULL(evt_handler);
if (!MODULE_INITIALIZED)
{
ret_code_t err_code;
internal_state_reset(&m_pdb);
err_code = pds_register(pds_evt_handler);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
PM_BUFFER_INIT(&m_pdb.write_buffer, N_WRITE_BUFFERS, PDB_WRITE_BUF_SIZE, err_code);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
m_pdb.evt_handlers[m_pdb.n_registrants] = evt_handler;
m_pdb.n_registrants += 1;
return NRF_SUCCESS;
}
pm_peer_id_t pdb_peer_allocate(void)
{
if (!MODULE_INITIALIZED)
{
return PM_PEER_ID_INVALID;
}
return pds_peer_id_allocate();
}
ret_code_t pdb_peer_free(pm_peer_id_t peer_id)
{
VERIFY_MODULE_INITIALIZED();
return pds_peer_id_free(peer_id);
}
ret_code_t pdb_read_buf_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_flash_t * p_peer_data,
pm_store_token_t * p_token)
{
VERIFY_MODULE_INITIALIZED();
return pds_peer_data_read_ptr_get(peer_id, data_id, p_peer_data, p_token);
}
static void peer_data_point_to_buffer(pm_peer_data_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint16_t n_bufs)
{
uint16_t n_bytes = n_bufs * PDB_WRITE_BUF_SIZE;
p_peer_data->data_type = data_id;
switch(p_peer_data->data_type)
{
case PM_PEER_DATA_ID_BONDING:
p_peer_data->data.p_bonding_data = (pm_peer_data_bonding_t *)p_buffer_memory;
p_peer_data->length_words = PM_BONDING_DATA_N_WORDS();
break;
case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
p_peer_data->data.p_service_changed_pending = (bool *)p_buffer_memory;
p_peer_data->length_words = PM_SC_STATE_N_WORDS();
break;
case PM_PEER_DATA_ID_GATT_LOCAL:
p_peer_data->data.p_local_gatt_db = (pm_peer_data_local_gatt_db_t *)p_buffer_memory;
p_peer_data->length_words = PM_LOCAL_DB_N_WORDS(n_bytes);
break;
case PM_PEER_DATA_ID_GATT_REMOTE:
p_peer_data->data.p_remote_gatt_db = (pm_peer_data_remote_gatt_db_t *)p_buffer_memory;
p_peer_data->length_words = PM_REMOTE_DB_N_WORDS(n_bytes / sizeof(ble_gatt_db_srv_t));
break;
case PM_PEER_DATA_ID_APPLICATION:
p_peer_data->data.p_application_data = p_buffer_memory;
p_peer_data->length_words = PM_N_WORDS(n_bytes);
break;
default:
p_peer_data->length_words = 0;
break;
}
}
static void peer_data_const_point_to_buffer(pm_peer_data_const_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint32_t n_bufs)
{
peer_data_point_to_buffer((pm_peer_data_t*)p_peer_data, data_id, p_buffer_memory, n_bufs);
}
ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
uint32_t n_bufs,
pm_peer_data_t * p_peer_data)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_peer_data);
if ( !PM_PEER_DATA_ID_IS_VALID(data_id)
|| (n_bufs == 0)
|| (n_bufs > N_WRITE_BUFFERS)
|| !pds_peer_id_is_allocated(peer_id))
{
return NRF_ERROR_INVALID_PARAM;
}
pdb_buffer_record_t * write_buffer_record;
uint8_t * p_buffer_memory;
write_buffer_record = write_buffer_record_find(peer_id, data_id);
if ((write_buffer_record != NULL) && (write_buffer_record->n_bufs < n_bufs))
{
// @TODO: Copy?
// Existing buffer is too small.
for (uint8_t i = 0; i < write_buffer_record->n_bufs; i++)
{
pm_buffer_release(&m_pdb.write_buffer, write_buffer_record->buffer_block_id + i);
}
write_buffer_record_invalidate(write_buffer_record);
write_buffer_record = NULL;
}
else if ((write_buffer_record != NULL) && write_buffer_record->n_bufs > n_bufs)
{
// Release excess blocks.
for (uint8_t i = n_bufs; i < write_buffer_record->n_bufs; i++)
{
pm_buffer_release(&m_pdb.write_buffer, write_buffer_record->buffer_block_id + i);
}
}
if (write_buffer_record == NULL)
{
write_buffer_record_get(&write_buffer_record, peer_id, data_id);
if (write_buffer_record == NULL)
{
return NRF_ERROR_BUSY;
}
}
if (write_buffer_record->buffer_block_id == BUFFER_INVALID_ID)
{
write_buffer_record->buffer_block_id = pm_buffer_block_acquire(&m_pdb.write_buffer, n_bufs);
if (write_buffer_record->buffer_block_id == BUFFER_INVALID_ID)
{
write_buffer_record_invalidate(write_buffer_record);
return NRF_ERROR_BUSY;
}
}
write_buffer_record->n_bufs = n_bufs;
p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, write_buffer_record->buffer_block_id);
if (p_buffer_memory == NULL)
{
return NRF_ERROR_INTERNAL;
}
peer_data_point_to_buffer(p_peer_data, data_id, p_buffer_memory, n_bufs);
switch(data_id)
{
case PM_PEER_DATA_ID_BONDING:
/* No action needed. */
break;
case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
/* No action needed. */
break;
case PM_PEER_DATA_ID_GATT_LOCAL:
{
uint32_t size_offset = sizeof(pm_peer_data_local_gatt_db_t);
p_peer_data->data.p_local_gatt_db->p_data = &p_buffer_memory[size_offset];
p_peer_data->data.p_local_gatt_db->len = (PDB_WRITE_BUF_SIZE*n_bufs)-size_offset;
}
break;
case PM_PEER_DATA_ID_GATT_REMOTE:
{
uint32_t size_offset = sizeof(pm_peer_data_remote_gatt_db_t);
p_peer_data->data.p_remote_gatt_db->p_data = (ble_gatt_db_srv_t*)&(p_buffer_memory[size_offset]);
p_peer_data->data.p_remote_gatt_db->service_count
= ((PDB_WRITE_BUF_SIZE*n_bufs)-size_offset)/sizeof(ble_gatt_db_srv_t);
}
break;
case PM_PEER_DATA_ID_APPLICATION:
{
p_peer_data->data.p_application_data = p_buffer_memory;
}
break;
default:
// Invalid data_id. This should have been picked up earlier.
return NRF_ERROR_INTERNAL;
}
return NRF_SUCCESS;
}
ret_code_t pdb_write_buf_release(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
VERIFY_MODULE_INITIALIZED();
ret_code_t err_code = NRF_SUCCESS;
pdb_buffer_record_t * p_write_buffer_record;
p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
if (p_write_buffer_record == NULL)
{
return NRF_ERROR_NOT_FOUND;
}
if (p_write_buffer_record->prepare_token != PDS_PREPARE_TOKEN_INVALID)
{
err_code = pds_peer_data_write_prepare_cancel(p_write_buffer_record->prepare_token);
if (err_code != NRF_SUCCESS)
{
err_code = NRF_ERROR_INTERNAL;
}
}
write_buffer_record_release(p_write_buffer_record);
return err_code;
}
ret_code_t pdb_write_buf_store_prepare(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
VERIFY_MODULE_INITIALIZED();
ret_code_t err_code = NRF_SUCCESS;
pdb_buffer_record_t * p_write_buffer_record;
p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
if (p_write_buffer_record == NULL)
{
return NRF_ERROR_NOT_FOUND;
}
if (p_write_buffer_record->prepare_token == PDS_PREPARE_TOKEN_INVALID)
{
uint8_t * p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id);
pm_peer_data_const_t peer_data = {.data_type = data_id};
if (p_buffer_memory == NULL)
{
return NRF_ERROR_INTERNAL;
}
peer_data_const_point_to_buffer(&peer_data, data_id, p_buffer_memory, p_write_buffer_record->n_bufs);
err_code = pds_peer_data_write_prepare(&peer_data, &p_write_buffer_record->prepare_token);
if (err_code == NRF_ERROR_INVALID_LENGTH)
{
return NRF_ERROR_INTERNAL;
}
}
return err_code;
}
static ret_code_t write_or_update(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_const_t * p_peer_data,
pm_store_token_t * p_store_token,
pm_prepare_token_t prepare_token)
{
pm_peer_data_flash_t old_peer_data;
pm_store_token_t old_store_token;
ret_code_t err_code = pds_peer_data_read_ptr_get(peer_id, data_id, &old_peer_data, &old_store_token);
if (err_code == NRF_SUCCESS)
{
pds_peer_data_write_prepare_cancel(prepare_token);
err_code = pds_peer_data_update(peer_id, p_peer_data, old_store_token, p_store_token);
}
else if (err_code == NRF_ERROR_NOT_FOUND)
{
if (prepare_token == PDS_PREPARE_TOKEN_INVALID)
{
err_code = pds_peer_data_write(peer_id, p_peer_data, p_store_token);
}
else
{
err_code = pds_peer_data_write_prepared(peer_id, p_peer_data, prepare_token, p_store_token);
}
}
return err_code;
}
ret_code_t pdb_write_buf_store(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id)
{
VERIFY_MODULE_INITIALIZED();
ret_code_t err_code = NRF_SUCCESS;
pdb_buffer_record_t * p_write_buffer_record;
uint8_t * p_buffer_memory;
pm_peer_data_const_t peer_data = {.data_type = data_id};
p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
if (p_write_buffer_record == NULL)
{
return NRF_ERROR_NOT_FOUND;
}
if (p_write_buffer_record->store_requested)
{
return NRF_SUCCESS;
}
p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id);
if (p_buffer_memory == NULL)
{
return NRF_ERROR_INTERNAL;
}
peer_data_const_point_to_buffer(&peer_data, data_id, p_buffer_memory, p_write_buffer_record->n_bufs);
switch (data_id)
{
case PM_PEER_DATA_ID_BONDING:
peer_data.length_words = PM_BONDING_DATA_N_WORDS();
break;
case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
peer_data.length_words = PM_SC_STATE_N_WORDS();
break;
case PM_PEER_DATA_ID_GATT_LOCAL:
peer_data.length_words = PM_LOCAL_DB_N_WORDS(peer_data.data.p_local_gatt_db->len);
break;
case PM_PEER_DATA_ID_GATT_REMOTE:
peer_data.length_words = PM_REMOTE_DB_N_WORDS(peer_data.data.p_remote_gatt_db->service_count);
break;
case PM_PEER_DATA_ID_APPLICATION:
peer_data.length_words = PM_N_WORDS(p_write_buffer_record->n_bufs * PDB_WRITE_BUF_SIZE);
break;
default:
return NRF_ERROR_INVALID_PARAM;
}
err_code = write_or_update(peer_id, data_id, &peer_data, &p_write_buffer_record->store_token, p_write_buffer_record->prepare_token);
if (p_write_buffer_record->store_busy && p_write_buffer_record->store_flash_full)
{
m_pdb.n_writes--;
}
if (err_code == NRF_SUCCESS)
{
p_write_buffer_record->store_requested = true;
p_write_buffer_record->store_busy = false;
p_write_buffer_record->store_flash_full = false;
}
else
{
if (err_code == NRF_ERROR_BUSY)
{
m_pdb.n_writes++;
p_write_buffer_record->store_busy = true;
p_write_buffer_record->store_flash_full = false;
err_code = NRF_SUCCESS;
}
else if (err_code == NRF_ERROR_NO_MEM)
{
m_pdb.n_writes++;
p_write_buffer_record->store_busy = false;
p_write_buffer_record->store_flash_full = true;
}
else if ((err_code != NRF_ERROR_NO_MEM) && (err_code != NRF_ERROR_INVALID_PARAM))
{
err_code = NRF_ERROR_INTERNAL;
}
}
return err_code;
}
ret_code_t pdb_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
VERIFY_MODULE_INITIALIZED();
return pds_peer_data_clear(peer_id, data_id);
}
uint32_t pdb_n_peers(void)
{
if (!MODULE_INITIALIZED)
{
return 0;
}
return pds_n_peers();
}
pm_peer_id_t pdb_next_peer_id_get(pm_peer_id_t prev_peer_id)
{
if (!MODULE_INITIALIZED)
{
return PM_PEER_ID_INVALID;
}
return pds_next_peer_id_get(prev_peer_id);
}
ret_code_t pdb_raw_read(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_t * p_peer_data)
{
VERIFY_MODULE_INITIALIZED();
return pds_peer_data_read(peer_id, data_id, p_peer_data, &p_peer_data->length_words);
}
ret_code_t pdb_raw_store(pm_peer_id_t peer_id,
pm_peer_data_const_t * p_peer_data,
pm_store_token_t * p_store_token)
{
VERIFY_MODULE_INITIALIZED();
return write_or_update(peer_id, p_peer_data->data_type, p_peer_data, p_store_token, PDS_PREPARE_TOKEN_INVALID);
}

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.
*
*/
#include "peer_id.h"
#include <stdint.h>
#include <string.h>
#include "sdk_errors.h"
#include "peer_manager_types.h"
#include "pm_mutex.h"
typedef struct
{
uint8_t peer_ids[MUTEX_STORAGE_SIZE(PM_PEER_ID_N_AVAILABLE_IDS)]; /*< bitmap. */
} pi_t;
static pi_t m_pi = {.peer_ids = {0}};
static void internal_state_reset(pi_t * p_pi)
{
memset(p_pi, 0, sizeof(pi_t));
}
void peer_id_init(void)
{
internal_state_reset(&m_pi);
pm_mutex_init(m_pi.peer_ids, PM_PEER_ID_N_AVAILABLE_IDS);
}
pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id)
{
pm_peer_id_t allocated_peer_id = PM_PEER_ID_INVALID;
if (peer_id == PM_PEER_ID_INVALID)
{
allocated_peer_id = pm_mutex_lock_first_available(m_pi.peer_ids, PM_PEER_ID_N_AVAILABLE_IDS);
if (allocated_peer_id == PM_PEER_ID_N_AVAILABLE_IDS)
{
allocated_peer_id = PM_PEER_ID_INVALID;
}
}
else if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
{
bool lock_success = pm_mutex_lock(m_pi.peer_ids, peer_id);
allocated_peer_id = lock_success ? peer_id : PM_PEER_ID_INVALID;
}
return allocated_peer_id;
}
void peer_id_free(pm_peer_id_t peer_id)
{
if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
{
pm_mutex_unlock(m_pi.peer_ids, peer_id);
}
}
bool peer_id_is_allocated(pm_peer_id_t peer_id)
{
if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
{
return pm_mutex_lock_status_get(m_pi.peer_ids, peer_id);
}
return false;
}
pm_peer_id_t peer_id_next_id_get(pm_peer_id_t prev_peer_id)
{
pm_peer_id_t i = (prev_peer_id == PM_PEER_ID_INVALID) ? 0 : (prev_peer_id + 1);
for (; i < PM_PEER_ID_N_AVAILABLE_IDS; i++)
{
if (pm_mutex_lock_status_get(m_pi.peer_ids, i))
{
return i;
}
}
return PM_PEER_ID_INVALID;
}
uint32_t peer_id_n_ids(void)
{
uint32_t n_ids = 0;
for (pm_peer_id_t i = 0; i < PM_PEER_ID_N_AVAILABLE_IDS; i++)
{
n_ids += pm_mutex_lock_status_get(m_pi.peer_ids, i);
}
return n_ids;
}

View File

@ -0,0 +1,112 @@
/*
* 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_H__
#define PEER_ID_H__
#include "stdint.h"
#include "sdk_errors.h"
#include "ble_gap.h"
#include "peer_manager_types.h"
/**
* @defgroup peer_id Peer IDs
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. This module keeps track of which peer IDs are in
* use and which are free.
*/
/**@brief Function for initializing the module.
*/
void peer_id_init(void);
/**@brief Function for claiming an unused peer ID.
*
* @param peer_id The peer ID to allocate. If this is @ref PM_PEER_ID_INVALID, the first available
* will be allocated.
*
* @return The allocated peer ID.
* @retval PM_PEER_ID_INVALID If no peer ID could be allocated or module is not initialized.
*/
pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id);
/**@brief Function for freeing a peer ID and clearing all data associated with it in persistent
* storage.
*
* @param[in] peer_id Peer ID to free.
*/
void peer_id_free(pm_peer_id_t peer_id);
/**@brief Function for finding out whether a peer ID is in use.
*
* @param[in] peer_id The peer ID to inquire about.
*
* @retval true peer_id is in use.
* @retval false peer_id is free, or the module is not initialized.
*/
bool peer_id_is_allocated(pm_peer_id_t peer_id);
/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
* used to loop through all used peer IDs.
*
* @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
* peer ID.
*
* @param[in] prev_peer_id The previous peer ID.
*
* @return The next peer ID.
* @return The first used peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
* @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module is
* not initialized.
*/
pm_peer_id_t peer_id_next_id_get(pm_peer_id_t prev_peer_id);
/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
* in persistent storage.
*
* @return The number of valid peer IDs, or 0 if module is not initialized.
*/
uint32_t peer_id_n_ids(void);
/** @} */
#endif /* PEER_ID_H__ */

View File

@ -0,0 +1,142 @@
/*
* 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 "pm_buffer.h"
#include <stdbool.h>
#include <string.h>
#include "nrf_error.h"
#include "pm_mutex.h"
#define BUFFER_IS_VALID(p_buffer) ((p_buffer != NULL) \
&& (p_buffer->p_memory != NULL) \
&& (p_buffer->p_mutex != NULL))
ret_code_t pm_buffer_init(pm_buffer_t * p_buffer,
uint8_t * p_buffer_memory,
uint32_t buffer_memory_size,
uint8_t * p_mutex_memory,
uint32_t mutex_memory_size,
uint32_t n_blocks,
uint32_t block_size)
{
if ( (p_buffer != NULL)
&& (p_buffer_memory != NULL)
&& (p_mutex_memory != NULL)
&& (buffer_memory_size >= (n_blocks*block_size))
&& (mutex_memory_size >= MUTEX_STORAGE_SIZE(n_blocks))
&& (n_blocks != 0)
&& (block_size != 0))
{
p_buffer->p_memory = p_buffer_memory;
p_buffer->p_mutex = p_mutex_memory;
p_buffer->n_blocks = n_blocks;
p_buffer->block_size = block_size;
pm_mutex_init(p_buffer->p_mutex, n_blocks);
return NRF_SUCCESS;
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
}
uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks)
{
if (!BUFFER_IS_VALID(p_buffer))
{
return ( BUFFER_INVALID_ID );
}
uint8_t first_locked_mutex = BUFFER_INVALID_ID;
for (uint8_t i = 0; i < p_buffer->n_blocks; i++)
{
if (pm_mutex_lock(p_buffer->p_mutex, i))
{
if (first_locked_mutex == BUFFER_INVALID_ID)
{
first_locked_mutex = i;
}
if ((i - first_locked_mutex + 1) == n_blocks)
{
return first_locked_mutex;
}
}
else if (first_locked_mutex != BUFFER_INVALID_ID)
{
for (uint8_t j = first_locked_mutex; j < i; j++)
{
pm_buffer_release(p_buffer, j);
}
first_locked_mutex = BUFFER_INVALID_ID;
}
}
return ( BUFFER_INVALID_ID );
}
uint8_t * pm_buffer_ptr_get(pm_buffer_t * p_buffer, uint8_t id)
{
if (!BUFFER_IS_VALID(p_buffer))
{
return ( NULL );
}
if ( (id != BUFFER_INVALID_ID)
&& pm_mutex_lock_status_get(p_buffer->p_mutex, id) )
{
return ( &p_buffer->p_memory[id*p_buffer->block_size] );
}
else
{
return ( NULL );
}
}
void pm_buffer_release(pm_buffer_t * p_buffer, uint8_t id)
{
if ( BUFFER_IS_VALID(p_buffer)
&& (id != BUFFER_INVALID_ID)
&& pm_mutex_lock_status_get(p_buffer->p_mutex, id))
{
pm_mutex_unlock(p_buffer->p_mutex, id);
}
}

View File

@ -0,0 +1,133 @@
/*
* 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 BUFFER_H__
#define BUFFER_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "pm_mutex.h"
/**
* @defgroup pm_buffer Buffer
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. This module provides a simple buffer.
*/
#define BUFFER_INVALID_ID 0xFF
#define PM_BUFFER_INIT(p_buffer, n_blocks, block_size, err_code) \
do \
{ \
static uint8_t buffer_memory[(n_blocks) * (block_size)]; \
static uint8_t mutex_memory[MUTEX_STORAGE_SIZE(n_blocks)]; \
err_code = pm_buffer_init((p_buffer), \
buffer_memory, \
(n_blocks) * (block_size), \
mutex_memory, \
MUTEX_STORAGE_SIZE(n_blocks), \
(n_blocks), \
(block_size)); \
} while(0)
typedef struct
{
uint8_t * p_memory; /**< The storage for all buffer entries. The size of the buffer must be n_blocks*block_size. */
uint8_t * p_mutex; /**< A mutex group with one mutex for each buffer entry. */
uint32_t n_blocks; /**< The number of allocatable blocks in the buffer. */
uint32_t block_size; /**< The size of each block in the buffer. */
} pm_buffer_t;
/**@brief Function for initializing a buffer instance.
*
* @param[out] p_buffer The buffer instance to initialize.
* @param[in] p_buffer_memory The memory this buffer will use.
* @param[in] buffer_memory_size The size of p_buffer_memory. This must be at least
* n_blocks*block_size.
* @param[in] p_mutex_memory The memory for the mutexes. This must be at least
* @ref MUTEX_STORAGE_SIZE(n_blocks).
* @param[in] mutex_memory_size The size of p_mutex_memory.
* @param[in] n_blocks The number of blocks in the buffer.
* @param[in] block_size The size of each block.
*
* @retval NRF_SUCCESS Successfully initialized buffer instance.
* @retval NRF_ERROR_INVALID_PARAM A parameter was 0 or NULL or a size was too small.
*/
ret_code_t pm_buffer_init(pm_buffer_t * p_buffer,
uint8_t * p_buffer_memory,
uint32_t buffer_memory_size,
uint8_t * p_mutex_memory,
uint32_t mutex_memory_size,
uint32_t n_blocks,
uint32_t block_size);
/**@brief Function for acquiring a buffer block in a buffer.
*
* @param[in] p_buffer The buffer instance acquire from.
* @param[in] n_blocks The number of contiguous blocks to acquire.
*
* @return The id of the acquired block, if successful.
* @retval BUFFER_INVALID_ID If unsuccessful.
*/
uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks);
/**@brief Function for getting a pointer to a specific buffer block.
*
* @param[in] p_buffer The buffer instance get from.
* @param[in] id The id of the buffer to get the pointer for.
*
* @return A pointer to the buffer for the specified id, if the id is valid.
* @retval NULL If the id is invalid.
*/
uint8_t * pm_buffer_ptr_get(pm_buffer_t * p_buffer, uint8_t id);
/**@brief Function for releasing a buffer block.
*
* @param[in] p_buffer The buffer instance containing the block to release.
* @param[in] id The id of the block to release.
*/
void pm_buffer_release(pm_buffer_t * p_buffer, uint8_t id);
#endif // BUFFER_H__
/**
* @}
*/

View File

@ -0,0 +1,135 @@
/*
* 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 "pm_mutex.h"
#include <stdbool.h>
#include <string.h>
#include "nrf_error.h"
#include "app_util_platform.h"
/**@brief Locks the mutex defined by the mask.
*
* @param p_mutex pointer to the mutex storage.
* @param mutex_mask the mask identifying the mutex position.
*
* @retval true if the mutex could be locked.
* @retval false if the mutex was already locked.
*/
static bool lock_by_mask(uint8_t * p_mutex, uint8_t mutex_mask)
{
bool success = false;
if ( (*p_mutex & mutex_mask) == 0 )
{
CRITICAL_REGION_ENTER();
if ( (*p_mutex & mutex_mask) == 0 )
{
*p_mutex |= mutex_mask;
success = true;
}
CRITICAL_REGION_EXIT();
}
return ( success );
}
void pm_mutex_init(uint8_t * p_mutex, uint16_t mutex_size)
{
if (p_mutex != NULL)
{
memset(&p_mutex[0], 0, MUTEX_STORAGE_SIZE(mutex_size));
}
}
bool pm_mutex_lock(uint8_t * p_mutex, uint16_t mutex_id)
{
if (p_mutex != NULL)
{
return ( lock_by_mask(&(p_mutex[mutex_id >> 3]), (1 << (mutex_id & 0x07))) );
}
else
{
return false;
}
}
void pm_mutex_unlock(uint8_t * p_mutex, uint16_t mutex_id)
{
uint8_t mutex_base = mutex_id >> 3;
uint8_t mutex_mask = (1 << (mutex_id & 0x07));
if ((p_mutex != NULL)
&& (p_mutex[mutex_base] & mutex_mask))
{
CRITICAL_REGION_ENTER();
p_mutex[mutex_base] &= ~mutex_mask;
CRITICAL_REGION_EXIT();
}
}
uint16_t pm_mutex_lock_first_available(uint8_t * p_mutex, uint16_t mutex_size)
{
if (p_mutex != NULL)
{
for ( uint16_t i = 0; i < mutex_size; i++ )
{
if ( lock_by_mask(&(p_mutex[i >> 3]), 1 << (i & 0x07)) )
{
return ( i );
}
}
}
return ( mutex_size );
}
bool pm_mutex_lock_status_get(uint8_t * p_mutex, uint16_t mutex_id)
{
if (p_mutex != NULL)
{
return ( (p_mutex[mutex_id >> 3] & (1 << (mutex_id & 0x07))) );
}
else
{
return true;
}
}

View File

@ -0,0 +1,108 @@
/*
* 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 MUTEX_H__
#define MUTEX_H__
#include <stdint.h>
#include <stdbool.h>
/**
* @defgroup pm_mutex Mutex
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. This module provides thread-safe mutexes.
*/
/**@brief Defines the storage size of a specified mutex group.
*
* @param number_of_mutexes the number of mutexes in the group.
*/
#define MUTEX_STORAGE_SIZE(number_of_mutexes) ((7 + (number_of_mutexes)) >> 3)
/**@brief Initializes a mutex group.
*
* @param[in] p_mutex Pointer to the mutex group. See @ref MUTEX_STORAGE_SIZE().
* @param[in] mutex_size The size of the mutex group in number of mutexes.
*/
void pm_mutex_init(uint8_t * p_mutex, uint16_t mutex_size);
/**@brief Locks the mutex specified by the bit id.
*
* @param[inout] p_mutex Pointer to the mutex group.
* @param[in] mutex_bit_id The bit id of the mutex.
*
* @retval true if it was possible to lock the mutex.
* @retval false otherwise.
*/
bool pm_mutex_lock(uint8_t * p_mutex, uint16_t mutex_bit_id);
/**@brief Locks the first unlocked mutex within the mutex group.
*
* @param[in, out] p_mutex Pointer to the mutex group.
* @param[in] mutex_size The size of the mutex group.
*
* @return The first unlocked mutex id in the group.
* @retval group-size if there was no unlocked mutex available.
*/
uint16_t pm_mutex_lock_first_available(uint8_t * p_mutex, uint16_t mutex_size);
/**@brief Unlocks the mutex specified by the bit id.
*
* @param[in, out] p_mutex Pointer to the mutex group.
* @param[in] mutex_bit_id The bit id of the mutex.
*/
void pm_mutex_unlock(uint8_t * p_mutex, uint16_t mutex_bit_id);
/**@brief Gets the locking status of the specified mutex.
*
* @param[in, out] p_mutex Pointer to the mutex group.
* @param[in] mutex_bit_id The bit id of the mutex.
*
* @retval true if the mutex was locked.
* @retval false otherwise.
*/
bool pm_mutex_lock_status_get(uint8_t * p_mutex, uint16_t mutex_bit_id);
#endif // MUTEX_H__
/** @} */

View File

@ -0,0 +1,46 @@
/*
* 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 <stdio.h>
#include "compiler_abstraction.h"
#include "nrf.h"
#include "nrf_delay.h"
/*lint --e{438} "Variable not used" */
void nrf_delay_ms(uint32_t volatile number_of_ms)
{
while(number_of_ms != 0)
{
number_of_ms--;
nrf_delay_us(999);
}
}

View File

@ -0,0 +1,274 @@
/*
* 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 _NRF_DELAY_H
#define _NRF_DELAY_H
#include "nrf.h"
/**
* @brief Function for delaying execution for number of microseconds.
*
* @note NRF52 has instruction cache and because of that delay is not precise.
*
* @param number_of_ms
*/
/*lint --e{438, 522} "Variable not used" "Function lacks side-effects" */
#if defined ( __CC_ARM )
static __ASM void __INLINE nrf_delay_us(uint32_t volatile number_of_us)
{
loop
SUBS R0, R0, #1
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
#ifdef NRF52
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
#endif
BNE loop
BX LR
}
#elif defined ( __ICCARM__ )
static void __INLINE nrf_delay_us(uint32_t volatile number_of_us)
{
__ASM (
"loop:\n\t"
" SUBS R0, R0, #1\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
#ifdef NRF52
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
" NOP\n\t"
#endif
" BNE.n loop\n\t");
}
#elif defined ( _WIN32 ) || defined ( __unix ) || defined( __APPLE__ )
__STATIC_INLINE void nrf_delay_us(uint32_t volatile number_of_us);
#ifndef CUSTOM_NRF_DELAY_US
__STATIC_INLINE void nrf_delay_us(uint32_t volatile number_of_us)
{}
#endif
#elif defined ( __GNUC__ )
static void __INLINE nrf_delay_us(uint32_t volatile number_of_us) __attribute__((always_inline));
static void __INLINE nrf_delay_us(uint32_t volatile number_of_us)
{
register uint32_t delay __ASM ("r0") = number_of_us;
__ASM volatile (
#ifdef NRF51
".syntax unified\n"
#endif
"1:\n"
" SUBS %0, %0, #1\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
#ifdef NRF52
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
" NOP\n"
#endif
" BNE 1b\n"
#ifdef NRF51
".syntax divided\n"
#endif
: "+r" (delay));
}
#endif
void nrf_delay_ms(uint32_t volatile number_of_ms);
#endif

View File

@ -0,0 +1,319 @@
/*
* 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.
*
*/
/**
* @defgroup nrf_wdt_hal WDT HAL
* @{
* @ingroup nrf_wdt
*
* @brief Hardware access layer for accessing the watchdog timer (WDT) peripheral.
*/
#ifndef NRF_WDT_H__
#define NRF_WDT_H__
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#define NRF_WDT_CHANNEL_NUMBER 0x8UL
#define NRF_WDT_RR_VALUE 0x6E524635UL /* Fixed value, shouldn't be modified.*/
#define NRF_WDT_TASK_SET 1UL
#define NRF_WDT_EVENT_CLEAR 0UL
/**
* @enum nrf_wdt_task_t
* @brief WDT tasks.
*/
typedef enum
{
/*lint -save -e30 -esym(628,__INTADDR__)*/
NRF_WDT_TASK_START = offsetof(NRF_WDT_Type, TASKS_START), /**< Task for starting WDT. */
/*lint -restore*/
} nrf_wdt_task_t;
/**
* @enum nrf_wdt_event_t
* @brief WDT events.
*/
typedef enum
{
/*lint -save -e30*/
NRF_WDT_EVENT_TIMEOUT = offsetof(NRF_WDT_Type, EVENTS_TIMEOUT), /**< Event from WDT time-out. */
/*lint -restore*/
} nrf_wdt_event_t;
/**
* @enum nrf_wdt_behaviour_t
* @brief WDT behavior in CPU SLEEP or HALT mode.
*/
typedef enum
{
NRF_WDT_BEHAVIOUR_RUN_SLEEP = WDT_CONFIG_SLEEP_Msk, /**< WDT will run when CPU is in SLEEP mode. */
NRF_WDT_BEHAVIOUR_RUN_HALT = WDT_CONFIG_HALT_Msk, /**< WDT will run when CPU is in HALT mode. */
NRF_WDT_BEHAVIOUR_RUN_SLEEP_HALT = WDT_CONFIG_SLEEP_Msk | WDT_CONFIG_HALT_Msk, /**< WDT will run when CPU is in SLEEP or HALT mode. */
NRF_WDT_BEHAVIOUR_PAUSE_SLEEP_HALT = 0, /**< WDT will be paused when CPU is in SLEEP or HALT mode. */
} nrf_wdt_behaviour_t;
/**
* @enum nrf_wdt_rr_register_t
* @brief WDT reload request registers.
*/
typedef enum
{
NRF_WDT_RR0 = 0, /**< Reload request register 0. */
NRF_WDT_RR1, /**< Reload request register 1. */
NRF_WDT_RR2, /**< Reload request register 2. */
NRF_WDT_RR3, /**< Reload request register 3. */
NRF_WDT_RR4, /**< Reload request register 4. */
NRF_WDT_RR5, /**< Reload request register 5. */
NRF_WDT_RR6, /**< Reload request register 6. */
NRF_WDT_RR7 /**< Reload request register 7. */
} nrf_wdt_rr_register_t;
/**
* @enum nrf_wdt_int_mask_t
* @brief WDT interrupts.
*/
typedef enum
{
NRF_WDT_INT_TIMEOUT_MASK = WDT_INTENSET_TIMEOUT_Msk, /**< WDT interrupt from time-out event. */
} nrf_wdt_int_mask_t;
/**
* @brief Function for configuring the watchdog behavior when the CPU is sleeping or halted.
*
* @param behaviour Watchdog behavior when CPU is in SLEEP or HALT mode.
*/
__STATIC_INLINE void nrf_wdt_behaviour_set(nrf_wdt_behaviour_t behaviour)
{
NRF_WDT->CONFIG = behaviour;
}
/**
* @brief Function for starting the watchdog.
*
* @param[in] task Task.
*/
__STATIC_INLINE void nrf_wdt_task_trigger(nrf_wdt_task_t task)
{
*((volatile uint32_t *)((uint8_t *)NRF_WDT + task)) = NRF_WDT_TASK_SET;
}
/**
* @brief Function for clearing the WDT event.
*
* @param[in] event Event.
*/
__STATIC_INLINE void nrf_wdt_event_clear(nrf_wdt_event_t event)
{
*((volatile uint32_t *)((uint8_t *)NRF_WDT + (uint32_t)event)) = NRF_WDT_EVENT_CLEAR;
}
/**
* @brief Function for retrieving the state of the WDT event.
*
* @param[in] event Event.
*
* @retval true If the event is set.
* @retval false If the event is not set.
*/
__STATIC_INLINE bool nrf_wdt_event_check(nrf_wdt_event_t event)
{
return (bool)*((volatile uint32_t *)((uint8_t *)NRF_WDT + event));
}
/**
* @brief Function for enabling a specific interrupt.
*
* @param[in] int_mask Interrupt.
*/
__STATIC_INLINE void nrf_wdt_int_enable(uint32_t int_mask)
{
NRF_WDT->INTENSET = int_mask;
}
/**
* @brief Function for retrieving the state of given interrupt.
*
* @param[in] int_mask Interrupt.
*
* @retval true Interrupt is enabled.
* @retval false Interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_wdt_int_enable_check(uint32_t int_mask)
{
return (bool)(NRF_WDT->INTENSET & int_mask);
}
/**
* @brief Function for disabling a specific interrupt.
*
* @param[in] int_mask Interrupt.
*/
__STATIC_INLINE void nrf_wdt_int_disable(uint32_t int_mask)
{
NRF_WDT->INTENCLR = int_mask;
}
/**
* @brief Function for returning the address of a specific WDT task register.
*
* @param[in] task Task.
*/
__STATIC_INLINE uint32_t nrf_wdt_task_address_get(nrf_wdt_task_t task)
{
return ((uint32_t)NRF_WDT + task);
}
/**
* @brief Function for returning the address of a specific WDT event register.
*
* @param[in] event Event.
*
* @retval address of requested event register
*/
__STATIC_INLINE uint32_t nrf_wdt_event_address_get(nrf_wdt_event_t event)
{
return ((uint32_t)NRF_WDT + event);
}
/**
* @brief Function for retrieving the watchdog status.
*
* @retval true If the watchdog is started.
* @retval false If the watchdog is not started.
*/
__STATIC_INLINE bool nrf_wdt_started(void)
{
return (bool)(NRF_WDT->RUNSTATUS);
}
/**
* @brief Function for retrieving the watchdog reload request status.
*
* @param[in] rr_register Reload request register to check.
*
* @retval true If a reload request is running.
* @retval false If no reload request is running.
*/
__STATIC_INLINE bool nrf_wdt_request_status(nrf_wdt_rr_register_t rr_register)
{
return (bool)(((NRF_WDT->REQSTATUS) >> rr_register) & 0x1UL);
}
/**
* @brief Function for setting the watchdog reload value.
*
* @param[in] reload_value Watchdog counter initial value.
*/
__STATIC_INLINE void nrf_wdt_reload_value_set(uint32_t reload_value)
{
NRF_WDT->CRV = reload_value;
}
/**
* @brief Function for retrieving the watchdog reload value.
*
* @retval Reload value.
*/
__STATIC_INLINE uint32_t nrf_wdt_reload_value_get(void)
{
return (uint32_t)NRF_WDT->CRV;
}
/**
* @brief Function for enabling a specific reload request register.
*
* @param[in] rr_register Reload request register to enable.
*/
__STATIC_INLINE void nrf_wdt_reload_request_enable(nrf_wdt_rr_register_t rr_register)
{
NRF_WDT->RREN |= 0x1UL << rr_register;
}
/**
* @brief Function for disabling a specific reload request register.
*
* @param[in] rr_register Reload request register to disable.
*/
__STATIC_INLINE void nrf_wdt_reload_request_disable(nrf_wdt_rr_register_t rr_register)
{
NRF_WDT->RREN &= ~(0x1UL << rr_register);
}
/**
* @brief Function for retrieving the status of a specific reload request register.
*
* @param[in] rr_register Reload request register to check.
*
* @retval true If the reload request register is enabled.
* @retval false If the reload request register is not enabled.
*/
__STATIC_INLINE bool nrf_wdt_reload_request_is_enabled(nrf_wdt_rr_register_t rr_register)
{
return (bool)(NRF_WDT->RREN & (0x1UL << rr_register));
}
/**
* @brief Function for setting a specific reload request register.
*
* @param[in] rr_register Reload request register to set.
*/
__STATIC_INLINE void nrf_wdt_reload_request_set(nrf_wdt_rr_register_t rr_register)
{
NRF_WDT->RR[rr_register] = NRF_WDT_RR_VALUE;
}
#endif
/** @} */

View File

@ -0,0 +1,52 @@
/*
* 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 memory_pool_internal Memory Pool Internal
* @{
* @ingroup memory_pool
*
* @brief Memory pool internal definitions
*/
#ifndef MEM_POOL_INTERNAL_H__
#define MEM_POOL_INTERNAL_H__
#define TX_BUF_SIZE 4u /**< TX buffer size in bytes. */
#define RX_BUF_SIZE 32u /**< RX buffer size in bytes. */
#define RX_BUF_QUEUE_SIZE 8u /**< RX buffer element size. */
#endif // MEM_POOL_INTERNAL_H__
/** @} */

View File

@ -0,0 +1,323 @@
/*
* 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 SECTION_VARS_H__
#define SECTION_VARS_H__
#include "app_util.h"
#if defined __ICC_ARM__
// turn on language extensions for iar
#pragma language=extended
#endif
/**
* @defgroup section_vars Section variables
* @ingroup app_common
* @{
* @brief Section variables.
*/
/**@brief Macro to delay macro expression of pragma
*
*/
#define NRF_PRAGMA(x) _Pragma(#x)
/**@brief Macro to register section by name in code
*
* @param[in] section_name Name of the section to register
**/
#if defined __CC_ARM
// Not required by this compiler
#define NRF_SECTION_VARS_REGISTER_SECTION(section_name)
#elif defined __GNUC__
// Not required by this compiler
#define NRF_SECTION_VARS_REGISTER_SECTION(section_name)
#elif defined __ICCARM__
#define NRF_SECTION_VARS_REGISTER_SECTION(section_name) NRF_PRAGMA(section = ## #section_name )
#else
#error TODO
#endif
/*lint -save -e27 */
/**@brief Macro for accessing start of a named data section by symbol
*
* @details The symbol that this macro resolves to is used to access the section
* by start address.
*
* @param[in] section_name Name of the section
*/
#if defined __CC_ARM
#define NRF_SECTION_VARS_START_SYMBOL(section_name) section_name ## $$Base
#elif defined __GNUC__
#define NRF_SECTION_VARS_START_SYMBOL(section_name) __start_ ## section_name
#elif defined __ICCARM__
#define NRF_SECTION_VARS_START_SYMBOL(section_name) __section_begin(#section_name)
#else
#error TODO
#endif
/**@brief Macro for accessing end of a named data section by symbol
*
* @details The symbol that this macro resolves to is used to access the section
* by end address.
*
* @param[in] section_name Name of the section
*/
#if defined __CC_ARM
#define NRF_SECTION_VARS_END_SYMBOL(section_name) section_name ## $$Limit
#elif defined __GNUC__
#define NRF_SECTION_VARS_END_SYMBOL(section_name) __stop_ ## section_name
#elif defined __ICCARM__
#define NRF_SECTION_VARS_END_SYMBOL(section_name) __section_end(#section_name)
#endif
/*lint -restore */
/**@brief Macro for accessing Length of a named section
*
* @details This macro is used to get the size of a named section.
*
* @param[in] section_name Name of the section
*/
#if defined __CC_ARM
#define NRF_SECTION_VARS_LENGTH(section_name) \
((uint32_t)&NRF_SECTION_VARS_END_SYMBOL(section_name) - (uint32_t)&NRF_SECTION_VARS_START_SYMBOL(section_name))
#elif defined __GNUC__
#define NRF_SECTION_VARS_LENGTH(section_name) \
((uint32_t)&NRF_SECTION_VARS_END_SYMBOL(section_name) - (uint32_t)&NRF_SECTION_VARS_START_SYMBOL(section_name))
#elif defined __ICCARM__
#define NRF_SECTION_VARS_LENGTH(section_name) \
((uint32_t)NRF_SECTION_VARS_END_SYMBOL(section_name) - (uint32_t)NRF_SECTION_VARS_START_SYMBOL(section_name))
#else
#error TODO
#endif
/**@brief Macro for accessing the start address of a named section
*
* param[in] section_name Name of the section to get the start address from
*/
#if defined __CC_ARM
#define NRF_SECTION_VARS_START_ADDR(section_name) (uint32_t)&NRF_SECTION_VARS_START_SYMBOL(section_name)
#elif defined __GNUC__
#define NRF_SECTION_VARS_START_ADDR(section_name) (uint32_t)&NRF_SECTION_VARS_START_SYMBOL(section_name)
#elif defined __ICCARM__
#define NRF_SECTION_VARS_START_ADDR(section_name) (uint32_t)iar_ ## section_name ## _start
#else
#error TODO
#endif
/*@brief Macro for accessing the end address of a named section
*
* @param[in] section_name Name of the section to get end address from
*/
#if defined __CC_ARM
#define NRF_SECTION_VARS_END_ADDR(section_name) (uint32_t)&NRF_SECTION_VARS_END_SYMBOL(section_name)
#elif defined __GNUC__
#define NRF_SECTION_VARS_END_ADDR(section_name) (uint32_t)&NRF_SECTION_VARS_END_SYMBOL(section_name)
#elif defined __ICCARM__
#define NRF_SECTION_VARS_END_ADDR(section_name) (uint32_t)iar_ ## section_name ## _end
#else
#error TODO
#endif
/**@brief Macro for declaring symbols for named sections
*
* @note These external declarations of section specific symbols are required for the linker in GCC and Keil (not IAR)
*
* @param[in] type_name Name of the type stored in the section
* @param[in] section_name Name of the section
*/
#if defined __CC_ARM
#define NRF_SECTION_VARS_REGISTER_SYMBOLS(type_name, section_name) \
extern type_name* NRF_SECTION_VARS_START_SYMBOL(section_name); \
extern void* NRF_SECTION_VARS_END_SYMBOL(section_name)
#elif defined __GNUC__
#define NRF_SECTION_VARS_REGISTER_SYMBOLS(type_name, section_name) \
extern type_name* NRF_SECTION_VARS_START_SYMBOL(section_name); \
extern void* NRF_SECTION_VARS_END_SYMBOL(section_name)
#elif defined __ICCARM__
// No symbol registration required for IAR
#define NRF_SECTION_VARS_REGISTER_SYMBOLS(type_name, section_name) \
extern void* iar_ ## section_name ## _start = __section_begin(#section_name); \
extern void* iar_ ## section_name ## _end = __section_end(#section_name)
#else
#error TODO
#endif
/**@brief Macro to add symbols to a named section
*
* @details The symbols are placed in a named section. All calls to this macro
* will result in symbols being placed in a contiguous manner in the named section.
* This macro ensures that the symbol is not removed because of optimization level.
*
* @warning There is no guarantee for ordering of placement. If ordering is required
*
* @warning The symbols added in the named section must be word aligned to
* ensure that compilers do not pad the section during symbol placement.
*
* @param[in] section_name Name of the section
* @param[in] type_def Datatype of the symbol to place in the given section
*/
#if defined __CC_ARM
#define NRF_SECTION_VARS_ADD(section_name, type_def) \
static type_def __attribute__((section( #section_name ))) __attribute__((used))
#elif defined __GNUC__
#define NRF_SECTION_VARS_ADD(section_name, type_def) \
static type_def __attribute__ ((section( #section_name ))) __attribute__ ((used))
#elif defined __ICCARM__
#define NRF_SECTION_VARS_ADD(section_name, type_def) \
__root type_def @ #section_name
#else
#error TODO
#endif
/**@brief Macro to get symbol from named section
*
* @warning The stored symbol can only be resolved using this macro if the
* type of the data is word aligned. The operation of acquiring
* the stored symbol relies on sizeof of the stored type, no
* padding can exist in the named section in between individual
* stored items or this macro will fail.
*
* @param[in] i Index of item in section
* @param[in] type_name Type name of item in section
* @param[in] section_name Name of the section
*/
#if defined __CC_ARM
#define NRF_SECTION_VARS_GET(i, type_name, section_name) \
(type_name*)(NRF_SECTION_VARS_START_ADDR(section_name) + i * sizeof(type_name))
#elif defined __GNUC__
#define NRF_SECTION_VARS_GET(i, type_name, section_name) \
(type_name*)(NRF_SECTION_VARS_START_ADDR(section_name) + i * sizeof(type_name))
#elif defined __ICCARM__
#define NRF_SECTION_VARS_GET(i, type_name, section_name) \
(type_name*)iar_ ## section_name ## _start + (i * sizeof(type_name))
#else
#error TODO
#endif
/**@brief Macro to get number of items in named section
*
* @param[in] type_name Type name of item in section
* @param[in] section_name Name of the section
*/
#define NRF_SECTION_VARS_COUNT(type_name, section_name) \
NRF_SECTION_VARS_LENGTH(section_name) / sizeof(type_name)
/** @} */
#endif // SECTION_VARS_H__

View File

@ -0,0 +1,566 @@
/*
* 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 FDS_H__
#define FDS_H__
/**
* @defgroup flash_data_storage Flash Data Storage
* @ingroup app_common
* @{
* @brief Flash Data Storage (FDS).
*
* @details Flash Data Storage (FDS) is a minimalistic filesystem for the on-chip flash.
* It can be used to manipulate @e records, which consist of a piece of data, made up
* of one or more chunks, and an associated key pair.
*/
#include <stdint.h>
#include <stdbool.h>
#include "sdk_errors.h"
/**@brief */
#define SIZEOF_WORDS(val) (sizeof(val) / 4)
/**@brief Reserved type key used to flag cleared records.
* May not be used as a record key by the application. */
#define FDS_TYPE_ID_INVALID (0x0000)
/**@brief Reserved instance key used to check for missing or corrupted metadata.
* May not be used as a record key by the application. */
#define FDS_INSTANCE_ID_INVALID (0xFFFF)
typedef uint32_t fds_record_id_t;
typedef uint16_t fds_type_id_t;
typedef uint16_t fds_length_t;
typedef uint16_t fds_instance_id_t;
typedef uint16_t fds_checksum_t;
/**@brief A piece of a record metadata, keeping information about one of its keys (type) and its
* lenght, expressed in 4 byte words. */
typedef struct
{
fds_type_id_t type; /**< The record type ID. */
fds_length_t length_words; /**< Length of the record's data, in 4 byte words. */
} fds_tl_t;
/**@brief A piece of a record metadata, keeping information about one of its keys (instance) and
* its checksum. */
typedef struct
{
fds_instance_id_t instance; /**< The record instance ID. */
fds_checksum_t checksum; /**< Checksum of the entire record, including the metadata. */
} fds_ic_t;
/**@brief The record metadata. */
typedef struct
{
fds_tl_t tl; /**< See @ref fds_tl_t. */
fds_ic_t ic; /**< See @ref fds_ic_t. */
fds_record_id_t id; /**< The unique record ID (32 bits). */
} fds_header_t;
typedef fds_header_t fds_record_header_t;
/**@brief The record descriptor structure, used to manipulate a record.
* @note This structure is meant to be opaque to the user, who does not need to access
* any of its fields.
* @note This structure does not need special initialization.
* @warning Do not reuse the same descriptor for different records. If you do, be sure to set
* its fields to zero. */
typedef struct
{
uint32_t record_id; /**< The unique record ID. */
uint32_t const * p_rec; /**< The last known record address in flash. */
uint16_t vpage_id; /**< The virtual page ID in which the record is stored. */
uint16_t gc_magic; /**< Number of times the GC algorithm has been run. */
uint16_t ptr_magic; /**< Used to verify the validity of p_rec. */
} fds_record_desc_t;
/**@brief The record key, used to lookup records.
* @note The uniqueness of either field is not enforced by the system. */
typedef struct
{
uint16_t type;
uint16_t instance;
} fds_record_key_t;
/**@brief Structure used for reading a record back from flash memory. */
typedef struct
{
// TODO: the header should be a pointer.
fds_header_t header; /**< The record header (metadata), as stored in flash. */
uint32_t const * p_data; /**< The record data. */
} fds_record_t;
/**@brief A record chunk, containing a piece of data to be stored in a record.
*
* @note p_data must be aligned on a (4 bytes) word boundary.
*/
typedef struct
{
void const * p_data; /**< Pointer to the data to store. Must be word aligned. */
fds_length_t length_words; /**< Length of data pointed by p_data, in 4 byte words. */
} fds_record_chunk_t;
/**@brief A token to a reserved space in flash, created by @ref fds_reserve.
* Use @ref fds_write_reserved to write the record in the reserved space,
* or @ref fds_reserve_cancel to cancel the reservation.
*/
typedef struct
{
uint16_t vpage_id; /**< The virtual ID of the page where space was reserved. */
fds_length_t length_words; /**< The amount of space reserved, in 4 byte words. */
} fds_write_token_t;
/**@brief A token to keep information about the progress of @ref fds_find, @ref fds_find_by_type
* and @ref fds_find_by_instance operations.
* @note This structure is meant to be opaque to the user, who does not need to access any of its
* fields.
* @note The token does not need special initialization.
* @warning Do not reuse the same token to search for different records. If you do, be sure to set
* its fields to zero. */
typedef struct
{
uint32_t const * p_addr;
uint32_t magic;
uint16_t vpage_id;
} fds_find_token_t;
typedef enum
{
FDS_CMD_NONE, /**< No command. */
FDS_CMD_INIT, /**< Module initialization commnad. Used in @ref fds_init */
FDS_CMD_WRITE, /**< Write command. Used in @ref fds_write and @ref fds_write_reserved. */
FDS_CMD_UPDATE, /**< Update command. Used in @ref fds_update. */
FDS_CMD_CLEAR, /**< Clear record command. Used in @ref fds_clear and @ref fds_update. */
FDS_CMD_CLEAR_INST, /**< Clear instance command. Used in @ref fds_clear_by_instance. */
FDS_CMD_GC /**< Garbage collection. Used in @ref fds_gc. */
} fds_cmd_id_t;
/**@brief Flash data storage callback function.
*
* @param result Result of the command.
* @param cmd The command associated with the callback.
* @param record_id The unique ID of the record associated with the callback.
* @param record_key The key pair of the record associated with the callback.
*/
typedef void (*fds_cb_t)(ret_code_t result,
fds_cmd_id_t cmd,
fds_record_id_t record_id,
fds_record_key_t record_key);
/**@brief Function to register a callback for the module events.
* @details The maximum amount of callback which can be registered can be configured by
* changing the FDS_MAX_USERS macro in fds_config.h.
*
* @param[in] cb The callback function.
*
*
* @retval NRF_SUCCESS Success.
* @retval NRF_ERROR_NO_MEM Error. Maximum number of registered callbacks reached.
*/
ret_code_t fds_register(fds_cb_t cb);
/**@brief Function to initialize the module.
*
* @details This function initializes the module and installs the filesystem, if it is not
* installed yet.
*
* @note This function is asynchronous. Completion is reported with a callback through the
* registered event handler. To be able to receive such callback, be sure to call
* @ref fds_register before calling @ref fds_init.
*
* @retval NRF_SUCCESS Success. The command was queued.
* @retval NRF_ERROR_INVALID_STATE Error. The module is currently undergoing initialization.
* @retval NRF_ERROR_NO_MEM Error. Insufficient space to install the filesystem, or
* insufficient resources to perform the installation.
*/
ret_code_t fds_init(void);
/**@brief Function to write a record to flash.
*
* @details This function can be used to write a record to flash. A record data consists of
* multiple chunks and is supplied to the function as an array of fds_record_chunk_t
* structures. The maximum lenght of a record data may not exceed the size of one flash
* page minus FDS_HEADER_SIZE words.
*
* @note This function is asynchronous, therefore, completion is reported with a callback
* through the registered event handler.
*
* @note The record data must be aligned on a 4 byte boundary, and because it is not buffered
* internally, it must be kept in memory by the application until the callback for the
* command has been received, i.e., the command completed.
*
* @param[out] p_desc The record descriptor. It may be NULL.
* @param[in] key The record key pair.
* @param[in] num_chunks The number of elements in the chunks array.
* @param[in] chunks An array of chunks making up the record data.
*
* @retval NRF_SUCCESS Success. The command was queued.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_INVALID_DATA Error. The key contains an invalid type or instance.
* @retval NRF_ERROR_INVALID_ADDR Error. The record data is not aligned on a 4 byte boundary.
* @retval NRF_ERROR_INVALID_LENGTH Error. The record length exceeds the maximum lenght.
* @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation.
* @retval NRF_ERROR_NO_MEM Error. No flash space available to store the record.
*/
ret_code_t fds_write(fds_record_desc_t * const p_desc,
fds_record_key_t key,
uint8_t num_chunks,
fds_record_chunk_t chunks[]);
/**@brief Function to reserve space for a record.
*
* @details This function can be used to reserve flash space to store a record, which can be
* later written down using @ref fds_write_reserved. It is possible to cancel a
* reservation by using @ref fds_reserve_cancel.
*
* @param[out] p_tok A token which can be used to write a record in the reserved space
* using @ref fds_write_reserved.
* @param[in] length_words The lenght of the record data, in 4 byte words.
*
* @retval NRF_SUCCESS Success. Flash space was successfully reserved.
* @retval NRF_ERROR_NULL Error. p_tok is NULL.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_NO_MEM Error. Insufficient space.
*/
ret_code_t fds_reserve(fds_write_token_t * const p_tok, uint16_t length_words);
/**@brief Function to cancel a space reservation.
*
* @param[in] p_tok The token produced by @ref fds_reserve, identifying the reservation to cancel.
*
* @retval NRF_SUCCESS Success. The reservation was canceled.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_NULL Error. p_tok is NULL.
* @retval NRF_ERROR_INVALID_DATA Error. p_tok contains invalid data.
*/
ret_code_t fds_reserve_cancel(fds_write_token_t * const p_tok);
/**@brief Function to write a record to flash, the space for which has been previously reserved
* using @ref fds_reserve.
*
* @details This function behaves similarly to @ref fds_write, with the exception that it never
* fails with NRF_ERROR_NO_MEM.
*
* @note This function is asynchronous, therefore, completion is reported with a callback
* through the registered event handler.
*
* @note The record data must be aligned on a 4 byte boundary, and because it is not buffered
* internally, it must be kept in memory by the application until the callback for the
* command has been received, i.e., the command completed.
*
* @param[in] p_tok The token return by @ref fds_reserve.
* @param[out] p_desc The record descriptor. It may be NULL.
* @param[in] key The record key pair.
* @param[in] num_chunks The number of elements in the chunks array.
* @param[in] chunks An array of chunks making up the record data.
*
* @retval NRF_SUCCESS Success. The command was queued.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_INVALID_DATA Error. The key contains an invalid type or instance.
* @retval NRF_ERROR_INVALID_ADDR Error. The record data is not aligned on a 4 byte boundary.
* @retval NRF_ERROR_INVALID_LENGTH Error. The record length exceeds the maximum lenght.
* @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation.
*/
ret_code_t fds_write_reserved(fds_write_token_t const * const p_tok,
fds_record_desc_t * const p_desc,
fds_record_key_t key,
uint8_t num_chunks,
fds_record_chunk_t chunks[]);
/**@brief Function to clear a record.
*
* @details Clearing a record has the effect of preventing the system from retrieving the record
* descriptor using the @ref fds_find, @ref fds_find_by_type and @ref fds_find_by_instance
* functions. Additionally, @ref fds_open calls shall fail when supplied a descritpor for
* a record which has been cleared. Clearing a record does not free the space it occupies
* in flash. The reclaim flash space used by cleared records, use @ref fds_gc.
*
* @note This function is asynchronous, therefore, completion is reported with a callback
* through the registered event handler.
*
* @param[in] p_desc The descriptor of the record to clear.
*
* @retval NRF_SUCCESS Success. The command was queued.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_NULL Error. p_desc is NULL.
* @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation.
*/
ret_code_t fds_clear(fds_record_desc_t * const p_desc);
/**@brief Function to clear all records with a given instance.
*
* @details Clearing a record has the effect of preventing the system from retrieving the record
* descriptor using the @ref fds_find, @ref fds_find_by_type and @ref fds_find_by_instance
* functions. Additionally, @ref fds_open calls shall fail when supplied a descritpor for
* a record which has been cleared. Clearing a record does not free the space it occupies
* in flash. The reclaim flash space used by cleared records, use @ref fds_gc.
*
* @note This function is asynchronous, therefore, completion is reported with a callback
* through the registered event handler. Only one callback will be issued. The record
* instance ID in the key parameter of the callback will contain the instance ID passed as
* parameter to this function. The record ID parameter will be zero, and the type ID equal
* to FDS_TYPE_ID_INVALID.
*
* @param[in] instance The instance ID of the records to clear.
*
* @retval NRF_SUCCESS Success. The command was queued.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_NULL Error. p_desc is NULL.
* @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation.
*/
ret_code_t fds_clear_by_instance(fds_instance_id_t instance);
/**@brief Function to update an existing record.
*
* @details Updating a record writes a new record with the given key and data in flash, and then
* clears the old record.
*
* @note This function is asynchronous, therefore, completion is reported with a callback
* through the registered event handler. Two callbacks will be issued, one to signal that
* the updated record has been written down, and another to signal that the old one has been
* cleared.
*
* @note The record data must be aligned on a 4 byte boundary, and because it is not buffered
* internally, it must be kept in memory by the application until the callback for the
* command has been received, i.e., the command completed.
*
* @param[in, out] p_desc The descriptor of the record to update. The descriptor of the updated
* record, after the function has returned with NRF_SUCCESS.
* @param[in] key The record new key pair.
* @param[in] num_chunks The number of elements in the chunks array.
* @param[in] chunks An array of chunks making up the record new data.
*
* @retval NRF_SUCCESS Success. The command was queued.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_INVALID_DATA Error. The key contains an invalid type or instance.
* @retval NRF_ERROR_INVALID_ADDR Error. The record data is not aligned on a 4 byte boundary.
* @retval NRF_ERROR_INVALID_LENGTH Error. The record length exceeds the maximum lenght.
* @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation.
* @retval NRF_ERROR_NO_MEM Error. No flash space available to store the record.
*/
ret_code_t fds_update(fds_record_desc_t * const p_desc,
fds_record_key_t key,
uint8_t num_chunks,
fds_record_chunk_t chunks[]);
/**@brief Function to search for records with a given key pair.
*
* @details Because types are not unique, to search for the next record with the given key call
* the function again and supply the same fds_find_token_t structure to resume searching
* from the last record found.
*
* @param[in] type The record type ID.
* @param[in] instance The record instance ID.
* @param[out] p_desc The descriptor of the record found.
* @param[out] p_token A token containing information about the progress of the operation.
*
* @retval NRF_SUCCESS Success. A record was found.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_NULL Error. Either p_desc or p_token are NULL.
* @retval NRF_ERROR_NOT_FOUND Error. No record with the given key pair was found.
*/
ret_code_t fds_find(fds_type_id_t type,
fds_instance_id_t instance,
fds_record_desc_t * const p_desc,
fds_find_token_t * const p_token);
/**@brief Function to search for records with a given type.
*
* @details Because types are not unique, to search for the next record with the given key call
* the function again and supply the same fds_find_token_t structure to resume searching
* from the last record found.
*
* @param[in] type The type ID in the record key.
* @param[out] p_desc The descriptor of the record found.
* @param[out] p_token A token containing information about the progress of the operation.
*
* @retval NRF_SUCCESS Success. A record was found.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_NULL Error. Either p_desc or p_token are NULL.
* @retval NRF_ERROR_NOT_FOUND Error. No record with the given type was found.
*/
ret_code_t fds_find_by_type(fds_type_id_t type,
fds_record_desc_t * const p_desc,
fds_find_token_t * const p_token);
/**@brief Function to search for records with a given instance.
*
* @details Because types are not unique, to search for the next record with the given key call
* the function again and supply the same fds_find_token_t structure to resume searching
* from the last record found.
*
* @param[in] instance The instance ID in the record key.
* @param[out] p_desc The descriptor of the record found.
* @param[out] p_token A token containing information about the progress of the operation.
*
* @retval NRF_SUCCESS Success. A record was found.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_NULL Error. Either p_desc or p_token are NULL.
* @retval NRF_ERROR_NOT_FOUND Error. No record with the given instance was found.
*/
ret_code_t fds_find_by_instance(fds_instance_id_t instance,
fds_record_desc_t * const p_desc,
fds_find_token_t * const p_token);
/**@brief Function to open a record for reading.
*
* @details Function to read a record which has been written to flash. This function initializes
* a fds_record_t structure which can be used to access the record data as well as
* its associated metadata. The pointers provided in the fds_record_t structure are
* pointers to flash memory. Opening a record with @ref fds_open prevents the garbage
* collection to run on the flash page in which record is stored, therefore the contents
* of the memory pointed by the fds_record_t p_data field is guaranteed to remain
* unmodified, as long as the record is kept open.
*
* @note When you are done reading a record, close it using @ref fds_close so that successive
* garbage collections can reclaim space on the page where the record is stored, if necessary.
*
* @param[in] p_desc The descriptor of the record to open.
* @param[out] p_record The record data and metadata, as stored in flash.
*
* @retval NRF_SUCCESS Success. The record was opened.
* @retval NRF_ERROR_NOT_FOUND Error. The record was not found. It may have been cleared, or it
* may have not been written yet.
* @retval NRF_ERROR_INVALID_DATA Error. The descriptor contains invalid data.
* @retval NRF_ERROR_NULL Error. Either p_desc or p_record are NULL.
*/
ret_code_t fds_open(fds_record_desc_t * const p_desc,
fds_record_t * const p_record);
/**@brief Function to close a record, after its contents have been read.
*
* @details Closing a record allows garbage collection to be run on the page in which the
* record being closed is stored (if no other records remain open on that page).
*
* @note Closing a record, does NOT invalidate its descriptor, which can be safely supplied to
* all functions which accept a descriptor as a parameter.
*
* @param[in] p_desc The descriptor of the record to close.
*
* @retval NRF_SUCCESS Success. The record was closed.
* @retval NRF_ERROR_NULL Error. p_desc is NULL.
* @retval NRF_ERROR_INVALID_DATA Error. The descriptor contains invalid data.
*/
ret_code_t fds_close(fds_record_desc_t const * const p_desc);
/**@brief Function to perform a garbage collection.
*
* @details Garbage collection reclaims the flash space occupied by records which have been cleared
* using @ref fds_clear.
*
* @note This function is asynchronous, therefore, completion is reported with a callback
* through the registered event handler.
*/
ret_code_t fds_gc(void);
/**@brief Function to compare two record descriptors.
*
* @param[in] p_desc_one First descriptor.
* @param[in] p_desc_two Second descriptor.
*
* @retval true If the descriptors identify the same record.
* @retval false Otherwise.
*/
bool fds_descriptor_match(fds_record_desc_t const * const p_desc_one,
fds_record_desc_t const * const p_desc_two);
/**@brief Function to obtain a descriptor from a record ID.
*
* @details This function can be used to reconstruct a descriptor from a record ID, such as the
* one passed to the callback function.
*
* @warning This function does not check if a record with the given record ID exists or not. If a
* non-existing record ID is supplied, the resulting descriptor will cause other functions
* to fail when used as parameter.
*
* @param[out] p_desc The descriptor of the record with given record ID.
* @param[in] record_id The record ID for which to provide a descriptor.
*
* @retval NRF_SUCCESS Success.
* @retval NRF_ERROR_NULL Error. p_desc is NULL.
*/
ret_code_t fds_descriptor_from_rec_id(fds_record_desc_t * const p_desc,
fds_record_id_t record_id);
/**@brief Function to obtain a record ID from a record descriptor.
*
* @details This function can be used to extract a record ID from a descriptor. It may be used
* in the callback function to determine which record the callback is associated to, if
* you have its descriptor.
*
* @warning This function does not check the record descriptor sanity. If the descriptor is
* uninitialized, or has been tampered with, the resulting record ID may be invalid.
*
* @param[in] p_desc The descriptor from which to extract the record ID.
* @param[out] p_record_id The record ID contained in the given descriptor.
*
* @retval NRF_SUCCESS Success.
* @retval NRF_ERROR_NULL Error. Either p_desc is NULL or p_record_id is NULL.
*/
ret_code_t fds_record_id_from_desc(fds_record_desc_t const * const p_desc,
fds_record_id_t * const p_record_id);
/** @} */
#endif // FDS_H__

View File

@ -0,0 +1,65 @@
/*
* 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 FDS_CONFIG_H__
#define FDS_CONFIG_H__
/**
* @file fds_config.h
*
* @addtogroup flash_data_storage
* @{
*/
/**@brief Configures the size of the internal queue. */
#define FDS_CMD_QUEUE_SIZE (8)
/**@brief Determines how many @ref fds_record_chunk_t structures can be buffered at any time. */
#define FDS_CHUNK_QUEUE_SIZE (8)
/**@brief Configures the number of physical flash pages to use. Out of the total, one is reserved
* for garbage collection, hence, two pages is the minimum: one for the application data
* and one for the system. */
#define FDS_MAX_PAGES (2)
/**@brief Configures the maximum number of callbacks which can be registred. */
#define FDS_MAX_USERS (10)
/** Page tag definitions. */
#define FDS_PAGE_TAG_WORD_0_SWAP (0xA5A5A5A5)
#define FDS_PAGE_TAG_WORD_0_VALID (0xA4A4A4A4)
#define FDS_PAGE_TAG_WORD_1 (0xAABBCCDD)
#define FDS_PAGE_TAG_WORD_2 (0xAABB01DD) /**< Includes version. */
#define FDS_PAGE_TAG_WORD_3 (0x1CEB00DA)
#define FDS_PAGE_TAG_WORD_3_GC (0x1CEB00D8)
/** @} */
#endif // FDS_CONFIG_H__

View File

@ -0,0 +1,178 @@
/*
* 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 FDS_TYPES_INTERNAL__
#define FDS_TYPES_INTERNAL__
#include "fds.h"
#include <stdint.h>
#include <stdbool.h>
#include "nrf_soc.h"
#define COMMAND_EXECUTING (NRF_SUCCESS)
#define COMMAND_COMPLETED (0x1234)
//#define COMMAND_FAILED (0x1236)
#define FDS_MAGIC_HWORD (0xF11E)
#define FDS_MAGIC_WORD (0x15ABE11A)
#define FDS_ERASED_WORD (0xFFFFFFFF)
#define FDS_PAGE_TAG_SIZE (4) /**< Page tag size, in 4 byte words. */
#define FDS_VPAGE_ID_UNKNOWN (0xFFFF)
#define FDS_WRITE_OFFSET_TL (0) /**< Offset of TL from the record base address, in 4 byte words. */
#define FDS_WRITE_OFFSET_IC (1) /**< Offset of IC from the record base address, in 4 byte words. */
#define FDS_WRITE_OFFSET_ID (2) /**< Offset of ID from the record base address, in 4 byte words. */
#define FDS_WRITE_OFFSET_DATA (3) /**< Offset of the data (chunks) from the record base address, in 4 byte words. */
#define FDS_HEADER_SIZE_TL (1) /**< Size of the TL part of the header, in 4 byte words. */
#define FDS_HEADER_SIZE_ID (1) /**< Size of the IC part of the header, in 4 byte words. */
#define FDS_HEADER_SIZE_IC (1) /**< Size of the IC part of the header, in 4 byte words. */
#define FDS_HEADER_SIZE (3) /**< Size of the whole header, in 4 byte words. */
#define FDS_CMD_QUEUE_SIZE_INIT (1)
#define FDS_CMD_QUEUE_SIZE_WRITE (1)
#define FDS_CMD_QUEUE_SIZE_CLEAR (1)
#define FDS_CMD_QUEUE_SIZE_UPDATE (2)
#define FDS_CMD_QUEUE_SIZE_GC (1)
static uint8_t m_nested_critical;
/** Macros to enable and disable application interrupts. */
#define CRITICAL_SECTION_ENTER() //sd_nvic_critical_region_enter(&m_nested_critical)
#define CRITICAL_SECTION_EXIT() //sd_nvic_critical_region_exit ( m_nested_critical)
/**@brief Page types. */
typedef enum
{
FDS_PAGE_UNDEFINED, /**< Undefined page type. */
FDS_PAGE_ERASED, /**< Page is erased. */
FDS_PAGE_VALID, /**< Page is ready for storage. */
FDS_PAGE_SWAP, /**< Page is reserved for GC. */
FDS_PAGE_GC /**< Page is being garbage collected. */
} fds_page_type_t;
typedef enum
{
FDS_OP_NONE = 0x00, /**< No operation. */
FDS_OP_WRITE_TL, /**< Write the type and length. */
FDS_OP_WRITE_ID, /**< Write the record ID. */
FDS_OP_WRITE_CHUNK, /**< Write the record value. */
FDS_OP_WRITE_IC, /**< Write the instance and checksum. */
FDS_OP_CLEAR_TL,
FDS_OP_CLEAR_INSTANCE,
FDS_OP_DONE,
} fds_opcode_t;
typedef enum
{
FDS_FLAG_INITIALIZING = (1 << 0), /**< TODO: Not really needed atm? */
FDS_FLAG_INITIALIZED = (1 << 1), /**< Flag indicating that flash data storage has been initialized. */
FDS_FLAG_PROCESSING = (1 << 2), /**< Flag indicating that queue is being processed. */
FDS_FLAG_CAN_GC = (1 << 3), /**< Flag indicating that fds can regain data by performing garbage collection. */
} fds_flags_t;
typedef struct
{
uint32_t const * start_addr;
uint16_t vpage_id; /**< The page logical ID. */
uint16_t volatile write_offset; /**< The page write offset, in 4 bytes words. */
uint16_t volatile words_reserved; /**< The amount of words reserved by fds_write_reserve() on this page. */
uint16_t volatile records_open;
fds_page_type_t page_type : 4; /**< The page type. */
} fds_page_t;
typedef struct
{
fds_cmd_id_t id : 4; /**< The ID of the command. */
fds_opcode_t op_code : 4;
uint8_t num_chunks; /**< Number of operations this command has left in the operation queue. */
uint16_t chunk_offset; /**< Offset used for writing the record value(s), in 4 byte words. */
uint16_t vpage_id; /**< The virtual page ID where we reserved the flash space for this command. */
fds_record_header_t record_header;
} fds_cmd_t;
/**@brief Defines command queue, an element is free if the op_code field is not invalid.
*
* @details Defines commands enqueued for flash access. At any point in time, this queue has one or
* more flash access operations pending if the count field is not zero. When the queue is
* not empty, the rp (read pointer) field points to the flash access command in progress
* or, if none is in progress, the command to be requested next. The queue implements a
* simple first in first out algorithm. Data addresses are assumed to be resident.
*/
typedef struct
{
fds_cmd_t cmd[FDS_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
uint8_t volatile rp; /**< The index of the command being executed. */
uint8_t volatile count; /**< Number of elements in the queue. */
} fds_cmd_queue_t;
typedef struct
{
fds_record_chunk_t chunk[FDS_CHUNK_QUEUE_SIZE];
uint8_t volatile rp;
uint8_t volatile count;
} fds_chunk_queue_t;
typedef enum
{
NONE,
BEGIN,
RESUME,
GC_PAGE,
COPY_RECORD,
READY_SWAP,
NEW_SWAP,
INIT_SWAP
} fds_gc_state_t;
typedef struct
{
uint16_t cur_page;
uint16_t swap_page;
uint32_t const * p_scan_addr;
fds_gc_state_t state;
bool do_gc_page[FDS_MAX_PAGES];
} fds_gc_data_t;
#endif // FDS_TYPES_INTERNAL__

View File

@ -0,0 +1,569 @@
/*
* 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 "fstorage.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "fstorage_config.h"
#include "nrf_error.h"
#include "nrf_soc.h"
#define FS_FLAG_INIT (1 << 0) /**< fstorage has been initialized. */
#define FS_FLAG_PROCESSING (1 << 1) /**< fstorage is executing queued flash operations. */
#define FS_FLAG_FLASH_REQ_PENDING (1 << 2) /**< fstorage is waiting for a flash operation initiated by another module to complete. */
/**@brief Macro invocation that registers section fs_data.
*
* @details Required for compilation.
*/
NRF_SECTION_VARS_REGISTER_SECTION(fs_data);
/**@brief Macro invocation that declares symbols used to find the beginning and end of the section fs_data.
*
* @details Required for compilation.
*/
NRF_SECTION_VARS_REGISTER_SYMBOLS(fs_config_t, fs_data);
/**@defgroup Section vars helper macros.
*
* @details Macros used to manipulate registered section variables.
*/
/**@brief Get section variable with fstorage configuration by index. */
#define FS_SECTION_VARS_GET(i) NRF_SECTION_VARS_GET(i, fs_config_t, fs_data)
/**@brief Get the number of registered section variables. */
#define FS_SECTION_VARS_COUNT NRF_SECTION_VARS_COUNT(fs_config_t, fs_data)
/**@brief Get the start address of the registered section variables. */
#define FS_SECTION_VARS_START_ADDR NRF_SECTION_VARS_START_ADDR(fs_data)
/**@brief Get the end address of the registered section variables. */
#define FS_SECTION_VARS_END_ADDR NRF_SECTION_VARS_END_ADDR(fs_data)
/** @} */
/**@brief The command queue element.
*
* @details Encapsulate details of a command requested to this module.
*/
typedef struct
{
fs_config_t const * p_config; /**< The configuration of the user who requested the operation. */
uint8_t op_code; /**< Operation code. */
uint32_t const * p_src; /**< Pointer to the data to be written to flash. The data must be kept in memory until the operation has finished. */
uint32_t const * p_addr; /**< Destination of the data in flash. */
fs_length_t length_words; /**< Length of the operation */
fs_length_t offset; /**< Offset of the operation if operation is done in chunks */
} fs_cmd_t;
/**@brief Structure that defines the command queue
*
* @details This queue holds flash operations requested to the module.
* The data to be written must be kept in memory until the write operation is completed,
* i.e., a callback indicating completion is received by the application.
*/
typedef struct
{
uint8_t rp; /**< The current element being processed. */
uint8_t count; /**< Number of elements in the queue. */
fs_cmd_t cmd[FS_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
} fs_cmd_queue_t;
static uint8_t m_flags; /**< FStorage status flags. */
static fs_cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */
static uint16_t m_retry_count = 0; /**< Number of times a single flash operation was retried. */
// Function prototypes
static ret_code_t queue_process(void);
static ret_code_t queue_process_impl(void);
static void app_notify(uint32_t result, fs_cmd_t const * p_cmd);
/**@brief Macro to check that the configuration is non-NULL and within
* valid section variable memory bounds.
*
* @param[in] config Configuration to check.
*/
#define FS_CHECK_CONFIG(config) \
((FS_SECTION_VARS_START_ADDR < config) && (config < FS_SECTION_VARS_END_ADDR))
/**@brief Function to check that the configuration is non-NULL and within
* valid section variable memory bounds.
*
* @param[in] config Configuration to check.
*/
static bool check_config(fs_config_t const * const config)
{
if (config == NULL)
{
return false;
}
if ((FS_SECTION_VARS_START_ADDR <= (uint32_t)config) && ((uint32_t)config < FS_SECTION_VARS_END_ADDR))
{
return true;
}
else
{
return false;
}
}
/**@brief Function to initialize the queue. */
static void queue_init(void)
{
memset(&m_cmd_queue, 0, sizeof(fs_cmd_queue_t));
}
/**@brief Function to reset a queue item to its default values.
*
* @param index Index of the queue element.
*/
static void cmd_reset(uint32_t index)
{
memset(&m_cmd_queue.cmd[index], 0, sizeof(fs_cmd_t));
}
/**@brief Function to enqueue flash access command
*
* @param[in] config Registered configuration.
* @param[in] op_code Operation code.
* @param[in] address Destination of the data.
* @param[in] p_src Source of data or NULL if n/a.
* @param[in] length Length of the data, in 4 byte words.
*
* @retval NRF_SUCCESS Success. Command enqueued.
* @retval NRF_ERROR_NO_MEM Error. Queue is full.
* @retval Any error returned by the SoftDevice flash API.
*/
static ret_code_t cmd_enqueue(fs_config_t const * p_config,
uint8_t op_code,
uint32_t const * p_addr,
uint32_t const * p_src,
fs_length_t length_words)
{
fs_cmd_t * p_cmd;
uint8_t write_pos;
if (m_cmd_queue.count == FS_CMD_QUEUE_SIZE - 1)
{
return NRF_ERROR_NO_MEM;
}
write_pos = (m_cmd_queue.rp + m_cmd_queue.count) % FS_CMD_QUEUE_SIZE;
p_cmd = &m_cmd_queue.cmd[write_pos];
p_cmd->p_config = p_config;
p_cmd->op_code = op_code;
p_cmd->p_src = p_src;
p_cmd->p_addr = p_addr;
p_cmd->length_words = length_words;
m_cmd_queue.count++;
return queue_process();
}
/**@brief Function to consume queue item and notify the return value of the operation.
*
* @details This function will report the result and remove the command from the queue after
* notification.
*/
static void cmd_consume(uint32_t result, const fs_cmd_t * p_cmd)
{
// Consume the current item on the queue.
uint8_t rp = m_cmd_queue.rp;
m_cmd_queue.count--;
if (m_cmd_queue.count == 0)
{
// There are no elements left. Stop processing the queue.
m_flags &= ~FS_FLAG_PROCESSING;
}
if (++(m_cmd_queue.rp) == FS_CMD_QUEUE_SIZE)
{
m_cmd_queue.rp = 0;
}
// Notify upon successful operation.
app_notify(result, p_cmd);
// Reset the queue element.
cmd_reset(rp);
}
/**@brief Function to store data to flash.
*
* @param[in] p_cmd The queue element associated with the operation.
*
* @retval NRF_SUCCESS Success. The request was sent to the SoftDevice.
* @retval Any error returned by the SoftDevice flash API.
*/
static __INLINE uint32_t store_execute(fs_cmd_t const * const p_cmd)
{
// Write in chunks if write-size is larger than FS_MAX_WRITE_SIZE.
fs_length_t const length = ((p_cmd->length_words - p_cmd->offset) < FS_MAX_WRITE_SIZE_WORDS) ?
(p_cmd->length_words - p_cmd->offset) : FS_MAX_WRITE_SIZE_WORDS;
return sd_flash_write((uint32_t*)p_cmd->p_addr + p_cmd->offset /* destination */,
(uint32_t*)p_cmd->p_src + p_cmd->offset /* source */,
length);
}
/**@brief Function to erase a page.
*
* @param[in] p_cmd The queue element associated with the operation.
*
* @retval NRF_SUCCESS Success. The request was sent to the SoftDevice.
* @retval Any error returned by the SoftDevice flash API.
*/
static __INLINE uint32_t erase_execute(fs_cmd_t const * const p_cmd)
{
// Erase the page.
return sd_flash_page_erase((uint32_t)(p_cmd->p_addr + p_cmd->offset) / FS_PAGE_SIZE);
}
/**@brief Function to process the current element in the queue and return the result.
*
* @retval NRF_SUCCESS Success.
* @retval NRF_ERROR_FORBIDDEN Error. Undefined command.
* @retval Any error returned by the SoftDevice flash API.
*/
static uint32_t queue_process_impl(void)
{
uint32_t ret;
fs_cmd_t const * const p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
switch (p_cmd->op_code)
{
case FS_OP_STORE:
ret = store_execute(p_cmd);
break;
case FS_OP_ERASE:
ret = erase_execute(p_cmd);
break;
case FS_OP_NONE:
ret = NRF_SUCCESS;
break;
default:
ret = NRF_ERROR_FORBIDDEN;
break;
}
return ret;
}
/**@brief Starts processing the queue if there are no pending flash operations
* for which we are awaiting a callback.
*/
static ret_code_t queue_process(void)
{
ret_code_t ret = NRF_SUCCESS;
/** If the queue is not being processed, and there are still
* some elements in it, then start processing. */
if ( !(m_flags & FS_FLAG_PROCESSING) &&
(m_cmd_queue.count > 0))
{
m_flags |= FS_FLAG_PROCESSING;
ret = queue_process_impl();
/** There is ongoing flash-operation which was not
* initiated by fstorage. */
if (ret == NRF_ERROR_BUSY)
{
// Wait for a system callback.
m_flags |= FS_FLAG_FLASH_REQ_PENDING;
// Stop processing the queue.
m_flags &= ~FS_FLAG_PROCESSING;
ret = NRF_SUCCESS;
}
else if (ret != NRF_SUCCESS)
{
// Another error has occurred.
app_notify(ret, &m_cmd_queue.cmd[m_cmd_queue.rp]);
}
}
// If we are already processing the queue, return immediately.
return ret;
}
/**@brief Flash operation success callback handler.
*
* @details This function updates read/write pointers.
* This function resets retry count.
*/
static __INLINE void on_operation_success(void)
{
fs_cmd_t * const p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
m_retry_count = 0;
switch (p_cmd->op_code)
{
case FS_OP_STORE:
// Update the offset on successful write.
p_cmd->offset += FS_MAX_WRITE_SIZE_WORDS;
break;
case FS_OP_ERASE:
// Update the offset to correspond to the page that has been erased.
p_cmd->offset += FS_PAGE_SIZE_WORDS;
break;
}
// If offset is equal to or larger than length, then the operation has finished.
if (p_cmd->offset >= p_cmd->length_words)
{
cmd_consume(NRF_SUCCESS, p_cmd);
}
queue_process();
}
/**@brief Flash operation failure callback handler.
*
* @details Function to keep track of retries and notify failures.
*/
static __INLINE void on_operation_failure(uint32_t sys_evt)
{
const fs_cmd_t * p_cmd;
if (++m_retry_count > FS_CMD_MAX_RETRIES)
{
p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
cmd_consume(NRF_ERROR_TIMEOUT, p_cmd);
}
queue_process();
}
/**@brief Function to notify users.
*
* @param[in] result Result of the flash operation.
* @param[in] p_cmd The command associated with the callback.
*/
static void app_notify(uint32_t result, fs_cmd_t const * const p_cmd)
{
p_cmd->p_config->cb(p_cmd->op_code, result, p_cmd->p_addr, p_cmd->length_words);
}
ret_code_t fs_init(void)
{
uint16_t lowest_index = 0;
uint16_t lowest_order = 0xFFFF;
uint32_t * current_end = (uint32_t*)FS_PAGE_END_ADDR;
uint32_t num_left = FS_SECTION_VARS_COUNT;
queue_init();
/** Assign pages to registered users, beginning with the ones with the lowest
* order, which will be assigned pages with the lowest memory address. */
do
{
fs_config_t * p_config;
for (uint16_t i = 0; i < FS_SECTION_VARS_COUNT; i++)
{
p_config = FS_SECTION_VARS_GET(i);
// Skip the ones which have the end-address already set.
if (p_config->p_end_addr != NULL)
continue;
if (p_config->page_order < lowest_order)
{
lowest_order = p_config->page_order;
lowest_index = i;
}
}
p_config = FS_SECTION_VARS_GET(lowest_index);
p_config->p_end_addr = current_end;
p_config->p_start_addr = p_config->p_end_addr - (p_config->num_pages * FS_PAGE_SIZE_WORDS);
current_end = p_config->p_start_addr;
lowest_order = 0xFFFF;
} while ( --num_left > 0 );
m_flags |= FS_FLAG_INIT;
return NRF_SUCCESS;
}
ret_code_t fs_store(fs_config_t const * p_config,
uint32_t const * p_addr,
uint32_t const * const p_data,
fs_length_t length_words)
{
if ((m_flags & FS_FLAG_INIT) == 0)
{
return NRF_ERROR_INVALID_STATE;
}
if (!check_config(p_config))
{
return NRF_ERROR_FORBIDDEN;
}
if (!is_word_aligned(p_addr))
{
return NRF_ERROR_INVALID_ADDR;
}
// Check that the erase operation is on pages owned by this user (configuration).
if ((p_addr < p_config->p_start_addr) || ((p_addr + length_words) > p_config->p_end_addr))
{
return NRF_ERROR_INVALID_ADDR;
}
return cmd_enqueue(p_config, FS_OP_STORE, p_addr, p_data, length_words);
}
ret_code_t fs_erase(fs_config_t const * p_config,
uint32_t * const p_addr,
fs_length_t const length_words)
{
if ((m_flags & FS_FLAG_INIT) == 0)
{
return NRF_ERROR_INVALID_STATE;
}
if (!check_config(p_config))
{
return NRF_ERROR_FORBIDDEN;
}
/** Check that the address is aligned on a page boundary and the length to erase
* is a multiple of the page size. */
if (((uint32_t)p_addr & (FS_PAGE_SIZE - 1)) ||
(length_words & (FS_PAGE_SIZE_WORDS - 1)))
{
return NRF_ERROR_INVALID_ADDR;
}
// Check that the erase operation is on pages owned by this user (configuration).
if ((p_addr < p_config->p_start_addr) || ((p_addr + length_words) > p_config->p_end_addr))
{
return NRF_ERROR_INVALID_ADDR;
}
return cmd_enqueue(p_config, FS_OP_ERASE, p_addr, NULL, length_words);
}
/**@brief Function to handle system events from the SoftDevice.
*
* @details This function should be dispatched system events if any of the modules used by
* the application rely on FStorage. Examples include @ref Peer Manager and
* @ref Flash Data Storage.
*
* @param[in] sys_evt System Event received.
*/
void fs_sys_event_handler(uint32_t sys_evt)
{
if (m_flags & FS_FLAG_PROCESSING)
{
/** A flash operation was initiated by this module.
* Handle its result. */
switch (sys_evt)
{
case NRF_EVT_FLASH_OPERATION_SUCCESS:
on_operation_success();
break;
case NRF_EVT_FLASH_OPERATION_ERROR:
on_operation_failure(sys_evt);
break;
}
}
else if ((m_flags & FS_FLAG_FLASH_REQ_PENDING))
{
/** A flash operation was initiated outside this module.
* We have now receveid a callback which indicates it has
* finished. Clear the FS_FLAG_FLASH_REQ_PENDING flag. */
m_flags &= ~FS_FLAG_FLASH_REQ_PENDING;
// Resume processing the queue, if necessary.
queue_process();
}
}
// Just for testing out section vars (across many compilers).
void fs_debug_print()
{
printf("fs start address: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_START_ADDR);
printf("fs end address: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_END_ADDR);
printf("Num items: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_COUNT);
printf("===== ITEMS %lu =====\r\n", (unsigned long)FS_SECTION_VARS_COUNT);
for(int i = 0; i < FS_SECTION_VARS_COUNT; i++)
{
fs_config_t* config = FS_SECTION_VARS_GET(i);
printf( "Address: 0x%08lx, CB: 0x%08lx\r\n",
(unsigned long)config, (unsigned long)config->cb );
}
printf("\r\n");
}

View File

@ -0,0 +1,176 @@
/*
* 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 FS_H__
#define FS_H__
/** @file
*
* @defgroup fstorage FStorage
* @{
* @ingroup app_common
* @brief Module which provides low level functionality to store data to flash.
*
*/
#include <stdint.h>
#include "section_vars.h"
#include "fstorage_config.h"
#include "sdk_errors.h"
typedef uint16_t fs_length_t;
typedef enum
{
FS_OP_NONE = 0,
FS_OP_STORE = 1,
FS_OP_ERASE = 2
} fs_oper_t;
/**@brief Callback for flash operations.
*
* @param[in] op_code Flash access operation code.
* @param[in] result Result of the operation.
* @param[in] data Pointer to resulting data (or NULL if not in use).
* @param[in] length_words Length of data in words.
*/
typedef void (*fs_cb_t)(uint8_t op_code,
uint32_t result,
uint32_t const * p_data,
fs_length_t length_words);
/**@brief Function prototype for a callback handler.
*
* @details This function is expected to be implemented by the module that
* registers for fstorage usage. Its usage is described
* in the function pointer type fs_cb_t.
*
* @param[in] op_code Flash operation code.
* @param[in] result Result of the flash operation.
* @param[in] p_data Pointer to the resulting data (or NULL if not in use).
* @param[in] length_words Length of data in words.
*/
static void fs_callback(uint8_t op_code,
uint32_t result,
uint32_t const * p_data,
fs_length_t length_words);
/**@brief Flash storage config variable.
*
* @details The fstorage module will update the start_addr and end_address according to
* ordering rules and the number of pages requested by the fstorage module user.
*/
typedef struct
{
const fs_cb_t cb; /**< Callback to run when flash operation has completed. */
const uint8_t num_pages; /**< The number of pages to reserve for flash storage. */
const uint8_t page_order; /**< The order used to allocate pages. */
uint32_t * p_start_addr; /**< Pointer to the start address of the allocated flash storage. Set by running @ref fs_init. */
uint32_t * p_end_addr; /**< Pointer to the end address of the allcoated flash storage. Set by running @ref fs_init. */
} fs_config_t;
/**@brief Macro for registering of flash storage configuration variable.
*
* @details This macro is expected to be invoked in the code unit that that require
* flash storage. Invoking this places the registered configuration variable
* in a section named "fs_data" that the fstorage module uses during initialization
* and regular operation.
*/
#define FS_SECTION_VARS_ADD(type_def) NRF_SECTION_VARS_ADD(fs_data, type_def)
/**@brief Function to initialize FStorage.
*
* @details This function allocates flash data pages according to the
* number requested in the config variable. The data used to initialize.
* the fstorage is section placed variables in the data section "fs_data".
*/
ret_code_t fs_init(void);
/**@brief Function to store data in flash.
*
* @warning The data to be written to flash has to be kept in memory until the operation has
* terminated, i.e., a callback is received.
*
* @param[in] p_config Const pointer to configiguration of module user that requests a store operation.
* @param[in] p_addr Write address of store operation.
* @param[in] p_data Pointer to the data to store.
* @param[in] length_words Length of the data to store.
*
* @retval NRF_SUCCESS Success. Command queued.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_INVALID_ADDR Error. Data is unaligned or invalid configuration.
* @retval Any error returned by the SoftDevice flash API.
*/
ret_code_t fs_store(fs_config_t const * p_config,
uint32_t const * p_addr,
uint32_t const * const p_data,
fs_length_t length_words);
/** Function to erase a page in flash.
*
* @note The erase address must be aligned on a page boundary. The length in words must be
* equivalent to the page size.
*
* @param[in] p_config Pointer to the configuration of the user that requests the operation.
* @param[in] p_addr Address of page to erase (the same as first word in the page).
* @param[in] length_words Length (in 4 byte words) of the area to erase.
*
* @retval NRF_SUCCESS Success. Command queued.
* @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized.
* @retval NRF_ERROR_INVALID_ADDR Error. Data is unaligned or invalid configuration.
* @retval Any error returned by the SoftDevice flash API.
*/
ret_code_t fs_erase(fs_config_t const * p_config,
uint32_t * const p_addr,
fs_length_t length_words);
/**@brief Function to call to handle events from the SoftDevice
*
* @param sys_evt System event from the SoftDevice
*/
void fs_sys_event_handler(uint32_t sys_evt);
/** @} */
#endif // FS_H__

View File

@ -0,0 +1,113 @@
/*
* 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 FS_CONFIG_H__
#define FS_CONFIG_H__
#include <stdint.h>
#include "nrf.h"
/**
* @defgroup fstorage_config FStorage configuration
* @ingroup fstorage
* @{
* @brief FStorage configuration.
*/
/**@brief Macro for max number of operations in the fs cmd queue.
*/
#define FS_CMD_QUEUE_SIZE (8)
/**@brief Macro for max number of retries for a flash command before it notifies as failed.
*/
#define FS_CMD_MAX_RETRIES (3)
/**@brief Macro for the content of a flash address that has not been written to.
*/
#define FS_EMPTY_MASK (0xFFFFFFFF)
/**@brief Macro for flash page size according to chip family
*/
#if defined (NRF51)
#define FS_PAGE_SIZE (1024)
#elif defined (NRF52)
#define FS_PAGE_SIZE (4096)
#else
#error "Device family must be defined. See nrf.h."
#endif
/*@brief Macro for flash page size according to chip family
*/
#define FS_PAGE_SIZE_WORDS (FS_PAGE_SIZE/4)
/**@brief Static inline function that provides last page address
*
* @note If there is a bootloader present the bootloader address read from UICR
* will act as the page beyond the end of the available flash storage
*/
static __INLINE uint32_t fs_flash_page_end_addr()
{
uint32_t const bootloader_addr = NRF_UICR->NRFFW[0];
return ((bootloader_addr != FS_EMPTY_MASK) ?
bootloader_addr : NRF_FICR->CODESIZE * FS_PAGE_SIZE);
}
/**@brief Macro for last page address
*
* @note If there is a bootloader present the bootloader address read from UICR
* will act as the page beyond the end of the available flash storage
*/
#define FS_PAGE_END_ADDR fs_flash_page_end_addr()
/**@brief Macro to describe the write
*
*/
#if defined (NRF51)
#define FS_MAX_WRITE_SIZE_WORDS (256)
#elif defined (NRF52)
#define FS_MAX_WRITE_SIZE_WORDS (1024)
#else
#error "Device family must be defined. see nrf.h"
#endif
/** @} */
#endif // FS_CONFIG_H__

View File

@ -0,0 +1,32 @@
/*
* 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,181 @@
/*
* 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 "sdk_mapped_flags.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "compiler_abstraction.h"
/**@brief Function for setting the state of a flag to true.
*
* @note This function does not check whether the index is valid.
*
* @param[in] p_flags The collection of flags to modify.
* @param[in] index The index of the flag to modify.
*/
static __INLINE void sdk_mapped_flags_set_by_index(sdk_mapped_flags_t * p_flags, uint16_t index)
{
*p_flags |= (1U << index);
}
/**@brief Function for setting the state of a flag to false.
*
* @note This function does not check whether the index is valid.
*
* @param[in] p_flags The collection of flags to modify.
* @param[in] index The index of the flag to modify.
*/
static __INLINE void sdk_mapped_flags_clear_by_index(sdk_mapped_flags_t * p_flags, uint16_t index)
{
*p_flags &= ~(1U << index);
}
/**@brief Function for getting the state of a flag.
*
* @note This function does not check whether the index is valid.
*
* @param[in] p_flags The collection of flags to read.
* @param[in] index The index of the flag to get.
*/
static __INLINE bool sdk_mapped_flags_get_by_index(sdk_mapped_flags_t flags, uint16_t index)
{
return ((flags & (1 << index)) != 0);
}
uint16_t sdk_mapped_flags_first_key_index_get(sdk_mapped_flags_t flags)
{
for (uint16_t i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++)
{
if (sdk_mapped_flags_get_by_index(flags, i))
{
return i;
}
}
return SDK_MAPPED_FLAGS_INVALID_INDEX;
}
void sdk_mapped_flags_update_by_key(uint16_t * p_keys,
sdk_mapped_flags_t * p_flags,
uint16_t key,
bool value)
{
sdk_mapped_flags_bulk_update_by_key(p_keys, p_flags, 1, key, value);
}
void sdk_mapped_flags_bulk_update_by_key(uint16_t * p_keys,
sdk_mapped_flags_t * p_flags,
uint32_t n_flag_collections,
uint16_t key,
bool value)
{
if ((p_keys != NULL) && (p_flags != NULL) && (n_flag_collections > 0))
{
for (int i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++)
{
if (p_keys[i] == key)
{
for (int j = 0; j < n_flag_collections; j++)
{
if (value)
{
sdk_mapped_flags_set_by_index(&p_flags[j], i);
}
else
{
sdk_mapped_flags_clear_by_index(&p_flags[j], i);
}
}
return;
}
}
}
}
bool sdk_mapped_flags_get_by_key(uint16_t * p_keys, sdk_mapped_flags_t flags, uint16_t key)
{
if (p_keys != NULL)
{
for (int i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++)
{
if (p_keys[i] == key)
{
return sdk_mapped_flags_get_by_index(flags, i);
}
}
}
return false;
}
sdk_mapped_flags_key_list_t sdk_mapped_flags_key_list_get(uint16_t * p_keys,
sdk_mapped_flags_t flags)
{
sdk_mapped_flags_key_list_t key_list;
key_list.len = 0;
if (p_keys != NULL)
{
for (int i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++)
{
if (sdk_mapped_flags_get_by_index(flags, i))
{
key_list.flag_keys[key_list.len++] = p_keys[i];
}
}
}
return key_list;
}
uint32_t sdk_mapped_flags_n_flags_set(sdk_mapped_flags_t flags)
{
uint32_t n_flags_set = 0;
for (int i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++)
{
if (sdk_mapped_flags_get_by_index(flags, i))
{
n_flags_set += 1;
}
}
return n_flags_set;
}

View File

@ -0,0 +1,21 @@
# Copyright 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.
message("omit frame pointer for bootloader startup asm")
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
set_source_files_properties(
"${CMAKE_CURRENT_LIST_DIR}/nordic_sdk/components/libraries/bootloader_dfu/bootloader_util.c"
PROPERTIES COMPILE_FLAGS -fomit-frame-pointer)
endif()

View File

@ -0,0 +1,21 @@
# Copyright 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.
message("suppressing warnings from nrf51-sdk")
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
set_target_properties(nrf51-sdk
PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function -Wno-missing-field-initializers"
)
endif()

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