├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md └── workflows │ ├── stale.yml │ └── sync_issues.yml ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── examples ├── BLE_client │ └── BLE_client.ino ├── BLE_iBeacon │ └── BLE_iBeacon.ino ├── BLE_iBeacon_3Asix │ └── BLE_iBeacon_3Asix.ino ├── BLE_scan │ └── BLE_scan.ino ├── BLE_server │ └── BLE_server.ino └── BLE_uart │ └── BLE_uart.ino ├── keywords.txt ├── library.properties └── src ├── BLE2902.cpp ├── BLE2902.h ├── BLE2904.cpp ├── BLE2904.h ├── BLEAddress.cpp ├── BLEAddress.h ├── BLEAdvertisedDevice.cpp ├── BLEAdvertisedDevice.h ├── BLEAdvertising.cpp ├── BLEAdvertising.h ├── BLEBeacon.cpp ├── BLEBeacon.h ├── BLECharacteristic.cpp ├── BLECharacteristic.h ├── BLECharacteristicMap.cpp ├── BLEClient.cpp ├── BLEClient.h ├── BLEDescriptor.cpp ├── BLEDescriptor.h ├── BLEDescriptorMap.cpp ├── BLEDevice.cpp ├── BLEDevice.h ├── BLEDeviceDefaultCallbacks.cpp ├── BLEEddystoneTLM.cpp ├── BLEEddystoneTLM.h ├── BLEEddystoneURL.cpp ├── BLEEddystoneURL.h ├── BLEExceptions.cpp ├── BLEExceptions.h ├── BLEFreeRTOS.cpp ├── BLEFreeRTOS.h ├── BLEHIDDevice.cpp ├── BLEHIDDevice.h ├── BLERemoteCharacteristic.cpp ├── BLERemoteCharacteristic.h ├── BLERemoteDescriptor.cpp ├── BLERemoteDescriptor.h ├── BLERemoteService.cpp ├── BLERemoteService.h ├── BLEScan.cpp ├── BLEScan.h ├── BLEServer.cpp ├── BLEServer.h ├── BLEService.cpp ├── BLEService.h ├── BLEServiceMap.cpp ├── BLEUUID.cpp ├── BLEUUID.h ├── BLEValue.cpp ├── BLEValue.h ├── HIDKeyboardTypes.h ├── HIDTypes.h └── rpcBLEDevice.h /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 4 * * *' 7 | 8 | jobs: 9 | stale: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Checkout script repository 17 | uses: actions/checkout@v4 18 | with: 19 | repository: Seeed-Studio/sync-github-all-issues 20 | path: ci 21 | 22 | - name: Run script 23 | run: ./ci/tools/stale.sh 24 | env: 25 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/sync_issues.yml: -------------------------------------------------------------------------------- 1 | name: Automate Issue Management 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - edited 8 | - assigned 9 | - unassigned 10 | - labeled 11 | - unlabeled 12 | - reopened 13 | 14 | jobs: 15 | add_issue_to_project: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Add issue to GitHub Project 19 | uses: actions/add-to-project@v1.0.2 20 | with: 21 | project-url: https://github.com/orgs/Seeed-Studio/projects/17 22 | github-token: ${{ secrets.ISSUE_ASSEMBLE }} 23 | labeled: bug 24 | label-operator: NOT -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | dist: bionic 3 | sudo: false 4 | cache: 5 | directories: 6 | - ~/arduino_ide 7 | - ~/.arduino15/packages/ 8 | 9 | before_install: 10 | - wget -c https://files.seeedstudio.com/arduino/seeed-arduino-ci.sh 11 | 12 | script: 13 | - chmod +x seeed-arduino-ci.sh 14 | - cat $PWD/seeed-arduino-ci.sh 15 | - bash $PWD/seeed-arduino-ci.sh -b "Seeeduino:samd:seeed_wio_terminal" -s BLE_client/BLE_server/BLE_iBeacon/BLE_iBeacon_3Asix/BLE_scan/BLE_uart Seeed-Studio/Seeed_Arduino_FreeRTOS.git Seeed-Studio/Seeed_Arduino_rpcUnified.git Seeed-Studio/Seeed_Arduino_LIS3DHTR.git 16 | 17 | notifications: 18 | email: 19 | on_success: change 20 | on_failure: change 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at zuobaozhu@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to Seeed Software 2 | 3 | #### **Did you find a bug?** 4 | 5 | * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE/issues). 6 | 7 | * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE//issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. 8 | 9 | * If possible, use the relevant bug report templates to create the issue. Simply copy the content of the appropriate template into a .md file, make the necessary changes to demonstrate the issue, and **paste the content into the issue description**: 10 | * [**Bug** issues](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE/blob/master/.github/ISSUE_TEMPLATE/bug_report.md) 11 | * [**feature** issues](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE/blob/master/.github/ISSUE_TEMPLATE/feature_request.md) 12 | * [**custom** for other issues](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE/blob/master/.github/ISSUE_TEMPLATE/custom.md) 13 | 14 | 15 | #### **Did you write a patch that fixes a bug?** 16 | 17 | * Open a new GitHub pull request with the patch. 18 | 19 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 20 | 21 | * Before submitting, please read the [Contributing to Seeed Software](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE/blob/master/CONTRIBUTING.md) guide to know more about coding conventions and benchmarks. 22 | 23 | #### **Did you fix whitespace, format code, or make a purely cosmetic patch?** 24 | 25 | Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of Software will generally not be accepted . 26 | #### **Do you intend to add a new feature or change an existing one?** 27 | 28 | * Suggest you mailing our administrator(zuobaozhu@gmail.com) first and start writing code. 29 | 30 | * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes. 31 | 32 | 33 | #### **Do you want to contribute to the Seeed documentation?** 34 | 35 | * Please read [Contributing to the Seeed Documentation](https://github.com/Seeed-Studio/wiki-documents/blob/master/README.md). 36 | 37 | Seeed Software is a volunteer effort. We encourage you to pitch in and join [the team](https://github.com/Seeed-Studio)! 38 | 39 | Thanks! :heart: :heart: :heart: 40 | 41 | Seeed Software Team 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Seeed Studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/Seeed-Studio/Seeed-Arduino-Rpc-Ble.svg?branch=master)](https://travis-ci.com/Seeed-Studio/Seeed-Arduino-Rpc-Ble) 2 | 3 | Seeed Arduino rpcBLE software library calls Seeed Arduino rpcUnified to implement BLE function compatibility with Arduino-ESP32. To reduce the cost of using the software, you can import your favorite ESP32 ble app directly, with minor changes, and then use it. You'll find that your favorite ESP32 app has BLE5.0 features, runs on ARM and other architectures. Hope you like this software and let us know if you have any feedback. 4 | 5 | ### **Feature** 6 | 7 | - Maximum Compatible with ESP32 BLE library 8 | - Powered by Realtek RTL8720DN 9 | - BLE / BLE 5.0 10 | - low power consumption 11 | 12 | 13 | [**More detailed documentation**](https://wiki.seeedstudio.com/Wio-Terminal-Bluetooth-Overview/) 14 | 15 | ## **License** 16 | 17 | This software is written by seeed studio and is licensed under The MIT License. Check License.txt for more information. 18 | 19 | Contributing to this software is warmly welcomed. You can do this basically by forking, committing modifications and then pulling requests (follow the links above for operating guide). Adding change log and your contact into file header is encouraged. Thanks for your contribution. 20 | -------------------------------------------------------------------------------- /examples/BLE_client/BLE_client.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * A BLE client example that is rich in capabilities. 3 | * There is a lot new capabilities implemented. 4 | * author unknown 5 | * updated by chegewara 6 | */ 7 | 8 | #include "rpcBLEDevice.h" 9 | #include 10 | #include 11 | 12 | // The remote service we wish to connect to. 13 | static BLEUUID serviceUUID(0x180F); 14 | // The characteristic of the remote service we are interested in. 15 | static BLEUUID charUUID(0x2A19); 16 | 17 | static boolean doConnect = false; 18 | static boolean connected = false; 19 | static boolean doScan = false; 20 | static BLERemoteCharacteristic* pRemoteCharacteristic; 21 | static BLEAdvertisedDevice* myDevice; 22 | uint8_t bd_addr[6] = {0x7d, 0x18, 0x1b, 0xf1, 0xf7, 0x2c}; 23 | BLEAddress BattServer(bd_addr); 24 | 25 | static void notifyCallback( 26 | BLERemoteCharacteristic* pBLERemoteCharacteristic, 27 | uint8_t* pData, 28 | size_t length, 29 | bool isNotify) { 30 | Serial.print("Notify callback for characteristic "); 31 | Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); 32 | Serial.print(" of data length "); 33 | Serial.println(length); 34 | Serial.print("data: "); 35 | Serial.print(*(uint8_t *)pData); 36 | } 37 | 38 | 39 | class MyClientCallback : public BLEClientCallbacks { 40 | void onConnect(BLEClient* pclient) { 41 | } 42 | 43 | void onDisconnect(BLEClient* pclient) { 44 | connected = false; 45 | Serial.println("onDisconnect"); 46 | } 47 | }; 48 | 49 | 50 | bool connectToServer() { 51 | Serial.print("Forming a connection to "); 52 | Serial.println(myDevice->getAddress().toString().c_str()); 53 | 54 | BLEClient* pClient = BLEDevice::createClient(); 55 | Serial.println(" - Created client"); 56 | 57 | pClient->setClientCallbacks(new MyClientCallback()); 58 | 59 | 60 | // Connect to the remove BLE Server. 61 | pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private) 62 | Serial.println(" - Connected to server"); 63 | 64 | // Obtain a reference to the service we are after in the remote BLE server. 65 | BLERemoteService* pRemoteService = pClient->getService(serviceUUID); 66 | Serial.println(serviceUUID.toString().c_str()); 67 | if (pRemoteService == nullptr) { 68 | Serial.print("Failed to find our service UUID: "); 69 | Serial.println(serviceUUID.toString().c_str()); 70 | pClient->disconnect(); 71 | return false; 72 | } 73 | Serial.println(" - Found our service"); 74 | 75 | 76 | // Obtain a reference to the characteristic in the service of the remote BLE server. 77 | pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); 78 | if (pRemoteCharacteristic == nullptr) { 79 | Serial.print("Failed to find our characteristic UUID: "); 80 | Serial.println(charUUID.toString().c_str()); 81 | pClient->disconnect(); 82 | return false; 83 | } 84 | Serial.println(" - Found our characteristic"); 85 | 86 | 87 | // Read the value of the characteristic. 88 | if(pRemoteCharacteristic->canRead()) { 89 | Serial.println(" - can read start"); 90 | std::string value = pRemoteCharacteristic->readValue(); 91 | Serial.print("The characteristic value was: "); 92 | Serial.println(value.c_str()); 93 | } 94 | 95 | if(pRemoteCharacteristic->canNotify()) 96 | pRemoteCharacteristic->registerForNotify(notifyCallback); 97 | 98 | connected = true; 99 | return true; 100 | } 101 | /** 102 | * Scan for BLE servers and find the first one that advertises the service we are looking for. 103 | */ 104 | class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { 105 | /** 106 | * Called for each advertising BLE server. 107 | */ 108 | void onResult(BLEAdvertisedDevice advertisedDevice) { 109 | Serial.print("BLE Advertised Device found: "); 110 | Serial.println(advertisedDevice.toString().c_str()); 111 | 112 | // We have found a device, let us now see if it contains the service we are looking for. 113 | if (memcmp(advertisedDevice.getAddress().getNative(),BattServer.getNative(), 6) == 0) { 114 | Serial.print("BATT Device found: "); 115 | Serial.println(advertisedDevice.toString().c_str()); 116 | BLEDevice::getScan()->stop(); 117 | Serial.println("new BLEAdvertisedDevice"); 118 | myDevice = new BLEAdvertisedDevice(advertisedDevice); 119 | Serial.println("new BLEAdvertisedDevice done"); 120 | doConnect = true; 121 | doScan = true; 122 | } // onResult 123 | } 124 | }; // MyAdvertisedDeviceCallbacks 125 | 126 | 127 | void setup() { 128 | Serial.begin(115200); 129 | while(!Serial){}; 130 | delay(2000); 131 | Serial.println("Starting Arduino BLE Client application..."); 132 | BLEDevice::init(""); 133 | 134 | // Retrieve a Scanner and set the callback we want to use to be informed when we 135 | // have detected a new device. Specify that we want active scanning and start the 136 | // scan to run for 5 seconds. 137 | BLEScan* pBLEScan = BLEDevice::getScan(); 138 | pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); 139 | pBLEScan->setInterval(1349); 140 | pBLEScan->setWindow(449); 141 | pBLEScan->setActiveScan(true); 142 | pBLEScan->start(5, false); 143 | } // End of setup. 144 | 145 | 146 | // This is the Arduino main loop function. 147 | void loop() { 148 | 149 | // If the flag "doConnect" is true then we have scanned for and found the desired 150 | // BLE Server with which we wish to connect. Now we connect to it. Once we are 151 | // connected we set the connected flag to be true. 152 | if (doConnect == true) { 153 | if (connectToServer()) { 154 | Serial.println("We are now connected to the BLE Server."); 155 | } else { 156 | Serial.println("We have failed to connect to the server; there is nothin more we will do."); 157 | } 158 | doConnect = false; 159 | } 160 | Serial.printf("."); 161 | delay(1000); 162 | } // End of loop 163 | -------------------------------------------------------------------------------- /examples/BLE_iBeacon/BLE_iBeacon.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp 3 | Ported to Arduino ESP32 by pcbreflux 4 | */ 5 | 6 | 7 | /* 8 | Create a BLE server that will send periodic iBeacon frames. 9 | The design of creating the BLE server is: 10 | 1. Create a BLE Server 11 | 2. Create advertising data 12 | 3. Start advertising. 13 | 4. wait 14 | 5. Stop advertising. 15 | 6. deep sleep 16 | 17 | */ 18 | #include "sys/time.h" 19 | #include "rpcBLEDevice.h" 20 | #include "BLEBeacon.h" 21 | 22 | 23 | // See the following for generating UUIDs: 24 | // https://www.uuidgenerator.net/ 25 | BLEAdvertising *pAdvertising; 26 | //struct timeval now; 27 | 28 | #define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) 29 | 30 | void setBeacon() { 31 | 32 | BLEBeacon oBeacon = BLEBeacon(); 33 | oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) 34 | oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); 35 | oBeacon.setMajor(0x007B); 36 | oBeacon.setMinor(0x01C8); 37 | BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); 38 | BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); 39 | 40 | oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 41 | 42 | std::string strServiceData = ""; 43 | 44 | strServiceData += (char)26; // Len 45 | strServiceData += (char)0xFF; // Type 46 | strServiceData += oBeacon.getData(); 47 | oAdvertisementData.addData(strServiceData); 48 | 49 | pAdvertising->setAdvertisementData(oAdvertisementData); 50 | pAdvertising->setScanResponseData(oScanResponseData); 51 | pAdvertising->setAdvertisementType(GAP_ADTYPE_ADV_NONCONN_IND); 52 | 53 | } 54 | 55 | void setup() { 56 | 57 | 58 | Serial.begin(115200); 59 | while(!Serial){}; 60 | 61 | // Create the BLE Device 62 | BLEDevice::init(""); 63 | 64 | // Create the BLE Server 65 | // BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage 66 | 67 | pAdvertising = BLEDevice::getAdvertising(); 68 | 69 | setBeacon(); 70 | // Start advertising 71 | pAdvertising->start(); 72 | Serial.println("Advertizing started..."); 73 | delay(100); 74 | Serial.printf("in deep sleep\n"); 75 | } 76 | 77 | void loop() { 78 | delay(1000); 79 | } 80 | -------------------------------------------------------------------------------- /examples/BLE_iBeacon_3Asix/BLE_iBeacon_3Asix.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp 3 | Ported to Arduino ESP32 by pcbreflux 4 | */ 5 | 6 | 7 | /* 8 | Create a BLE server that will send periodic iBeacon frames. 9 | The design of creating the BLE server is: 10 | 1. Create a BLE Server 11 | 2. Create advertising data 12 | 3. Start advertising. 13 | 4. wait 14 | 5. Stop advertising. 15 | 6. deep sleep 16 | 17 | */ 18 | 19 | 20 | #include "sys/time.h" 21 | #include "rpcBLEDevice.h" 22 | #include "BLEBeacon.h" 23 | #include"LIS3DHTR.h" 24 | 25 | #include // Hardware-specific library 26 | #include 27 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 28 | TFT_eSprite spr = TFT_eSprite(&tft); // Sprite 29 | 30 | LIS3DHTR lis; 31 | BLEAdvertising *pAdvertising; 32 | 33 | 34 | #define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) 35 | #define SERVICE_UUID 0x1801 36 | #define SERVICE_UUID1 0x1802 37 | #define SERVICE_UUID2 0x1803 38 | 39 | 40 | void setBeacon() { 41 | 42 | BLEBeacon oBeacon = BLEBeacon(); 43 | oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) 44 | oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); 45 | oBeacon.setMajor(0x007B); 46 | oBeacon.setMinor(0x01C8); 47 | BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); 48 | BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); 49 | 50 | oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 51 | std::string strServiceData = ""; 52 | strServiceData += (char)26; // Len 53 | strServiceData += (char)0xFF; // Type 54 | strServiceData += oBeacon.getData(); 55 | oAdvertisementData.addData(strServiceData); 56 | 57 | union cracked_float_t{ 58 | float f; 59 | uint32_t l; 60 | word w[sizeof(float)/sizeof(word)]; 61 | byte b[sizeof(float)]; 62 | }; 63 | 64 | float x_values, y_values, z_values; 65 | x_values = lis.getAccelerationX(); 66 | y_values = lis.getAccelerationY(); 67 | z_values = lis.getAccelerationZ(); 68 | 69 | std::string m_data = std::string((char*) &x_values, sizeof(x_values)); 70 | std::string m_data1 = std::string((char*) &y_values, sizeof(y_values)); 71 | std::string m_data2 = std::string((char*) &z_values, sizeof(z_values)); 72 | oScanResponseData.setName("wio"); 73 | oScanResponseData.setServiceData(BLEUUID(SERVICE_UUID),m_data); 74 | oScanResponseData.setServiceData(BLEUUID(SERVICE_UUID1),m_data1); 75 | oScanResponseData.setServiceData(BLEUUID(SERVICE_UUID2),m_data2); 76 | 77 | pAdvertising->setAdvertisementData(oAdvertisementData); 78 | pAdvertising->setScanResponseData(oScanResponseData); 79 | pAdvertising->setAdvertisementType(GAP_ADTYPE_ADV_SCAN_IND); 80 | 81 | 82 | 83 | cracked_float_t X = {x_values}; 84 | cracked_float_t Y = {y_values}; 85 | cracked_float_t Z = {z_values}; 86 | 87 | spr.fillSprite(TFT_BLACK); 88 | spr.createSprite(240, 160); 89 | spr.fillSprite(TFT_BLACK); 90 | spr.setTextColor(TFT_WHITE, TFT_BLACK); 91 | spr.setFreeFont(&FreeSansBoldOblique12pt7b); 92 | 93 | uint8_t x_values_b [4]; 94 | memcpy(x_values_b, &x_values, 4); 95 | char x[10]; 96 | sprintf(x, "%02X%02X%02X%02X", x_values_b [0],x_values_b [1],x_values_b [2],x_values_b [3]); 97 | 98 | uint8_t y_values_b [4]; 99 | memcpy(y_values_b, &y_values, 4); 100 | char y[10]; 101 | sprintf(y, "%02X%02X%02X%02X", y_values_b [0],y_values_b [1],y_values_b [2],y_values_b [3]); 102 | 103 | uint8_t z_values_b [4]; 104 | memcpy(z_values_b, &z_values, 4); 105 | char z[10]; 106 | sprintf(z, "%02X%02X%02X%02X", z_values_b [0],z_values_b [1],z_values_b [2],z_values_b [3]); 107 | 108 | 109 | spr.drawString("X- 0x",20 ,10); 110 | spr.drawString(x, 80, 10); 111 | spr.drawString("X-value",20 ,35); 112 | spr.drawFloat(x_values, 2, 120, 35); 113 | 114 | spr.drawString("Y- 0x",20 , 60); 115 | spr.drawString(y, 80, 60); 116 | spr.drawString("Y-value",20 ,85); 117 | spr.drawFloat(y_values, 2, 120, 85); 118 | 119 | spr.drawString("Z- 0x",20 , 110); 120 | spr.drawString(z, 80, 110); 121 | spr.drawString("Z-value",20 ,135); 122 | spr.drawFloat(z_values, 2, 120, 135); 123 | 124 | spr.pushSprite(0,0); 125 | 126 | 127 | } 128 | 129 | void setup() { 130 | 131 | tft.begin(); 132 | tft.init(); 133 | tft.setRotation(3); 134 | tft.fillScreen(TFT_BLACK); 135 | Serial.begin(115200); 136 | 137 | // Create the BLE Device 138 | BLEDevice::init(""); 139 | lis.begin(Wire1); 140 | if (!lis) { 141 | Serial.println("ERROR"); 142 | while(1); 143 | } 144 | lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); //Data output rate 145 | lis.setFullScaleRange(LIS3DHTR_RANGE_2G); //Scale range set to 2g 146 | 147 | 148 | pAdvertising = BLEDevice::getAdvertising(); 149 | 150 | 151 | 152 | Serial.println("Advertizing started..."); 153 | delay(100); 154 | } 155 | 156 | void loop() { 157 | setBeacon(); 158 | // Start advertising 159 | pAdvertising->start(); 160 | delay(5000); 161 | pAdvertising->stop(); 162 | delay(1000); 163 | } 164 | -------------------------------------------------------------------------------- /examples/BLE_scan/BLE_scan.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to Arduino ESP32 by Evandro Copercini 3 | */ 4 | #include 5 | #include 6 | #include 7 | int scanTime = 5; //In seconds 8 | BLEScan* pBLEScan; 9 | 10 | class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { 11 | void onResult(BLEAdvertisedDevice advertisedDevice) { 12 | Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str()); 13 | } 14 | }; 15 | 16 | void setup() { 17 | Serial.begin(115200); 18 | Serial.printf("Scanning..."); 19 | 20 | BLEDevice::init(""); 21 | pBLEScan = BLEDevice::getScan(); //create new scan 22 | pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); 23 | pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster 24 | pBLEScan->setInterval(100); 25 | pBLEScan->setWindow(99); // less or equal setInterval value 26 | } 27 | 28 | void loop() { 29 | // put your main code here, to run repeatedly: 30 | BLEScanResults foundDevices = pBLEScan->start(scanTime, false); 31 | Serial.print("Devices found: "); 32 | Serial.println(foundDevices.getCount()); 33 | Serial.println("Scan done!"); 34 | pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory 35 | delay(2000); 36 | } 37 | -------------------------------------------------------------------------------- /examples/BLE_server/BLE_server.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp 3 | Ported to Arduino ESP32 by Evandro Copercini 4 | updates by chegewara 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | // See the following for generating UUIDs: 11 | // https://www.uuidgenerator.net/ 12 | 13 | #define SERVICE_UUID "180f" 14 | #define CHARACTERISTIC_UUID "2a19" 15 | #define DESCRIPTOR_UUID "4545" 16 | 17 | 18 | class MyCallbacks: public BLECharacteristicCallbacks { 19 | void onWrite(BLECharacteristic *pCharacteristic) { 20 | std::string rxValue = pCharacteristic->getValue(); 21 | 22 | if (rxValue.length() > 0) { 23 | Serial.println("*********"); 24 | Serial.print("Received Value: "); 25 | for (int i = 0; i < rxValue.length(); i++) 26 | Serial.print(rxValue[i]); 27 | 28 | Serial.println(); 29 | Serial.println("*********"); 30 | } 31 | } 32 | }; 33 | 34 | void setup() { 35 | Serial.begin(115200); 36 | while(!Serial){}; 37 | Serial.println("Starting BLE work!"); 38 | 39 | BLEDevice::init("Long name works now"); 40 | BLEServer *pServer = BLEDevice::createServer(); 41 | BLEService *pService = pServer->createService(SERVICE_UUID); 42 | BLECharacteristic *pCharacteristic = pService->createCharacteristic( 43 | CHARACTERISTIC_UUID, 44 | BLECharacteristic::PROPERTY_READ | 45 | BLECharacteristic::PROPERTY_WRITE 46 | ); 47 | pCharacteristic->setAccessPermissions(GATT_PERM_READ | GATT_PERM_WRITE); 48 | BLEDescriptor *pDescriptor = pCharacteristic->createDescriptor( 49 | DESCRIPTOR_UUID, 50 | ATTRIB_FLAG_VOID | ATTRIB_FLAG_ASCII_Z, 51 | GATT_PERM_READ | GATT_PERM_WRITE, 52 | 2 53 | ); 54 | pCharacteristic->setValue("Hello World says Neil"); 55 | pCharacteristic->setCallbacks(new MyCallbacks()); 56 | pService->start(); 57 | 58 | // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility 59 | BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); 60 | pAdvertising->addServiceUUID(SERVICE_UUID); 61 | pAdvertising->setScanResponse(true); 62 | pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue 63 | pAdvertising->setMinPreferred(0x12); 64 | BLEDevice::startAdvertising(); 65 | Serial.println("Characteristic defined! Now you can read it in your phone!"); 66 | } 67 | 68 | void loop() { 69 | // put your main code here, to run repeatedly: 70 | Serial.println("1"); 71 | delay(2000); 72 | } 73 | -------------------------------------------------------------------------------- /examples/BLE_uart/BLE_uart.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Video: https://www.youtube.com/watch?v=oCMOYS71NIU 3 | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp 4 | Ported to Arduino ESP32 by Evandro Copercini 5 | 6 | Create a BLE server that, once we receive a connection, will send periodic notifications. 7 | The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E 8 | Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" 9 | Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY" 10 | 11 | The design of creating the BLE server is: 12 | 1. Create a BLE Server 13 | 2. Create a BLE Service 14 | 3. Create a BLE Characteristic on the Service 15 | 4. Create a BLE Descriptor on the characteristic 16 | 5. Start the service. 17 | 6. Start advertising. 18 | 19 | In this example rxValue is the data received (only accessible inside that function). 20 | And txValue is the data to be sent, in this example just a byte incremented every second. 21 | */ 22 | #include 23 | #include 24 | #include 25 | 26 | BLEServer *pServer = NULL; 27 | BLECharacteristic * pTxCharacteristic; 28 | bool deviceConnected = false; 29 | bool oldDeviceConnected = false; 30 | uint8_t txValue = 0; 31 | 32 | // See the following for generating UUIDs: 33 | // https://www.uuidgenerator.net/ 34 | 35 | #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID 36 | #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" 37 | #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" 38 | 39 | 40 | class MyServerCallbacks: public BLEServerCallbacks { 41 | void onConnect(BLEServer* pServer) { 42 | Serial.println("MyServerCallbacks onConnect "); 43 | deviceConnected = true; 44 | }; 45 | 46 | void onDisconnect(BLEServer* pServer) { 47 | deviceConnected = false; 48 | } 49 | }; 50 | 51 | class MyCallbacks: public BLECharacteristicCallbacks { 52 | void onWrite(BLECharacteristic *pCharacteristic) { 53 | std::string rxValue = pCharacteristic->getValue(); 54 | 55 | if (rxValue.length() > 0) { 56 | Serial.println("*********"); 57 | Serial.print("Received Value: "); 58 | for (int i = 0; i < rxValue.length(); i++) 59 | Serial.print(rxValue[i]); 60 | 61 | Serial.println(); 62 | Serial.println("*********"); 63 | } 64 | } 65 | }; 66 | 67 | 68 | void setup() { 69 | Serial.begin(115200); 70 | while(!Serial){}; 71 | // Create the BLE Device 72 | BLEDevice::init("UART Service"); 73 | 74 | // Create the BLE Server 75 | pServer = BLEDevice::createServer(); 76 | pServer->setCallbacks(new MyServerCallbacks()); 77 | 78 | // Create the BLE Service 79 | BLEService *pService = pServer->createService(SERVICE_UUID); 80 | 81 | // Create a BLE Characteristic 82 | pTxCharacteristic = pService->createCharacteristic( 83 | CHARACTERISTIC_UUID_TX, 84 | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ 85 | ); 86 | pTxCharacteristic->setAccessPermissions(GATT_PERM_READ); 87 | pTxCharacteristic->addDescriptor(new BLE2902()); 88 | 89 | BLECharacteristic * pRxCharacteristic = pService->createCharacteristic( 90 | CHARACTERISTIC_UUID_RX, 91 | BLECharacteristic::PROPERTY_WRITE 92 | ); 93 | pRxCharacteristic->setAccessPermissions(GATT_PERM_READ | GATT_PERM_WRITE); 94 | 95 | pRxCharacteristic->setCallbacks(new MyCallbacks()); 96 | 97 | // Start the service 98 | pService->start(); 99 | 100 | // Start advertising 101 | pServer->getAdvertising()->start(); 102 | Serial.println("Waiting a client connection to notify..."); 103 | } 104 | 105 | void loop() { 106 | 107 | if (deviceConnected) { 108 | 109 | pTxCharacteristic->setValue(&txValue, 1); 110 | pTxCharacteristic->notify(); 111 | txValue++; 112 | delay(10); // bluetooth stack will go into conges tion, if too many packets are sent 113 | } 114 | 115 | // disconnecting 116 | if (!deviceConnected && oldDeviceConnected) { 117 | delay(500); // give the bluetooth stack the chance to get things ready 118 | pServer->startAdvertising(); // restart advertising 119 | Serial.println("start advertising"); 120 | oldDeviceConnected = deviceConnected; 121 | } 122 | // connecting 123 | if (deviceConnected && !oldDeviceConnected) { 124 | // do stuff here on connecting 125 | oldDeviceConnected = deviceConnected; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For rpcBLE 3 | ####################################### 4 | 5 | ####################################### 6 | # Library (KEYWORD3) 7 | ####################################### 8 | BLEevice KEYWORD3 9 | rpcBLEevice KEYWORD3 10 | ####################################### 11 | # Datatypes (KEYWORD1) 12 | ####################################### 13 | BLESCan KEYWORD1 14 | BLEAdvertisedDevice KEYWORD1 15 | BLEAdvertising KEYWORD1 16 | BLEClient KEYWORD1 17 | BLEServer KEYWORD1 18 | BLEUUID KEYWORD1 19 | BLEAddress KEYWORD1 20 | BLEDesciptor KEYWORD1 21 | BLECharacteristic KEYWORD1 22 | BLEService KEYWORD1 23 | BLE2902 KEYWORD1 24 | BLE2904 KEYWORD1 25 | BLEBeacon KEYWORD1 26 | BLEValue KEYWORD1 27 | ####################################### 28 | # Methods and Functions (KEYWORD2) 29 | ####################################### 30 | connect KEYWORD2 31 | disconnect KEYWORD2 32 | isConnected KEYWORD2 33 | 34 | ####################################### 35 | # Constants (LITERAL1) 36 | ####################################### 37 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Seeed Arduino rpcBLE 2 | version=1.0.0 3 | author=Seeed Studio 4 | maintainer=Seeed Studio 5 | sentence=A lightweight BLE Arduino Library 6 | paragraph=A lightweight BLE Arduino library which communicates with RTL8720DN through Seeed_Arduino_rpcUnified to realize local Bluetooth access. 7 | category=Communication 8 | url=https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE.git 9 | architectures=* 10 | includes=rpcBLEDevice.h, BLEDevice.h, BLEUtils.h, BLEScan.h, BLEAdvertisedDevice.h 11 | -------------------------------------------------------------------------------- /src/BLE2902.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLE2902.cpp 3 | * 4 | * Created on: Jun 25, 2017 5 | * Author: kolban 6 | */ 7 | 8 | /* 9 | * See also: 10 | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml 11 | */ 12 | 13 | #include "BLE2902.h" 14 | 15 | BLE2902::BLE2902() : BLEDescriptor(BLEUUID((uint16_t) 0x2902), ATTRIB_FLAG_CCCD_APPL, (GATT_PERM_READ | GATT_PERM_WRITE), 2) { 16 | uint8_t data[2] = { 0, 0 }; 17 | setValue(data, 2); 18 | } // BLE2902 19 | 20 | 21 | /** 22 | * @brief Get the notifications value. 23 | * @return The notifications value. True if notifications are enabled and false if not. 24 | */ 25 | bool BLE2902::getNotifications() { 26 | return (getValue()[0] & (1 << 0)) != 0; 27 | } // getNotifications 28 | 29 | 30 | /** 31 | * @brief Get the indications value. 32 | * @return The indications value. True if indications are enabled and false if not. 33 | */ 34 | bool BLE2902::getIndications() { 35 | return (getValue()[0] & (1 << 1)) != 0; 36 | } // getIndications 37 | 38 | 39 | /** 40 | * @brief Set the indications flag. 41 | * @param [in] flag The indications flag. 42 | */ 43 | void BLE2902::setIndications(bool flag) { 44 | uint8_t *pValue = getValue(); 45 | if (flag) pValue[0] |= 1 << 1; 46 | else pValue[0] &= ~(1 << 1); 47 | } // setIndications 48 | 49 | 50 | /** 51 | * @brief Set the notifications flag. 52 | * @param [in] flag The notifications flag. 53 | */ 54 | void BLE2902::setNotifications(bool flag) { 55 | uint8_t *pValue = getValue(); 56 | if (flag) pValue[0] |= 1 << 0; 57 | else pValue[0] &= ~(1 << 0); 58 | } // setNotifications 59 | 60 | -------------------------------------------------------------------------------- /src/BLE2902.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLE2902.h 3 | * 4 | * Created on: Jun 25, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLE2902_H_ 9 | #define COMPONENTS_CPP_UTILS_BLE2902_H_ 10 | 11 | #include "BLEDescriptor.h" 12 | 13 | /** 14 | * @brief Descriptor for Client Characteristic Configuration. 15 | * 16 | * This is a convenience descriptor for the Client Characteristic Configuration which has a UUID of 0x2902. 17 | * 18 | * See also: 19 | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml 20 | */ 21 | class BLE2902: public BLEDescriptor { 22 | public: 23 | BLE2902(); 24 | bool getNotifications(); 25 | bool getIndications(); 26 | void setNotifications(bool flag); 27 | void setIndications(bool flag); 28 | 29 | }; // BLE2902 30 | 31 | #endif /* COMPONENTS_CPP_UTILS_BLE2902_H_ */ 32 | -------------------------------------------------------------------------------- /src/BLE2904.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLE2904.cpp 3 | * 4 | * Created on: Dec 23, 2017 5 | * Author: kolban 6 | */ 7 | 8 | /* 9 | * See also: 10 | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml 11 | */ 12 | #include "BLE2904.h" 13 | 14 | 15 | BLE2904::BLE2904() : BLEDescriptor(BLEUUID((uint16_t) 0x2904), ATTRIB_FLAG_VALUE_APPL, (GATT_PERM_READ | GATT_PERM_WRITE), sizeof(m_data)) { 16 | m_data.m_format = 0; 17 | m_data.m_exponent = 0; 18 | m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers 19 | m_data.m_unit = 0; 20 | m_data.m_description = 0; 21 | setValue((uint8_t*) &m_data, sizeof(m_data)); 22 | } // BLE2902 23 | 24 | 25 | /** 26 | * @brief Set the description. 27 | */ 28 | void BLE2904::setDescription(uint16_t description) { 29 | m_data.m_description = description; 30 | setValue((uint8_t*) &m_data, sizeof(m_data)); 31 | } 32 | 33 | 34 | /** 35 | * @brief Set the exponent. 36 | */ 37 | void BLE2904::setExponent(int8_t exponent) { 38 | m_data.m_exponent = exponent; 39 | setValue((uint8_t*) &m_data, sizeof(m_data)); 40 | } // setExponent 41 | 42 | 43 | /** 44 | * @brief Set the format. 45 | */ 46 | void BLE2904::setFormat(uint8_t format) { 47 | m_data.m_format = format; 48 | setValue((uint8_t*) &m_data, sizeof(m_data)); 49 | } // setFormat 50 | 51 | 52 | /** 53 | * @brief Set the namespace. 54 | */ 55 | void BLE2904::setNamespace(uint8_t namespace_value) { 56 | m_data.m_namespace = namespace_value; 57 | setValue((uint8_t*) &m_data, sizeof(m_data)); 58 | } // setNamespace 59 | 60 | 61 | /** 62 | * @brief Set the units for this value. It should be one of the encoded values defined here: 63 | * https://www.bluetooth.com/specifications/assigned-numbers/units 64 | * @param [in] unit The type of units of this characteristic as defined by assigned numbers. 65 | */ 66 | void BLE2904::setUnit(uint16_t unit) { 67 | m_data.m_unit = unit; 68 | setValue((uint8_t*) &m_data, sizeof(m_data)); 69 | } // setUnit -------------------------------------------------------------------------------- /src/BLE2904.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLE2904.h 3 | * 4 | * Created on: Dec 23, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLE2904_H_ 9 | #define COMPONENTS_CPP_UTILS_BLE2904_H_ 10 | #include "BLEDescriptor.h" 11 | 12 | struct BLE2904_Data { 13 | uint8_t m_format; 14 | int8_t m_exponent; 15 | uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units 16 | uint8_t m_namespace; 17 | uint16_t m_description; 18 | 19 | } __attribute__((packed)); 20 | 21 | /** 22 | * @brief Descriptor for Characteristic Presentation Format. 23 | * 24 | * This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904. 25 | * 26 | * See also: 27 | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml 28 | */ 29 | class BLE2904: public BLEDescriptor { 30 | public: 31 | BLE2904(); 32 | static const uint8_t FORMAT_BOOLEAN = 1; 33 | static const uint8_t FORMAT_UINT2 = 2; 34 | static const uint8_t FORMAT_UINT4 = 3; 35 | static const uint8_t FORMAT_UINT8 = 4; 36 | static const uint8_t FORMAT_UINT12 = 5; 37 | static const uint8_t FORMAT_UINT16 = 6; 38 | static const uint8_t FORMAT_UINT24 = 7; 39 | static const uint8_t FORMAT_UINT32 = 8; 40 | static const uint8_t FORMAT_UINT48 = 9; 41 | static const uint8_t FORMAT_UINT64 = 10; 42 | static const uint8_t FORMAT_UINT128 = 11; 43 | static const uint8_t FORMAT_SINT8 = 12; 44 | static const uint8_t FORMAT_SINT12 = 13; 45 | static const uint8_t FORMAT_SINT16 = 14; 46 | static const uint8_t FORMAT_SINT24 = 15; 47 | static const uint8_t FORMAT_SINT32 = 16; 48 | static const uint8_t FORMAT_SINT48 = 17; 49 | static const uint8_t FORMAT_SINT64 = 18; 50 | static const uint8_t FORMAT_SINT128 = 19; 51 | static const uint8_t FORMAT_FLOAT32 = 20; 52 | static const uint8_t FORMAT_FLOAT64 = 21; 53 | static const uint8_t FORMAT_SFLOAT16 = 22; 54 | static const uint8_t FORMAT_SFLOAT32 = 23; 55 | static const uint8_t FORMAT_IEEE20601 = 24; 56 | static const uint8_t FORMAT_UTF8 = 25; 57 | static const uint8_t FORMAT_UTF16 = 26; 58 | static const uint8_t FORMAT_OPAQUE = 27; 59 | 60 | void setDescription(uint16_t); 61 | void setExponent(int8_t exponent); 62 | void setFormat(uint8_t format); 63 | void setNamespace(uint8_t namespace_value); 64 | void setUnit(uint16_t unit); 65 | 66 | private: 67 | BLE2904_Data m_data; 68 | }; // BLE2904 69 | 70 | #endif /* COMPONENTS_CPP_UTILS_BLE2904_H_ */ 71 | -------------------------------------------------------------------------------- /src/BLEAddress.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEAddress.cpp 3 | * 4 | * Created on: Jul 2, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #include "BLEAddress.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | /** 18 | * @brief Determine if this address equals another. 19 | * @param [in] otherAddress The other address to compare against. 20 | * @return True if the addresses are equal. 21 | */ 22 | bool BLEAddress::equals(BLEAddress otherAddress) { 23 | return memcmp(otherAddress.getNative(), m_address, 6) == 0; 24 | } // equals 25 | 26 | 27 | /** 28 | * @brief Return the native representation of the address. 29 | * @return The native representation of the address. 30 | */ 31 | bd_addr_t *BLEAddress::getNative() { 32 | return &m_address; 33 | } // getNative 34 | 35 | 36 | /** 37 | * @brief Create an address from a hex string 38 | * 39 | * A hex string is of the format: 40 | * ``` 41 | * 00:00:00:00:00:00 42 | * ``` 43 | * which is 17 characters in length. 44 | * 45 | * @param [in] stringAddress The hex representation of the address. 46 | */ 47 | BLEAddress::BLEAddress(std::string stringAddress) { 48 | if (stringAddress.length() != 17) return; 49 | 50 | int data[6]; 51 | sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]); 52 | m_address[0] = (uint8_t) data[0]; 53 | m_address[1] = (uint8_t) data[1]; 54 | m_address[2] = (uint8_t) data[2]; 55 | m_address[3] = (uint8_t) data[3]; 56 | m_address[4] = (uint8_t) data[4]; 57 | m_address[5] = (uint8_t) data[5]; 58 | } // BLEAddress 59 | 60 | 61 | /** 62 | * @brief Create an address from the native ESP32 representation. 63 | * @param [in] address The native representation. 64 | */ 65 | BLEAddress::BLEAddress(bd_addr_t address) { 66 | memcpy(m_address, address, BD_ADDR_LEN); 67 | } // BLEAddress 68 | 69 | /** 70 | * @brief Convert a BLE address to a string. 71 | * 72 | * A string representation of an address is in the format: 73 | * 74 | * ``` 75 | * xx:xx:xx:xx:xx:xx 76 | * ``` 77 | * 78 | * @return The string representation of the address. 79 | */ 80 | std::string BLEAddress::toString() { 81 | auto size = 18; 82 | char *res = (char*)malloc(size); 83 | snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]); 84 | std::string ret(res); 85 | free(res); 86 | return ret; 87 | } // toString 88 | 89 | -------------------------------------------------------------------------------- /src/BLEAddress.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEAddress.h 3 | * 4 | * Created on: Jul 2, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEADDRESS_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEADDRESS_H_ 10 | 11 | #include 12 | 13 | /// Bluetooth address length 14 | #define BD_ADDR_LEN 6 15 | 16 | /// Bluetooth device address 17 | typedef uint8_t bd_addr_t[BD_ADDR_LEN]; 18 | 19 | /** 20 | * @brief A %BLE device address. 21 | * 22 | * Every %BLE device has a unique address which can be used to identify it and form connections. 23 | */ 24 | class BLEAddress { 25 | public: 26 | BLEAddress(bd_addr_t address); 27 | BLEAddress(std::string stringAddress); 28 | bool equals(BLEAddress otherAddress); 29 | bd_addr_t* getNative(); 30 | std::string toString(); 31 | 32 | private: 33 | bd_addr_t m_address; 34 | }; 35 | 36 | #endif /* COMPONENTS_CPP_UTILS_BLEADDRESS_H_ */ 37 | -------------------------------------------------------------------------------- /src/BLEAdvertisedDevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEAdvertisedDevice.h 3 | * 4 | * Created on: Jul 3, 2020 5 | * Author: coolc 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ 10 | 11 | #include 12 | #include "BLEScan.h" 13 | #include "BLEAddress.h" 14 | #include "BLEUUID.h" 15 | #include 16 | #include "seeed_rpcUnified.h" 17 | #include "rtl_ble/ble_unified.h" 18 | 19 | class BLEScan; 20 | 21 | /** 22 | * @brief A representation of a %BLE advertised device found by a scan. 23 | * 24 | * When we perform a %BLE scan, the result will be a set of devices that are advertising. This 25 | * class provides a model of a detected device. 26 | */ 27 | class BLEAdvertisedDevice { 28 | public: 29 | BLEAdvertisedDevice(); 30 | BLEAddress getAddress(); 31 | std::string getName(); 32 | BLEUUID getServiceUUID(); 33 | BLEUUID getServiceUUID(int i); 34 | uint16_t getAppearance(); 35 | int8_t getTXPower(); 36 | uint8_t* getManufacturerData(); 37 | uint8_t getManufacturerDataLength(); 38 | uint8_t* getServiceData(); 39 | uint8_t getServiceDataLength(); 40 | int getRSSI(); 41 | BLEScan* getScan(); 42 | std::string toString(); 43 | bool haveServiceUUID(); 44 | bool haveTXPower(); 45 | bool haveName(); 46 | bool haveAppearance(); 47 | bool haveRSSI(); 48 | void setAddressType(T_GAP_REMOTE_ADDR_TYPE type); 49 | bool isAdvertisingService(BLEUUID uuid); 50 | T_GAP_REMOTE_ADDR_TYPE getAddressType(); 51 | bool haveManufacturerData(); 52 | bool haveServiceData(); 53 | private: 54 | friend class BLEScan; 55 | void clear(void); 56 | bool m_haveAppearance; 57 | bool m_haveServiceUUID; 58 | bool m_haveTXPower; 59 | bool m_haveManufacturerData; 60 | bool m_haveName; 61 | bool m_haveRSSI; 62 | bool m_haveServiceData; 63 | std::vector m_serviceUUIDs; 64 | 65 | T_GAP_ADV_EVT_TYPE _advType; 66 | T_GAP_REMOTE_ADDR_TYPE _addrType; 67 | BLEAddress m_address = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); 68 | 69 | uint8_t m_data[31] ={0}; // array for storing formatted advertising data for receiving and sending 70 | uint8_t m_dataSize = 0; 71 | int m_rssi; 72 | BLEScan* m_pScan; 73 | uint8_t m_adFlag; 74 | uint8_t m_serviceCount = 0; 75 | std::string m_name; 76 | int8_t m_txPower = 0; 77 | uint16_t m_appearance = 0; 78 | uint16_t m_manufacturer = 0; 79 | uint8_t m_manufacturerData[27] = {0}; 80 | uint8_t m_manufacturerDataLength = 0; 81 | uint8_t m_serviceData[27] = {0}; 82 | uint8_t m_serviceDataLength = 0; 83 | BLEUUID _serviceList[7]; // A 31byte advert can only fit a maximum of 7 service UUIDs of 16bit length 84 | uint8_t _serviceCount = 0; 85 | int m_deviceType; 86 | void parseAdvertisement(T_LE_CB_DATA *p_data); 87 | void setAddress(BLEAddress address); 88 | void setRSSI(int rssi); 89 | void setScan(BLEScan* pScan); 90 | void setServiceUUID(BLEUUID serviceUUID); 91 | T_GAP_REMOTE_ADDR_TYPE m_addressType; 92 | }; 93 | /** 94 | * @brief A callback handler for callbacks associated device scanning. 95 | * 96 | * When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising 97 | * has been found. This class can be sub-classed and registered such that when a scan is performed and 98 | * a new advertised device has been found, we will be called back to be notified. 99 | */ 100 | class BLEAdvertisedDeviceCallbacks { 101 | public: 102 | virtual ~BLEAdvertisedDeviceCallbacks() {} 103 | /** 104 | * @brief Called when a new scan result is detected. 105 | * 106 | * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the 107 | * device that was found. During any individual scan, a device will only be detected one time. 108 | */ 109 | virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0; 110 | }; 111 | #endif /* COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ */ 112 | -------------------------------------------------------------------------------- /src/BLEAdvertising.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEAdvertising.h 3 | * 4 | * Created on: Jun 21, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ 10 | #include "BLEUUID.h" 11 | #include 12 | #include "BLEFreeRTOS.h" 13 | #include "seeed_rpcUnified.h" 14 | #include "rtl_ble/ble_unified.h" 15 | 16 | 17 | /// Advertising data type 18 | typedef enum { 19 | adv_data, 20 | adv_scan_data, 21 | } ble_adv_data_type; 22 | 23 | 24 | 25 | /** 26 | * @brief Advertisement data set by the programmer to be published by the %BLE server. 27 | */ 28 | class BLEAdvertisementData { 29 | public: 30 | void setAppearance(uint16_t appearance); 31 | void setCompleteServices(BLEUUID uuid); 32 | void setFlags(uint8_t); 33 | void setManufacturerData(std::string data); 34 | void setName(std::string name); 35 | void setPartialServices(BLEUUID uuid); 36 | void setServiceData(BLEUUID uuid, std::string data); 37 | void setShortName(std::string name); 38 | void addData(std::string data); // Add data to the payload. 39 | std::string getPayload(); // Retrieve the current advert payload. 40 | 41 | 42 | private: 43 | friend class BLEAdvertising; 44 | std::string m_payload; // The payload of the advertisement. 45 | }; // BLEAdvertisementData 46 | 47 | 48 | 49 | /** 50 | * @brief Perform and manage %BLE advertising. 51 | * 52 | * A %BLE server will want to perform advertising in order to make itself known to %BLE clients. 53 | */ 54 | class BLEAdvertising { 55 | public: 56 | BLEAdvertising(); 57 | void start(); 58 | void stop(); 59 | void setAppearance(uint16_t appearance); 60 | void addServiceUUID(const char* serviceUUID); 61 | uint8_t addServiceUUID(BLEUUID serviceUUID); 62 | void setScanResponse(bool); 63 | void setMinPreferred(uint16_t); 64 | void setMaxPreferred(uint16_t); 65 | void setMaxInterval(uint16_t maxinterval); 66 | void setMinInterval(uint16_t mininterval); 67 | void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly); 68 | void setDeviceAddress(uint8_t* addr, T_GAP_REMOTE_ADDR_TYPE type); 69 | uint8_t addCompleteName(const char* str); 70 | uint8_t addShortName(const char* str); 71 | uint8_t addFlags(uint8_t flags); 72 | void setAdvData(); 73 | void addData(const uint8_t* data, uint8_t size,ble_adv_data_type type); 74 | void setAdvertisementData(BLEAdvertisementData& advertisementData); 75 | void setScanResponseData(BLEAdvertisementData& advertisementData); 76 | void setAdvertisementType(uint8_t adv_type); 77 | T_APP_RESULT handleGAPEvent(uint8_t cb_type, void *p_cb_data); 78 | private: 79 | bool m_customAdvData = false; // Are we using custom advertising data? 80 | bool m_customScanResponseData = false; 81 | 82 | uint8_t _data[31] ={0}; // array for storing formatted advertising data for receiving and sending 83 | uint8_t _dataSize = 0; 84 | 85 | uint8_t scan_data[31] ={0}; // array for storing formatted advertising data for receiving and sending 86 | uint8_t scan_dataSize = 0; 87 | String _devName; 88 | int m_appearance; 89 | 90 | uint8_t _serviceCount = 0; 91 | BLEUUID _serviceList[7]; 92 | std::vector m_serviceUUIDs; 93 | uint16_t _advIntMin = 320; // Minimum advertising interval for undirected and low duty cycle directed advertising. Value range: 0x0020 - 0x4000 (20ms - 10240ms)(0.625ms/step) 94 | uint16_t _advIntMax = 480; // Maximum advertising interval for undirected and low duty cycle directed advertising. Value range: 0x0020 - 0x4000 (20ms - 10240ms)(0.625ms/step) 95 | uint8_t _slaveInitMtuReq = false; 96 | uint8_t _advEvtType = GAP_ADTYPE_ADV_IND; 97 | uint8_t _advDirectType = GAP_REMOTE_ADDR_LE_PUBLIC; 98 | uint8_t _advDirectAddr[GAP_BD_ADDR_LEN] = {0}; 99 | uint8_t _advChannMap = GAP_ADVCHAN_ALL; 100 | uint8_t _advFilterPolicy = GAP_ADV_FILTER_ANY; 101 | 102 | uint8_t _scanRspData[31] = { 103 | 0x03, /* length */ 104 | GAP_ADTYPE_APPEARANCE, /* type="Appearance" */ 105 | LO_WORD(GAP_GATT_APPEARANCE_MOUSE), 106 | HI_WORD(GAP_GATT_APPEARANCE_MOUSE), 107 | }; 108 | uint8_t _advDataSize = 18; 109 | uint8_t _scanRspDataSize = 4; 110 | 111 | uint8_t _advData[31] = { 112 | /* Flags */ 113 | 0x02, /* length */ 114 | GAP_ADTYPE_FLAGS, /* type="Flags" */ 115 | GAP_ADTYPE_FLAGS_LIMITED | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED, 116 | /* Local name */ 117 | 0x0E, /* length */ 118 | GAP_ADTYPE_LOCAL_NAME_COMPLETE, 119 | }; 120 | 121 | }; 122 | #endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ 123 | -------------------------------------------------------------------------------- /src/BLEBeacon.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEBeacon.cpp 3 | * 4 | * Created on: Jan 4, 2018 5 | * Author: kolban 6 | */ 7 | #include 8 | #include "BLEBeacon.h" 9 | 10 | #define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) 11 | 12 | 13 | BLEBeacon::BLEBeacon() { 14 | m_beaconData.manufacturerId = 0x4c00; 15 | m_beaconData.subType = 0x02; 16 | m_beaconData.subTypeLength = 0x15; 17 | m_beaconData.major = 0; 18 | m_beaconData.minor = 0; 19 | m_beaconData.signalPower = 0; 20 | memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID)); 21 | } // BLEBeacon 22 | 23 | std::string BLEBeacon::getData() { 24 | return std::string((char*) &m_beaconData, sizeof(m_beaconData)); 25 | } // getData 26 | 27 | uint16_t BLEBeacon::getMajor() { 28 | return m_beaconData.major; 29 | } 30 | 31 | uint16_t BLEBeacon::getManufacturerId() { 32 | return m_beaconData.manufacturerId; 33 | } 34 | 35 | uint16_t BLEBeacon::getMinor() { 36 | return m_beaconData.minor; 37 | } 38 | 39 | BLEUUID BLEBeacon::getProximityUUID() { 40 | return BLEUUID(m_beaconData.proximityUUID, 16, false); 41 | } 42 | 43 | int8_t BLEBeacon::getSignalPower() { 44 | return m_beaconData.signalPower; 45 | } 46 | 47 | /** 48 | * Set the raw data for the beacon record. 49 | */ 50 | void BLEBeacon::setData(std::string data) { 51 | if (data.length() != sizeof(m_beaconData)) { 52 | return; 53 | } 54 | memcpy(&m_beaconData, data.data(), sizeof(m_beaconData)); 55 | } // setData 56 | 57 | void BLEBeacon::setMajor(uint16_t major) { 58 | m_beaconData.major = ENDIAN_CHANGE_U16(major); 59 | } // setMajor 60 | 61 | void BLEBeacon::setManufacturerId(uint16_t manufacturerId) { 62 | m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId); 63 | } // setManufacturerId 64 | 65 | void BLEBeacon::setMinor(uint16_t minor) { 66 | m_beaconData.minor = ENDIAN_CHANGE_U16(minor); 67 | } // setMinior 68 | 69 | void BLEBeacon::setProximityUUID(BLEUUID uuid) { 70 | uuid = uuid.to128(); 71 | memcpy(m_beaconData.proximityUUID, uuid.getNative()->uuid.uuid128, 16); 72 | } // setProximityUUID 73 | 74 | void BLEBeacon::setSignalPower(int8_t signalPower) { 75 | m_beaconData.signalPower = signalPower; 76 | } // setSignalPower 77 | 78 | -------------------------------------------------------------------------------- /src/BLEBeacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEBeacon2.h 3 | * 4 | * Created on: Jan 4, 2018 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEBEACON_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEBEACON_H_ 10 | #include "BLEUUID.h" 11 | /** 12 | * @brief Representation of a beacon. 13 | * See: 14 | * * https://en.wikipedia.org/wiki/IBeacon 15 | */ 16 | class BLEBeacon { 17 | private: 18 | struct { 19 | uint16_t manufacturerId; 20 | uint8_t subType; 21 | uint8_t subTypeLength; 22 | uint8_t proximityUUID[16]; 23 | uint16_t major; 24 | uint16_t minor; 25 | int8_t signalPower; 26 | } __attribute__((packed)) m_beaconData; 27 | public: 28 | BLEBeacon(); 29 | std::string getData(); 30 | uint16_t getMajor(); 31 | uint16_t getMinor(); 32 | uint16_t getManufacturerId(); 33 | BLEUUID getProximityUUID(); 34 | int8_t getSignalPower(); 35 | void setData(std::string data); 36 | void setMajor(uint16_t major); 37 | void setMinor(uint16_t minor); 38 | void setManufacturerId(uint16_t manufacturerId); 39 | void setProximityUUID(BLEUUID uuid); 40 | void setSignalPower(int8_t signalPower); 41 | }; // BLEBeacon 42 | 43 | #endif /* COMPONENTS_CPP_UTILS_BLEBEACON_H_ */ 44 | -------------------------------------------------------------------------------- /src/BLECharacteristic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLECharacteristic.h 3 | * 4 | * Created on: Jun 22, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ 9 | #define COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ 10 | #include 11 | #include 12 | #include "BLEUUID.h" 13 | #include "BLEDescriptor.h" 14 | #include "BLEValue.h" 15 | #include "BLEFreeRTOS.h" 16 | #include "seeed_rpcUnified.h" 17 | #include "rtl_ble/ble_unified.h" 18 | 19 | class BLEService; 20 | class BLEDescriptor; 21 | class BLECharacteristicCallbacks; 22 | 23 | /** 24 | * @brief A management structure for %BLE descriptors. 25 | */ 26 | class BLEDescriptorMap { 27 | public: 28 | void setByUUID(const char* uuid, BLEDescriptor* pDescriptor); 29 | void setByUUID(BLEUUID uuid, BLEDescriptor* pDescriptor); 30 | void setByHandle(uint16_t handle, BLEDescriptor* pDescriptor); 31 | BLEDescriptor* getByUUID(const char* uuid); 32 | BLEDescriptor* getByUUID(BLEUUID uuid); 33 | BLEDescriptor* getFirst(); 34 | BLEDescriptor* getNext(); 35 | BLEDescriptor* getByHandle(uint16_t handle); 36 | std::string toString(); 37 | void handleGATTServerEvent(T_SERVER_ID service_id, void *p_data); 38 | 39 | private: 40 | std::map m_uuidMap; 41 | std::map m_handleMap; 42 | std::map::iterator m_iterator; 43 | }; 44 | 45 | 46 | /** 47 | * @brief The model of a %BLE Characteristic. 48 | * 49 | * A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE server and 50 | * can be read and written to by a %BLE client. 51 | */ 52 | class BLECharacteristic { 53 | public: 54 | BLECharacteristic(const char* uuid, uint32_t properties = 0); 55 | BLECharacteristic(BLEUUID uuid, uint32_t properties = 0); 56 | virtual ~BLECharacteristic(); 57 | void setBroadcastProperty(bool value); 58 | void setReadProperty(bool value); 59 | void setWriteProperty(bool value); 60 | void setNotifyProperty(bool value); 61 | void setIndicateProperty(bool value); 62 | void setWriteNoResponseProperty(bool value); 63 | void setValue(double& data64); 64 | void setValue(float& data32); 65 | void setValue(int& data32); 66 | void setValue(uint32_t& data32); 67 | void setValue(uint16_t& data16); 68 | void setValue(std::string value); 69 | void setValue(uint8_t* data, size_t size); 70 | void setAccessPermissions(uint32_t perm); 71 | void setCallbacks(BLECharacteristicCallbacks* pCallbacks); 72 | BLEDescriptor* createDescriptor(BLEUUID uuid,uint16_t flags,uint32_t permissions,uint16_t max_len); 73 | BLEDescriptor* createDescriptor(const char* uuid, uint16_t flags,uint32_t permissions,uint16_t max_len); 74 | void addDescriptor(BLEDescriptor* pDescriptor); 75 | BLEDescriptor* getDescriptorByUUID(const char* descriptorUUID); 76 | BLEDescriptor* getDescriptorByUUID(BLEUUID descriptorUUID); 77 | BLEService* getService(); 78 | std::string getValue(); 79 | void indicate(); 80 | void notify(bool is_notification = true); 81 | BLEUUID getUUID(); 82 | uint8_t* getData(); 83 | uint8_t getHandle(); 84 | uint32_t getAccessPermissions(); 85 | std::string toString(); 86 | static const uint32_t PROPERTY_READ = GATT_CHAR_PROP_READ; 87 | static const uint32_t PROPERTY_WRITE = GATT_CHAR_PROP_WRITE; 88 | static const uint32_t PROPERTY_NOTIFY = GATT_CHAR_PROP_NOTIFY; 89 | static const uint32_t PROPERTY_BROADCAST = GATT_CHAR_PROP_BROADCAST; 90 | static const uint32_t PROPERTY_INDICATE = GATT_CHAR_PROP_INDICATE; 91 | static const uint32_t PROPERTY_WRITE_NR = GATT_CHAR_PROP_WRITE_NO_RSP; 92 | 93 | static const uint32_t indicationTimeout = 1000; 94 | 95 | private: 96 | friend class BLEServer; 97 | friend class BLEService; 98 | friend class BLECharacteristicMap; 99 | friend class BLEDescriptor; 100 | 101 | BLEUUID m_bleUUID; 102 | uint8_t m_handle; 103 | uint8_t m_properties; 104 | uint32_t m_permissions; 105 | BLECharacteristicCallbacks* m_pCallbacks; 106 | 107 | 108 | BLEValue m_value; 109 | BLEService* m_pService; 110 | BLEDescriptorMap m_descriptorMap; 111 | 112 | void executeCreate(BLEService* pService); 113 | uint8_t getProperties(); 114 | void handleGATTServerEvent(T_SERVER_ID service_id, void *p_data); 115 | BLEFreeRTOS::Semaphore m_semaphoreCreateEvt = BLEFreeRTOS::Semaphore("CreateEvt"); 116 | BLEFreeRTOS::Semaphore m_semaphoreSetValue = BLEFreeRTOS::Semaphore("SetValue"); 117 | BLEFreeRTOS::Semaphore m_semaphoreConfEvt = BLEFreeRTOS::Semaphore("ConfEvt"); 118 | 119 | 120 | 121 | }; // BLECharacteristic 122 | 123 | 124 | /** 125 | * @brief Callbacks that can be associated with a %BLE characteristic to inform of events. 126 | * 127 | * When a server application creates a %BLE characteristic, we may wish to be informed when there is either 128 | * a read or write request to the characteristic's value. An application can register a 129 | * sub-classed instance of this class and will be notified when such an event happens. 130 | */ 131 | class BLECharacteristicCallbacks { 132 | public: 133 | typedef enum { 134 | SUCCESS_INDICATE, 135 | SUCCESS_NOTIFY, 136 | ERROR_INDICATE_DISABLED, 137 | ERROR_NOTIFY_DISABLED, 138 | ERROR_GATT, 139 | ERROR_NO_CLIENT, 140 | ERROR_INDICATE_TIMEOUT, 141 | ERROR_INDICATE_FAILURE 142 | }Status; 143 | 144 | virtual ~BLECharacteristicCallbacks(); 145 | virtual void onRead(BLECharacteristic* pCharacteristic); 146 | virtual void onWrite(BLECharacteristic* pCharacteristic); 147 | virtual void onNotify(BLECharacteristic* pCharacteristic); 148 | virtual void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code); 149 | 150 | }; 151 | #endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */ 152 | -------------------------------------------------------------------------------- /src/BLECharacteristicMap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLECharacteristicMap.cpp 3 | * 4 | * Created on: Jun 22, 2017 5 | * Author: kolban 6 | */ 7 | #include 8 | #include 9 | #include "BLEService.h" 10 | #include "Arduino.h" 11 | 12 | 13 | /** 14 | * @brief Set the characteristic by UUID. 15 | * @param [in] uuid The uuid of the characteristic. 16 | * @param [in] characteristic The characteristic to cache. 17 | * @return N/A. 18 | */ 19 | void BLECharacteristicMap::setByUUID(BLECharacteristic* pCharacteristic, BLEUUID uuid) { 20 | m_uuidMap.insert(std::pair(pCharacteristic, uuid.toString())); 21 | } // setByUUID 22 | 23 | 24 | /** 25 | * @brief Set the characteristic by handle. 26 | * @param [in] handle The handle of the characteristic. 27 | * @param [in] characteristic The characteristic to cache. 28 | * @return N/A. 29 | */ 30 | void BLECharacteristicMap::setByHandle(uint16_t handle, BLECharacteristic* characteristic) { 31 | m_handleMap.insert(std::pair(handle, characteristic)); 32 | } // setByHandle 33 | 34 | 35 | 36 | /** 37 | * @brief Return the characteristic by handle. 38 | * @param [in] handle The handle to look up the characteristic. 39 | * @return The characteristic. 40 | */ 41 | BLECharacteristic* BLECharacteristicMap::getByHandle(uint16_t handle) { 42 | return m_handleMap.at(handle); 43 | } // getByHandle 44 | 45 | /** 46 | * @brief Return the characteristic by UUID. 47 | * @param [in] UUID The UUID to look up the characteristic. 48 | * @return The characteristic. 49 | */ 50 | BLECharacteristic* BLECharacteristicMap::getByUUID(BLEUUID uuid) { 51 | for (auto &myPair : m_uuidMap) { 52 | if (myPair.first->getUUID().equals(uuid)) { 53 | return myPair.first; 54 | } 55 | } 56 | return nullptr; 57 | } // getByUUID 58 | 59 | /** 60 | * @brief Get the first characteristic in the map. 61 | * @return The first characteristic in the map. 62 | */ 63 | BLECharacteristic* BLECharacteristicMap::getFirst() { 64 | m_iterator = m_uuidMap.begin(); 65 | if (m_iterator == m_uuidMap.end()) return nullptr; 66 | BLECharacteristic* pRet = m_iterator->first; 67 | m_iterator++; 68 | return pRet; 69 | } // getFirst 70 | 71 | 72 | /** 73 | * @brief Get the next characteristic in the map. 74 | * @return The next characteristic in the map. 75 | */ 76 | BLECharacteristic* BLECharacteristicMap::getNext() { 77 | if (m_iterator == m_uuidMap.end()) return nullptr; 78 | BLECharacteristic* pRet = m_iterator->first; 79 | m_iterator++; 80 | return pRet; 81 | } // getNext 82 | 83 | 84 | /** 85 | * @brief Pass the GATT server event onwards to each of the characteristics found in the mapping 86 | * @param [in] event 87 | * @param [in] gatts_if 88 | * @param [in] param 89 | */ 90 | void BLECharacteristicMap::handleGATTServerEvent(T_SERVER_ID service_id, void *p_data) { 91 | // Invoke the handler for every Service we have. 92 | for (auto& myPair : m_uuidMap) { 93 | myPair.first->handleGATTServerEvent(service_id,p_data); 94 | } 95 | } // handleGATTServerEvent 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/BLEClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEDevice.cpp 3 | * 4 | * Created on: Mar 22, 2017 5 | * Author: kolban 6 | */ 7 | #define TAG "client" 8 | #include "BLEClient.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "BLEDevice.h" 14 | #include "rpc_unified_log.h" 15 | #include "BLEAdvertisedDevice.h" 16 | 17 | uint16_t BLEDevice::m_appId = 0; 18 | BLEClient::BLEClient() { 19 | m_pClientCallbacks = nullptr; 20 | m_conn_id = 0xff; 21 | m_gattc_if = 0xff; 22 | m_haveServices = false; 23 | m_isConnected = false; // Initially, we are flagged as not connected. 24 | } // BLEClient 25 | 26 | 27 | /** 28 | * @brief Destructor. 29 | */ 30 | BLEClient::~BLEClient() { 31 | // We may have allocated service references associated with this client. Before we are finished 32 | // with the client, we must release resources. 33 | for (auto &myPair : m_servicesMap) { 34 | delete myPair.second; 35 | } 36 | m_servicesMap.clear(); 37 | } // ~BLEClient 38 | 39 | 40 | /** 41 | * @brief Set the callbacks that will be invoked. 42 | */ 43 | void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) { 44 | m_pClientCallbacks = pClientCallbacks; 45 | } // setClientCallbacks 46 | 47 | 48 | /** 49 | * @brief Set the value of a specific characteristic associated with a specific service. 50 | * @param [in] serviceUUID The service that owns the characteristic. 51 | * @param [in] characteristicUUID The characteristic whose value we wish to write. 52 | * @throws BLEUuidNotFound 53 | */ 54 | void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) { 55 | getService(serviceUUID)->getCharacteristic(characteristicUUID)->writeValue(value); 56 | } // setValue 57 | 58 | /** 59 | * Add overloaded function to ease connect to peer device with not public address 60 | */ 61 | bool BLEClient::connect(BLEAdvertisedDevice* device) { 62 | /* 63 | * client initialization 64 | */ 65 | ble_client_init(BLE_CLIENT_MAX_APPS); 66 | T_CLIENT_ID client_id = ble_add_client(0, BLE_LE_MAX_LINKS); 67 | m_gattc_if = client_id; 68 | BLEAddress address = device->getAddress(); 69 | T_GAP_REMOTE_ADDR_TYPE type = device->getAddressType(); 70 | return connect(address, type); 71 | } 72 | 73 | 74 | /** 75 | * @brief Connect to the partner (BLE Server). 76 | * @param [in] address The address of the partner. 77 | * @return True on success. 78 | */ 79 | bool BLEClient::connect(BLEAddress address, T_GAP_REMOTE_ADDR_TYPE type) { 80 | 81 | m_appId = BLEDevice::m_appId++; 82 | BLEDevice::addPeerDevice(this, true, m_appId); 83 | m_peerAddress = address; 84 | 85 | //connect client 86 | T_GAP_LE_CONN_REQ_PARAM conn_req_param; 87 | conn_req_param.scan_interval = 0x10; 88 | conn_req_param.scan_window = 0x10; 89 | conn_req_param.conn_interval_min = 80; 90 | conn_req_param.conn_interval_max = 80; 91 | conn_req_param.conn_latency = 0; 92 | conn_req_param.supv_tout = 1000; 93 | conn_req_param.ce_len_min = 2 * (conn_req_param.conn_interval_min - 1); 94 | conn_req_param.ce_len_max = 2 * (conn_req_param.conn_interval_max - 1); 95 | le_set_conn_param(GAP_CONN_PARAM_1M, &conn_req_param); 96 | 97 | T_GAP_CAUSE result = le_connect(0, (uint8_t *)address.getNative(), type, GAP_LOCAL_ADDR_LE_PUBLIC, 1000); 98 | if (result == GAP_CAUSE_SUCCESS) 99 | { 100 | m_isConnected = true; 101 | } 102 | delay(2000); 103 | uint8_t conn_id = 0xff; 104 | le_get_conn_id((uint8_t *)address.getNative(), GAP_REMOTE_ADDR_LE_PUBLIC, &conn_id); 105 | m_conn_id = conn_id; 106 | } // connect 107 | 108 | uint8_t BLEClient::getGattcIf() { 109 | return m_gattc_if; 110 | } // getGattcIf 111 | 112 | uint16_t BLEClient::getConnId() { 113 | return m_conn_id; 114 | } // getConnId 115 | 116 | /** 117 | * @brief Retrieve the address of the peer. 118 | * 119 | * Returns the Bluetooth device address of the %BLE peer to which this client is connected. 120 | */ 121 | BLEAddress BLEClient::getPeerAddress() { 122 | return m_peerAddress; 123 | } // getAddress 124 | 125 | /** 126 | * @brief Ask the BLE server for the RSSI value. 127 | * @return The RSSI value. 128 | */ 129 | int BLEClient::getRssi() { 130 | if (!isConnected()) { 131 | RPC_DEBUG("<< getRssi(): Not connected"); 132 | return 0; 133 | } 134 | // We make the API call to read the RSSI value which is an asynchronous operation. We expect to receive 135 | // an ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT to indicate completion. 136 | // 137 | m_semaphoreRssiCmplEvt.take("getRssi"); 138 | le_read_rssi(getConnId()); 139 | int rssiValue = m_semaphoreRssiCmplEvt.wait("getRssi"); 140 | return rssiValue; 141 | } // getRssi 142 | 143 | uint16_t BLEClient::getMTU() { 144 | return m_mtu; 145 | } 146 | 147 | 148 | uint16_t BLEClient::setMTU(uint16_t mtu_size) { 149 | m_mtu = mtu_size; 150 | return m_mtu; 151 | } 152 | /** 153 | * @brief Get the value of a specific characteristic associated with a specific service. 154 | * @param [in] serviceUUID The service that owns the characteristic. 155 | * @param [in] characteristicUUID The characteristic whose value we wish to read. 156 | * @throws BLEUuidNotFound 157 | */ 158 | std::string BLEClient::getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID) { 159 | std::string ret = getService(serviceUUID)->getCharacteristic(characteristicUUID)->readValue(); 160 | return ret; 161 | } // getValue 162 | 163 | 164 | /** 165 | * @brief Disconnect from the peer. 166 | * @return N/A. 167 | */ 168 | void BLEClient::disconnect() { 169 | le_disconnect(getConnId()); 170 | } // disconnect 171 | 172 | /** 173 | * @brief Are we connected to a partner? 174 | * @return True if we are connected and false if we are not connected. 175 | */ 176 | bool BLEClient::isConnected() { 177 | return m_isConnected; 178 | } // isConnected 179 | 180 | /** 181 | * @brief Get the service BLE Remote Service instance corresponding to the uuid. 182 | * @param [in] uuid The UUID of the service being sought. 183 | * @return A reference to the Service or nullptr if don't know about it. 184 | */ 185 | BLERemoteService* BLEClient::getService(const char* uuid) { 186 | return getService(BLEUUID(uuid)); 187 | } // getService 188 | 189 | /** 190 | * @brief Get the service object corresponding to the uuid. 191 | * @param [in] uuid The UUID of the service being sought. 192 | * @return A reference to the Service or nullptr if don't know about it. 193 | * @throws BLEUuidNotFound 194 | */ 195 | BLERemoteService* BLEClient::getService(BLEUUID uuid) { 196 | if (!m_haveServices) { 197 | getServices(); 198 | } 199 | std::string uuidStr = uuid.toString(); 200 | 201 | for (auto &myPair : m_servicesMap) { 202 | if (myPair.first == uuidStr) { 203 | return myPair.second; 204 | } 205 | } // End of each of the services. 206 | 207 | RPC_DEBUG("end BLEClient::getServices():\n\r "); 208 | return nullptr; 209 | } // getService 210 | 211 | /** 212 | * @brief Ask the remote %BLE server for its services. 213 | * A %BLE Server exposes a set of services for its partners. Here we ask the server for its set of 214 | * services and wait until we have received them all. 215 | * @return N/A 216 | */ 217 | std::map* BLEClient::getServices() { 218 | 219 | clearServices(); // Clear any services that may exist. 220 | client_all_primary_srv_discovery(getConnId(),getGattcIf()); 221 | RPC_DEBUG("start BLEClient::getServices():\n\r "); 222 | m_semaphoreSearchCmplEvt.take("getServices"); 223 | // If sucessfull, remember that we now have services. 224 | m_haveServices = (m_semaphoreSearchCmplEvt.wait("getServices") == 0); 225 | m_haveServices = true; 226 | 227 | return &m_servicesMap; 228 | } // getServices 229 | 230 | /** 231 | * @brief Clear any existing services. 232 | * 233 | */ 234 | void BLEClient::clearServices() { 235 | // Delete all the services. 236 | for (auto &myPair : m_servicesMap) { 237 | delete myPair.second; 238 | } 239 | m_servicesMap.clear(); 240 | m_haveServices = false; 241 | } // clearServices 242 | 243 | 244 | /** 245 | * @brief Handle a received GAP event. 246 | * 247 | * @param [in] event 248 | * @param [in] param 249 | */ 250 | T_APP_RESULT BLEClient::handleGAPEvent(uint8_t cb_type, void *p_cb_data) { 251 | RPC_DEBUG("BLEClient ... handling GAP event!"); 252 | T_APP_RESULT result = APP_RESULT_SUCCESS; 253 | T_LE_CB_DATA *p_data = (T_LE_CB_DATA *)p_cb_data; 254 | switch (cb_type) { 255 | case GAP_MSG_LE_READ_RSSI: { 256 | m_semaphoreRssiCmplEvt.give((p_data->p_le_read_rssi_rsp->rssi)); 257 | break; 258 | } // GAP_MSG_LE_READ_RSSI 259 | 260 | default: 261 | break; 262 | } 263 | return result; 264 | } // handleGAPEvent 265 | 266 | /** 267 | * @brief Return a string representation of this client. 268 | * @return A string representation of this client. 269 | */ 270 | std::string BLEClient::toString() { 271 | std::string res = "peer address: " + m_peerAddress.toString(); 272 | res += "\nServices:\n"; 273 | for (auto &myPair : m_servicesMap) { 274 | res += myPair.second->toString() + "\n"; 275 | } 276 | return res; 277 | } // toString 278 | 279 | T_APP_RESULT BLEClient::clientCallbackDefault(T_CLIENT_ID client_id, uint8_t conn_id, void *p_data) { 280 | 281 | T_APP_RESULT result = APP_RESULT_SUCCESS; 282 | T_BLE_CLIENT_CB_DATA *p_ble_client_cb_data = (T_BLE_CLIENT_CB_DATA *)p_data; 283 | 284 | switch (p_ble_client_cb_data->cb_type) 285 | { 286 | case BLE_CLIENT_CB_TYPE_DISCOVERY_STATE: 287 | { 288 | RPC_DEBUG("discov_state:%d\n\r", p_ble_client_cb_data->cb_content.discov_state.state); 289 | T_DISCOVERY_STATE state = p_ble_client_cb_data->cb_content.discov_state.state; 290 | switch(state) 291 | { 292 | case DISC_STATE_SRV_DONE: 293 | { 294 | m_semaphoreSearchCmplEvt.give(0); 295 | break; 296 | } 297 | } 298 | 299 | break; 300 | } 301 | case BLE_CLIENT_CB_TYPE_DISCOVERY_RESULT: 302 | { 303 | T_DISCOVERY_RESULT_TYPE discov_type = p_ble_client_cb_data->cb_content.discov_result.discov_type; 304 | switch (discov_type) 305 | { 306 | RPC_DEBUG("discov_type:%d\n\r", discov_type); 307 | case DISC_RESULT_ALL_SRV_UUID16: 308 | { 309 | T_GATT_SERVICE_ELEM16 *disc_data = (T_GATT_SERVICE_ELEM16 *)&(p_ble_client_cb_data->cb_content.discov_result.result.srv_uuid16_disc_data); 310 | 311 | BLEUUID uuid = BLEUUID(disc_data->uuid16); 312 | BLERemoteService* pRemoteService = new BLERemoteService( 313 | disc_data->att_handle, 314 | disc_data->end_group_handle, 315 | uuid, 316 | this 317 | ); 318 | 319 | RPC_DEBUG(pRemoteService->getUUID().toString().c_str()); 320 | m_servicesMap.insert(std::pair(uuid.toString(), pRemoteService)); 321 | break; 322 | } 323 | case DISC_RESULT_ALL_SRV_UUID128: 324 | { 325 | T_GATT_SERVICE_ELEM128 *disc_data = (T_GATT_SERVICE_ELEM128 *)&(p_ble_client_cb_data->cb_content.discov_result.result.srv_uuid128_disc_data); 326 | BLEUUID uuid = BLEUUID(disc_data->uuid128,16); 327 | BLERemoteService* pRemoteService = new BLERemoteService( 328 | disc_data->att_handle, 329 | disc_data->end_group_handle, 330 | uuid, 331 | this 332 | ); 333 | 334 | RPC_DEBUG(pRemoteService->getUUID().toString().c_str()); 335 | m_servicesMap.insert(std::pair(uuid.toString(), pRemoteService)); 336 | break; 337 | } 338 | case DISC_RESULT_SRV_DATA: 339 | { 340 | T_GATT_SERVICE_BY_UUID_ELEM *disc_data = (T_GATT_SERVICE_BY_UUID_ELEM *)&(p_ble_client_cb_data->cb_content.discov_result.result.srv_disc_data); 341 | RPC_DEBUG("start_handle:%d, end handle:%d\n\r", disc_data->att_handle, disc_data->end_group_handle); 342 | break; 343 | } 344 | 345 | default: 346 | break; 347 | } 348 | 349 | } 350 | case BLE_CLIENT_CB_TYPE_READ_RESULT: 351 | break; 352 | case BLE_CLIENT_CB_TYPE_WRITE_RESULT: 353 | break; 354 | case BLE_CLIENT_CB_TYPE_NOTIF_IND: 355 | break; 356 | case BLE_CLIENT_CB_TYPE_DISCONNECT_RESULT: { 357 | m_isConnected = false; 358 | if (m_pClientCallbacks != nullptr) { 359 | m_pClientCallbacks->onDisconnect(this); 360 | } 361 | m_semaphoreSearchCmplEvt.give(1); 362 | BLEDevice::removePeerDevice(m_appId, true); 363 | break; 364 | } 365 | default: 366 | break; 367 | } 368 | 369 | // Pass the request on to all services. 370 | for (auto &myPair : m_servicesMap) { 371 | myPair.second->clientCallbackDefault(client_id,conn_id,p_data); 372 | } 373 | return result; 374 | 375 | } -------------------------------------------------------------------------------- /src/BLEClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEDevice.h 3 | * 4 | * Created on: Mar 22, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef MAIN_BLEDEVICE_H_ 9 | #define MAIN_BLEDEVICE_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "BLEFreeRTOS.h" 15 | #include "BLEAddress.h" 16 | #include "BLEAdvertisedDevice.h" 17 | #include "BLERemoteService.h" 18 | #include "BLERemoteDescriptor.h" 19 | #include "seeed_rpcUnified.h" 20 | #include "rtl_ble/ble_unified.h" 21 | 22 | typedef uint8_t T_CLIENT_ID; 23 | typedef uint8_t T_SERVER_ID; 24 | class BLERemoteService; 25 | class BLEClientCallbacks; 26 | class BLEAdvertisedDevice; 27 | class BLERemoteCharacteristic; 28 | class BLERemoteDescriptor; 29 | 30 | 31 | /** 32 | * @brief A model of a %BLE client. 33 | */ 34 | class BLEClient { 35 | public: 36 | BLEClient(); 37 | ~BLEClient(); 38 | 39 | bool connect(BLEAdvertisedDevice* device); 40 | bool connect(BLEAddress address, T_GAP_REMOTE_ADDR_TYPE type = GAP_REMOTE_ADDR_LE_PUBLIC); // Connect to the remote BLE Server 41 | void disconnect(); 42 | void setClientCallbacks(BLEClientCallbacks *pClientCallbacks); 43 | BLEAddress m_peerAddress = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); // The BD address of the remote server. 44 | 45 | void setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a given characteristic at a given service. 46 | bool isConnected(); 47 | uint8_t getGattcIf(); 48 | uint16_t getConnId(); 49 | std::map* getServices(); 50 | BLERemoteService* getService(const char* uuid); // Get a reference to a specified service offered by the remote BLE server. 51 | BLERemoteService* getService(BLEUUID uuid); 52 | BLEAddress getPeerAddress(); // Get the address of the remote BLE Server 53 | int getRssi(); // Get the RSSI of the remote BLE Server 54 | std::string getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a given characteristic at a given service. 55 | T_APP_RESULT handleGAPEvent(uint8_t cb_type, void *p_cb_data); 56 | std::string toString(); // Return a string representation of this client. 57 | uint16_t getMTU(); 58 | uint16_t setMTU(uint16_t mtu_size); 59 | uint16_t m_appId; 60 | private: 61 | friend class BLEDevice; 62 | friend class BLERemoteService; 63 | friend class BLERemoteCharacteristic; 64 | friend class BLERemoteDescriptor; 65 | 66 | 67 | T_APP_RESULT clientCallbackDefault(T_CLIENT_ID client_id, uint8_t conn_id, void *p_data); 68 | BLEClientCallbacks* m_pClientCallbacks; 69 | uint16_t m_conn_id; 70 | static uint8_t m_gattc_if; 71 | bool m_haveServices = false; 72 | bool m_isConnected = false; 73 | 74 | BLEFreeRTOS::Semaphore m_semaphoreSearchCmplEvt = BLEFreeRTOS::Semaphore("SearchCmplEvt"); 75 | BLEFreeRTOS::Semaphore m_semaphoreRssiCmplEvt = BLEFreeRTOS::Semaphore("RssiCmplEvt"); 76 | void clearServices(); // Clear any existing services. 77 | std::map m_servicesMap; 78 | uint16_t m_mtu = 23; 79 | }; // class BLEDevice 80 | 81 | 82 | /** 83 | * @brief Callbacks associated with a %BLE client. 84 | */ 85 | class BLEClientCallbacks { 86 | public: 87 | virtual ~BLEClientCallbacks() {}; 88 | virtual void onConnect(BLEClient *pClient) = 0; 89 | virtual void onDisconnect(BLEClient *pClient) = 0; 90 | 91 | }; 92 | 93 | #endif /* MAIN_BLEDEVICE_H_ */ 94 | -------------------------------------------------------------------------------- /src/BLEDescriptor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEDescriptor.cpp 3 | * 4 | * Created on: Jun 22, 2017 5 | * Author: kolban 6 | */ 7 | #define TAG "BLEDescriptor" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "BLEService.h" 13 | #include "BLEDescriptor.h" 14 | #include "rpc_unified_log.h" 15 | 16 | #define NULL_HANDLE (0xffff) 17 | 18 | /** 19 | * @brief BLEDescriptor constructor. 20 | */ 21 | BLEDescriptor::BLEDescriptor(BLEUUID uuid, uint16_t flags, uint32_t permissions, uint16_t max_len) 22 | { 23 | m_attr_len = 0; // Initial length is 0. 24 | m_handle = NULL_HANDLE; // Handle is initially unknown. 25 | m_pCharacteristic = nullptr; // No initial characteristic. 26 | m_pCallback = nullptr; // No initial callback 27 | 28 | m_bleUUID = uuid; 29 | m_flags = flags; 30 | m_permissions = permissions; 31 | m_attr_max_len = max_len; // Maximum length of the data. 32 | m_attr_value = (uint8_t *)malloc(max_len); // Allocate storage for the value. 33 | } // BLEDescriptor 34 | 35 | /** 36 | * @brief BLEDescriptor destructor. 37 | */ 38 | BLEDescriptor::~BLEDescriptor() 39 | { 40 | free(m_attr_value); // Release the storage we created in the constructor. 41 | } // ~BLEDescriptor 42 | 43 | /** 44 | * @brief Set the value of the descriptor. 45 | * @param [in] data The data to set for the descriptor. 46 | * @param [in] length The length of the data in bytes. 47 | */ 48 | void BLEDescriptor::setValue(uint8_t *data, size_t length) 49 | { 50 | if (length > 600) 51 | { 52 | return; 53 | } 54 | m_attr_max_len = length; 55 | memcpy(m_attr_value, data, length); 56 | m_semaphoreSetValue.take(); 57 | m_value.setValue(data, length); 58 | m_semaphoreSetValue.give(); 59 | } // setValue 60 | 61 | /** 62 | * @brief Set the value of the descriptor. 63 | * @param [in] value The value of the descriptor in string form. 64 | */ 65 | void BLEDescriptor::setValue(std::string value) 66 | { 67 | setValue((uint8_t *)value.data(), value.length()); 68 | } // setValue 69 | 70 | void BLEDescriptor::setAccessPermissions(uint32_t perm) 71 | { 72 | m_permissions = perm; 73 | } 74 | 75 | /** 76 | * @brief Set the callback handlers for this descriptor. 77 | * @param [in] pCallbacks An instance of a callback structure used to define any callbacks for the descriptor. 78 | */ 79 | void BLEDescriptor::setCallbacks(BLEDescriptorCallbacks *pCallback) 80 | { 81 | m_pCallback = pCallback; 82 | } // setCallbacks 83 | 84 | /** 85 | * @brief Get the UUID of the descriptor. 86 | */ 87 | BLEUUID BLEDescriptor::getUUID() 88 | { 89 | return m_bleUUID; 90 | } // getUUID 91 | 92 | /** 93 | * @brief Get the BLE handle for this descriptor. 94 | * @return The handle for this descriptor. 95 | */ 96 | uint16_t BLEDescriptor::getHandle() 97 | { 98 | return m_handle; 99 | } // getHandle 100 | 101 | /** 102 | * @brief Get the value of this descriptor. 103 | * @return A pointer to the value of this descriptor. 104 | */ 105 | uint8_t *BLEDescriptor::getValue() 106 | { 107 | return m_attr_value; 108 | } // getValue 109 | 110 | uint16_t BLEDescriptor::getflags() 111 | { 112 | return m_flags; 113 | } // m_flags 114 | 115 | uint16_t BLEDescriptor::getmaxlen() 116 | { 117 | return m_attr_max_len; 118 | } // m_attr_max_len 119 | 120 | uint32_t BLEDescriptor::getpermissions() 121 | { 122 | return m_permissions; 123 | } // m_attr_max_len 124 | 125 | /** 126 | * @brief Execute the creation of the descriptor with the BLE runtime in ESP. 127 | * @param [in] pCharacteristic The characteristic to which to register this descriptor. 128 | */ 129 | void BLEDescriptor::executeCreate(BLECharacteristic *pCharacteristic) 130 | { 131 | m_pCharacteristic = pCharacteristic; // Save the characteristic associated with this service. 132 | ble_desc_t desc; 133 | desc.flags = getflags(); 134 | desc.uuid_length = getUUID().getNative()->len; 135 | memcpy(&(desc.uuid), &(getUUID().getNative()->uuid), desc.uuid_length); 136 | desc.p_value = getValue(); 137 | desc.vlaue_length = getmaxlen(); 138 | desc.permissions = getpermissions(); 139 | uint8_t desc_handle = ble_create_desc(m_pCharacteristic->getService()->getgiff(), m_pCharacteristic->getHandle(), desc); 140 | m_handle = desc_handle; 141 | RPC_DEBUG("desc_handle: %d\n\r", desc_handle); 142 | } // executeCreate 143 | 144 | /** 145 | * @brief Return a string representation of the descriptor. 146 | * @return A string representation of the descriptor. 147 | */ 148 | std::string BLEDescriptor::toString() 149 | { 150 | char hex[5]; 151 | snprintf(hex, sizeof(hex), "%04x", m_handle); 152 | std::string res = "UUID: " + m_bleUUID.toString() + ", handle: 0x" + hex; 153 | return res; 154 | } // toString 155 | 156 | BLEDescriptorCallbacks::~BLEDescriptorCallbacks() {} 157 | 158 | /** 159 | * @brief Callback function to support a read request. 160 | * @param [in] pDescriptor The descriptor that is the source of the event. 161 | */ 162 | void BLEDescriptorCallbacks::onRead(BLEDescriptor *pDescriptor) 163 | { 164 | 165 | } // onRead 166 | 167 | /** 168 | * @brief Callback function to support a write request. 169 | * @param [in] pDescriptor The descriptor that is the source of the event. 170 | */ 171 | void BLEDescriptorCallbacks::onWrite(BLEDescriptor *pDescriptor) 172 | { 173 | 174 | } // onWrite 175 | 176 | /** 177 | * @brief Handle GATT server events for the descripttor. 178 | * @param [in] event 179 | * @param [in] gatts_if 180 | * @param [in] param 181 | */ 182 | void BLEDescriptor::handleGATTServerEvent( 183 | T_SERVER_ID service_id, 184 | void *p_data) 185 | { 186 | RPC_DEBUG("BLEDescriptor handleGATTServerEvent: service_id: %d\n\r", service_id); 187 | ble_service_cb_data_t *cb_data = (ble_service_cb_data_t *)p_data; 188 | if (getHandle() == cb_data->attrib_handle) 189 | { 190 | switch (cb_data->event) 191 | { 192 | case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION: 193 | { 194 | RPC_DEBUG("SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION: cccdbit: %d\n\r", cb_data->cb_data_context.cccd_update_data.cccbits); 195 | setValue((uint8_t *)&cb_data->cb_data_context.cccd_update_data.cccbits, 2); 196 | break; 197 | } 198 | case SERVICE_CALLBACK_TYPE_READ_CHAR_VALUE: 199 | { 200 | 201 | if (m_pCallback != nullptr) 202 | { 203 | m_pCallback->onRead(this); 204 | } 205 | cb_data->cb_data_context.read_data.length = m_value.getLength(); 206 | cb_data->cb_data_context.read_data.offset = m_value.getReadOffset(); 207 | cb_data->cb_data_context.read_data.p_value = (uint8_t *)(m_value.getData() + cb_data->cb_data_context.read_data.offset); 208 | m_value.setReadOffset(0); 209 | break; 210 | } 211 | case SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE: 212 | { 213 | 214 | //m_attr_value.addPart(cb_data->cb_data_context.write_data.p_value,cb_data->cb_data_context.write_data.length); 215 | //m_attr_value.commit(); 216 | setValue(cb_data->cb_data_context.write_data.p_value, cb_data->cb_data_context.write_data.length); 217 | if (m_pCallback != nullptr) 218 | { 219 | m_pCallback->onWrite(this); 220 | } 221 | 222 | break; 223 | } 224 | default: 225 | break; 226 | } 227 | } 228 | 229 | } // handleGATTServerEvent -------------------------------------------------------------------------------- /src/BLEDescriptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEDescriptor.h 3 | * 4 | * Created on: Jun 22, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ 10 | 11 | #include 12 | #include "BLEUUID.h" 13 | #include "BLECharacteristic.h" 14 | #include "BLEFreeRTOS.h" 15 | #include "BLEValue.h" 16 | #include "seeed_rpcUnified.h" 17 | #include "rtl_ble/ble_unified.h" 18 | 19 | typedef uint8_t T_SERVER_ID; 20 | class BLEService; 21 | class BLECharacteristic; 22 | class BLEDescriptorCallbacks; 23 | 24 | /** 25 | * @brief A model of a %BLE descriptor. 26 | */ 27 | class BLEDescriptor { 28 | public: 29 | BLEDescriptor(BLEUUID uuid,uint16_t flags,uint32_t permissions,uint16_t max_len); 30 | virtual ~BLEDescriptor(); 31 | BLEUUID getUUID(); 32 | uint16_t getHandle(); 33 | void setValue(uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data. 34 | void setValue(std::string value); 35 | void setAccessPermissions(uint32_t perm); // Set the permissions of the descriptor. 36 | void setCallbacks(BLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor. 37 | uint16_t getflags(); 38 | uint8_t* getValue(); 39 | uint16_t getmaxlen(); 40 | uint32_t getpermissions(); 41 | BLECharacteristic* getCharacteristic(); 42 | void handleGATTServerEvent(T_SERVER_ID service_id, void *p_data); 43 | std::string toString(); // Convert the descriptor to a string representation. 44 | private: 45 | friend class BLEDescriptorMap; 46 | friend class BLECharacteristic; 47 | 48 | BLEValue m_value; 49 | BLEUUID m_bleUUID; 50 | uint8_t m_handle; 51 | uint16_t m_attr_len; 52 | uint16_t m_attr_max_len; 53 | uint8_t* m_attr_value; 54 | BLECharacteristic* m_pCharacteristic; 55 | BLEDescriptorCallbacks* m_pCallback; 56 | 57 | uint16_t m_flags; 58 | uint32_t m_permissions = 0; 59 | 60 | 61 | BLEFreeRTOS::Semaphore m_semaphoreCreateEvt = BLEFreeRTOS::Semaphore("CreateEvt"); 62 | BLEFreeRTOS::Semaphore m_semaphoreSetValue = BLEFreeRTOS::Semaphore("SetValue"); 63 | 64 | void executeCreate(BLECharacteristic* pCharacteristic); 65 | 66 | 67 | }; // BLEDescriptor 68 | 69 | 70 | /** 71 | * @brief Callbacks that can be associated with a %BLE descriptors to inform of events. 72 | * 73 | * When a server application creates a %BLE descriptor, we may wish to be informed when there is either 74 | * a read or write request to the descriptors value. An application can register a 75 | * sub-classed instance of this class and will be notified when such an event happens. 76 | */ 77 | class BLEDescriptorCallbacks { 78 | public: 79 | virtual ~BLEDescriptorCallbacks(); 80 | virtual void onRead(BLEDescriptor* pDescriptor); 81 | virtual void onWrite(BLEDescriptor* pDescriptor); 82 | }; 83 | 84 | #endif /* COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ */ 85 | -------------------------------------------------------------------------------- /src/BLEDescriptorMap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEDescriptorMap.cpp 3 | * 4 | * Created on: Jun 22, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #include 9 | #include 10 | #include "BLECharacteristic.h" 11 | #include "BLEDescriptor.h" 12 | 13 | /** 14 | * @brief Return the descriptor by UUID. 15 | * @param [in] UUID The UUID to look up the descriptor. 16 | * @return The descriptor. If not present, then nullptr is returned. 17 | */ 18 | BLEDescriptor* BLEDescriptorMap::getByUUID(const char* uuid) { 19 | return getByUUID(BLEUUID(uuid)); 20 | } 21 | 22 | /** 23 | * @brief Return the descriptor by UUID. 24 | * @param [in] UUID The UUID to look up the descriptor. 25 | * @return The descriptor. If not present, then nullptr is returned. 26 | */ 27 | BLEDescriptor* BLEDescriptorMap::getByUUID(BLEUUID uuid) { 28 | for (auto &myPair : m_uuidMap) { 29 | if (myPair.first->getUUID().equals(uuid)) { 30 | return myPair.first; 31 | } 32 | } 33 | return nullptr; 34 | } // getByUUID 35 | 36 | /** 37 | * @brief Set the descriptor by UUID. 38 | * @param [in] uuid The uuid of the descriptor. 39 | * @param [in] characteristic The descriptor to cache. 40 | * @return N/A. 41 | */ 42 | void BLEDescriptorMap::setByUUID(const char* uuid, BLEDescriptor* pDescriptor){ 43 | m_uuidMap.insert(std::pair(pDescriptor, uuid)); 44 | } // setByUUID 45 | 46 | /** 47 | * @brief Set the descriptor by UUID. 48 | * @param [in] uuid The uuid of the descriptor. 49 | * @param [in] characteristic The descriptor to cache. 50 | * @return N/A. 51 | */ 52 | void BLEDescriptorMap::setByUUID(BLEUUID uuid, BLEDescriptor* pDescriptor) { 53 | m_uuidMap.insert(std::pair(pDescriptor, uuid.toString())); 54 | } // setByUUID 55 | 56 | 57 | 58 | /** 59 | * @brief Set the descriptor by handle. 60 | * @param [in] handle The handle of the descriptor. 61 | * @param [in] descriptor The descriptor to cache. 62 | * @return N/A. 63 | */ 64 | void BLEDescriptorMap::setByHandle(uint16_t handle, BLEDescriptor* pDescriptor) { 65 | m_handleMap.insert(std::pair(handle, pDescriptor)); 66 | } // setByHandle 67 | 68 | 69 | /** 70 | * @brief Get the first descriptor in the map. 71 | * @return The first descriptor in the map. 72 | */ 73 | BLEDescriptor* BLEDescriptorMap::getFirst() { 74 | m_iterator = m_uuidMap.begin(); 75 | if (m_iterator == m_uuidMap.end()) return nullptr; 76 | BLEDescriptor* pRet = m_iterator->first; 77 | m_iterator++; 78 | return pRet; 79 | } // getFirst 80 | 81 | 82 | /** 83 | * @brief Get the next descriptor in the map. 84 | * @return The next descriptor in the map. 85 | */ 86 | BLEDescriptor* BLEDescriptorMap::getNext() { 87 | if (m_iterator == m_uuidMap.end()) return nullptr; 88 | BLEDescriptor* pRet = m_iterator->first; 89 | m_iterator++; 90 | return pRet; 91 | } // getNext 92 | 93 | 94 | 95 | /** 96 | * @brief Return the descriptor by handle. 97 | * @param [in] handle The handle to look up the descriptor. 98 | * @return The descriptor. 99 | */ 100 | BLEDescriptor* BLEDescriptorMap::getByHandle(uint16_t handle) { 101 | return m_handleMap.at(handle); 102 | } // getByHandle 103 | 104 | 105 | 106 | /** 107 | * @breif Pass the GATT server event onwards to each of the descriptors found in the mapping 108 | * @param [in] event 109 | * @param [in] gatts_if 110 | * @param [in] param 111 | */ 112 | void BLEDescriptorMap::handleGATTServerEvent( 113 | T_SERVER_ID service_id, 114 | void *p_datas) { 115 | // Invoke the handler for every descriptor we have. 116 | for (auto &myPair : m_uuidMap) { 117 | myPair.first->handleGATTServerEvent(service_id,p_datas); 118 | } 119 | } // handleGATTServerEvent 120 | 121 | 122 | /** 123 | * @brief Return a string representation of the descriptor map. 124 | * @return A string representation of the descriptor map. 125 | */ 126 | std::string BLEDescriptorMap::toString() { 127 | std::string res; 128 | char hex[5]; 129 | int count = 0; 130 | for (auto &myPair : m_uuidMap) { 131 | if (count > 0) {res += "\n";} 132 | snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle()); 133 | count++; 134 | res += "handle: 0x"; 135 | res += hex; 136 | res += ", uuid: " + myPair.first->getUUID().toString(); 137 | } 138 | return res; 139 | } // toString -------------------------------------------------------------------------------- /src/BLEDevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEDevice.h 3 | * 4 | * Created on: Mar 16, 2020 5 | * Author: coolc 6 | */ 7 | 8 | #ifndef MAIN_BLEDevice_H_ 9 | #define MAIN_BLEDevice_H_ 10 | 11 | #include // Part of C++ STL 12 | #include 13 | #include "BLEServer.h" 14 | #include "BLEScan.h" 15 | #include "BLEFreeRTOS.h" 16 | #include "BLEClient.h" 17 | #include "BLEAdvertising.h" 18 | #include "seeed_rpcUnified.h" 19 | #include "rtl_ble/ble_unified.h" 20 | typedef uint8_t T_CLIENT_ID; 21 | 22 | class BLEDevice { 23 | public: 24 | static BLEClient* createClient(); // Create a new BLE client. 25 | static BLEServer* createServer(); // Cretae a new BLE server. 26 | static BLEScan* getScan(); // Get the scan object 27 | static BLEAddress getAddress(); // Retrieve our own local BD address. 28 | static std::string getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a characteristic of a service on a server. 29 | static void setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a characteristic on a service on a server. 30 | static void init(std::string deviceName); // Initialize the local BLE environment. 31 | static std::map getPeerDevices(bool client); 32 | static std::string toString(); // Return a string representation of our device. 33 | static void whiteListAdd(T_GAP_WHITE_LIST_OP operation, uint8_t *bd_addr,T_GAP_REMOTE_ADDR_TYPE bd_type); // Add an entry to the BLE white list. 34 | static void whiteListRemove(T_GAP_WHITE_LIST_OP operation, uint8_t *bd_addr,T_GAP_REMOTE_ADDR_TYPE bd_type); // Remove an entry from the BLE white list. 35 | static void addPeerDevice(void* peer, bool is_client, uint16_t conn_id); 36 | static void removePeerDevice(uint16_t conn_id, bool client); 37 | static void updatePeerDevice(void* peer, bool _client, uint16_t conn_id); 38 | static bool getInitialized(); // Returns the state of the device, is it initialized or not? 39 | static BLEAdvertising* getAdvertising(); 40 | static void startAdvertising(); 41 | static void stopAdvertising(); 42 | static BLEServer* getServer(); 43 | static BLEClient* getClient(); 44 | static void setMTU(uint16_t mtu); 45 | static uint16_t getMTU(); 46 | static BLEClient* getClientByGattIf(uint16_t conn_id); 47 | static void deinit(); 48 | static uint16_t m_appId; 49 | static uint16_t m_localMTU; 50 | static std::string ble_name; 51 | static bool ble_start_flags; 52 | private: 53 | friend class BLEClient; 54 | friend class BLEServer; 55 | static BLEServer* m_pServer; 56 | static BLEClient* m_pClient; 57 | static BLEScan* _pBLEScan; 58 | static BLEAdvertising* m_bleAdvertising; 59 | static std::map m_connectedClientsMap; 60 | 61 | static T_APP_RESULT gapEventHandler(uint8_t cb_type, void *p_cb_data); 62 | static T_APP_RESULT gattClientEventHandler(T_CLIENT_ID client_id, uint8_t conn_id, void *p_data ); 63 | static void ble_handle_gap_msg(T_IO_MSG *p_gap_msg); 64 | static T_APP_RESULT gattServerEventHandler(T_SERVER_ID service_id, void *p_data); 65 | }; 66 | 67 | #endif /* MAIN_BLEDevice_H_ */ 68 | -------------------------------------------------------------------------------- /src/BLEDeviceDefaultCallbacks.cpp: -------------------------------------------------------------------------------- 1 | #define TAG "ScanCallback" 2 | #include "BLEDevice.h" 3 | #include 4 | #include "BLEScan.h" 5 | #include "BLEAdvertisedDevice.h" 6 | #include "BLEFreeRTOS.h" 7 | #include "rpc_unified_log.h" 8 | #include "seeed_rpcUnified.h" 9 | #include "rtl_ble/ble_unified.h" 10 | 11 | /** @brief APP Return Result List */ 12 | T_APP_RESULT BLEScan::gapCallbackDefault(uint8_t cb_type, void *p_cb_data) { 13 | T_APP_RESULT result = APP_RESULT_SUCCESS; 14 | T_LE_CB_DATA *p_data = (T_LE_CB_DATA *)p_cb_data; 15 | RPC_DEBUG("gapCallbackDefault into \r\n"); 16 | switch (cb_type) { 17 | case GAP_MSG_LE_DATA_LEN_CHANGE_INFO: { 18 | RPC_INFO("GAP_MSG_LE_DATA_LEN_CHANGE_INFO: conn_id %d, tx octets 0x%x, max_tx_time 0x%x\r\n", p_data->p_le_data_len_change_info->conn_id, p_data->p_le_data_len_change_info->max_tx_octets, p_data->p_le_data_len_change_info->max_tx_time); 19 | break; 20 | } 21 | case GAP_MSG_LE_MODIFY_WHITE_LIST: { 22 | RPC_INFO("GAP_MSG_LE_MODIFY_WHITE_LIST: operation %d, cause 0x%x\r\n", p_data->p_le_modify_white_list_rsp->operation, p_data->p_le_modify_white_list_rsp->cause); 23 | break; 24 | } 25 | case GAP_MSG_LE_CONN_UPDATE_IND: { 26 | RPC_INFO("GAP_MSG_LE_CONN_UPDATE_IND: conn_id %d, conn_interval_max 0x%x, conn_interval_min 0x%x, conn_latency 0x%x,supervision_timeout 0x%x", p_data->p_le_conn_update_ind->conn_id, p_data->p_le_conn_update_ind->conn_interval_max, p_data->p_le_conn_update_ind->conn_interval_min, p_data->p_le_conn_update_ind->conn_latency, p_data->p_le_conn_update_ind->supervision_timeout); 27 | /* if reject the proposed connection parameter from peer device, use APP_RESULT_REJECT. */ 28 | result = APP_RESULT_ACCEPT; 29 | break; 30 | } 31 | case GAP_MSG_LE_PHY_UPDATE_INFO: { 32 | RPC_INFO("GAP_MSG_LE_PHY_UPDATE_INFO:conn_id %d, cause 0x%x, rx_phy %d, tx_phy %d\r\n", p_data->p_le_phy_update_info->conn_id, p_data->p_le_phy_update_info->cause, p_data->p_le_phy_update_info->rx_phy, p_data->p_le_phy_update_info->tx_phy); 33 | break; 34 | } 35 | case GAP_MSG_LE_REMOTE_FEATS_INFO: { 36 | uint8_t remote_feats[8]; 37 | if (p_data->p_le_remote_feats_info->cause == GAP_SUCCESS) { 38 | memcpy(remote_feats, p_data->p_le_remote_feats_info->remote_feats, 8); 39 | if (remote_feats[LE_SUPPORT_FEATURES_MASK_ARRAY_INDEX1] & LE_SUPPORT_FEATURES_LE_2M_MASK_BIT) { 40 | RPC_DEBUG("GAP_MSG_LE_REMOTE_FEATS_INFO: support 2M\r\n"); 41 | } 42 | if (remote_feats[LE_SUPPORT_FEATURES_MASK_ARRAY_INDEX1] & LE_SUPPORT_FEATURES_LE_CODED_PHY_MASK_BIT) { 43 | RPC_DEBUG("GAP_MSG_LE_REMOTE_FEATS_INFO: support CODED\r\n"); 44 | } 45 | } 46 | break; 47 | } 48 | case GAP_MSG_LE_SCAN_CMPL: 49 | { 50 | RPC_DEBUG("GAP_MSG_LE_SCAN_CMPL"); 51 | m_semaphoreScanEnd.give(); 52 | if(m_scanCompleteCB != nullptr) { 53 | m_scanCompleteCB(m_scanResults); 54 | } 55 | break; 56 | } 57 | case GAP_MSG_LE_SCAN_INFO: { 58 | RPC_DEBUG("GAP_MSG_LE_SCAN_INFO:adv_type 0x%x, bd_addr %02x:%02x:%02x:%02x:%02x:%02x, remote_addr_type %d, rssi %d, data_len %d", 59 | p_data->p_le_scan_info->adv_type, 60 | (p_data->p_le_scan_info->bd_addr)[5], 61 | (p_data->p_le_scan_info->bd_addr)[4], 62 | (p_data->p_le_scan_info->bd_addr)[3], 63 | (p_data->p_le_scan_info->bd_addr)[2], 64 | (p_data->p_le_scan_info->bd_addr)[1], 65 | (p_data->p_le_scan_info->bd_addr)[0], 66 | p_data->p_le_scan_info->remote_addr_type, 67 | p_data->p_le_scan_info->rssi, 68 | p_data->p_le_scan_info->data_len); 69 | RPC_DEBUG("GAP_MSG_LE_SCAN_INFO:\r\n"); 70 | BLEAddress advertisedAddress(p_data->p_le_scan_info->bd_addr); 71 | bool found = false; 72 | if (m_scanResults.m_vectorAdvertisedDevices.count(advertisedAddress.toString()) != 0) { 73 | found = true; 74 | } 75 | 76 | if (found && !m_wantDuplicates) { // If we found a previous entry AND we don't want duplicates, then we are done. 77 | vTaskDelay(1); // <--- allow to switch task in case we scan infinity and dont have new devices to report, or we are blocked here 78 | break; 79 | } 80 | 81 | BLEAdvertisedDevice *advertisedDevice = new BLEAdvertisedDevice(); 82 | advertisedDevice->setAddress(advertisedAddress); 83 | advertisedDevice->setRSSI(p_data->p_le_scan_info->rssi); 84 | advertisedDevice->parseAdvertisement(p_data); 85 | advertisedDevice->setScan(this); 86 | advertisedDevice->setAddressType(p_data->p_le_scan_info->remote_addr_type); 87 | 88 | if (!found) { // If we have previously seen this device, don't record it again. 89 | m_scanResults.m_vectorAdvertisedDevices.insert(std::pair(advertisedAddress.toString(), advertisedDevice)); 90 | } 91 | 92 | if (m_pAdvertisedDeviceCallbacks) { 93 | m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice); 94 | } 95 | if(found) 96 | delete advertisedDevice; 97 | break; 98 | } 99 | default: 100 | RPC_DEBUG("gapCallbackDefault: unhandled cb_type 0x%x\r\n", cb_type); 101 | break; 102 | } 103 | return result; 104 | } 105 | -------------------------------------------------------------------------------- /src/BLEEddystoneTLM.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEEddystoneTLM.cpp 3 | * 4 | * Created on: Mar 12, 2018 5 | * Author: pcbreflux 6 | */ 7 | #include 8 | #include 9 | #include "BLEEddystoneTLM.h" 10 | 11 | static const char LOG_TAG[] = "BLEEddystoneTLM"; 12 | #define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) 13 | #define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24)) 14 | 15 | BLEEddystoneTLM::BLEEddystoneTLM() { 16 | beaconUUID = 0xFEAA; 17 | m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE; 18 | m_eddystoneData.version = 0; 19 | m_eddystoneData.volt = 3300; // 3300mV = 3.3V 20 | m_eddystoneData.temp = (uint16_t) ((float) 23.00); 21 | m_eddystoneData.advCount = 0; 22 | m_eddystoneData.tmil = 0; 23 | } // BLEEddystoneTLM 24 | 25 | std::string BLEEddystoneTLM::getData() { 26 | return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData)); 27 | } // getData 28 | 29 | BLEUUID BLEEddystoneTLM::getUUID() { 30 | return BLEUUID(beaconUUID); 31 | } // getUUID 32 | 33 | uint8_t BLEEddystoneTLM::getVersion() { 34 | return m_eddystoneData.version; 35 | } // getVersion 36 | 37 | uint16_t BLEEddystoneTLM::getVolt() { 38 | return m_eddystoneData.volt; 39 | } // getVolt 40 | 41 | float BLEEddystoneTLM::getTemp() { 42 | return (float)m_eddystoneData.temp; 43 | } // getTemp 44 | 45 | uint32_t BLEEddystoneTLM::getCount() { 46 | return m_eddystoneData.advCount; 47 | } // getCount 48 | 49 | uint32_t BLEEddystoneTLM::getTime() { 50 | return m_eddystoneData.tmil; 51 | } // getTime 52 | 53 | std::string BLEEddystoneTLM::toString() { 54 | std::string out = ""; 55 | uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil); 56 | char val[6]; 57 | 58 | out += "Version " + m_eddystoneData.version; 59 | out += "\n"; 60 | out += "Battery Voltage " + ENDIAN_CHANGE_U16(m_eddystoneData.volt); 61 | out += " mV\n"; 62 | 63 | out += "Temperature "; 64 | snprintf(val, sizeof(val), "%d", m_eddystoneData.temp); 65 | out += val; 66 | out += ".0 °C\n"; 67 | 68 | out += "Adv. Count "; 69 | snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U32(m_eddystoneData.advCount)); 70 | out += val; 71 | out += "\n"; 72 | 73 | out += "Time "; 74 | 75 | snprintf(val, sizeof(val), "%04d", rawsec / 864000); 76 | out += val; 77 | out += "."; 78 | 79 | snprintf(val, sizeof(val), "%02d", (rawsec / 36000) % 24); 80 | out += val; 81 | out += ":"; 82 | 83 | snprintf(val, sizeof(val), "%02d", (rawsec / 600) % 60); 84 | out += val; 85 | out += ":"; 86 | 87 | snprintf(val, sizeof(val), "%02d", (rawsec / 10) % 60); 88 | out += val; 89 | out += "\n"; 90 | 91 | return out; 92 | } // toString 93 | 94 | /** 95 | * Set the raw data for the beacon record. 96 | */ 97 | void BLEEddystoneTLM::setData(std::string data) { 98 | if (data.length() != sizeof(m_eddystoneData)) { 99 | return; 100 | } 101 | memcpy(&m_eddystoneData, data.data(), data.length()); 102 | } // setData 103 | 104 | void BLEEddystoneTLM::setUUID(BLEUUID l_uuid) { 105 | beaconUUID = l_uuid.getNative()->uuid.uuid16; 106 | } // setUUID 107 | 108 | void BLEEddystoneTLM::setVersion(uint8_t version) { 109 | m_eddystoneData.version = version; 110 | } // setVersion 111 | 112 | void BLEEddystoneTLM::setVolt(uint16_t volt) { 113 | m_eddystoneData.volt = volt; 114 | } // setVolt 115 | 116 | void BLEEddystoneTLM::setTemp(float temp) { 117 | m_eddystoneData.temp = (uint16_t)temp; 118 | } // setTemp 119 | 120 | void BLEEddystoneTLM::setCount(uint32_t advCount) { 121 | m_eddystoneData.advCount = advCount; 122 | } // setCount 123 | 124 | void BLEEddystoneTLM::setTime(uint32_t tmil) { 125 | m_eddystoneData.tmil = tmil; 126 | } // setTime 127 | -------------------------------------------------------------------------------- /src/BLEEddystoneTLM.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEEddystoneTLM.cpp 3 | * 4 | * Created on: Mar 12, 2018 5 | * Author: pcbreflux 6 | */ 7 | 8 | #ifndef _BLEEddystoneTLM_H_ 9 | #define _BLEEddystoneTLM_H_ 10 | #include "BLEUUID.h" 11 | 12 | #define EDDYSTONE_TLM_FRAME_TYPE 0x20 13 | 14 | /** 15 | * @brief Representation of a beacon. 16 | * See: 17 | * * https://github.com/google/eddystone 18 | */ 19 | class BLEEddystoneTLM { 20 | public: 21 | BLEEddystoneTLM(); 22 | std::string getData(); 23 | BLEUUID getUUID(); 24 | uint8_t getVersion(); 25 | uint16_t getVolt(); 26 | float getTemp(); 27 | uint32_t getCount(); 28 | uint32_t getTime(); 29 | std::string toString(); 30 | void setData(std::string data); 31 | void setUUID(BLEUUID l_uuid); 32 | void setVersion(uint8_t version); 33 | void setVolt(uint16_t volt); 34 | void setTemp(float temp); 35 | void setCount(uint32_t advCount); 36 | void setTime(uint32_t tmil); 37 | 38 | private: 39 | uint16_t beaconUUID; 40 | struct { 41 | uint8_t frameType; 42 | uint8_t version; 43 | uint16_t volt; 44 | uint16_t temp; 45 | uint32_t advCount; 46 | uint32_t tmil; 47 | } __attribute__((packed)) m_eddystoneData; 48 | 49 | }; // BLEEddystoneTLM 50 | 51 | #endif /* _BLEEddystoneTLM_H_ */ 52 | -------------------------------------------------------------------------------- /src/BLEEddystoneURL.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEEddystoneURL.cpp 3 | * 4 | * Created on: Mar 12, 2018 5 | * Author: pcbreflux 6 | */ 7 | 8 | #include 9 | #include "BLEEddystoneURL.h" 10 | 11 | static const char LOG_TAG[] = "BLEEddystoneURL"; 12 | 13 | BLEEddystoneURL::BLEEddystoneURL() { 14 | beaconUUID = 0xFEAA; 15 | lengthURL = 0; 16 | m_eddystoneData.frameType = EDDYSTONE_URL_FRAME_TYPE; 17 | m_eddystoneData.advertisedTxPower = 0; 18 | memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); 19 | } // BLEEddystoneURL 20 | 21 | std::string BLEEddystoneURL::getData() { 22 | return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData)); 23 | } // getData 24 | 25 | BLEUUID BLEEddystoneURL::getUUID() { 26 | return BLEUUID(beaconUUID); 27 | } // getUUID 28 | 29 | int8_t BLEEddystoneURL::getPower() { 30 | return m_eddystoneData.advertisedTxPower; 31 | } // getPower 32 | 33 | std::string BLEEddystoneURL::getURL() { 34 | return std::string((char*) &m_eddystoneData.url, sizeof(m_eddystoneData.url)); 35 | } // getURL 36 | 37 | std::string BLEEddystoneURL::getDecodedURL() { 38 | std::string decodedURL = ""; 39 | 40 | switch (m_eddystoneData.url[0]) { 41 | case 0x00: 42 | decodedURL += "http://www."; 43 | break; 44 | case 0x01: 45 | decodedURL += "https://www."; 46 | break; 47 | case 0x02: 48 | decodedURL += "http://"; 49 | break; 50 | case 0x03: 51 | decodedURL += "https://"; 52 | break; 53 | default: 54 | decodedURL += m_eddystoneData.url[0]; 55 | } 56 | 57 | for (int i = 1; i < lengthURL; i++) { 58 | if (m_eddystoneData.url[i] > 33 && m_eddystoneData.url[i] < 127) { 59 | decodedURL += m_eddystoneData.url[i]; 60 | } else { 61 | switch (m_eddystoneData.url[i]) { 62 | case 0x00: 63 | decodedURL += ".com/"; 64 | break; 65 | case 0x01: 66 | decodedURL += ".org/"; 67 | break; 68 | case 0x02: 69 | decodedURL += ".edu/"; 70 | break; 71 | case 0x03: 72 | decodedURL += ".net/"; 73 | break; 74 | case 0x04: 75 | decodedURL += ".info/"; 76 | break; 77 | case 0x05: 78 | decodedURL += ".biz/"; 79 | break; 80 | case 0x06: 81 | decodedURL += ".gov/"; 82 | break; 83 | case 0x07: 84 | decodedURL += ".com"; 85 | break; 86 | case 0x08: 87 | decodedURL += ".org"; 88 | break; 89 | case 0x09: 90 | decodedURL += ".edu"; 91 | break; 92 | case 0x0A: 93 | decodedURL += ".net"; 94 | break; 95 | case 0x0B: 96 | decodedURL += ".info"; 97 | break; 98 | case 0x0C: 99 | decodedURL += ".biz"; 100 | break; 101 | case 0x0D: 102 | decodedURL += ".gov"; 103 | break; 104 | default: 105 | break; 106 | } 107 | } 108 | } 109 | return decodedURL; 110 | } // getDecodedURL 111 | 112 | 113 | 114 | /** 115 | * Set the raw data for the beacon record. 116 | */ 117 | void BLEEddystoneURL::setData(std::string data) { 118 | if (data.length() > sizeof(m_eddystoneData)) { 119 | return; 120 | } 121 | memset(&m_eddystoneData, 0, sizeof(m_eddystoneData)); 122 | memcpy(&m_eddystoneData, data.data(), data.length()); 123 | lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url)); 124 | } // setData 125 | 126 | void BLEEddystoneURL::setUUID(BLEUUID l_uuid) { 127 | beaconUUID = l_uuid.getNative()->uuid.uuid16; 128 | } // setUUID 129 | 130 | void BLEEddystoneURL::setPower(int8_t advertisedTxPower) { 131 | m_eddystoneData.advertisedTxPower = advertisedTxPower; 132 | } // setPower 133 | 134 | void BLEEddystoneURL::setURL(std::string url) { 135 | if (url.length() > sizeof(m_eddystoneData.url)) { 136 | return; 137 | } 138 | memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); 139 | memcpy(m_eddystoneData.url, url.data(), url.length()); 140 | lengthURL = url.length(); 141 | } // setURL 142 | -------------------------------------------------------------------------------- /src/BLEEddystoneURL.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEEddystoneURL.cpp 3 | * 4 | * Created on: Mar 12, 2018 5 | * Author: pcbreflux 6 | */ 7 | 8 | #ifndef _BLEEddystoneURL_H_ 9 | #define _BLEEddystoneURL_H_ 10 | #include "BLEUUID.h" 11 | 12 | #define EDDYSTONE_URL_FRAME_TYPE 0x10 13 | 14 | /** 15 | * @brief Representation of a beacon. 16 | * See: 17 | * * https://github.com/google/eddystone 18 | */ 19 | class BLEEddystoneURL { 20 | public: 21 | BLEEddystoneURL(); 22 | std::string getData(); 23 | BLEUUID getUUID(); 24 | int8_t getPower(); 25 | std::string getURL(); 26 | std::string getDecodedURL(); 27 | void setData(std::string data); 28 | void setUUID(BLEUUID l_uuid); 29 | void setPower(int8_t advertisedTxPower); 30 | void setURL(std::string url); 31 | 32 | private: 33 | uint16_t beaconUUID; 34 | uint8_t lengthURL; 35 | struct { 36 | uint8_t frameType; 37 | int8_t advertisedTxPower; 38 | uint8_t url[16]; 39 | } __attribute__((packed)) m_eddystoneData; 40 | 41 | }; // BLEEddystoneURL 42 | 43 | #endif /* _BLEEddystoneURL_H_ */ 44 | -------------------------------------------------------------------------------- /src/BLEExceptions.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLExceptions.cpp 3 | * 4 | * Created on: Nov 27, 2017 5 | * Author: kolban 6 | */ 7 | 8 | //#include "BLEExceptions.h" 9 | 10 | -------------------------------------------------------------------------------- /src/BLEExceptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLExceptions.h 3 | * 4 | * Created on: Nov 27, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_ 10 | 11 | #if CONFIG_CXX_EXCEPTIONS != 1 12 | #error "C++ exception handling must be enabled within make menuconfig. See Compiler Options > Enable C++ Exceptions." 13 | #endif 14 | 15 | #include 16 | 17 | 18 | class BLEDisconnectedException : public std::exception { 19 | const char* what() const throw () { 20 | return "BLE Disconnected"; 21 | } 22 | }; 23 | 24 | class BLEUuidNotFoundException : public std::exception { 25 | const char* what() const throw () { 26 | return "No such UUID"; 27 | } 28 | }; 29 | 30 | #endif /* COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_ */ 31 | -------------------------------------------------------------------------------- /src/BLEFreeRTOS.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "BLEFreeRTOS.h" 6 | /** 7 | * Sleep for the specified number of milliseconds. 8 | * @param[in] ms The period in milliseconds for which to sleep. 9 | */ 10 | void BLEFreeRTOS::sleep(uint32_t ms) 11 | { 12 | vTaskDelay(ms / portTICK_PERIOD_MS); 13 | } // sleep 14 | 15 | /** 16 | * Start a new task. 17 | * @param[in] task The function pointer to the function to be run in the task. 18 | * @param[in] taskName A string identifier for the task. 19 | * @param[in] param An optional parameter to be passed to the started task. 20 | * @param[in] stackSize An optional paremeter supplying the size of the stack in which to run the task. 21 | */ 22 | void BLEFreeRTOS::startTask(void task(void *), std::string taskName, void *param, uint32_t stackSize) 23 | { 24 | xTaskCreate(task, taskName.data(), stackSize, param, 5, NULL); 25 | } // startTask 26 | 27 | /** 28 | * Delete the task. 29 | * @param[in] pTask An optional handle to the task to be deleted. If not supplied the calling task will be deleted. 30 | */ 31 | void BLEFreeRTOS::deleteTask(TaskHandle_t pTask) 32 | { 33 | vTaskDelete(pTask); 34 | } // deleteTask 35 | 36 | /** 37 | * Get the time in milliseconds since the %BLEFreeRTOS scheduler started. 38 | * @return The time in milliseconds since the %BLEFreeRTOS scheduler started. 39 | */ 40 | uint32_t BLEFreeRTOS::getTimeSinceStart() 41 | { 42 | return (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS); 43 | } // getTimeSinceStart 44 | 45 | /** 46 | * @brief Wait for a semaphore to be released by trying to take it and 47 | * then releasing it again. 48 | * @param [in] owner A debug tag. 49 | * @return The value associated with the semaphore. 50 | */ 51 | uint32_t BLEFreeRTOS::Semaphore::wait(std::string owner) 52 | { 53 | xSemaphoreTake(m_semaphore, portMAX_DELAY); 54 | xSemaphoreGive(m_semaphore); 55 | return m_value; 56 | } // wait 57 | 58 | /** 59 | * @brief Wait for a semaphore to be released in a given period of time by trying to take it and 60 | * then releasing it again. The value associated with the semaphore can be taken by value() call after return 61 | * @param [in] owner A debug tag. 62 | * @param [in] timeoutMs timeout to wait in ms. 63 | * @return True if we took the semaphore within timeframe. 64 | */ 65 | bool BLEFreeRTOS::Semaphore::timedWait(std::string owner, uint32_t timeoutMs) 66 | { 67 | auto ret = pdTRUE; 68 | ret = xSemaphoreTake(m_semaphore, timeoutMs); 69 | xSemaphoreGive(m_semaphore); 70 | return ret; 71 | } // wait 72 | 73 | BLEFreeRTOS::Semaphore::Semaphore(std::string name) 74 | { 75 | m_semaphore = xSemaphoreCreateBinary(); 76 | xSemaphoreGive(m_semaphore); 77 | m_name = name; 78 | m_owner = std::string(""); 79 | m_value = 0; 80 | } 81 | 82 | BLEFreeRTOS::Semaphore::~Semaphore() 83 | { 84 | vSemaphoreDelete(m_semaphore); 85 | } 86 | 87 | /** 88 | * @brief Give a semaphore. 89 | * The Semaphore is given. 90 | */ 91 | void BLEFreeRTOS::Semaphore::give() 92 | { 93 | m_owner = std::string(""); 94 | xSemaphoreGive(m_semaphore); 95 | } // Semaphore::give 96 | 97 | /** 98 | * @brief Give a semaphore. 99 | * The Semaphore is given with an associated value. 100 | * @param [in] value The value to associate with the semaphore. 101 | */ 102 | void BLEFreeRTOS::Semaphore::give(uint32_t value) 103 | { 104 | m_value = value; 105 | give(); 106 | } // give 107 | 108 | /** 109 | * @brief Give a semaphore from an ISR. 110 | */ 111 | void BLEFreeRTOS::Semaphore::giveFromISR() 112 | { 113 | BaseType_t higherPriorityTaskWoken; 114 | xSemaphoreGiveFromISR(m_semaphore, &higherPriorityTaskWoken); 115 | } // giveFromISR 116 | 117 | /** 118 | * @brief Take a semaphore. 119 | * Take a semaphore and wait indefinitely. 120 | * @param [in] owner The new owner (for debugging) 121 | * @return True if we took the semaphore. 122 | */ 123 | bool BLEFreeRTOS::Semaphore::take(std::string owner) 124 | { 125 | bool rc = false; 126 | rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY) == pdTRUE; 127 | m_owner = owner; 128 | return rc; 129 | } // Semaphore::take 130 | 131 | /** 132 | * @brief Take a semaphore. 133 | * Take a semaphore but return if we haven't obtained it in the given period of milliseconds. 134 | * @param [in] timeoutMs Timeout in milliseconds. 135 | * @param [in] owner The new owner (for debugging) 136 | * @return True if we took the semaphore. 137 | */ 138 | bool BLEFreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) 139 | { 140 | bool rc = false; 141 | rc = ::xSemaphoreTake(m_semaphore, timeoutMs / portTICK_PERIOD_MS) == pdTRUE; 142 | m_owner = owner; 143 | return rc; 144 | } // Semaphore::take 145 | 146 | /** 147 | * @brief Create a string representation of the semaphore. 148 | * @return A string representation of the semaphore. 149 | */ 150 | std::string BLEFreeRTOS::Semaphore::toString() 151 | { 152 | char hex[9]; 153 | std::string res = "name: " + m_name + " (0x"; 154 | snprintf(hex, sizeof(hex), "%08x", (uint32_t)m_semaphore); 155 | res += hex; 156 | res += "), owner: " + m_owner; 157 | return res; 158 | } // toString 159 | 160 | /** 161 | * @brief Set the name of the semaphore. 162 | * @param [in] name The name of the semaphore. 163 | */ 164 | void BLEFreeRTOS::Semaphore::setName(std::string name) 165 | { 166 | m_name = name; 167 | } // setName 168 | -------------------------------------------------------------------------------- /src/BLEFreeRTOS.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_FREERTOS_H_ 2 | #define MAIN_FREERTOS_H_ 3 | #include "Seeed_Arduino_FreeRTOS.h" 4 | #include 5 | #include 6 | 7 | /** 8 | * @brief Interface to %BLEFreeRTOS functions. 9 | */ 10 | class BLEFreeRTOS { 11 | public: 12 | static void sleep(uint32_t ms); 13 | static void startTask(void task(void*), std::string taskName, void* param = nullptr, uint32_t stackSize = 2048); 14 | static void deleteTask(TaskHandle_t pTask = nullptr); 15 | 16 | static uint32_t getTimeSinceStart(); 17 | 18 | class Semaphore { 19 | public: 20 | Semaphore(std::string owner = ""); 21 | ~Semaphore(); 22 | void give(); 23 | void give(uint32_t value); 24 | void giveFromISR(); 25 | void setName(std::string name); 26 | bool take(std::string owner = ""); 27 | bool take(uint32_t timeoutMs, std::string owner = ""); 28 | std::string toString(); 29 | uint32_t wait(std::string owner = ""); 30 | bool timedWait(std::string owner = "", uint32_t timeoutMs = portMAX_DELAY); 31 | uint32_t value(){ return m_value; }; 32 | 33 | private: 34 | SemaphoreHandle_t m_semaphore; 35 | std::string m_name; 36 | std::string m_owner; 37 | uint32_t m_value; 38 | bool m_usePthreads; 39 | 40 | }; 41 | }; 42 | 43 | #endif /* MAIN_FREERTOS_H_ */ 44 | -------------------------------------------------------------------------------- /src/BLEHIDDevice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEHIDDevice.cpp 3 | * 4 | * Created on: Jan 03, 2018 5 | * Author: chegewara 6 | */ 7 | #include "BLEHIDDevice.h" 8 | #include "BLE2904.h" 9 | 10 | 11 | BLEHIDDevice::BLEHIDDevice(BLEServer* server) { 12 | /* 13 | * Here we create mandatory services described in bluetooth specification 14 | */ 15 | m_deviceInfoService = server->createService(BLEUUID((uint16_t) 0x180a)); 16 | m_hidService = server->createService(BLEUUID((uint16_t) 0x1812), 40); 17 | m_batteryService = server->createService(BLEUUID((uint16_t) 0x180f)); 18 | 19 | /* 20 | * Mandatory characteristic for device info service 21 | */ 22 | m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, BLECharacteristic::PROPERTY_READ); 23 | 24 | /* 25 | * Mandatory characteristics for HID service 26 | */ 27 | m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, BLECharacteristic::PROPERTY_READ); 28 | //m_reportMapCharacteristic->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ); 29 | m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, BLECharacteristic::PROPERTY_READ); 30 | //m_hidInfoCharacteristic->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ); 31 | m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, BLECharacteristic::PROPERTY_WRITE_NR | BLECharacteristic::PROPERTY_READ); 32 | //m_protocolModeCharacteristic->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ|GATT_PERM_WRITE_AUTHEN_REQ); 33 | m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, BLECharacteristic::PROPERTY_WRITE_NR); 34 | //m_hidControlCharacteristic->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ|GATT_PERM_WRITE_AUTHEN_REQ); 35 | 36 | /* 37 | * Mandatory battery level characteristic with notification and presence descriptor 38 | */ 39 | BLE2904* batteryLevelDescriptor = new BLE2904(); 40 | batteryLevelDescriptor->setFormat(BLE2904::FORMAT_UINT8); 41 | batteryLevelDescriptor->setNamespace(1); 42 | batteryLevelDescriptor->setUnit(0x27ad); 43 | 44 | m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); 45 | m_batteryLevelCharacteristic->addDescriptor(batteryLevelDescriptor); 46 | m_batteryLevelCharacteristic->addDescriptor(new BLE2902()); 47 | 48 | /* 49 | * This value is setup here because its default value in most usage cases, its very rare to use boot mode 50 | * and we want to simplify library using as much as possible 51 | */ 52 | const uint8_t pMode[] = { 0x01 }; 53 | protocolMode()->setValue((uint8_t*) pMode, 1); 54 | } 55 | 56 | BLEHIDDevice::~BLEHIDDevice() { 57 | } 58 | 59 | /* 60 | * @brief 61 | */ 62 | void BLEHIDDevice::reportMap(uint8_t* map, uint16_t size) { 63 | Serial.printf("set report map.........................\n\r"); 64 | m_reportMapCharacteristic->setValue(map, size); 65 | } 66 | 67 | /* 68 | * @brief This function suppose to be called at the end, when we have created all characteristics we need to build HID service 69 | */ 70 | void BLEHIDDevice::startServices() { 71 | m_deviceInfoService->start(); 72 | m_hidService->start(); 73 | m_batteryService->start(); 74 | } 75 | 76 | /* 77 | * @brief Create manufacturer characteristic (this characteristic is optional) 78 | */ 79 | BLECharacteristic* BLEHIDDevice::manufacturer() { 80 | m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, BLECharacteristic::PROPERTY_READ); 81 | return m_manufacturerCharacteristic; 82 | } 83 | 84 | /* 85 | * @brief Set manufacturer name 86 | * @param [in] name manufacturer name 87 | */ 88 | void BLEHIDDevice::manufacturer(std::string name) { 89 | m_manufacturerCharacteristic->setValue(name); 90 | } 91 | 92 | /* 93 | * @brief 94 | */ 95 | void BLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) { 96 | uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version }; 97 | m_pnpCharacteristic->setValue(pnp, sizeof(pnp)); 98 | } 99 | 100 | /* 101 | * @brief 102 | */ 103 | void BLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) { 104 | uint8_t info[] = { 0x11, 0x1, country, flags }; 105 | m_hidInfoCharacteristic->setValue(info, sizeof(info)); 106 | } 107 | 108 | /* 109 | * @brief Create input report characteristic that need to be saved as new characteristic object so can be further used 110 | * @param [in] reportID input report ID, the same as in report map for input object related to created characteristic 111 | * @return pointer to new input report characteristic 112 | */ 113 | BLECharacteristic* BLEHIDDevice::inputReport(uint8_t reportID) { 114 | BLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); 115 | BLEDescriptor* inputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908), ATTRIB_FLAG_CCCD_APPL, (GATT_PERM_READ | GATT_PERM_WRITE), 2); 116 | BLE2902* p2902 = new BLE2902(); 117 | inputReportCharacteristic->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ); 118 | inputReportDescriptor->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ | GATT_PERM_WRITE_AUTHEN_REQ); 119 | p2902->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ | GATT_PERM_WRITE_AUTHEN_REQ); 120 | 121 | uint8_t desc1_val[] = { reportID, 0x01 }; 122 | inputReportDescriptor->setValue((uint8_t*) desc1_val, 2); 123 | inputReportCharacteristic->addDescriptor(p2902); 124 | inputReportCharacteristic->addDescriptor(inputReportDescriptor); 125 | 126 | return inputReportCharacteristic; 127 | } 128 | 129 | /* 130 | * @brief Create output report characteristic that need to be saved as new characteristic object so can be further used 131 | * @param [in] reportID Output report ID, the same as in report map for output object related to created characteristic 132 | * @return Pointer to new output report characteristic 133 | */ 134 | BLECharacteristic* BLEHIDDevice::outputReport(uint8_t reportID) { 135 | BLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR); 136 | BLEDescriptor* outputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908), ATTRIB_FLAG_CCCD_APPL, (GATT_PERM_READ | GATT_PERM_WRITE), 2); 137 | outputReportCharacteristic->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ | GATT_PERM_WRITE_AUTHEN_REQ); 138 | outputReportDescriptor->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ); 139 | 140 | uint8_t desc1_val[] = { reportID, 0x02 }; 141 | outputReportDescriptor->setValue((uint8_t*) desc1_val, 2); 142 | outputReportCharacteristic->addDescriptor(outputReportDescriptor); 143 | 144 | return outputReportCharacteristic; 145 | } 146 | 147 | /* 148 | * @brief Create feature report characteristic that need to be saved as new characteristic object so can be further used 149 | * @param [in] reportID Feature report ID, the same as in report map for feature object related to created characteristic 150 | * @return Pointer to new feature report characteristic 151 | */ 152 | BLECharacteristic* BLEHIDDevice::featureReport(uint8_t reportID) { 153 | BLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE); 154 | BLEDescriptor* featureReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908), ATTRIB_FLAG_CCCD_APPL, (GATT_PERM_READ | GATT_PERM_WRITE), 2); 155 | 156 | featureReportCharacteristic->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ | GATT_PERM_WRITE_AUTHEN_REQ); 157 | featureReportDescriptor->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ); 158 | 159 | uint8_t desc1_val[] = { reportID, 0x03 }; 160 | featureReportDescriptor->setValue((uint8_t*) desc1_val, 2); 161 | featureReportCharacteristic->addDescriptor(featureReportDescriptor); 162 | 163 | return featureReportCharacteristic; 164 | } 165 | 166 | /* 167 | * @brief 168 | */ 169 | BLECharacteristic* BLEHIDDevice::bootInput() { 170 | BLECharacteristic* bootInputCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a22, BLECharacteristic::PROPERTY_NOTIFY); 171 | bootInputCharacteristic->setAccessPermissions(GATT_PERM_READ_AUTHEN_REQ | GATT_PERM_WRITE_AUTHEN_REQ); 172 | bootInputCharacteristic->addDescriptor(new BLE2902()); 173 | 174 | return bootInputCharacteristic; 175 | } 176 | 177 | /* 178 | * @brief 179 | */ 180 | BLECharacteristic* BLEHIDDevice::bootOutput() { 181 | BLECharacteristic *bootOutputCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a32, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR); 182 | bootOutputCharacteristic->setAccessPermissions( GATT_PERM_READ_AUTHEN_REQ | GATT_PERM_WRITE_AUTHEN_REQ ); 183 | return bootOutputCharacteristic; 184 | } 185 | 186 | /* 187 | * @brief 188 | */ 189 | BLECharacteristic* BLEHIDDevice::hidControl() { 190 | return m_hidControlCharacteristic; 191 | } 192 | 193 | /* 194 | * @brief 195 | */ 196 | BLECharacteristic* BLEHIDDevice::protocolMode() { 197 | return m_protocolModeCharacteristic; 198 | } 199 | 200 | void BLEHIDDevice::setBatteryLevel(uint8_t level) { 201 | m_batteryLevelCharacteristic->setValue(&level, 1); 202 | } 203 | /* 204 | * @brief Returns battery level characteristic 205 | * @ return battery level characteristic 206 | *//* 207 | BLECharacteristic* BLEHIDDevice::batteryLevel() { 208 | return m_batteryLevelCharacteristic; 209 | } 210 | 211 | 212 | 213 | BLECharacteristic* BLEHIDDevice::reportMap() { 214 | return m_reportMapCharacteristic; 215 | } 216 | 217 | BLECharacteristic* BLEHIDDevice::pnp() { 218 | return m_pnpCharacteristic; 219 | } 220 | 221 | 222 | BLECharacteristic* BLEHIDDevice::hidInfo() { 223 | return m_hidInfoCharacteristic; 224 | } 225 | */ 226 | /* 227 | * @brief 228 | */ 229 | BLEService* BLEHIDDevice::deviceInfo() { 230 | return m_deviceInfoService; 231 | } 232 | 233 | /* 234 | * @brief 235 | */ 236 | BLEService* BLEHIDDevice::hidService() { 237 | return m_hidService; 238 | } 239 | 240 | /* 241 | * @brief 242 | */ 243 | BLEService* BLEHIDDevice::batteryService() { 244 | return m_batteryService; 245 | } 246 | 247 | 248 | -------------------------------------------------------------------------------- /src/BLEHIDDevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEHIDDevice.h 3 | * 4 | * Created on: Jan 03, 2018 5 | * Author: chegewara 6 | */ 7 | 8 | #ifndef _BLEHIDDEVICE_H_ 9 | #define _BLEHIDDEVICE_H_ 10 | 11 | 12 | #include "BLECharacteristic.h" 13 | #include "BLEService.h" 14 | #include "BLEDescriptor.h" 15 | #include "BLE2902.h" 16 | #include "HIDTypes.h" 17 | 18 | #define GENERIC_HID 0x03C0 19 | #define HID_KEYBOARD 0x03C1 20 | #define HID_MOUSE 0x03C2 21 | #define HID_JOYSTICK 0x03C3 22 | #define HID_GAMEPAD 0x03C4 23 | #define HID_TABLET 0x03C5 24 | #define HID_CARD_READER 0x03C6 25 | #define HID_DIGITAL_PEN 0x03C7 26 | #define HID_BARCODE 0x03C8 27 | 28 | class BLEHIDDevice { 29 | public: 30 | BLEHIDDevice(BLEServer*); 31 | virtual ~BLEHIDDevice(); 32 | 33 | void reportMap(uint8_t* map, uint16_t); 34 | void startServices(); 35 | 36 | BLEService* deviceInfo(); 37 | BLEService* hidService(); 38 | BLEService* batteryService(); 39 | 40 | BLECharacteristic* manufacturer(); 41 | void manufacturer(std::string name); 42 | //BLECharacteristic* pnp(); 43 | void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version); 44 | //BLECharacteristic* hidInfo(); 45 | void hidInfo(uint8_t country, uint8_t flags); 46 | //BLECharacteristic* batteryLevel(); 47 | void setBatteryLevel(uint8_t level); 48 | 49 | 50 | //BLECharacteristic* reportMap(); 51 | BLECharacteristic* hidControl(); 52 | BLECharacteristic* inputReport(uint8_t reportID); 53 | BLECharacteristic* outputReport(uint8_t reportID); 54 | BLECharacteristic* featureReport(uint8_t reportID); 55 | BLECharacteristic* protocolMode(); 56 | BLECharacteristic* bootInput(); 57 | BLECharacteristic* bootOutput(); 58 | 59 | private: 60 | BLEService* m_deviceInfoService; //0x180a 61 | BLEService* m_hidService; //0x1812 62 | BLEService* m_batteryService = 0; //0x180f 63 | 64 | BLECharacteristic* m_manufacturerCharacteristic; //0x2a29 65 | BLECharacteristic* m_pnpCharacteristic; //0x2a50 66 | BLECharacteristic* m_hidInfoCharacteristic; //0x2a4a 67 | BLECharacteristic* m_reportMapCharacteristic; //0x2a4b 68 | BLECharacteristic* m_hidControlCharacteristic; //0x2a4c 69 | BLECharacteristic* m_protocolModeCharacteristic; //0x2a4e 70 | BLECharacteristic* m_batteryLevelCharacteristic; //0x2a19 71 | }; 72 | #endif /* _BLEHIDDEVICE_H_ */ 73 | -------------------------------------------------------------------------------- /src/BLERemoteCharacteristic.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ 3 | #define COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ 4 | #include 5 | #include "BLERemoteService.h" 6 | #include "BLEUUID.h" 7 | #include "BLEFreeRTOS.h" 8 | #include "BLERemoteDescriptor.h" 9 | #include "seeed_rpcUnified.h" 10 | #include "rtl_ble/ble_unified.h" 11 | 12 | class BLERemoteService; 13 | class BLERemoteDescriptor; 14 | class BLERemoteCharacteristic; 15 | 16 | typedef void (*notify_callback)(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify); 17 | /** 18 | * @brief A model of a remote %BLE characteristic. 19 | */ 20 | class BLERemoteCharacteristic { 21 | public: 22 | ~BLERemoteCharacteristic(); 23 | BLEUUID getUUID(); 24 | uint16_t getHandle(); 25 | uint16_t getendHandle(); 26 | bool canBroadcast(); 27 | bool canRead(); 28 | bool canNotify(); 29 | bool canWrite(); 30 | bool canIndicate(); 31 | bool canWriteNoResponse(); 32 | std::string readValue(); 33 | uint8_t readUInt8(); 34 | uint16_t readUInt16(); 35 | uint32_t readUInt32(); 36 | float readFloat(); 37 | void writeValue(uint8_t* data, size_t length, bool response = false); 38 | void writeValue(std::string newValue, bool response = false); 39 | void writeValue(uint8_t newValue, bool response = false); 40 | BLERemoteDescriptor* getDescriptor(BLEUUID uuid); 41 | std::map* getDescriptors(); 42 | void registerForNotify(notify_callback _callback, bool notifications = true); 43 | uint8_t* readRawData(); 44 | std::string toString(); 45 | 46 | private: 47 | friend class BLEClient; 48 | friend class BLERemoteService; 49 | friend class BLERemoteDescriptor; 50 | 51 | BLERemoteCharacteristic(uint16_t decl_handle, 52 | uint16_t properties, 53 | uint16_t value_handle, 54 | BLEUUID uuid, 55 | BLERemoteService* pRemoteService 56 | ); 57 | // Private properties 58 | BLEUUID m_uuid; 59 | uint16_t m_end_handle; 60 | uint16_t m_handle; 61 | BLERemoteService* m_pRemoteService; 62 | uint8_t *m_rawData; 63 | uint16_t m_charProp; 64 | std::string m_value; 65 | 66 | 67 | BLERemoteService* getRemoteService(); 68 | notify_callback m_notifyCallback; 69 | void retrieveDescriptors(); 70 | void removeDescriptors(); 71 | bool m_haveDescriptor; 72 | 73 | std::map m_descriptorMap; 74 | BLEFreeRTOS::Semaphore m_semaphoreReadCharEvt = BLEFreeRTOS::Semaphore("ReadCharEvt"); 75 | BLEFreeRTOS::Semaphore m_semaphoreRegForNotifyEvt = BLEFreeRTOS::Semaphore("RegForNotifyEvt"); 76 | BLEFreeRTOS::Semaphore m_semaphoregetdescEvt = BLEFreeRTOS::Semaphore("getDescriptor"); 77 | BLEFreeRTOS::Semaphore m_semaphoreWriteCharEvt = BLEFreeRTOS::Semaphore("WriteCharEvt"); 78 | 79 | T_APP_RESULT clientCallbackDefault(T_CLIENT_ID client_id, uint8_t conn_id, void *p_data); 80 | 81 | 82 | }; // BLERemoteCharacteristic 83 | #endif /* COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ */ 84 | -------------------------------------------------------------------------------- /src/BLERemoteDescriptor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLERemoteDescriptor.cpp 3 | * 4 | * Created on: Jul 8, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #include 9 | #include "BLERemoteDescriptor.h" 10 | 11 | BLERemoteDescriptor::BLERemoteDescriptor( 12 | uint16_t handle, 13 | BLEUUID uuid, 14 | BLERemoteCharacteristic* pRemoteCharacteristic) { 15 | 16 | m_handle = handle; 17 | m_uuid = uuid; 18 | m_pRemoteCharacteristic = pRemoteCharacteristic; 19 | } 20 | 21 | 22 | /** 23 | * @brief Return a string representation of this BLE Remote Descriptor. 24 | * @retun A string representation of this BLE Remote Descriptor. 25 | */ 26 | std::string BLERemoteDescriptor::toString() { 27 | char val[6]; 28 | snprintf(val, sizeof(val), "%d", getHandle()); 29 | std::string res = "handle: "; 30 | res += val; 31 | res += ", uuid: " + getUUID().toString(); 32 | return res; 33 | } // toString 34 | 35 | /** 36 | * @brief Retrieve the UUID associated this remote descriptor. 37 | * @return The UUID associated this remote descriptor. 38 | */ 39 | BLEUUID BLERemoteDescriptor::getUUID() { 40 | return m_uuid; 41 | } // getUUID 42 | 43 | /** 44 | * @brief Retrieve the handle associated with this remote descriptor. 45 | * @return The handle associated with this remote descriptor. 46 | */ 47 | uint16_t BLERemoteDescriptor::getHandle() { 48 | return m_handle; 49 | } // getHandle 50 | 51 | /** 52 | * @brief Get the characteristic that owns this descriptor. 53 | * @return The characteristic that owns this descriptor. 54 | */ 55 | BLERemoteCharacteristic* BLERemoteDescriptor::getRemoteCharacteristic() { 56 | return m_pRemoteCharacteristic; 57 | } // getRemoteCharacteristic 58 | 59 | 60 | void BLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool response) { 61 | // Check to see that we are connected. 62 | if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) { 63 | return; 64 | } 65 | client_attr_write(m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(),m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),GATT_WRITE_TYPE_REQ,getHandle(),length,(uint8_t *)data); 66 | } // writeValue 67 | 68 | 69 | /** 70 | * @brief Write data represented as a string to the BLE Remote Descriptor. 71 | * @param [in] newValue The data to send to the remote descriptor. 72 | * @param [in] response True if we expect a response. 73 | */ 74 | void BLERemoteDescriptor::writeValue(std::string newValue, bool response) { 75 | writeValue((uint8_t*) newValue.data(), newValue.length(), response); 76 | } // writeValue 77 | 78 | 79 | /** 80 | * @brief Write a byte value to the Descriptor. 81 | * @param [in] The single byte to write. 82 | * @param [in] True if we expect a response. 83 | */ 84 | void BLERemoteDescriptor::writeValue(uint8_t newValue, bool response) { 85 | writeValue(&newValue, 1, response); 86 | } // writeValue 87 | 88 | std::string BLERemoteDescriptor::readValue() { 89 | // Check to see that we are connected. 90 | if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) { 91 | return std::string(); 92 | } 93 | m_semaphoreReadDescrEvt.take("readValue"); 94 | client_attr_read(m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(), m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),getHandle()); 95 | // Block waiting for the event that indicates that the read has completed. When it has, the std::string found 96 | // in m_value will contain our data. 97 | m_semaphoreReadDescrEvt.wait("readValue"); 98 | return m_value; 99 | } // readValue 100 | 101 | uint8_t BLERemoteDescriptor::readUInt8() { 102 | std::string value = readValue(); 103 | if (value.length() >= 1) { 104 | return (uint8_t) value[0]; 105 | } 106 | return 0; 107 | } // readUInt8 108 | 109 | uint16_t BLERemoteDescriptor::readUInt16() { 110 | std::string value = readValue(); 111 | if (value.length() >= 2) { 112 | return *(uint16_t*) value.data(); 113 | } 114 | return 0; 115 | } // readUInt16 116 | 117 | uint32_t BLERemoteDescriptor::readUInt32() { 118 | std::string value = readValue(); 119 | if (value.length() >= 4) { 120 | return *(uint32_t*) value.data(); 121 | } 122 | return 0; 123 | } // readUInt32 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /src/BLERemoteDescriptor.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ 4 | #define COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ 5 | 6 | 7 | #include 8 | #include "BLERemoteCharacteristic.h" 9 | #include "BLEUUID.h" 10 | #include "BLEFreeRTOS.h" 11 | #include "seeed_rpcUnified.h" 12 | #include "rtl_ble/ble_unified.h" 13 | 14 | class BLEClient; 15 | class BLERemoteCharacteristic; 16 | /** 17 | * @brief A model of remote %BLE descriptor. 18 | */ 19 | class BLERemoteDescriptor { 20 | public: 21 | BLEUUID getUUID(); 22 | uint16_t getHandle(); 23 | std::string toString(void); 24 | BLERemoteCharacteristic* getRemoteCharacteristic(); 25 | void writeValue(uint8_t* data, size_t length, bool response = false); 26 | void writeValue(std::string newValue, bool response = false); 27 | void writeValue(uint8_t newValue, bool response = false); 28 | std::string readValue(void); 29 | uint8_t readUInt8(void); 30 | uint16_t readUInt16(void); 31 | uint32_t readUInt32(void); 32 | private: 33 | friend class BLERemoteCharacteristic; 34 | friend class BLEClient; 35 | BLERemoteDescriptor( 36 | uint16_t handle, 37 | BLEUUID uuid, 38 | BLERemoteCharacteristic* pRemoteCharacteristic 39 | ); 40 | uint16_t m_handle; // Server handle of this descriptor. 41 | BLEUUID m_uuid; // UUID of this descriptor. 42 | std::string m_value; // Last received value of the descriptor. 43 | BLERemoteCharacteristic* m_pRemoteCharacteristic; // 44 | BLEFreeRTOS::Semaphore m_semaphoreReadDescrEvt = BLEFreeRTOS::Semaphore("ReadDescrEvt"); 45 | 46 | }; 47 | 48 | #endif /* COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ */ 49 | -------------------------------------------------------------------------------- /src/BLERemoteService.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLERemoteService.cpp 3 | * 4 | * Created on: Jul 8, 2017 5 | * Author: kolban 6 | */ 7 | 8 | 9 | #define TAG "RemoteService" 10 | #include 11 | #include "BLERemoteService.h" 12 | #include "rpc_unified_log.h" 13 | #pragma GCC diagnostic warning "-Wunused-but-set-parameter" 14 | 15 | BLERemoteService::BLERemoteService( 16 | uint16_t att_handle, 17 | uint16_t end_group_handle, 18 | BLEUUID uuid, 19 | BLEClient* pClient 20 | ) { 21 | m_uuid = uuid; 22 | m_haveCharacteristics = false; 23 | m_startHandle = att_handle; 24 | m_endHandle = end_group_handle; 25 | m_pClient = pClient; 26 | } 27 | 28 | 29 | BLERemoteService::~BLERemoteService() { 30 | } 31 | 32 | /** 33 | * @brief Get the client associated with this service. 34 | * @return A reference to the client associated with this service. 35 | */ 36 | BLEClient* BLERemoteService::getClient() { 37 | return m_pClient; 38 | } // getClient 39 | 40 | /** 41 | * @brief Get the client associated with this service. 42 | * @return A reference to the client associated with this service. 43 | */ 44 | uint16_t BLERemoteService::getEndHandle() { 45 | return m_endHandle; 46 | } // getClient 47 | 48 | 49 | uint16_t BLERemoteService::getStartHandle() { 50 | return m_startHandle; 51 | } // getStartHandle 52 | 53 | uint16_t BLERemoteService::getHandle() { 54 | return getStartHandle(); 55 | } // getHandle 56 | 57 | 58 | BLEUUID BLERemoteService::getUUID() { 59 | return m_uuid; 60 | } 61 | 62 | /** 63 | * @brief Read the value of a characteristic associated with this service. 64 | */ 65 | std::string BLERemoteService::getValue(BLEUUID characteristicUuid) { 66 | std::string ret = getCharacteristic(characteristicUuid)->readValue(); 67 | return ret; 68 | } // readValue 69 | 70 | /** 71 | * @brief Set the value of a characteristic. 72 | * @param [in] characteristicUuid The characteristic to set. 73 | * @param [in] value The value to set. 74 | * @throws BLEUuidNotFound 75 | */ 76 | void BLERemoteService::setValue(BLEUUID characteristicUuid, std::string value) { 77 | getCharacteristic(characteristicUuid)->writeValue(value); 78 | } // setValue 79 | 80 | /** 81 | * @brief Get the remote characteristic object for the characteristic UUID. 82 | * @param [in] uuid Remote characteristic uuid. 83 | * @return Reference to the remote characteristic object. 84 | * @throws BLEUuidNotFoundException 85 | */ 86 | BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) { 87 | return getCharacteristic(BLEUUID(uuid)); 88 | } // getCharacteristic 89 | 90 | /** 91 | * @brief Get the characteristic object for the UUID. 92 | * @param [in] uuid Characteristic uuid. 93 | * @return Reference to the characteristic object. 94 | * @throws BLEUuidNotFoundException 95 | */ 96 | BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) { 97 | if (!m_haveCharacteristics) { 98 | retrieveCharacteristics(); 99 | } 100 | std::string v = uuid.toString(); 101 | for (auto &myPair : m_characteristicMap) { 102 | if (myPair.first == v) { 103 | return myPair.second; 104 | } 105 | } 106 | // throw new BLEUuidNotFoundException(); // <-- we dont want exception here, which will cause app crash, we want to search if any characteristic can be found one after another 107 | return nullptr; 108 | } // getCharacteristic 109 | 110 | /** 111 | * @brief Retrieve a map of all the characteristics of this service. 112 | * @return A map of all the characteristics of this service. 113 | */ 114 | std::map* BLERemoteService::getCharacteristics() { 115 | // If is possible that we have not read the characteristics associated with the service so do that 116 | // now. The request to retrieve the characteristics by calling "retrieveCharacteristics" is a blocking 117 | // call and does not return until all the characteristics are available. 118 | if (!m_haveCharacteristics) { 119 | retrieveCharacteristics(); 120 | } 121 | return &m_characteristicMap; 122 | } // getCharacteristics 123 | 124 | /** 125 | * @brief Retrieve a map of all the characteristics of this service. 126 | * @return A map of all the characteristics of this service. 127 | */ 128 | std::map* BLERemoteService::getCharacteristicsByHandle() { 129 | // If is possible that we have not read the characteristics associated with the service so do that 130 | // now. The request to retrieve the characteristics by calling "retrieveCharacteristics" is a blocking 131 | // call and does not return until all the characteristics are available. 132 | if (!m_haveCharacteristics) { 133 | retrieveCharacteristics(); 134 | } 135 | return &m_characteristicMapByHandle; 136 | } // getCharacteristicsByHandle 137 | 138 | /** 139 | * @brief This function is designed to get characteristics map when we have multiple characteristics with the same UUID 140 | */ 141 | void BLERemoteService::getCharacteristics(std::map* pCharacteristicMap) { 142 | pCharacteristicMap = &m_characteristicMapByHandle; 143 | } // Get the characteristics map. 144 | 145 | 146 | /** 147 | * @brief Retrieve all the characteristics for this service. 148 | * This function will not return until we have all the characteristics. 149 | * @return N/A 150 | */ 151 | void BLERemoteService::retrieveCharacteristics() { 152 | removeCharacteristics(); // Forget any previous characteristics. 153 | client_all_char_discovery(m_pClient->getConnId(), m_pClient->getGattcIf(),m_startHandle,m_endHandle); 154 | m_semaphoregetchaEvt.take("getCharacteristic"); 155 | m_haveCharacteristics = (m_semaphoregetchaEvt.wait("getCharacteristic") == 0); 156 | 157 | } // getCharacteristics 158 | 159 | /** 160 | * @brief Delete the characteristics in the characteristics map. 161 | * We maintain a map called m_characteristicsMap that contains pointers to BLERemoteCharacteristic 162 | * object references. Since we allocated these in this class, we are also responsible for deleteing 163 | * them. This method does just that. 164 | * @return N/A. 165 | */ 166 | void BLERemoteService::removeCharacteristics() { 167 | for (auto &myPair : m_characteristicMap) { 168 | delete myPair.second; 169 | //m_characteristicMap.erase(myPair.first); // Should be no need to delete as it will be deleted by the clear 170 | } 171 | m_characteristicMap.clear(); // Clear the map 172 | for (auto &myPair : m_characteristicMapByHandle) { 173 | delete myPair.second; 174 | } 175 | m_characteristicMapByHandle.clear(); // Clear the map 176 | } // removeCharacteristics 177 | 178 | /** 179 | * @brief Create a string representation of this remote service. 180 | * @return A string representation of this remote service. 181 | */ 182 | std::string BLERemoteService::toString() { 183 | std::string res = "Service: uuid: " + m_uuid.toString(); 184 | char val[6]; 185 | res += ", start_handle: "; 186 | snprintf(val, sizeof(val), "%d", m_startHandle); 187 | res += val; 188 | snprintf(val, sizeof(val), "%04x", m_startHandle); 189 | res += " 0x"; 190 | res += val; 191 | res += ", end_handle: "; 192 | snprintf(val, sizeof(val), "%d", m_endHandle); 193 | res += val; 194 | snprintf(val, sizeof(val), "%04x", m_endHandle); 195 | res += " 0x"; 196 | res += val; 197 | for (auto &myPair : m_characteristicMap) { 198 | res += "\n" + myPair.second->toString(); 199 | // myPair.second is the value 200 | } 201 | return res; 202 | } // toString 203 | 204 | T_APP_RESULT BLERemoteService::clientCallbackDefault( 205 | T_CLIENT_ID client_id, uint8_t conn_id, void *p_data) { 206 | T_APP_RESULT result = APP_RESULT_SUCCESS; 207 | T_BLE_CLIENT_CB_DATA *p_ble_client_cb_data = (T_BLE_CLIENT_CB_DATA *)p_data; 208 | 209 | switch (p_ble_client_cb_data->cb_type) 210 | { 211 | case BLE_CLIENT_CB_TYPE_DISCOVERY_STATE: 212 | { 213 | RPC_DEBUG("discov_state:%d\n\r", p_ble_client_cb_data->cb_content.discov_state.state); 214 | //give se 215 | T_DISCOVERY_STATE state = p_ble_client_cb_data->cb_content.discov_state.state; 216 | switch(state) 217 | { 218 | case DISC_STATE_CHAR_DONE: 219 | { 220 | BLERemoteService::m_semaphoregetchaEvt.give(0); 221 | break; 222 | } 223 | } 224 | 225 | break; 226 | } 227 | case BLE_CLIENT_CB_TYPE_DISCOVERY_RESULT: 228 | { 229 | T_DISCOVERY_RESULT_TYPE discov_type = p_ble_client_cb_data->cb_content.discov_result.discov_type; 230 | switch (discov_type) 231 | { 232 | RPC_DEBUG("discov_type:%d\n\r", discov_type); 233 | 234 | case DISC_RESULT_SRV_DATA: 235 | { 236 | T_GATT_SERVICE_BY_UUID_ELEM *disc_data = (T_GATT_SERVICE_BY_UUID_ELEM *)&(p_ble_client_cb_data->cb_content.discov_result.result.srv_disc_data); 237 | RPC_DEBUG("start_handle:%d, end handle:%d\n\r", disc_data->att_handle, disc_data->end_group_handle); 238 | break; 239 | } 240 | case DISC_RESULT_CHAR_UUID16: 241 | { 242 | T_GATT_CHARACT_ELEM16 *disc_data = (T_GATT_CHARACT_ELEM16 *)&(p_ble_client_cb_data->cb_content.discov_result.result.char_uuid16_disc_data); 243 | 244 | BLEUUID uuid = BLEUUID(disc_data->uuid16); 245 | BLERemoteCharacteristic *pNewRemoteCharacteristic = new BLERemoteCharacteristic( 246 | disc_data->decl_handle, 247 | disc_data->properties, 248 | disc_data->value_handle, 249 | uuid, 250 | this 251 | ); 252 | m_characteristicMap.insert(std::pair(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic)); 253 | m_characteristicMapByHandle.insert(std::pair(disc_data->decl_handle, pNewRemoteCharacteristic)); 254 | break; 255 | } 256 | case DISC_RESULT_CHAR_UUID128: 257 | { 258 | T_GATT_CHARACT_ELEM128 *disc_data = (T_GATT_CHARACT_ELEM128 *)&(p_ble_client_cb_data->cb_content.discov_result.result.char_uuid128_disc_data); 259 | 260 | BLEUUID uuid = BLEUUID(disc_data->uuid128,16); 261 | BLERemoteCharacteristic *pNewRemoteCharacteristic = new BLERemoteCharacteristic( 262 | disc_data->decl_handle, 263 | disc_data->properties, 264 | disc_data->value_handle, 265 | uuid, 266 | this 267 | ); 268 | 269 | m_characteristicMap.insert(std::pair(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic)); 270 | m_characteristicMapByHandle.insert(std::pair(disc_data->decl_handle, pNewRemoteCharacteristic)); 271 | break; 272 | } 273 | default: 274 | break; 275 | } 276 | 277 | } 278 | 279 | default: 280 | break; 281 | } 282 | // Send the event to each of the characteristics owned by this service. 283 | for (auto &myPair : m_characteristicMapByHandle) { 284 | myPair.second->clientCallbackDefault(client_id,conn_id,p_data); 285 | } 286 | return result; 287 | } // gattClientEventHandler 288 | 289 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /src/BLERemoteService.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ 2 | #define COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ 3 | 4 | #include 5 | 6 | #include "BLEClient.h" 7 | #include "BLEUUID.h" 8 | #include "FreeRTOS.h" 9 | #include "BLERemoteCharacteristic.h" 10 | typedef uint8_t T_CLIENT_ID; 11 | 12 | class BLEClient; 13 | class BLERemoteCharacteristic; 14 | 15 | 16 | /** 17 | * @brief A model of a remote %BLE service. 18 | */ 19 | class BLERemoteService { 20 | public: 21 | virtual ~BLERemoteService(); 22 | BLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic A model of a remote %BLE service.. 23 | BLERemoteCharacteristic* getCharacteristic(BLEUUID uuid); 24 | std::map* getCharacteristics(); 25 | std::map* getCharacteristicsByHandle(); // Get the characteristics map. 26 | void getCharacteristics(std::map* pCharacteristicMap); 27 | BLEClient* getClient(void); 28 | std::string getValue(BLEUUID characteristicUuid); // Get the value of a characteristic. 29 | void setValue(BLEUUID characteristicUuid, std::string value); // Set the value of a characteristic. 30 | uint16_t getHandle(); 31 | uint16_t getEndHandle(); 32 | BLEUUID getUUID(void); 33 | std::string toString(void); 34 | 35 | 36 | private: 37 | friend class BLEClient; 38 | BLERemoteService(uint16_t att_handle, uint16_t end_group_handle, BLEUUID uuid, BLEClient* pClient); 39 | 40 | 41 | uint16_t getStartHandle(); 42 | 43 | 44 | void retrieveCharacteristics(void); 45 | void removeCharacteristics(); 46 | 47 | BLEUUID m_uuid; 48 | uint16_t m_startHandle; 49 | uint16_t m_endHandle; 50 | BLEClient* m_pClient; 51 | bool m_haveCharacteristics; 52 | 53 | std::map m_characteristicMap; 54 | std::map m_characteristicMapByHandle; 55 | BLEFreeRTOS::Semaphore m_semaphoregetchaEvt = BLEFreeRTOS::Semaphore("getCharacteristic"); 56 | 57 | T_APP_RESULT clientCallbackDefault(T_CLIENT_ID client_id, uint8_t conn_id, void *p_dat); 58 | }; // BLERemoteService 59 | 60 | #endif /* COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ */ 61 | -------------------------------------------------------------------------------- /src/BLEScan.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEScan.cpp 3 | * 4 | * Created on: Jul 1, 2020 5 | * Author: coolc 6 | */ 7 | 8 | #define TAG "Scan" 9 | #include 10 | #include 11 | #include "BLEScan.h" 12 | #include 13 | #include "BLEDevice.h" 14 | #include "rpc_unified_log.h" 15 | /** 16 | * Constructor 17 | */ 18 | 19 | BLEScan::BLEScan() { 20 | } // BLEScan 21 | 22 | 23 | 24 | /** 25 | * @brief Should we perform an active or passive scan? 26 | * The default is a passive scan. An active scan means that we will wish a scan response. 27 | * @param [in] active If true, we perform an active scan otherwise a passive scan. 28 | * @return N/A. 29 | */ 30 | void BLEScan::setActiveScan(bool active) { 31 | 32 | if (active) { 33 | m_scanMode = GAP_SCAN_MODE_ACTIVE; 34 | RPC_DEBUG("setActiveScan ACTIVE..................."); 35 | } else { 36 | m_scanMode = GAP_SCAN_MODE_PASSIVE; 37 | RPC_DEBUG("setActiveScan PASSIVE..................."); 38 | } 39 | 40 | } // setActiveScan 41 | 42 | /** 43 | * @brief Set the interval to scan. 44 | * @param [in] The interval in msecs. 45 | */ 46 | void BLEScan::setInterval(uint16_t intervalMSecs) { 47 | if ((intervalMSecs >= 3) && (intervalMSecs <= 10240)) { 48 | m_scanInterval = (intervalMSecs*1000/625); 49 | } 50 | } // setInterval 51 | 52 | 53 | /** 54 | * @brief Set the window to actively scan. 55 | * @param [in] windowMSecs How long to actively scan. 56 | */ 57 | void BLEScan::setWindow(uint16_t windowMSecs) { 58 | if ((windowMSecs * 1000 / 625) > m_scanInterval) { 59 | return; 60 | } 61 | if ((windowMSecs >= 3) && (windowMSecs <= 10240)) { 62 | m_scanWindow = (windowMSecs*1000/625); 63 | } 64 | } // setWindow 65 | 66 | 67 | /** 68 | * Set scan parameters 69 | */ 70 | void BLEScan::updateScanParams() { 71 | uint8_t _scanMode = m_scanMode; 72 | le_scan_set_param(GAP_PARAM_SCAN_MODE, sizeof(_scanMode), &_scanMode); 73 | uint16_t _scanInterval = m_scanInterval; 74 | le_scan_set_param(GAP_PARAM_SCAN_INTERVAL, sizeof(_scanInterval), &_scanInterval); 75 | uint16_t _scanWindow = m_scanWindow; 76 | le_scan_set_param(GAP_PARAM_SCAN_WINDOW, sizeof(_scanWindow), &_scanWindow); 77 | } 78 | 79 | /** 80 | * @brief Start scanning and block until scanning has been completed. 81 | * @param [in] duration The duration in seconds for which to scan. 82 | * @return The BLEScanResults. 83 | */ 84 | BLEScanResults BLEScan::start(uint32_t duration, bool is_continue) { 85 | if (!BLEDevice::ble_start_flags) 86 | { 87 | BLEDevice::ble_start_flags = true; 88 | ble_start(); 89 | } 90 | if(start(duration, nullptr, is_continue)) { 91 | m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release. 92 | } 93 | return m_scanResults; 94 | } // start 95 | 96 | 97 | 98 | /** 99 | * @brief Start scanning. 100 | * @param [in] duration The duration in seconds for which to scan. 101 | * @param [in] scanCompleteCB A function to be called when scanning has completed. 102 | * @param [in] are we continue scan (true) or we want to clear stored devices (false) 103 | * @return True if scan started or false if there was an error. 104 | */ 105 | bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue) { 106 | m_semaphoreScanEnd.take(std::string("start")); 107 | m_scanCompleteCB = scanCompleteCB; // Save the callback to be invoked when the scan completes. 108 | 109 | // if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals 110 | // then we should not clear map or we will connect the same device few times 111 | if(!is_continue) { 112 | for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){ 113 | delete _dev.second; 114 | } 115 | m_scanResults.m_vectorAdvertisedDevices.clear(); 116 | } 117 | updateScanParams(); 118 | uint32_t m_duration = duration * 1000; 119 | le_scan_timer_start(m_duration); 120 | RPC_DEBUG("Scan is processing, please end\n\r"); 121 | return true; 122 | } // start 123 | 124 | 125 | /** 126 | * @brief Stop an in progress scan. 127 | * @return N/A. 128 | */ 129 | void BLEScan::stop() { 130 | le_scan_stop(); 131 | m_semaphoreScanEnd.give(); 132 | RPC_DEBUG("Level BLEScan stop\n\r"); 133 | } // stop 134 | 135 | // delete peer device from cache after disconnecting, it is required in case we are connecting to devices with not public address 136 | void BLEScan::erase(BLEAddress address) { 137 | BLEAdvertisedDevice *advertisedDevice = m_scanResults.m_vectorAdvertisedDevices.find(address.toString())->second; 138 | m_scanResults.m_vectorAdvertisedDevices.erase(address.toString()); 139 | delete advertisedDevice; 140 | } 141 | 142 | 143 | /** 144 | * @brief Set the call backs to be invoked. 145 | * @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked. 146 | * @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false. 147 | */ 148 | void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates) { 149 | m_wantDuplicates = wantDuplicates; 150 | m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks; 151 | } // setAdvertisedDeviceCallbacks 152 | 153 | 154 | /** 155 | * @brief Return the count of devices found in the last scan. 156 | * @return The number of devices found in the last scan. 157 | */ 158 | int BLEScanResults::getCount() { 159 | return m_vectorAdvertisedDevices.size(); 160 | } // getCount 161 | 162 | /** 163 | * @brief Return the specified device at the given index. 164 | * The index should be between 0 and getCount()-1. 165 | * @param [in] i The index of the device. 166 | * @return The device at the specified index. 167 | */ 168 | BLEAdvertisedDevice BLEScanResults::getDevice(uint32_t i) { 169 | uint32_t x = 0; 170 | BLEAdvertisedDevice dev = *m_vectorAdvertisedDevices.begin()->second; 171 | for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) { 172 | dev = *it->second; 173 | if (x==i) break; 174 | x++; 175 | } 176 | return dev; 177 | } 178 | 179 | BLEScanResults BLEScan::getResults() { 180 | return m_scanResults; 181 | } 182 | 183 | void BLEScan::clearResults() { 184 | for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){ 185 | delete _dev.second; 186 | } 187 | m_scanResults.m_vectorAdvertisedDevices.clear(); 188 | } -------------------------------------------------------------------------------- /src/BLEScan.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEScan.h 3 | * 4 | * Created on: Jul 1, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLESCAN_H_ 9 | #define COMPONENTS_CPP_UTILS_BLESCAN_H_ 10 | 11 | // #include 12 | #include 13 | #include "BLEAdvertisedDevice.h" 14 | #include "BLEClient.h" 15 | #include "BLEFreeRTOS.h" 16 | #include "seeed_rpcUnified.h" 17 | #include "rtl_ble/ble_unified.h" 18 | 19 | class BLEScan; 20 | class BLEAdvertisedDeviceCallbacks; 21 | class BLEAdvertisedDevice; 22 | 23 | /** 24 | * @brief The result of having performed a scan. 25 | * When a scan completes, we have a set of found devices. Each device is described 26 | * by a BLEAdvertisedDevice object. The number of items in the set is given by 27 | * getCount(). We can retrieve a device by calling getDevice() passing in the 28 | * index (starting at 0) of the desired device. 29 | */ 30 | class BLEScanResults { 31 | public: 32 | int getCount(); 33 | BLEAdvertisedDevice getDevice(uint32_t i); 34 | private: 35 | friend BLEScan; 36 | std::map m_vectorAdvertisedDevices; 37 | }; 38 | 39 | 40 | class BLEScan { 41 | public: 42 | void setActiveScan(bool active); 43 | void setInterval(uint16_t intervalMSecs); 44 | void setWindow(uint16_t windowMSecs); 45 | void setAdvertisedDeviceCallbacks( 46 | BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, 47 | bool wantDuplicates = false); 48 | bool start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue = false); 49 | BLEScanResults start(uint32_t duration, bool is_continue = false); 50 | BLEScanResults getResults(); 51 | void clearResults(); 52 | void stop(); 53 | void erase(BLEAddress address); 54 | 55 | private: 56 | BLEScan(); // One doesn't create a new instance instead one asks the BLEDevice for the singleton. 57 | friend class BLEDevice; 58 | bool m_wantDuplicates = false; 59 | uint8_t m_scanMode = GAP_SCAN_MODE_ACTIVE; 60 | uint16_t m_scanInterval = 0x40; // Duration to wait between starting a scan. Value range: 0x0004 - 0x4000 (2.5ms - 10240ms)(0.625ms/step). 61 | uint16_t m_scanWindow = 0x30; // Duration to continuously scan for after starting. Value range: 0x0004 - 0x4000 (2.5ms - 10240ms)(0.625ms/step). 62 | BLEFreeRTOS::Semaphore m_semaphoreScanEnd = BLEFreeRTOS::Semaphore("ScanEnd"); 63 | void updateScanParams(); 64 | T_APP_RESULT gapCallbackDefault(uint8_t cb_type, void *p_cb_data); 65 | BLEScanResults m_scanResults; 66 | void (*m_scanCompleteCB)(BLEScanResults scanResults); 67 | BLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr; 68 | static uint8_t _scanProcessing; 69 | }; 70 | 71 | #endif /* COMPONENTS_CPP_UTILS_BLESCAN_H_ */ 72 | -------------------------------------------------------------------------------- /src/BLEServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEServer.cpp 3 | * 4 | * Created on: Apr 16, 2017 5 | * Author: kolban 6 | */ 7 | #define TAG "BLEServer" 8 | #include "BLEDevice.h" 9 | #include "BLEServer.h" 10 | //#include "BLEService.h" 11 | #include 12 | #include 13 | #include "rpc_unified_log.h" 14 | #include 15 | 16 | /** 17 | * @brief Construct a %BLE Server 18 | * 19 | * This class is not designed to be individually instantiated. Instead one should create a server by asking 20 | * the BLEDevice class. 21 | */ 22 | BLEServer::BLEServer() { 23 | m_appId = 0xff; 24 | m_gatts_if = 0xff; 25 | m_connectedCount = 0; 26 | m_connId = 0xff; 27 | m_pServerCallbacks = nullptr; 28 | } // BLEServer 29 | 30 | 31 | void BLEServer::createApp(uint16_t appId) { 32 | m_appId = appId; 33 | } // createApp 34 | 35 | 36 | /** 37 | * @brief Create a %BLE Service. 38 | * 39 | * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition 40 | * of a new service. Every service must have a unique UUID. 41 | * @param [in] uuid The UUID of the new service. 42 | * @return A reference to the new service object. 43 | */ 44 | BLEService* BLEServer::createService(const char* uuid) { 45 | return createService(BLEUUID(uuid)); 46 | } 47 | 48 | 49 | /** 50 | * @brief Create a %BLE Service. 51 | * 52 | * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition 53 | * of a new service. Every service must have a unique UUID. 54 | * @param [in] uuid The UUID of the new service. 55 | * @param [in] numHandles The maximum number of handles associated with this service. 56 | * @param [in] inst_id With multiple services with the same UUID we need to provide inst_id value different for each service. 57 | * @return A reference to the new service object. 58 | */ 59 | BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles, uint8_t inst_id) { 60 | BLEService* pService = new BLEService(uuid, numHandles); 61 | pService->m_instId = inst_id; 62 | m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server. 63 | pService->executeCreate(this); // Perform the API calls to actually create the service. 64 | return pService; 65 | } // createService 66 | 67 | 68 | /** 69 | * @brief Set the server callbacks. 70 | * 71 | * As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client 72 | * disconnecting. This function can be called to register a callback handler that will be invoked when these 73 | * events are detected. 74 | * 75 | * @param [in] pCallbacks The callbacks to be invoked. 76 | */ 77 | void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) { 78 | m_pServerCallbacks = pCallbacks; 79 | } // setCallbacks 80 | 81 | BLEServerCallbacks* BLEServer::getCallbacks() { 82 | return m_pServerCallbacks; 83 | } 84 | 85 | void BLEServerCallbacks::onConnect(BLEServer* pServer) { 86 | 87 | } // onConnect 88 | 89 | void BLEServerCallbacks::onDisconnect(BLEServer* pServer) { 90 | 91 | } // onDisconnect 92 | 93 | void BLEServer::addPeerDevice(void* peer, bool _client, uint16_t conn_id) { 94 | conn_status_t status = { 95 | .peer_device = peer, 96 | .connected = true, 97 | .mtu = 247 98 | }; 99 | m_connId = conn_id; 100 | m_connectedServersMap.insert(std::pair(conn_id, status)); 101 | } 102 | 103 | bool BLEServer::removePeerDevice(uint16_t conn_id, bool _client) { 104 | return m_connectedServersMap.erase(conn_id) > 0; 105 | } 106 | /* multi connect support */ 107 | 108 | uint16_t BLEServer::getPeerMTU(uint16_t conn_id) { 109 | return m_connectedServersMap.find(conn_id)->second.mtu; 110 | } 111 | 112 | uint16_t BLEServer::getconnId(){ 113 | return m_connId; 114 | } 115 | 116 | /* multi connect support */ 117 | /* TODO do some more tweaks */ 118 | void BLEServer::updatePeerMTU(uint16_t conn_id, uint16_t mtu) { 119 | // set mtu in conn_status_t 120 | const std::map::iterator it = m_connectedServersMap.find(conn_id); 121 | if (it != m_connectedServersMap.end()) { 122 | it->second.mtu = mtu; 123 | std::swap(m_connectedServersMap[conn_id], it->second); 124 | } 125 | } 126 | 127 | /** 128 | * @brief Return the number of connected clients. 129 | * @return The number of connected clients. 130 | */ 131 | uint32_t BLEServer::getConnectedCount() { 132 | return m_connectedCount; 133 | } // getConnectedCount 134 | 135 | uint32_t BLEServer::setConnectedCount() { 136 | return m_connectedCount++; 137 | } // getConnectedCount 138 | 139 | 140 | /** 141 | * @brief Get a %BLE Service by its UUID 142 | * @param [in] uuid The UUID of the new service. 143 | * @return A reference to the service object. 144 | */ 145 | BLEService* BLEServer::getServiceByUUID(const char* uuid) { 146 | return m_serviceMap.getByUUID(BLEUUID(uuid)); 147 | } 148 | 149 | /** 150 | * @brief Get a %BLE Service by its UUID 151 | * @param [in] uuid The UUID of the new service. 152 | * @return A reference to the service object. 153 | */ 154 | BLEService* BLEServer::getServiceByUUID(BLEUUID uuid) { 155 | return m_serviceMap.getByUUID(uuid); 156 | } 157 | 158 | /** 159 | * Allow to connect GATT server to peer device 160 | * Probably can be used in ANCS for iPhone 161 | */ 162 | bool BLEServer::connect(BLEAddress address) { 163 | 164 | } // connect 165 | 166 | void BLEServer::disconnect(uint16_t connId) { 167 | 168 | } 169 | 170 | /** 171 | * Update connection parameters can be called only after connection has been established 172 | */ 173 | void BLEServer::updateConnParams(uint8_t conn_id, 174 | uint16_t conn_interval_min, 175 | uint16_t conn_interval_max, 176 | uint16_t conn_latency, 177 | uint16_t supervision_timeout, 178 | uint16_t ce_length_min, 179 | uint16_t ce_length_max) { 180 | uint8_t update_conn_id = conn_id; 181 | uint16_t update_conn_interval_min = conn_interval_min; 182 | uint16_t update_conn_interval_max = conn_interval_max; 183 | uint16_t update_conn_latency = conn_latency; 184 | uint16_t update_supervision_timeout = supervision_timeout; 185 | uint16_t update_ce_length_min = ce_length_min; 186 | uint16_t update_ce_length_max = ce_length_max; 187 | le_update_conn_param(update_conn_id, 188 | update_conn_interval_min, 189 | update_conn_interval_max, 190 | update_conn_latency, 191 | update_supervision_timeout, 192 | update_ce_length_min, 193 | update_ce_length_max 194 | ); 195 | } 196 | 197 | /** 198 | * @brief Retrieve the advertising object that can be used to advertise the existence of the server. 199 | * 200 | * @return An advertising object. 201 | */ 202 | BLEAdvertising* BLEServer::getAdvertising() { 203 | return BLEDevice::getAdvertising(); 204 | } 205 | 206 | /** 207 | * @brief Start advertising. 208 | * 209 | * Start the server advertising its existence. This is a convenience function and is equivalent to 210 | * retrieving the advertising object and invoking start upon it. 211 | */ 212 | void BLEServer::startAdvertising() { 213 | BLEDevice::startAdvertising(); 214 | } // startAdvertising 215 | 216 | 217 | 218 | std::map BLEServer::getPeerDevices(bool _client) { 219 | return m_connectedServersMap; 220 | } 221 | 222 | /* 223 | * Remove service 224 | */ 225 | void BLEServer::removeService(BLEService* service) { 226 | service->stop(); 227 | service->executeDelete(service->getgiff()); 228 | m_serviceMap.removeService(service); 229 | } 230 | 231 | 232 | /** 233 | * @brief Handle a GATT Server Event. 234 | * 235 | * @param [in] event 236 | * @param [in] gatts_if 237 | * @param [in] param 238 | * 239 | */ 240 | void BLEServer::handleGATTServerEvent(T_SERVER_ID service_id, void *p_data) { 241 | RPC_DEBUG("into server :: handleGATTServerEvent\n\r"); 242 | // Invoke the handler for every Service we have. 243 | m_serviceMap.handleGATTServerEvent(service_id,p_data); 244 | } // handleGATTServerEvent 245 | -------------------------------------------------------------------------------- /src/BLEServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEServer.h 3 | * 4 | * Created on: Apr 16, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLESERVER_H_ 9 | #define COMPONENTS_CPP_UTILS_BLESERVER_H_ 10 | 11 | 12 | #include 13 | #include 14 | 15 | #include "BLEUUID.h" 16 | #include "BLEAdvertising.h" 17 | #include "BLECharacteristic.h" 18 | #include "BLEService.h" 19 | #include "BLEFreeRTOS.h" 20 | #include "BLEAddress.h" 21 | typedef uint8_t T_SERVER_ID; 22 | 23 | class BLEServerCallbacks; 24 | /* TODO possibly refactor this struct */ 25 | typedef struct { 26 | void *peer_device; // peer device BLEClient or BLEServer - maybe its better to have 2 structures or union here 27 | bool connected; // do we need it? 28 | uint16_t mtu; // every peer device negotiate own mtu 29 | } conn_status_t; 30 | 31 | /** 32 | * @brief A data structure that manages the %BLE servers owned by a BLE server. 33 | */ 34 | class BLEServiceMap { 35 | public: 36 | BLEService* getByUUID(const char* uuid); 37 | BLEService* getByUUID(BLEUUID uuid, uint8_t inst_id = 0); 38 | BLEService* getByHandle(uint16_t handle); 39 | void setByUUID(BLEUUID uuid, BLEService* service); 40 | void setByHandle(uint16_t handle, BLEService* service); 41 | void setByUUID(const char* uuid, BLEService* service); 42 | BLEService* getFirst(); 43 | BLEService* getNext(); 44 | std::string toString(); 45 | void handleGATTServerEvent(T_SERVER_ID service_id, void *p_data); 46 | void removeService(BLEService *service); 47 | int getRegisteredServiceCount(); 48 | private: 49 | std::map m_uuidMap; 50 | std::map m_handleMap; 51 | std::map::iterator m_iterator; 52 | 53 | }; 54 | 55 | /** 56 | * @brief The model of a %BLE server. 57 | */ 58 | class BLEServer { 59 | public: 60 | BLEService* createService(const char* uuid); 61 | BLEService* createService(BLEUUID uuid, uint32_t numHandles=15, uint8_t inst_id=0); 62 | void setCallbacks(BLEServerCallbacks* pCallbacks); 63 | BLEAdvertising* getAdvertising(); 64 | void startAdvertising(); 65 | uint32_t getConnectedCount(); 66 | uint32_t setConnectedCount(); 67 | void removeService(BLEService* service); 68 | BLEService* getServiceByUUID(const char* uuid); 69 | BLEService* getServiceByUUID(BLEUUID uuid); 70 | void addPeerDevice(void* peer, bool is_client, uint16_t conn_id); 71 | bool removePeerDevice(uint16_t conn_id, bool client); 72 | uint16_t getPeerMTU(uint16_t conn_id); 73 | bool connect(BLEAddress address); 74 | void disconnect(uint16_t connId); 75 | void updateConnParams(uint8_t conn_id, 76 | uint16_t conn_interval_min, 77 | uint16_t conn_interval_max, 78 | uint16_t conn_latency, 79 | uint16_t supervision_timeout, 80 | uint16_t ce_length_min, 81 | uint16_t ce_length_max); 82 | uint16_t getconnId(); 83 | BLEServerCallbacks* getCallbacks(); 84 | std::map getPeerDevices(bool client); 85 | void updatePeerMTU(uint16_t connId, uint16_t mtu); 86 | uint16_t m_appId; 87 | private: 88 | BLEServer(); 89 | friend class BLEDevice; 90 | 91 | uint16_t m_connId; 92 | uint32_t m_connectedCount; 93 | uint16_t m_gatts_if; 94 | BLEServerCallbacks* m_pServerCallbacks = nullptr; 95 | std::map m_connectedServersMap; 96 | 97 | BLEFreeRTOS::Semaphore m_semaphoreRegisterAppEvt = BLEFreeRTOS::Semaphore("RegisterAppEvt"); 98 | BLEFreeRTOS::Semaphore m_semaphoreCreateEvt = BLEFreeRTOS::Semaphore("CreateEvt"); 99 | void createApp(uint16_t appId); 100 | BLEServiceMap m_serviceMap; 101 | void handleGATTServerEvent(T_SERVER_ID service_id, void *p_data); 102 | 103 | 104 | }; // BLEServer 105 | 106 | 107 | /** 108 | * @brief Callbacks associated with the operation of a %BLE server. 109 | */ 110 | class BLEServerCallbacks { 111 | public: 112 | virtual ~BLEServerCallbacks() {}; 113 | /** 114 | * @brief Handle a new client connection. 115 | * 116 | * When a new client connects, we are invoked. 117 | * 118 | * @param [in] pServer A reference to the %BLE server that received the client connection. 119 | */ 120 | virtual void onConnect(BLEServer* pServer); 121 | // virtual void onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param); 122 | /** 123 | * @brief Handle an existing client disconnection. 124 | * 125 | * When an existing client disconnects, we are invoked. 126 | * 127 | * @param [in] pServer A reference to the %BLE server that received the existing client disconnection. 128 | */ 129 | virtual void onDisconnect(BLEServer* pServer); 130 | }; // BLEServerCallbacks 131 | 132 | #endif /* COMPONENTS_CPP_UTILS_BLESERVER_H_ */ 133 | -------------------------------------------------------------------------------- /src/BLEService.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEService.cpp 3 | * 4 | * Created on: Mar 25, 2017 5 | * Author: kolban 6 | */ 7 | 8 | // A service is identified by a UUID. A service is also the container for one or more characteristics 9 | #define TAG "BLEService" 10 | #include 11 | #include 12 | #include 13 | #include "BLEServer.h" 14 | #include "BLEService.h" 15 | #include "rpc_unified_log.h" 16 | 17 | #define NULL_HANDLE (0xffff) 18 | 19 | /** 20 | * @brief Construct an instance of the BLEService 21 | * @param [in] uuid The UUID of the service. 22 | * @param [in] numHandles The maximum number of handles associated with the service. 23 | */ 24 | BLEService::BLEService(BLEUUID uuid, uint16_t numHandles) { 25 | m_uuid = uuid; 26 | m_handle = NULL_HANDLE; 27 | m_pServer = nullptr; 28 | m_lastCreatedCharacteristic = nullptr; 29 | m_numHandles = numHandles; 30 | } // BLEService 31 | 32 | 33 | /** 34 | * @brief Create the service. 35 | * Create the service. 36 | * @param [in] gatts_if The handle of the GATT server interface. 37 | * @return N/A. 38 | */ 39 | 40 | void BLEService::executeCreate(BLEServer* pServer) { 41 | m_pServer = pServer; 42 | RPC_DEBUG("Service executeCreate"); 43 | ble_service_t srcv; 44 | srcv.uuid_length = getUUID().getNative()->len; 45 | memcpy(&(srcv.uuid), &(getUUID().getNative()->uuid), srcv.uuid_length); 46 | srcv.is_primary = true; 47 | uint8_t srcv_app_id = ble_create_service(srcv); 48 | RPC_DEBUG("srcv_app_id: %d\n\r", srcv_app_id); 49 | m_giff = srcv_app_id; 50 | } // executeCreate 51 | 52 | /** 53 | * @brief Delete the service. 54 | * Delete the service. 55 | * @return N/A. 56 | */ 57 | 58 | void BLEService::executeDelete(uint8_t m_giff) { 59 | ble_delete_service(m_giff); 60 | } // executeDelete 61 | 62 | /** 63 | * @brief Create a new BLE Characteristic associated with this service. 64 | * @param [in] uuid - The UUID of the characteristic. 65 | * @param [in] properties - The properties of the characteristic. 66 | * @return The new BLE characteristic. 67 | */ 68 | BLECharacteristic* BLEService::createCharacteristic(const char* uuid, uint32_t properties) { 69 | return createCharacteristic(BLEUUID(uuid), properties); 70 | } 71 | 72 | /** 73 | * @brief Create a new BLE Characteristic associated with this service. 74 | * @param [in] uuid - The UUID of the characteristic. 75 | * @param [in] properties - The properties of the characteristic. 76 | * @return The new BLE characteristic. 77 | */ 78 | BLECharacteristic* BLEService::createCharacteristic(BLEUUID uuid, uint32_t properties) { 79 | BLECharacteristic* pCharacteristic = new BLECharacteristic(uuid, properties); 80 | addCharacteristic(pCharacteristic); 81 | return pCharacteristic; 82 | } // createCharacteristic 83 | 84 | BLECharacteristic* BLEService::getCharacteristic(const char* uuid) { 85 | return getCharacteristic(BLEUUID(uuid)); 86 | } 87 | 88 | BLECharacteristic* BLEService::getCharacteristic(BLEUUID uuid) { 89 | return m_characteristicMap.getByUUID(uuid); 90 | } 91 | 92 | /** 93 | * @brief Add a characteristic to the service. 94 | * @param [in] pCharacteristic A pointer to the characteristic to be added. 95 | */ 96 | void BLEService::addCharacteristic(BLECharacteristic* pCharacteristic) { 97 | // We maintain a mapping of characteristics owned by this service. These are managed by the 98 | // BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic 99 | // to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF). 100 | // Check that we don't add the same characteristic twice. 101 | if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) { 102 | return; 103 | } 104 | // Remember this characteristic in our map of characteristics. At this point, we can lookup by UUID 105 | // but not by handle. The handle is allocated to us on the ESP_GATTS_ADD_CHAR_EVT. 106 | m_characteristicMap.setByUUID(pCharacteristic, pCharacteristic->getUUID()); 107 | } // addCharacteristic 108 | 109 | 110 | 111 | /** 112 | * @brief Get the UUID of the service. 113 | * @return the UUID of the service. 114 | */ 115 | BLEUUID BLEService::getUUID() { 116 | return m_uuid; 117 | } // getUUID 118 | 119 | 120 | /** 121 | * @brief Get the handle associated with this service. 122 | * @return The handle associated with this service. 123 | */ 124 | uint16_t BLEService::getHandle() { 125 | return m_handle; 126 | } // getHandle 127 | 128 | 129 | /** 130 | * @brief Get the BLE server associated with this service. 131 | * @return The BLEServer associated with this service. 132 | */ 133 | BLEServer* BLEService::getServer() { 134 | return m_pServer; 135 | } // getServer 136 | 137 | uint8_t BLEService::getgiff() { 138 | return m_giff; 139 | } 140 | 141 | /** 142 | * @brief Return a string representation of this service. 143 | * A service is defined by: 144 | * * Its UUID 145 | * * Its handle 146 | * @return A string representation of this service. 147 | */ 148 | std::string BLEService::toString() { 149 | std::string res = "UUID: " + getUUID().toString(); 150 | char hex[5]; 151 | snprintf(hex, sizeof(hex), "%04x", getHandle()); 152 | res += ", handle: 0x"; 153 | res += hex; 154 | return res; 155 | } // toString 156 | 157 | 158 | /** 159 | * @brief Start the service. 160 | * Here we wish to start the service which means that we will respond to partner requests about it. 161 | * Starting a service also means that we can create the corresponding characteristics. 162 | * @return Start the service. 163 | */ 164 | void BLEService::start() { 165 | // We ask the BLE runtime to start the service and then create each of the characteristics. 166 | // We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event 167 | // obtained as a result of calling esp_ble_gatts_create_service(). 168 | BLECharacteristic *pCharacteristic = m_characteristicMap.getFirst(); 169 | 170 | while (pCharacteristic != nullptr) { 171 | m_lastCreatedCharacteristic = pCharacteristic; 172 | pCharacteristic->executeCreate(this); 173 | 174 | pCharacteristic = m_characteristicMap.getNext(); 175 | } 176 | // Start each of the characteristics ... these are found in the m_characteristicMap. 177 | T_SERVER_ID handle = ble_service_start(getgiff()); 178 | m_handle = handle; 179 | RPC_DEBUG("ble_service_start: %d", handle); 180 | } // start 181 | 182 | /** 183 | * @brief Stop the service. 184 | */ 185 | void BLEService::stop() { 186 | // We ask the BLE runtime to start the service and then create each of the characteristics. 187 | // We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event 188 | // obtained as a result of calling esp_ble_gatts_create_service(). 189 | 190 | } // stop 191 | 192 | /** 193 | * @brief Handle a GATTS server event. 194 | */ 195 | void BLEService::handleGATTServerEvent(T_SERVER_ID service_id, void *p_data) { 196 | RPC_DEBUG("into BLEService :: handleGATTServerEvent\n\r"); 197 | // Invoke the GATTS handler in each of the associated characteristics. 198 | if(service_id == getHandle()){ 199 | m_characteristicMap.handleGATTServerEvent(service_id,p_data); 200 | } 201 | 202 | } // handleGATTServerEvent -------------------------------------------------------------------------------- /src/BLEService.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEService.h 3 | * 4 | * Created on: Mar 25, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLESERVICE_H_ 9 | #define COMPONENTS_CPP_UTILS_BLESERVICE_H_ 10 | 11 | #include "BLECharacteristic.h" 12 | #include "BLEServer.h" 13 | #include "BLEUUID.h" 14 | #include "BLEFreeRTOS.h" 15 | typedef uint8_t T_SERVER_ID; 16 | 17 | class BLEServer; 18 | 19 | /** 20 | * @brief A data mapping used to manage the set of %BLE characteristics known to the server. 21 | */ 22 | class BLECharacteristicMap { 23 | public: 24 | void setByUUID(BLECharacteristic* pCharacteristic, BLEUUID uuid); 25 | void setByHandle(uint16_t handle, BLECharacteristic* pCharacteristic); 26 | BLECharacteristic* getByUUID(BLEUUID uuid); 27 | BLECharacteristic* getFirst(); 28 | BLECharacteristic* getNext(); 29 | BLECharacteristic* getByHandle(uint16_t handle); 30 | void handleGATTServerEvent(T_SERVER_ID service_id, void *p_data); 31 | 32 | private: 33 | std::map m_uuidMap; 34 | std::map m_handleMap; 35 | std::map::iterator m_iterator; 36 | 37 | 38 | }; 39 | 40 | 41 | /** 42 | * @brief The model of a %BLE service. 43 | * 44 | */ 45 | class BLEService { 46 | public: 47 | void addCharacteristic(BLECharacteristic* pCharacteristic); 48 | BLEUUID getUUID(); 49 | uint16_t getHandle(); 50 | BLEServer* getServer(); 51 | uint8_t getgiff(); 52 | void executeCreate(BLEServer* pServer); 53 | void executeDelete(uint8_t m_giff); 54 | BLECharacteristic* createCharacteristic(BLEUUID uuid, uint32_t properties); 55 | BLECharacteristic* createCharacteristic(const char* uuid, uint32_t properties); 56 | BLECharacteristic* getCharacteristic(const char* uuid); 57 | BLECharacteristic* getCharacteristic(BLEUUID uuid); 58 | void start(); 59 | void stop(); 60 | std::string toString(); 61 | uint8_t m_instId = 0; 62 | 63 | private: 64 | BLEService(BLEUUID uuid, uint16_t numHandles); 65 | friend class BLEServer; 66 | friend class BLEServiceMap; 67 | friend class BLEDevice; 68 | 69 | BLEUUID m_uuid; 70 | uint16_t m_handle; 71 | BLECharacteristic* m_lastCreatedCharacteristic = nullptr; 72 | BLEServer* m_pServer = nullptr; 73 | uint16_t m_numHandles; 74 | 75 | uint8_t m_giff; 76 | 77 | BLECharacteristicMap m_characteristicMap; 78 | void handleGATTServerEvent(T_SERVER_ID service_id, void *p_data); 79 | BLEFreeRTOS::Semaphore m_semaphoreCreateEvt = BLEFreeRTOS::Semaphore("CreateEvt"); 80 | BLEFreeRTOS::Semaphore m_semaphoreStartEvt = BLEFreeRTOS::Semaphore("StartEvt"); 81 | 82 | }; // BLEService 83 | 84 | #endif /* COMPONENTS_CPP_UTILS_BLESERVICE_H_ */ 85 | -------------------------------------------------------------------------------- /src/BLEServiceMap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEServiceMap.cpp 3 | * 4 | * Created on: Jun 22, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #include 9 | #include 10 | #include "BLEService.h" 11 | 12 | 13 | /** 14 | * @brief Return the service by UUID. 15 | * @param [in] UUID The UUID to look up the service. 16 | * @return The characteristic. 17 | */ 18 | BLEService* BLEServiceMap::getByUUID(BLEUUID uuid, uint8_t inst_id) { 19 | for (auto &myPair : m_uuidMap) { 20 | if (myPair.first->getUUID().equals(uuid)) { 21 | return myPair.first; 22 | } 23 | } 24 | //return m_uuidMap.at(uuid.toString()); 25 | return nullptr; 26 | } // getByUUID 27 | 28 | 29 | /** 30 | * @brief Return the service by handle. 31 | * @param [in] handle The handle to look up the service. 32 | * @return The service. 33 | */ 34 | BLEService* BLEServiceMap::getByHandle(uint16_t handle) { 35 | return m_handleMap.at(handle); 36 | } // getByHandle 37 | 38 | BLEService* BLEServiceMap::getFirst() { 39 | m_iterator = m_uuidMap.begin(); 40 | if (m_iterator == m_uuidMap.end()) return nullptr; 41 | BLEService* pRet = m_iterator->first; 42 | m_iterator++; 43 | return pRet; 44 | } // getFirst 45 | 46 | /** 47 | * @brief Return the service by UUID. 48 | * @param [in] UUID The UUID to look up the service. 49 | * @return The characteristic. 50 | */ 51 | BLEService* BLEServiceMap::getByUUID(const char* uuid) { 52 | return getByUUID(BLEUUID(uuid)); 53 | } 54 | 55 | /** 56 | * @brief Get the next service in the map. 57 | * @return The next service in the map. 58 | */ 59 | BLEService* BLEServiceMap::getNext() { 60 | if (m_iterator == m_uuidMap.end()) return nullptr; 61 | BLEService* pRet = m_iterator->first; 62 | m_iterator++; 63 | return pRet; 64 | } // getNext 65 | 66 | 67 | 68 | 69 | /** 70 | * @brief Set the service by handle. 71 | * @param [in] handle The handle of the service. 72 | * @param [in] service The service to cache. 73 | * @return N/A. 74 | */ 75 | void BLEServiceMap::setByHandle(uint16_t handle, BLEService* service) { 76 | m_handleMap.insert(std::pair(handle, service)); 77 | } // setByHandle 78 | 79 | /** 80 | * @brief Set the service by UUID. 81 | * @param [in] uuid The uuid of the service. 82 | * @param [in] characteristic The service to cache. 83 | * @return N/A. 84 | */ 85 | void BLEServiceMap::setByUUID(BLEUUID uuid, BLEService* service) { 86 | m_uuidMap.insert(std::pair(service, uuid.toString())); 87 | } // setByUUID 88 | 89 | /** 90 | * @brief Return a string representation of the service map. 91 | * @return A string representation of the service map. 92 | */ 93 | std::string BLEServiceMap::toString() { 94 | std::string res; 95 | char hex[5]; 96 | for (auto &myPair: m_handleMap) { 97 | res += "handle: 0x"; 98 | snprintf(hex, sizeof(hex), "%04x", myPair.first); 99 | res += hex; 100 | res += ", uuid: " + myPair.second->getUUID().toString() + "\n"; 101 | } 102 | return res; 103 | } // toString 104 | 105 | /** 106 | * @brief Removes service from maps. 107 | * @return N/A. 108 | */ 109 | void BLEServiceMap::removeService(BLEService* service) { 110 | m_handleMap.erase(service->getHandle()); 111 | m_uuidMap.erase(service); 112 | } // removeService 113 | 114 | /** 115 | * @brief Returns the amount of registered services 116 | * @return amount of registered services 117 | */ 118 | int BLEServiceMap::getRegisteredServiceCount(){ 119 | return m_handleMap.size(); 120 | } 121 | 122 | void BLEServiceMap::handleGATTServerEvent(T_SERVER_ID service_id, void *p_datas) { 123 | // Invoke the handler for every Service we have. 124 | for (auto &myPair : m_uuidMap) { 125 | myPair.first->handleGATTServerEvent(service_id, p_datas); 126 | } 127 | } -------------------------------------------------------------------------------- /src/BLEUUID.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEUUID.cpp 3 | * 4 | * Created on: Jun 21, 2017 5 | * Author: kolban 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "BLEUUID.h" 16 | /** 17 | * @brief Get a string representation of the UUID. 18 | * 19 | * The format of a string is: 20 | * 01234567 8901 2345 6789 012345678901 21 | * 0000180d-0000-1000-8000-00805f9b34fb 22 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 23 | * 24 | * @return A string representation of the UUID. 25 | */ 26 | std::string BLEUUID::toString() { 27 | if (!m_valueSet) return ""; // If we have no value, nothing to format. 28 | // If the UUIDs are 16 or 32 bit, pad correctly. 29 | 30 | if (m_uuid.len == UUID_LEN_16) { // If the UUID is 16bit, pad correctly. 31 | char hex[9]; 32 | snprintf(hex, sizeof(hex), "%08x", m_uuid.uuid.uuid16); 33 | return std::string(hex) + "-0000-1000-8000-00805f9b34fb"; 34 | } // End 16bit UUID 35 | 36 | if (m_uuid.len == UUID_LEN_32) { // If the UUID is 32bit, pad correctly. 37 | char hex[9]; 38 | snprintf(hex, sizeof(hex), "%08x", m_uuid.uuid.uuid32); 39 | return std::string(hex) + "-0000-1000-8000-00805f9b34fb"; 40 | } // End 32bit UUID 41 | 42 | // The UUID is not 16bit or 32bit which means that it is 128bit. 43 | // 44 | // UUID string format: 45 | // AABBCCDD-EEFF-GGHH-IIJJ-KKLLMMNNOOPP 46 | auto size = 37; // 32 for UUID data, 4 for '-' delimiters and one for a terminator == 37 chars 47 | char *hex = (char *)malloc(size); 48 | snprintf(hex, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 49 | m_uuid.uuid.uuid128[15], m_uuid.uuid.uuid128[14], 50 | m_uuid.uuid.uuid128[13], m_uuid.uuid.uuid128[12], 51 | m_uuid.uuid.uuid128[11], m_uuid.uuid.uuid128[10], 52 | m_uuid.uuid.uuid128[9], m_uuid.uuid.uuid128[8], 53 | m_uuid.uuid.uuid128[7], m_uuid.uuid.uuid128[6], 54 | m_uuid.uuid.uuid128[5], m_uuid.uuid.uuid128[4], 55 | m_uuid.uuid.uuid128[3], m_uuid.uuid.uuid128[2], 56 | m_uuid.uuid.uuid128[1], m_uuid.uuid.uuid128[0]); 57 | std::string res(hex); 58 | free(hex); 59 | return res; 60 | } // toString 61 | 62 | BLEUUID::BLEUUID() { 63 | } 64 | 65 | BLEUUID::BLEUUID(uint8_t* data, uint8_t length) { 66 | 67 | switch(length) 68 | { 69 | case 2: 70 | { 71 | m_uuid.len = 2; 72 | break; 73 | } 74 | case 4: 75 | { 76 | m_uuid.len = 4; 77 | break; 78 | } 79 | case 16: 80 | { 81 | m_uuid.len = 16; 82 | break; 83 | } 84 | 85 | default: 86 | return; 87 | } 88 | 89 | _length = length; 90 | for (int i = 0; i < _length; i++) { 91 | _dataNative[i] = data[i]; 92 | _data[i] = data[(_length - 1 - i)]; 93 | } 94 | 95 | memcpy(&m_uuid.uuid, data, m_uuid.len); 96 | m_valueSet = true; 97 | } 98 | 99 | const char* BLEUUID::str() { 100 | if (_length == 2) { 101 | sprintf(_str, "%2x%2x", 102 | _dataNative[1], _dataNative[0]); 103 | } 104 | 105 | if (_length == 4) { 106 | sprintf(_str, "%2x%2x%2x%2x", 107 | _dataNative[3], _dataNative[2], 108 | _dataNative[1], _dataNative[0]); 109 | } 110 | 111 | if (_length == 16) { 112 | sprintf(_str, "%2x%2x%2x%2x-%2x%2x-%2x%2x-%2x%2x-%2x%2x%2x%2x%2x%2x", 113 | _dataNative[15], _dataNative[14], 114 | _dataNative[13], _dataNative[12], 115 | _dataNative[11], _dataNative[10], 116 | _dataNative[9], _dataNative[8], 117 | _dataNative[7], _dataNative[6], 118 | _dataNative[5], _dataNative[4], 119 | _dataNative[3], _dataNative[2], 120 | _dataNative[1], _dataNative[0]); 121 | } 122 | return _str; 123 | } 124 | 125 | 126 | /** 127 | * @brief Convert a UUID to its 128 bit representation. 128 | * 129 | * A UUID can be internally represented as 16bit, 32bit or the full 128bit. This method 130 | * will convert 16 or 32 bit representations to the full 128bit. 131 | */ 132 | BLEUUID BLEUUID::to128() { 133 | //log_v(">> toFull() - %s", toString().c_str()); 134 | 135 | // If we either don't have a value or are already a 128 bit UUID, nothing further to do. 136 | if (!m_valueSet || m_uuid.len == UUID_LEN_128) { 137 | return *this; 138 | } 139 | 140 | // If we are 16 bit or 32 bit, then set the 4 bytes of the variable part of the UUID. 141 | if (m_uuid.len == UUID_LEN_16) { 142 | uint16_t temp = m_uuid.uuid.uuid16; 143 | m_uuid.uuid.uuid128[15] = 0; 144 | m_uuid.uuid.uuid128[14] = 0; 145 | m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff; 146 | m_uuid.uuid.uuid128[12] = temp & 0xff; 147 | 148 | } 149 | else if (m_uuid.len == UUID_LEN_32) { 150 | uint32_t temp = m_uuid.uuid.uuid32; 151 | m_uuid.uuid.uuid128[15] = (temp >> 24) & 0xff; 152 | m_uuid.uuid.uuid128[14] = (temp >> 16) & 0xff; 153 | m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff; 154 | m_uuid.uuid.uuid128[12] = temp & 0xff; 155 | } 156 | 157 | // Set the fixed parts of the UUID. 158 | m_uuid.uuid.uuid128[11] = 0x00; 159 | m_uuid.uuid.uuid128[10] = 0x00; 160 | 161 | m_uuid.uuid.uuid128[9] = 0x10; 162 | m_uuid.uuid.uuid128[8] = 0x00; 163 | 164 | m_uuid.uuid.uuid128[7] = 0x80; 165 | m_uuid.uuid.uuid128[6] = 0x00; 166 | 167 | m_uuid.uuid.uuid128[5] = 0x00; 168 | m_uuid.uuid.uuid128[4] = 0x80; 169 | m_uuid.uuid.uuid128[3] = 0x5f; 170 | m_uuid.uuid.uuid128[2] = 0x9b; 171 | m_uuid.uuid.uuid128[1] = 0x34; 172 | m_uuid.uuid.uuid128[0] = 0xfb; 173 | 174 | m_uuid.len = UUID_LEN_128; 175 | 176 | return *this; 177 | } // to128 178 | 179 | 180 | BLEUUID::BLEUUID(uint16_t uuid) { 181 | m_uuid.len = 2; 182 | m_uuid.uuid.uuid16 = uuid; 183 | m_valueSet = true; 184 | } // BLEUUID 185 | 186 | /** 187 | * @brief Compare a UUID against this UUID. 188 | * 189 | * @param [in] uuid The UUID to compare against. 190 | * @return True if the UUIDs are equal and false otherwise. 191 | */ 192 | bool BLEUUID::equals(BLEUUID uuid) { 193 | if (!m_valueSet || !uuid.m_valueSet) return false; 194 | 195 | if (uuid.m_uuid.len != m_uuid.len) { 196 | return uuid.toString() == toString(); 197 | } 198 | 199 | if (uuid.m_uuid.len == UUID_LEN_16) { 200 | return uuid.m_uuid.uuid.uuid16 == m_uuid.uuid.uuid16; 201 | } 202 | 203 | if (uuid.m_uuid.len == UUID_LEN_32) { 204 | return uuid.m_uuid.uuid.uuid32 == m_uuid.uuid.uuid32; 205 | } 206 | 207 | return memcmp(uuid.m_uuid.uuid.uuid128, m_uuid.uuid.uuid128, 16) == 0; 208 | } // equals 209 | 210 | /** 211 | * @brief Get the native UUID value. 212 | * 213 | * @return The native UUID value or NULL if not set. 214 | */ 215 | bt_uuid_t* BLEUUID::getNative() { 216 | //log_d(">> getNative()") 217 | if (m_valueSet == false) { 218 | return nullptr; 219 | } 220 | return &m_uuid; 221 | } // getNative 222 | 223 | 224 | uint8_t BLEUUID::length() { 225 | return _length; 226 | } 227 | 228 | const uint8_t* BLEUUID::dataNative() { 229 | return _dataNative; 230 | } 231 | 232 | static void memrcpy(uint8_t* target, uint8_t* source, uint32_t size) { 233 | assert(size > 0); 234 | target += (size - 1); // Point target to the last byte of the target data 235 | while (size > 0) { 236 | *target = *source; 237 | target--; 238 | source++; 239 | size--; 240 | } 241 | } // memrcpy 242 | 243 | 244 | /** 245 | * @brief Create a UUID from a string. 246 | * 247 | * Create a UUID from a string. There will be two possible stories here. Either the string represents 248 | * a binary data field or the string represents a hex encoding of a UUID. 249 | * For the hex encoding, here is an example: 250 | * 251 | * ``` 252 | * "beb5483e-36e1-4688-b7f5-ea07361b26a8" 253 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 254 | * 12345678-90ab-cdef-1234-567890abcdef 255 | * ``` 256 | * 257 | * This has a length of 36 characters. We need to parse this into 16 bytes. 258 | * 259 | * @param [in] value The string to build a UUID from. 260 | */ 261 | BLEUUID::BLEUUID(std::string value) { 262 | m_valueSet = true; 263 | if (value.length() == 4) { 264 | m_uuid.len = UUID_LEN_16; 265 | m_uuid.uuid.uuid16 = 0; 266 | for(int i=0;i '9') MSB -= 7; 271 | if(LSB > '9') LSB -= 7; 272 | m_uuid.uuid.uuid16 += (((MSB&0x0F) <<4) | (LSB & 0x0F))<<(2-i)*4; 273 | i+=2; 274 | } 275 | } 276 | else if (value.length() == 8) { 277 | m_uuid.len = UUID_LEN_32; 278 | m_uuid.uuid.uuid32 = 0; 279 | for(int i=0;i '9') MSB -= 7; 284 | if(LSB > '9') LSB -= 7; 285 | m_uuid.uuid.uuid32 += (((MSB&0x0F) <<4) | (LSB & 0x0F))<<(6-i)*4; 286 | i+=2; 287 | } 288 | } 289 | else if (value.length() == 16) { // how we can have 16 byte length string reprezenting 128 bit uuid??? needs to be investigated (lack of time) 290 | m_uuid.len = UUID_LEN_128; 291 | memrcpy(m_uuid.uuid.uuid128, (uint8_t*)value.data(), 16); 292 | } 293 | else if (value.length() == 36) { 294 | // If the length of the string is 36 bytes then we will assume it is a long hex string in 295 | // UUID format. 296 | m_uuid.len = UUID_LEN_128; 297 | int n = 0; 298 | for(int i=0;i '9') MSB -= 7; 305 | if(LSB > '9') LSB -= 7; 306 | m_uuid.uuid.uuid128[15-n++] = ((MSB&0x0F) <<4) | (LSB & 0x0F); 307 | i+=2; 308 | } 309 | } 310 | else { 311 | m_valueSet = false; 312 | } 313 | } //BLEUUID(std::string) 314 | 315 | 316 | /** 317 | * @brief Create a UUID from 16 bytes of memory. 318 | * 319 | * @param [in] pData The pointer to the start of the UUID. 320 | * @param [in] size The size of the data. 321 | * @param [in] msbFirst Is the MSB first in pData memory? 322 | */ 323 | BLEUUID::BLEUUID(uint8_t* pData, size_t size, bool msbFirst) { 324 | if (size != 16) { 325 | return; 326 | } 327 | m_uuid.len = UUID_LEN_128; 328 | if (msbFirst) { 329 | memrcpy(m_uuid.uuid.uuid128, pData, 16); 330 | } else { 331 | memcpy(m_uuid.uuid.uuid128, pData, 16); 332 | } 333 | m_valueSet = true; 334 | } // BLEUUID 335 | 336 | 337 | /** 338 | * @brief Get the number of bits in this uuid. 339 | * @return The number of bits in the UUID. One of 16, 32 or 128. 340 | */ 341 | uint8_t BLEUUID::bitSize() { 342 | if (!m_valueSet) return 0; 343 | switch (m_uuid.len) { 344 | case UUID_LEN_16: 345 | return 16; 346 | case UUID_LEN_32: 347 | return 32; 348 | case UUID_LEN_128: 349 | return 128; 350 | default: 351 | return 0; 352 | } // End of switch 353 | } // bitSize 354 | -------------------------------------------------------------------------------- /src/BLEUUID.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEUUID.h 3 | * 4 | * Created on: Jun 21, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEUUID_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEUUID_H_ 10 | 11 | #include 12 | #include 13 | #define BLE_UUID_MAX_LENGTH 16 14 | 15 | /// UUID type 16 | typedef struct 17 | { 18 | #define UUID_LEN_16 2 19 | #define UUID_LEN_32 4 20 | #define UUID_LEN_128 16 21 | uint16_t len; /*!< UUID length, 16bit, 32bit or 128bit */ 22 | union { 23 | uint16_t uuid16; 24 | uint32_t uuid32; 25 | uint8_t uuid128[UUID_LEN_128]; 26 | } uuid; /*!< UUID */ 27 | } __attribute__((packed)) bt_uuid_t; 28 | 29 | /** 30 | * @brief A model of a %BLE UUID. 31 | */ 32 | class BLEUUID 33 | { 34 | public: 35 | std::string toString(); 36 | BLEUUID(); 37 | BLEUUID(std::string uuid); 38 | BLEUUID(uint16_t uuid); 39 | BLEUUID(uint8_t *data, uint8_t length); 40 | BLEUUID(uint8_t *pData, size_t size, bool msbFirst); 41 | const char *str(); 42 | bool equals(BLEUUID uuid); 43 | bt_uuid_t *getNative(); 44 | BLEUUID to128(); 45 | uint8_t bitSize(); // Get the number of bits in this uuid. 46 | 47 | uint8_t length(); 48 | const uint8_t *dataNative(); 49 | 50 | private: 51 | bool m_valueSet = false; // Is there a value set for this instance. 52 | bt_uuid_t m_uuid; // The underlying UUID structure that this class wraps. 53 | char _str[BLE_UUID_MAX_LENGTH * 2 + 5] = {0}; 54 | uint8_t _data[BLE_UUID_MAX_LENGTH] = {0}; // stores the UUID MSB in position 0, useful for printing as characters/strings 55 | uint8_t _dataNative[BLE_UUID_MAX_LENGTH] = {0}; // stores the UUID LSB in position 0 56 | uint8_t _length = 0; // number of bytes(characters) of UUID 57 | }; // BLEUUID 58 | #endif /* COMPONENTS_CPP_UTILS_BLEUUID_H_ */ 59 | -------------------------------------------------------------------------------- /src/BLEValue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEValue.cpp 3 | * 4 | * Created on: Jul 17, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #include "BLEValue.h" 9 | #include "Arduino.h" 10 | 11 | BLEValue::BLEValue() 12 | { 13 | m_accumulation = ""; 14 | m_value = NULL; 15 | m_length = 0; 16 | m_readOffset = 0; 17 | } // BLEValue 18 | 19 | /** 20 | * @brief Add a message part to the accumulation. 21 | * The accumulation is a growing set of data that is added to until a commit or cancel. 22 | * @param [in] part A message part being added. 23 | */ 24 | void BLEValue::addPart(std::string part) 25 | { 26 | m_accumulation += part; 27 | } // addPart 28 | 29 | /** 30 | * @brief Add a message part to the accumulation. 31 | * The accumulation is a growing set of data that is added to until a commit or cancel. 32 | * @param [in] pData A message part being added. 33 | * @param [in] length The number of bytes being added. 34 | */ 35 | void BLEValue::addPart(uint8_t *pData, size_t length) 36 | { 37 | m_accumulation += std::string((char *)pData, length); 38 | } // addPart 39 | 40 | /** 41 | * @brief Cancel the current accumulation. 42 | */ 43 | void BLEValue::cancel() 44 | { 45 | m_accumulation = ""; 46 | m_readOffset = 0; 47 | } // cancel 48 | 49 | /** 50 | * @brief Commit the current accumulation. 51 | * When writing a value, we may find that we write it in "parts" meaning that the writes come in in pieces 52 | * of the overall message. After the last part has been received, we may perform a commit which means that 53 | * we now have the complete message and commit the change as a unit. 54 | */ 55 | void BLEValue::commit() 56 | { 57 | // If there is nothing to commit, do nothing. 58 | if (m_accumulation.length() == 0) 59 | return; 60 | setValue(m_accumulation); 61 | m_accumulation = ""; 62 | m_readOffset = 0; 63 | } // commit 64 | 65 | /** 66 | * @brief Get a pointer to the data. 67 | * @return A pointer to the data. 68 | */ 69 | uint8_t *BLEValue::getData() 70 | { 71 | return (uint8_t *)m_value; 72 | } 73 | 74 | /** 75 | * @brief Get the length of the data in bytes. 76 | * @return The length of the data in bytes. 77 | */ 78 | size_t BLEValue::getLength() 79 | { 80 | return m_length; 81 | } // getLength 82 | 83 | /** 84 | * @brief Get the read offset. 85 | * @return The read offset into the read. 86 | */ 87 | uint16_t BLEValue::getReadOffset() 88 | { 89 | return m_readOffset; 90 | } // getReadOffset 91 | 92 | /** 93 | * @brief Get the current value. 94 | */ 95 | std::string BLEValue::getValue() 96 | { 97 | if (m_value != NULL && m_length != 0) 98 | { 99 | return std::string((char *)m_value, m_length); 100 | } 101 | return ""; 102 | } // getValue 103 | 104 | /** 105 | * @brief Set the read offset 106 | * @param [in] readOffset The offset into the read. 107 | */ 108 | void BLEValue::setReadOffset(uint16_t readOffset) 109 | { 110 | m_readOffset = readOffset; 111 | } // setReadOffset 112 | 113 | /** 114 | * @brief Set the current value. 115 | */ 116 | void BLEValue::setValue(std::string value) 117 | { 118 | if (m_value != NULL) 119 | { 120 | free(m_value); 121 | m_value = NULL; 122 | } 123 | m_value = (uint8_t *)malloc(sizeof(uint8_t) * value.length()); 124 | if (m_value != NULL) 125 | { 126 | memcpy(m_value, value.data(), value.length()); 127 | m_length = value.length(); 128 | } 129 | else 130 | { 131 | m_length = 0; 132 | } 133 | } // setValue 134 | 135 | /** 136 | * @brief Set the current value. 137 | * @param [in] pData The data for the current value. 138 | * @param [in] The length of the new current value. 139 | */ 140 | void BLEValue::setValue(uint8_t *pData, size_t length) 141 | { 142 | if (m_value != NULL) 143 | { 144 | free(m_value); 145 | m_value = NULL; 146 | } 147 | m_value = (uint8_t *)malloc(sizeof(uint8_t) * length); 148 | if (m_value != NULL) 149 | { 150 | memcpy(m_value, pData, length); 151 | m_length = length; 152 | } 153 | else 154 | { 155 | m_length = 0; 156 | } 157 | } // setValue -------------------------------------------------------------------------------- /src/BLEValue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEValue.h 3 | * 4 | * Created on: Jul 17, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef COMPONENTS_CPP_UTILS_BLEVALUE_H_ 9 | #define COMPONENTS_CPP_UTILS_BLEVALUE_H_ 10 | 11 | #include 12 | 13 | /** 14 | * @brief The model of a %BLE value. 15 | */ 16 | class BLEValue { 17 | public: 18 | BLEValue(); 19 | void addPart(std::string part); 20 | void addPart(uint8_t* pData, size_t length); 21 | void cancel(); 22 | void commit(); 23 | uint8_t* getData(); 24 | size_t getLength(); 25 | uint16_t getReadOffset(); 26 | std::string getValue(); 27 | void setReadOffset(uint16_t readOffset); 28 | void setValue(std::string value); 29 | void setValue(uint8_t* pData, size_t length); 30 | 31 | private: 32 | std::string m_accumulation; 33 | uint16_t m_readOffset; 34 | uint8_t *m_value; 35 | size_t m_length; 36 | 37 | }; 38 | 39 | #endif /* COMPONENTS_CPP_UTILS_BLEVALUE_H_ */ 40 | -------------------------------------------------------------------------------- /src/HIDTypes.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010-2011 mbed.org, MIT License 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 4 | * and associated documentation files (the "Software"), to deal in the Software without 5 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 6 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 7 | * Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or 10 | * substantial portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 13 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | #ifndef USBCLASS_HID_TYPES 20 | #define USBCLASS_HID_TYPES 21 | 22 | #include 23 | 24 | /* */ 25 | #define HID_VERSION_1_11 (0x0111) 26 | 27 | /* HID Class */ 28 | #define HID_CLASS (3) 29 | #define HID_SUBCLASS_NONE (0) 30 | #define HID_PROTOCOL_NONE (0) 31 | 32 | /* Descriptors */ 33 | #define HID_DESCRIPTOR (33) 34 | #define HID_DESCRIPTOR_LENGTH (0x09) 35 | #define REPORT_DESCRIPTOR (34) 36 | 37 | /* Class requests */ 38 | #define GET_REPORT (0x1) 39 | #define GET_IDLE (0x2) 40 | #define SET_REPORT (0x9) 41 | #define SET_IDLE (0xa) 42 | 43 | /* HID Class Report Descriptor */ 44 | /* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */ 45 | /* of data as per HID Class standard */ 46 | 47 | /* Main items */ 48 | // #ifdef ARDUINO_ARCH_ESP32 49 | #define HIDINPUT(size) (0x80 | size) 50 | #define HIDOUTPUT(size) (0x90 | size) 51 | // #else 52 | // #define INPUT(size) (0x80 | size) 53 | // #define OUTPUT(size) (0x90 | size) 54 | // #endif 55 | #define FEATURE(size) (0xb0 | size) 56 | #define COLLECTION(size) (0xa0 | size) 57 | #define END_COLLECTION(size) (0xc0 | size) 58 | 59 | /* Global items */ 60 | #define USAGE_PAGE(size) (0x04 | size) 61 | #define LOGICAL_MINIMUM(size) (0x14 | size) 62 | #define LOGICAL_MAXIMUM(size) (0x24 | size) 63 | #define PHYSICAL_MINIMUM(size) (0x34 | size) 64 | #define PHYSICAL_MAXIMUM(size) (0x44 | size) 65 | #define UNIT_EXPONENT(size) (0x54 | size) 66 | #define UNIT(size) (0x64 | size) 67 | #define REPORT_SIZE(size) (0x74 | size) //bits 68 | #define REPORT_ID(size) (0x84 | size) 69 | #define REPORT_COUNT(size) (0x94 | size) //bytes 70 | #define PUSH(size) (0xa4 | size) 71 | #define POP(size) (0xb4 | size) 72 | 73 | /* Local items */ 74 | #define USAGE(size) (0x08 | size) 75 | #define USAGE_MINIMUM(size) (0x18 | size) 76 | #define USAGE_MAXIMUM(size) (0x28 | size) 77 | #define DESIGNATOR_INDEX(size) (0x38 | size) 78 | #define DESIGNATOR_MINIMUM(size) (0x48 | size) 79 | #define DESIGNATOR_MAXIMUM(size) (0x58 | size) 80 | #define STRING_INDEX(size) (0x78 | size) 81 | #define STRING_MINIMUM(size) (0x88 | size) 82 | #define STRING_MAXIMUM(size) (0x98 | size) 83 | #define DELIMITER(size) (0xa8 | size) 84 | 85 | /* HID Report */ 86 | /* Where report IDs are used the first byte of 'data' will be the */ 87 | /* report ID and 'length' will include this report ID byte. */ 88 | 89 | #define MAX_HID_REPORT_SIZE (64) 90 | 91 | typedef struct { 92 | uint32_t length; 93 | uint8_t data[MAX_HID_REPORT_SIZE]; 94 | } HID_REPORT; 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/rpcBLEDevice.h: -------------------------------------------------------------------------------- 1 | #include "BLEDevice.h" --------------------------------------------------------------------------------