[
  {
    "path": ".codespellrc",
    "content": "# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/spell-check/.codespellrc\n# See: https://github.com/codespell-project/codespell#using-a-config-file\n[codespell]\n# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:\nignore-words-list = ,\nskip = ./.git,./.licenses,__pycache__,node_modules,./go.mod,./go.sum,./package-lock.json,./poetry.lock,./yarn.lock,./extras/test\nbuiltin = clear,informal,en-GB_to_en-US\ncheck-filenames =\ncheck-hidden =\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# See: https://docs.github.com/en/code-security/supply-chain-security/configuration-options-for-dependency-updates#about-the-dependabotyml-file\nversion: 2\n\nupdates:\n  # Configure check for outdated GitHub Actions actions in workflows.\n  # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/dependabot/README.md\n  # See: https://docs.github.com/en/code-security/supply-chain-security/keeping-your-actions-up-to-date-with-dependabot\n  - package-ecosystem: github-actions\n    directory: / # Check the repository's workflows under /.github/workflows/\n    schedule:\n      interval: daily\n    labels:\n      - \"topic: infrastructure\"\n"
  },
  {
    "path": ".github/workflows/compile-examples.yml",
    "content": "name: Compile Examples\n\n# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows\non:\n  push:\n    paths:\n      - \".github/workflows/compile-examples.yml\"\n      - \"examples/**\"\n      - \"src/**\"\n  pull_request:\n    paths:\n      - \".github/workflows/compile-examples.yml\"\n      - \"examples/**\"\n      - \"src/**\"\n  schedule:\n    # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms).\n    - cron: \"0 8 * * TUE\"\n  workflow_dispatch:\n  repository_dispatch:\n\njobs:\n  build:\n    name: ${{ matrix.board.fqbn }}\n    runs-on: ubuntu-latest\n\n    env:\n      SKETCHES_REPORTS_PATH: sketches-reports\n\n    strategy:\n      fail-fast: false\n\n      matrix:\n        board:\n          - fqbn: arduino:samd:mkrwifi1010\n            platforms: |\n              - name: arduino:samd\n            libraries: |\n              - name: Arduino_SpiNINA\n            artifact-name-suffix: arduino-samd-mkrwifi1010\n          - fqbn: arduino:samd:nano_33_iot\n            platforms: |\n              - name: arduino:samd\n            libraries: |\n              - name: Arduino_SpiNINA\n            artifact-name-suffix: arduino-samd-nano_33_iot\n          - fqbn: arduino:megaavr:uno2018:mode=on\n            platforms: |\n              - name: arduino:megaavr\n            libraries: |\n              - name: Arduino_SpiNINA\n            artifact-name-suffix: arduino-megaavr-uno2018\n          - fqbn: arduino:mbed_nano:nano33ble\n            platforms: |\n              - name: arduino:mbed_nano\n            libraries: \"\"\n            artifact-name-suffix: arduino-mbed_nano-nano33ble\n          - fqbn: arduino:mbed_nano:nanorp2040connect\n            platforms: |\n              - name: arduino:mbed_nano\n            libraries: |\n              - name: Arduino_SpiNINA\n            artifact-name-suffix: arduino-mbed_nano-nanorp2040connect\n          - fqbn: arduino:mbed_portenta:envie_m7\n            platforms: |\n              - name: arduino:mbed_portenta\n            libraries: \"\"\n            artifact-name-suffix: arduino-mbed_portenta-envie_m7\n          - fqbn: arduino:mbed_nicla:nicla_vision\n            platforms: |\n              - name: arduino:mbed_nicla\n            libraries: \"\"\n            artifact-name-suffix: arduino-mbed_nicla-nicla_vision\n          - fqbn: arduino:mbed_giga:giga\n            platforms: |\n              - name: arduino:mbed_giga\n            libraries: \"\"\n            artifact-name-suffix: arduino-mbed_giga-giga\n          - fqbn: arduino:mbed_opta:opta\n            platforms: |\n              - name: arduino:mbed_opta\n            libraries: \"\"\n            artifact-name-suffix: arduino-mbed_opta-opta\n          - fqbn: arduino:renesas_uno:unor4wifi\n            platforms: |\n              - name: arduino:renesas_uno\n            libraries: \"\"\n            artifact-name-suffix: arduino-renesas_uno-unor4wifi\n          - fqbn: arduino:renesas_portenta:portenta_c33\n            platforms: |\n              - name: arduino:renesas_portenta\n            libraries: \"\"\n            artifact-name-suffix: arduino-renesas_portenta-portenta_c33\n          - fqbn: arduino:esp32:nano_nora\n            platforms: |\n              - name: arduino:esp32\n            libraries: \"\"\n            artifact-name-suffix: arduino-esp32-nano_nora\n          - fqbn: arduino:zephyr_main:giga\n            platforms: |\n              - name: arduino:zephyr_main\n            libraries: \"\"\n            artifact-name-suffix: arduino-zephyr_main-giga\n          - fqbn: arduino:zephyr_main:nano33ble\n            platforms: |\n              - name: arduino:zephyr_main\n            libraries: \"\"\n            artifact-name-suffix: arduino-zephyr_main-nano33ble\n          - fqbn: arduino:zephyr_main:portentah7\n            platforms: |\n              - name: arduino:zephyr_main\n            libraries: \"\"\n            artifact-name-suffix: arduino-zephyr_main-portentah7\n          - fqbn: arduino:zephyr_main:niclasense\n            platforms: |\n              - name: arduino:zephyr_main\n            libraries: \"\"\n            artifact-name-suffix: arduino-zephyr_main-niclasense\n          - fqbn: arduino:zephyr_main:portentac33\n            platforms: |\n              - name: arduino:zephyr_main\n            libraries: \"\"\n            artifact-name-suffix: arduino-zephyr_main-portentac33\n          - fqbn: arduino:zephyr_main:opta\n            platforms: |\n              - name: arduino:zephyr_main\n            libraries: \"\"\n            artifact-name-suffix: arduino-zephyr_main-opta\n          - fqbn: arduino:zephyr:unoq\n            platforms: |\n              - name: arduino:zephyr\n            libraries: |\n              - name: MsgPack\n            artifact-name-suffix: arduino-zephyr-unoq\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Compile examples\n        uses: arduino/compile-sketches@v1\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          fqbn: ${{ matrix.board.fqbn }}\n          platforms: ${{ matrix.board.platforms }}\n          libraries: |\n            # Install the library from the local path.\n            - source-path: ./\n            ${{ matrix.board.libraries }}\n          sketch-paths: |\n            - examples\n          enable-deltas-report: true\n          sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}\n\n      - name: Save sketches report as workflow artifact\n        uses: actions/upload-artifact@v7\n        with:\n          if-no-files-found: error\n          path: ${{ env.SKETCHES_REPORTS_PATH }}\n          name: sketches-report-${{ matrix.board.artifact-name-suffix }}\n\n  build-for-esp32:\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        fqbn:\n          - esp32:esp32:esp32\n          - esp32:esp32:esp32s3\n          - esp32:esp32:esp32c3\n          - esp32:esp32:esp32c6\n          - esp32:esp32:esp32h2\n          # Not supported out of the box by ESP32 Arduino core\n          #- esp32:esp32:esp32c2\n\n    steps:\n      - uses: actions/checkout@v6\n      - uses: arduino/compile-sketches@v1\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          fqbn: ${{ matrix.fqbn }}\n          libraries: |\n            ${{ matrix.libraries }}\n          platforms: |\n            - name: esp32:esp32\n              source-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json\n          sketch-paths: |\n            - examples/Central/Scan\n            - examples/Central/PeripheralExplorer\n            - examples/Central/ScanCallback\n            - examples/Central/SensorTagButton\n            - examples/Peripheral/Advertising/EnhancedAdvertising\n            - examples/Peripheral/Advertising/RawDataAdvertising\n          cli-compile-flags: |\n            - --warnings=\"none\"\n"
  },
  {
    "path": ".github/workflows/report-size-deltas.yml",
    "content": "name: Report Size Deltas\n\n# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows\non:\n  push:\n    paths:\n      - \".github/workflows/report-size-deltas.yml\"\n  schedule:\n    # Run at the minimum interval allowed by GitHub Actions.\n    # Note: GitHub Actions periodically has outages which result in workflow failures.\n    # In this event, the workflows will start passing again once the service recovers.\n    - cron: \"*/5 * * * *\"\n  workflow_dispatch:\n  repository_dispatch:\n\njobs:\n  report:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Comment size deltas reports to PRs\n        uses: arduino/report-size-deltas@v1\n        with:\n          # Regex matching the names of the workflow artifacts created by the \"Compile Examples\" workflow\n          sketches-reports-source: ^sketches-report-.+\n"
  },
  {
    "path": ".github/workflows/spell-check.yml",
    "content": "# Source: https://github.com/per1234/.github/blob/main/workflow-templates/spell-check.md\nname: Spell Check\n\n# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows\non:\n  push:\n  pull_request:\n  schedule:\n    # Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates.\n    - cron: \"0 8 * * TUE\"\n  workflow_dispatch:\n  repository_dispatch:\n\njobs:\n  spellcheck:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Spell check\n        uses: codespell-project/actions-codespell@v2\n"
  },
  {
    "path": ".github/workflows/sync-labels.yml",
    "content": "# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md\nname: Sync Labels\n\n# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows\non:\n  push:\n    paths:\n      - \".github/workflows/sync-labels.ya?ml\"\n      - \".github/label-configuration-files/*.ya?ml\"\n  pull_request:\n    paths:\n      - \".github/workflows/sync-labels.ya?ml\"\n      - \".github/label-configuration-files/*.ya?ml\"\n  schedule:\n    # Run daily at 8 AM UTC to sync with changes to shared label configurations.\n    - cron: \"0 8 * * *\"\n  workflow_dispatch:\n  repository_dispatch:\n\nenv:\n  CONFIGURATIONS_FOLDER: .github/label-configuration-files\n  CONFIGURATIONS_ARTIFACT: label-configuration-files\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Download JSON schema for labels configuration file\n        id: download-schema\n        uses: carlosperate/download-file-action@v2\n        with:\n          file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json\n          location: ${{ runner.temp }}/label-configuration-schema\n\n      - name: Install JSON schema validator\n        run: |\n          sudo npm install \\\n            --global \\\n            ajv-cli \\\n            ajv-formats\n\n      - name: Validate local labels configuration\n        run: |\n          # See: https://github.com/ajv-validator/ajv-cli#readme\n          ajv validate \\\n            --all-errors \\\n            -c ajv-formats \\\n            -s \"${{ steps.download-schema.outputs.file-path }}\" \\\n            -d \"${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}\"\n\n  download:\n    needs: check\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        filename:\n          # Filenames of the shared configurations to apply to the repository in addition to the local configuration.\n          # https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels\n          - universal.yml\n\n    steps:\n      - name: Download\n        uses: carlosperate/download-file-action@v2\n        with:\n          file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }}\n\n      - name: Pass configuration files to next job via workflow artifact\n        uses: actions/upload-artifact@v7\n        with:\n          path: |\n            *.yaml\n            *.yml\n          if-no-files-found: error\n          name: ${{ env.CONFIGURATIONS_ARTIFACT }}\n\n  sync:\n    needs: download\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Set environment variables\n        run: |\n          # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable\n          echo \"MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml\" >> \"$GITHUB_ENV\"\n\n      - name: Determine whether to dry run\n        id: dry-run\n        if: >\n          github.event_name == 'pull_request' ||\n          (\n            (\n              github.event_name == 'push' ||\n              github.event_name == 'workflow_dispatch'\n            ) &&\n            github.ref != format('refs/heads/{0}', github.event.repository.default_branch)\n          )\n        run: |\n          # Use of this flag in the github-label-sync command will cause it to only check the validity of the\n          # configuration.\n          echo \"::set-output name=flag::--dry-run\"\n\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Download configuration files artifact\n        uses: actions/download-artifact@v8\n        with:\n          name: ${{ env.CONFIGURATIONS_ARTIFACT }}\n          path: ${{ env.CONFIGURATIONS_FOLDER }}\n\n      - name: Remove unneeded artifact\n        uses: geekyeggo/delete-artifact@v6\n        with:\n          name: ${{ env.CONFIGURATIONS_ARTIFACT }}\n\n      - name: Merge label configuration files\n        run: |\n          # Merge all configuration files\n          shopt -s extglob\n          cat \"${{ env.CONFIGURATIONS_FOLDER }}\"/*.@(yml|yaml) > \"${{ env.MERGED_CONFIGURATION_PATH }}\"\n\n      - name: Install github-label-sync\n        run: sudo npm install --global github-label-sync\n\n      - name: Sync labels\n        env:\n          GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          # See: https://github.com/Financial-Times/github-label-sync\n          github-label-sync \\\n            --labels \"${{ env.MERGED_CONFIGURATION_PATH }}\" \\\n            ${{ steps.dry-run.outputs.flag }} \\\n            ${{ github.repository }}\n"
  },
  {
    "path": ".github/workflows/unit-tests.yml",
    "content": "name: Unit Tests\n\non:\n  pull_request:\n    paths:\n      - \".github/workflows/unit-tests.yml\"\n      - 'extras/test/**'\n      - 'src/**'\n\n  push:\n    paths:\n      - \".github/workflows/unit-tests.yml\"\n      - 'extras/test/**'\n      - 'src/**'\n\njobs:\n  test:\n    name: Run unit tests\n    runs-on: ubuntu-latest\n\n    env:\n      COVERAGE_DATA_PATH: extras/coverage-data/coverage.info\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - uses: arduino/cpp-test-action@main\n        with:\n          runtime-paths: |\n            - extras/test/build/bin/TEST_TARGET_UUID\n            - extras/test/build/bin/TEST_TARGET_DISC_DEVICE\n            - extras/test/build/bin/TEST_TARGET_ADVERTISING_DATA\n          coverage-exclude-paths: |\n            - '*/extras/test/*'\n            - '/usr/*'\n          coverage-data-path: ${{ env.COVERAGE_DATA_PATH }}\n\n      # A token is used to avoid intermittent spurious job failures caused by rate limiting.\n      - name: Set up Codecov upload token\n        run: |\n          if [[ \"${{ github.repository }}\" == \"arduino-libraries/ArduinoBLE\" ]]; then\n            # In order to avoid uploads of data from forks, only use the token for runs in the parent repo.\n            # Token is intentionally exposed.\n            # See: https://community.codecov.com/t/upload-issues-unable-to-locate-build-via-github-actions-api/3954\n            CODECOV_TOKEN=\"8118de48-b2af-48b4-a66a-26026847bfc5\"\n          else\n            # codecov/codecov-action does unauthenticated upload if empty string is passed via the `token` input.\n            CODECOV_TOKEN=\"\"\n          fi\n          echo \"CODECOV_TOKEN=$CODECOV_TOKEN\" >> \"$GITHUB_ENV\"\n\n      - name: Upload coverage report to Codecov\n        uses: codecov/codecov-action@v3\n        with:\n          file: \"${{ env.COVERAGE_DATA_PATH }}\"\n          fail_ci_if_error: true\n          token: ${{ env.CODECOV_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "\n.DS_Store\n"
  },
  {
    "path": "CHANGELOG",
    "content": "ArduinoBLE ?.?.? - ????.??.??\n\nArduinoBLE 1.1.2 - 2019.11.12\n\n* cordio: switch to lower power when polling with timeout\n* Fixed issue with wrong types for disconnection event handling. Thanks @cparata\n\nArduinoBLE 1.1.1 - 2019.09.05\n\n* [Cordio] Fixed crashing when BLE.begin() is not called\n* Fixed ACL RX packet fragmentation, affected devices that supported large MTUs\n* Fixed BLECharacteristic::readValue(...) triggering a read request after a notification/indication was received\n* Added support for case insensitive comparison of UUID or address string inputs\n* Added (optional) company ID argument to BLE.setManufacturerData(...). Thanks @konikoni428\n\nArduinoBLE 1.1.0 - 2019.08.27\n\n* Added BLE Central support\n\nArduinoBLE 1.0.0 - 2019.07.31\n\n* Added support for Arduino Nano 33 BLE boards\n\nArduinoBLE 0.1.2 and older\n\n* Changes not recorded\n"
  },
  {
    "path": "LICENSE",
    "content": "                  GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n(This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.)\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it.  You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n  When we speak of free software, we are referring to freedom of use,\nnot price.  Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n  To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights.  These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library.  Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\n  Finally, software patents pose a constant threat to the existence of\nany free program.  We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder.  Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n  Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License.  This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License.  We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n  When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library.  The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom.  The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n  We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License.  It also provides other free software developers Less\nof an advantage over competing non-free programs.  These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries.  However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n  For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard.  To achieve this, non-free programs must be\nallowed to use the library.  A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries.  In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n  In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software.  For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n  Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\n                  GNU LESSER GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\n  6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Use a suitable shared library mechanism for linking with the\n    Library.  A suitable mechanism is one that (1) uses at run time a\n    copy of the library already present on the user's computer system,\n    rather than copying library functions into the executable, and (2)\n    will operate properly with a modified version of the library, if\n    the user installs one, as long as the modified version is\n    interface-compatible with the version that the work was made with.\n\n    c) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    d) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    e) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n                            NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    {description}\n    Copyright (C) {year} {fullname}\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n    USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random\n  Hacker.\n\n  {signature of Ty Coon}, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n"
  },
  {
    "path": "README.md",
    "content": "# ArduinoBLE\n\n[![Compile Examples Status](https://github.com/arduino-libraries/ArduinoBLE/workflows/Compile%20Examples/badge.svg)](https://github.com/arduino-libraries/ArduinoBLE/actions?workflow=Compile+Examples) [![Spell Check Status](https://github.com/arduino-libraries/ArduinoBLE/workflows/Spell%20Check/badge.svg)](https://github.com/arduino-libraries/ArduinoBLE/actions?workflow=Spell+Check)\n\nEnables Bluetooth® Low Energy connectivity on the Arduino MKR WiFi 1010, Arduino UNO WiFi Rev2, Arduino Nano 33 IoT, Arduino Nano 33 BLE, Arduino Portenta H7, Arduino Giga R1 and Arduino UNO R4 WiFi.\n\nThis library supports creating a Bluetooth® Low Energy peripheral & central mode.\n\nFor more information about this library please visit us at:\nhttps://www.arduino.cc/en/Reference/ArduinoBLE\n\n## Firmware compatibility\n\n| Board | Library Version | Required Firmware |\n| :--- | :--- | :--- |\n| **MKR WiFi 1010, UNO WiFi Rev2,<br>Nano 33 IoT, Nano RP2040 Connect** | **v2.0.0 or later** | [NINA-W102](https://github.com/arduino/nina-fw) **v3.0.0+** |\n| **MKR WiFi 1010, UNO WiFi Rev2,<br>Nano 33 IoT, Nano RP2040 Connect** | **Versions prior to v2.0.0** | [NINA-W102](https://github.com/arduino/nina-fw) **v1.2.0 – v2.0.0** |\n| **Arduino UNO R4 WiFi** | All versions | [ESP32-S3](https://github.com/arduino/uno-r4-wifi-usb-bridge) **v0.2.0+** |\n\n\n## License\n\n```\nCopyright (c) 2019 Arduino SA. All rights reserved.\n\nThis library is free software; you can redistribute it and/or\nmodify it under the terms of the GNU Lesser General Public\nLicense as published by the Free Software Foundation; either\nversion 2.1 of the License, or (at your option) any later version.\n\nThis library is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nLesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public\nLicense along with this library; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n```\n"
  },
  {
    "path": "docs/api.md",
    "content": "# ArduinoBLE library\n\n## BLE class\n\nUsed to enable the Bluetooth® Low Energy module.\n\n### `BLE.begin()`\n\nInitializes the Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nBLE.begin()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- 1 on success\n- 0 on failure\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n\n```\n\n### `BLE.end()`\n\nStops the Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nBLE.end()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // ....\n\n  BLE.end();\n\n\n```\n\n### `BLE.poll()`\n\nPoll for Bluetooth® Low Energy radio events and handle them.\n\n#### Syntax\n\n```\nBLE.poll()\nBLE.poll(timeout)\n\n```\n\n#### Parameters\n\n**timeout**: optional timeout in ms, to wait for event. If not specified defaults to 0 ms.\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n  // assign event handlers for connected, disconnected to peripheral\n  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);\n  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);\n\n\n  BLE.poll();\n\n\n```\n\n### `BLE.setEventHandler()`\n\nSet the event handler (callback) function that will be called when the specified event occurs.\n\n#### Syntax\n\n```\nBLE.setEventHandler(eventType, callback)\n\n```\n\n#### Parameters\n\n- **eventType**: event type (BLEConnected, BLEDisconnected)\n- **callback**: function to call when event occurs\n#### Returns\nNothing.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // ...\n\n  // assign event handlers for connected, disconnected to peripheral\n  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);\n  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);\n\n\n\nvoid blePeripheralConnectHandler(BLEDevice central) {\n  // central connected event handler\n  Serial.print(\"Connected event, central: \");\n  Serial.println(central.address());\n}\n\nvoid blePeripheralDisconnectHandler(BLEDevice central) {\n  // central disconnected event handler\n  Serial.print(\"Disconnected event, central: \");\n  Serial.println(central.address());\n}\n\n\n```\n\n### `BLE.connected()`\n\nQuery if another Bluetooth® Low Energy device is connected\n\n#### Syntax\n\n```\nBLE.connected()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true** if another Bluetooth® Low Energy device is connected,\n- otherwise **false**.\n\n#### Example\n\n```arduino\n\n    // while the central is still connected to peripheral:\n    while (BLE.connected()) {\n\n       // ...\n    }\n\n\n```\n\n### `BLE.disconnect()`\n\nDisconnect any Bluetooth® Low Energy devices that are connected\n\n#### Syntax\n\n```\nBLE.disconnect()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true** if any Bluetooth® Low Energy device that was previously connected was disconnected,\n- otherwise **false**.\n\n#### Example\n\n```arduino\n\n  if (BLE.connected()) {\n    BLE.disconnect();\n  }\n\n\n```\n\n### `BLE.address()`\n\nQuery the Bluetooth® address of the Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nBLE.address()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **Bluetooth® address** of the Bluetooth® Low Energy device (as a String).\n\n#### Example\n\n```arduino\n\n  String address = BLE.address();\n\n  Serial.print(\"Local address is: \");\n  Serial.println(address);\n\n\n```\n\n### `BLE.rssi()`\n\nQuery the RSSI (Received signal strength indication) of the connected Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nBLE.rssi()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **RSSI** of the connected Bluetooth® Low Energy device, 127 if no Bluetooth® Low Energy device is connected.\n\n#### Example\n\n```arduino\n\n  if (BLE.connected()) {\n    Serial.print(\"RSSI = \");\n    Serial.println(BLE.rssi());\n  }\n\n\n```\n\n### `BLE.setAdvertisedServiceUuid()`\n\nSet the advertised service UUID used when advertising.\n\n#### Syntax\n\n```\nBLE.setAdvertisedServiceUuid(uuid)\n\n```\n\n#### Parameters\n\n- **uuid:** 16-bit or 128-bit Bluetooth® Low Energy UUID in **String** format\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  BLE.setAdvertisedServiceUuid(\"19B10000-E8F2-537E-4F6C-D104768A1214\");\n\n  // ...\n\n  // start advertising\n  BLE.advertise();\n\n\n```\n\n### `BLE.setAdvertisedService()`\n\nSet the advertised service UUID used when advertising to the value of the BLEService provided.\n\n#### Syntax\n\n```\nBLE.setAdvertisedService(bleService)\n\n```\n\n#### Parameters\n\n- **bleService:** BLEService to use UUID from\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\nBLEService ledService(\"19B10000-E8F2-537E-4F6C-D104768A1214\"); // Bluetooth® Low Energy LED Service\n\n// ...\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  BLE.setAdvertisedService(ledService);\n\n  // ...\n\n  // start advertising\n  BLE.advertise();\n\n\n```\n\n### `BLE.setManufacturerData()`\n\nSet the manufacturer data value used when advertising.\n\n#### Syntax\n\n```\nBLE.setManufacturerData(data, length)\n\n```\n\n#### Parameters\n\n- **data:** byte array containing manufacturer data\n- **length:** length of manufacturer data array\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  byte data[5] = { 0x01, 0x02, 0x03, 0x04, 0x05};\n\n  BLE.setManufacturerData(data, 5);\n\n  // ...\n\n  // start advertising\n  BLE.advertise();\n\n\n\n```\n\n### `BLE.setLocalName()`\n\nSet the local value used when advertising.\n\n#### Syntax\n\n```\nBLE.setLocalName(name)\n\n```\n\n#### Parameters\n\n- **name:** local name value to use when advertising\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  BLE.setLocalName(\"LED\");\n\n  // ...\n\n  // start advertising\n  BLE.advertise();\n\n\n\n```\n\n### `BLE.setDeviceName()`\n\nSet the device name in the built in device name characteristic. If not set, the value defaults to “Arduino”.\n\n#### Syntax\n\n```\nBLE.setDeviceName(name)\n\n```\n\n#### Parameters\n\n- **name:** device name value\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  BLE.setDeviceName(\"LED\");\n\n  // ...\n\n  // start advertising\n  BLE.advertise();\n\n\n\n```\n\n### `BLE.setAppearance()`\n\nSet the appearance in the built in appearance characteristic. If not set, the value defaults to 0x0000.\n\n#### Syntax\n\n```\nBLE.setAppearance(appearance)\n\n```\n\n#### Parameters\n\n- **appearance:** appearance value\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  BLE.setAppearance(0x8000);\n\n  // ...\n\n  // start advertising\n  BLE.advertise();\n\n\n\n```\n\n### `BLE.addService()`\n\nAdd a BLEService to the set of services the Bluetooth® Low Energy device provides\n\n#### Syntax\n\n```\nBLE.addService(service)\n\n```\n\n#### Parameters\n\n- **service:** BLEService to add\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\nBLEService ledService(\"19B10000-E8F2-537E-4F6C-D104768A1214\"); // Bluetooth® Low Energy LED Service\n\n\n\n // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // ...\n\n  BLE.addService(ledService);\n\n  // ...\n\n\n```\n\n### `BLE.advertise()`\n\nStart advertising.\n\n#### Syntax\n\n```\nBLE.advertise()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- 1 on success,\n- 0 on failure.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // ...\n\n  BLE.advertise();\n\n  // ...\n\n\n```\n\n### `BLE.stopAdvertise()`\n\nStop advertising.\n\n#### Syntax\n\n```\nBLE.stopAdvertise()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // ...\n\n  BLE.advertise();\n\n  // ...\n\n  BLE.stopAdvertise();\n\n\n```\n\n### `BLE.central()`\n\nQuery the central Bluetooth® Low Energy device connected.\n\n#### Syntax\n\n```\nBLE.central()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **BLEDevice** representing the central.\n\n#### Example\n\n```arduino\n\n  // listen for Bluetooth® Low Energy peripherals to connect:\n  BLEDevice central = BLE.central();\n\n  // if a central is connected to peripheral:\n  if (central) {\n    Serial.print(\"Connected to central: \");\n    // print the central's MAC address:\n    Serial.println(central.address());\n  }\n\n\n```\n\n### `BLE.setAdvertisingInterval()`\n\nSet the advertising interval in units of 0.625 ms. Defaults to 100ms (160 * 0.625 ms) if not provided.\n\n#### Syntax\n\n```\nBLE.setAdvertisingInterval(advertisingInterval)\n\n```\n\n#### Parameters\n\n- **advertisingInterval:** advertising interval in units of 0.625 ms\n\n#### Returns\nNothing.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // ...\n\n  BLE.setAdvertisingInterval(320); // 200 * 0.625 ms\n\n  BLE.advertise();\n\n\n```\n\n### `BLE.setConnectionInterval()`\n\nSet the minimum and maximum desired connection intervals in units of 1.25 ms.\n\n#### Syntax\n\n```\nBLE.setConnectionInterval(minimum, maximum)\n\n```\n\n#### Parameters\n\n- **minimum:** minimum desired connection interval in units of 1.25 ms\n- **maximum:** maximum desired connection interval in units of 1.25 ms\n\n#### Returns\nNothing.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // ...\n\n  BLE.setConnectionInterval(0x0006, 0x0c80); // 7.5 ms minimum, 4 s maximum\n\n\n\n```\n\n### `BLE.setConnectable()`\n\nSet if the device is connectable after advertising, defaults to **true**.\n\n#### Syntax\n\n```\nBLE.setConnectable(connectable)\n\n```\n\n#### Parameters\n\n- **true**: the device will be connectable when advertising\n- **false**: the device will NOT be connectable when advertising\n\n#### Returns\nNothing.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // ...\n\n  BLE.setConnectable(false); // make the device unconnectable when advertising\n\n\n\n```\n\n### `BLE.scan()`\n\nStart scanning for Bluetooth® Low Energy devices that are advertising.\n\n#### Syntax\n\n```\nBLE.scan()\nBLE.scan(withDuplicates)\n\n```\n\n#### Parameters\n\n- **withDuplicates:** optional, defaults to **false**. If **true**, advertisements received more than once will not be filtered\n\n#### Returns\n- 1 on success,\n- 0 on failure.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n     // ...\n  }\n\n\n```\n\n### `BLE.scanForName()`\n\nStart scanning for Bluetooth® Low Energy devices that are advertising with a particular (local) name.\n\n#### Syntax\n\n```\nBLE.scanForName(name)\nBLE.scanForName(name, withDuplicates)\n\n```\n\n#### Parameters\n\n-  **name:** (local) name of device (as a **String**) to filter for\n- **withDuplicates:** optional, defaults to **false**. If **true**, advertisements received more than once will not be filtered.\n\n#### Returns\n- 1 on success,\n- 0 on failure.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scanForName(\"LED\");\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n     // ...\n  }\n\n\n```\n\n### `BLE.scanForAddress()`\n\nStart scanning for Bluetooth® Low Energy devices that are advertising with a particular (Bluetooth®) address.\n\n#### Syntax\n\n```\nBLE.scanForAddress(address)\nBLE.scanForAddress(address, withDuplicates)\n\n```\n\n#### Parameters\n\n- **address:** (Bluetooth®) address (as a String) to filter for\n- **withDuplicates:** optional, defaults to **false**. If **true**, advertisements received more than once will not be filtered\n\n#### Returns\n- 1 on success,\n- 0 on failure.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scanForAddress(\"aa:bb:cc:ee:dd:ff\");\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n     // ...\n  }\n\n\n```\n\n### `BLE.scanForUuid()`\n\nStart scanning for Bluetooth® Low Energy devices that are advertising with a particular (service) UUID.\n\n#### Syntax\n\n```\nBLE.scanForUuid(uuid)\nBLE.scanForUuid(uuid, withDuplicates)\n\n```\n\n#### Parameters\n\n- **uuid:** (service) UUID (as a **String**) to filter for\n- **withDuplicates:** optional, defaults to **false**. If **true**, advertisements received more than once will not be filtered.\n\n#### Returns\n- 1 on success,\n- 0 on failure.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scanForUuid(\"aa10\");\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n     // ...\n  }\n\n\n```\n\n### `BLE.stopScan()`\n\nStop scanning for Bluetooth® Low Energy devices that are advertising.\n\n#### Syntax\n\n```\nBLE.stopScan()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n  BLE.stopScan();\n\n\n```\n\n### `BLE.available()`\n\nQuery for a discovered Bluetooth® Low Energy device that was found during scanning.\n\n#### Syntax\n\n```\nBLE.available()\n\n```\n\n#### Parameters\n\nNothing\n\n#### Returns\n- **BLEDevice** representing the discovered device.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n     // ...\n  }\n\n\n```\n\n## BLEDevice Class\n\nUsed to get information about the devices connected or discovered while scanning\n\n### `bleDevice.poll()`\n\nPoll for Bluetooth® Low Energy radio events for the specified Bluetooth® Low Energy device and handle them.\n\n#### Syntax\n\n```\nbleDevice.poll()\nbleDevice.poll(timeout)\n\n```\n\n#### Parameters\n\n- **timeout**: optional timeout in ms, to wait for event. If not specified defaults to 0 ms.\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n  // listen for Bluetooth® Low Energy centrals to connect:\n  BLEDevice central = BLE.central();\n\n  // if a central is connected to peripheral:\n  if (central) {\n   central.poll();\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.connected()`\n\nQuery if a Bluetooth® Low Energy device is connected\n\n#### Syntax\n\n```\nbleDevice.connected()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true** if the Bluetooth® Low Energy device is connected,\n- otherwise **false**.\n\n#### Example\n\n```arduino\n\n  // listen for Bluetooth® Low Energy centrals to connect:\n  BLEDevice central = BLE.central();\n\n    // while the central is still connected\n    while (central.connected()) {\n\n       // ...\n    }\n\n\n```\n\n### `bleDevice.disconnect()`\n\nDisconnect the Bluetooth® Low Energy device, if connected\n\n#### Syntax\n\n```\nbleDevice.disconnect()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true** if the Bluetooth® Low Energy device was disconnected,\n- otherwise **false**.\n\n#### Example\n\n```arduino\n\n // listen for Bluetooth® Low Energy centrals to connect:\n  BLEDevice central = BLE.central();\n\n\n  central.disconnect();\n\n\n```\n\n### `bleDevice.address()`\n\nQuery the Bluetooth® address of the Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.address()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **Bluetooth® address** of the Bluetooth® Low Energy device (as a String).\n\n#### Example\n\n```arduino\n\n  // listen for Bluetooth® Low Energy peripherals to connect:\n  BLEDevice central = BLE.central();\n\n  // if a central is connected to peripheral:\n  if (central) {\n    Serial.print(\"Connected to central: \");\n    // print the central's MAC address:\n    Serial.println(central.address());\n  }\n\n\n```\n\n### `bleDevice.rssi()`\n\nQuery the RSSI (Received signal strength indication) of the Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.rssi()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **RSSI** of the connected Bluetooth® Low Energy device, 127 if the Bluetooth® Low Energy device is not connected.\n\n#### Example\n\n```arduino\n\n  if (bleDevice.connected()) {\n    Serial.print(\"RSSI = \");\n    Serial.println(bleDevice.rssi());\n  }\n\n\n```\n\n### `bleDevice.characteristic()`\n\nGet a BLECharacteristic representing a Bluetooth® Low Energy characteristic the device provides.\n\n#### Syntax\n\n```\nbleDevice.characteristic(index)\nbleDevice.characteristic(uuid)\nbleDevice.characteristic(uuid, index)\n\n```\n\n#### Parameters\n\n- **index**: index of characteristic\n- **uuid**: uuid (as a **String**)\n\n#### Returns\n- **BLECharacteristic** for provided parameters\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    BLECharacteristic batteryLevelCharacteristic = peripheral.characteristic(\"2a19\");\n\n    if (batteryLevelCharacteristic) {\n      // use the characteristic\n    } else {\n      Serial.println(\"Peripheral does NOT have battery level characteristic\");\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.discoverAttributes()`\n\nDiscover all of the attributes of Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.discoverAttributes()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if successful,\n- **false** on failure.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.discoverService()`\n\nDiscover the attributes of a particular service on the Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.discoverService(serviceUuid)\n\n```\n\n#### Parameters\n\n- **serviceUuid:** service UUID to discover (as a **String**)\n\n#### Returns\n- **true**, if successful,\n- **false** on failure.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover service attributes\n    Serial.println(\"Discovering service attributes ...\");\n    if (peripheral.serviceUuid(\"fffe\")) {\n      Serial.println(\"Service attributes discovered\");\n    } else {\n      Serial.println(\"Service attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.deviceName()`\n\nQuery the device name (BLE characteristic UUID 0x2a00) of a Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.deviceName()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **Device name** (as a String).\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    // read and print device name of peripheral\n    Serial.println();\n    Serial.print(\"Device name: \");\n    Serial.println(peripheral.deviceName());\n    Serial.print(\"Appearance: 0x\");\n    Serial.println(peripheral.appearance(), HEX);\n    Serial.println();\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.appearance()`\n\nQuery the appearance (BLE characteristic UUID 0x2a01) of a Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.appearance()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **Appearance value** (as a number).\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    // read and print device name of peripheral\n    Serial.println();\n    Serial.print(\"Device name: \");\n    Serial.println(peripheral.deviceName());\n    Serial.print(\"Appearance: 0x\");\n    Serial.println(peripheral.appearance(), HEX);\n    Serial.println();\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.serviceCount()`\n\nQuery the number of services discovered for the Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.serviceCount()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The number of **services discovered** for the Bluetooth® Low Energy device.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    int serviceCount = peripheral.serviceCount();\n\n    Serial.print(serviceCount);\n    Serial.println(\" services discovered\");\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.hasService()`\n\nQuery if the Bluetooth® Low Energy device has a particular service.\n\n#### Syntax\n\n```\nbleDevice.hasService(uuid)\nbleDevice.hasService(uuid, index)\n\n```\n\n#### Parameters\n\n- **uuid**: uuid to check (as a **String**)\n- **index**: optional, index of service to check if the device provides more than on. Defaults to 0, if not provided.\n\n#### Returns\n- **true**, if the device provides the service,\n- **false** otherwise.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    if (peripheral.hasService(\"180f\")) {\n      Serial.println(\"Peripheral has battery service\");\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.service()`\n\nGet a BLEService representing a Bluetooth® Low Energy service the device provides.\n\n#### Syntax\n\n```\nbleDevice.service(index)\nbleDevice.service(uuid)\nbleDevice.service(uuid, index)\n\n```\n\n#### Parameters\n\n- **index**: index of service\n- **uuid**: uuid (as a **String**)\n\n#### Returns\n- **BLEService** for provided parameters\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    BLEService batteryService = peripheral.service(\"180f\");\n\n    if (batteryService) {\n      // use the service\n    } else {\n      Serial.println(\"Peripheral does NOT have battery service\");\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.characteristicCount()`\n\nQuery the number of characteristics discovered for the Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.characteristicCount()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **number of characteristics** discovered for the Bluetooth® Low Energy device.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    int characteristicCount = peripheral.characteristicCount();\n\n    Serial.print(characteristicCount);\n    Serial.println(\" characteristics discovered\");\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.hasCharacteristic()`\n\nQuery if the Bluetooth® Low Energy device has a particular characteristic.\n\n#### Syntax\n\n```\nbleDevice.hasCharacteristic(uuid)\nbleDevice.hasCharacteristic(uuid, index)\n\n```\n\n#### Parameters\n\n- **uuid**: uuid to check (as a **String**)\n- **index**: optional, index of characteristic to check if the device provides more than on. Defaults to 0, if not provided.\n\n#### Returns\n- **true**, if the device provides the characteristic,\n- **false** otherwise.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    if (peripheral.hasCharacteristic(\"2a19\")) {\n      Serial.println(\"Peripheral has battery level characteristic\");\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.hasLocalName()`\n\nQuery if a discovered Bluetooth® Low Energy device is advertising a local name.\n\n#### Syntax\n\n```\nbleDevice.hasLocalName()\n\n```\n\n#### Parameters\n\nNothing\n\n#### Returns\n- **true**, if the device is advertising a local name,\n- **false** otherwise.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    // print the local name, if present\n    if (peripheral.hasLocalName()) {\n      Serial.print(\"Local Name: \");\n      Serial.println(peripheral.localName());\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.hasAdvertisedServiceUuid()`\n\nQuery if a discovered Bluetooth® Low Energy device is advertising a service UUID.\n\n#### Syntax\n\n```\nbleDevice.hasAdvertisedServiceUuid()\nbleDevice.hasAdvertisedServiceUuid(index)\n\n```\n\n#### Parameters\n\n- **index**: optional, defaults to 0, the index of the service UUID, if the device is advertising more than one.\n\n#### Returns\n- **true**, if the device is advertising a service UUID,\n- **false** otherwise.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    // print the advertised service UUIDs, if present\n    if (peripheral.hasAdvertisedServiceUuid()) {\n      Serial.print(\"Service UUIDs: \");\n      for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) {\n        Serial.print(peripheral.advertisedServiceUuid(i));\n        Serial.print(\" \");\n      }\n      Serial.println();\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.advertisedServiceUuidCount()`\n\nQuery the number of advertised services a discovered Bluetooth® Low Energy device is advertising.\n\n#### Syntax\n\n```\nbleDevice.advertisedServiceUuidCount()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **number of advertised services** a discovered Bluetooth® Low Energy device is advertising.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    // print the advertised service UUIDs, if present\n    if (peripheral.hasAdvertisedServiceUuid()) {\n      Serial.print(\"Service UUIDs: \");\n      for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) {\n        Serial.print(peripheral.advertisedServiceUuid(i));\n        Serial.print(\" \");\n      }\n      Serial.println();\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.localName()`\n\nQuery the local name a discovered Bluetooth® Low Energy device is advertising with.\n\n#### Syntax\n\n```\nbleDevice.localName()\n\n```\n\n#### Parameters\n\nNothing\n\n#### Returns\n- **Advertised local name** (as a String).\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    // print the local name, if present\n    if (peripheral.hasLocalName()) {\n      Serial.print(\"Local Name: \");\n      Serial.println(peripheral.localName());\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.advertisedServiceUuid()`\n\nQuery an advertised service UUID discovered Bluetooth® Low Energy device is advertising.\n\n#### Syntax\n\n```\nbleDevice.advertisedServiceUuid()\nbleDevice.advertisedServiceUuid(index)\n\n```\n\n#### Parameters\n\n- **index**: optional, defaults to 0, the index of the **service UUID**, if the device is advertising more than one.\n\n#### Returns\n- Advertised service **UUID** (as a String).\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    // print the advertised service UUIDs, if present\n    if (peripheral.hasAdvertisedServiceUuid()) {\n      Serial.print(\"Service UUIDs: \");\n      for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) {\n        Serial.print(peripheral.advertisedServiceUuid(i));\n        Serial.print(\" \");\n      }\n      Serial.println();\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleDevice.connect()`\n\nConnect to a Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleDevice.connect()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if the connection was successful,\n- **false** otherwise.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // ...\n  }\n\n\n```\n\n## BLEService Class\n\nUsed to enable the services board provides or interact with services a remote board provides.\n\n### `BLEService()`\n\nCreate a new Bluetooth® Low Energy service.\n\n#### Syntax\n\n```\nBLEService(uuid)\n\n```\n\n#### Parameters\n\n- **uuid**: 16-bit or 128-bit UUID in **String** format\n\n#### Returns\n- New **BLEService** with the specified **UUID**\n\n#### Example\n\n```arduino\n\nBLEService ledService(\"19B10000-E8F2-537E-4F6C-D104768A1214\"); // Bluetooth® Low Energy LED Service\n\n\n```\n\n### `bleService.uuid()`\n\nQuery the UUID of the specified BLEService.\n\n#### Syntax\n\n```\nbleService.uuid()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- UUID of the Bluetooth® Low Energy service as a **String**.\n\n#### Example\n\n```arduino\n\nBLEService ledService(\"19B10000-E8F2-537E-4F6C-D104768A1214\"); // Bluetooth® Low Energy LED Service\n\n\nSerial.print(\"LED service UUID = \");\nSerial.println(ledService.uuid());\n\n\n\n```\n\n### `bleService.addCharacteristic()`\n\nAdd a BLECharacteristic to the Bluetooth® Low Energy service.\n\n#### Syntax\n\n```\nbleService.addCharacteristic(bleCharacteristic)\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\nBLEService ledService(\"19B10000-E8F2-537E-4F6C-D104768A1214\"); // Bluetooth® Low Energy LED Service\n\n// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, readable and writable by central\nBLECharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite, 1);\n\n\n\n\n// add the characteristic to the service\nledService.addCharacteristic(switchCharacteristic);\n\n\n\n```\n\n### `bleService.characteristicCount()`\n\nQuery the number of characteristics discovered for the Bluetooth® Low Energy service.\n\n#### Syntax\n\n```\nbleService.characteristicCount()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **number of characteristics** discovered for the Bluetooth® Low Energy service.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    BLEService batteryService = peripheral.service(\"180f\");\n\n    if (batteryService) {\n      // use the service\n      int characteristicCount = batteryService.characteristicCount();\n\n      Serial.print(characteristicCount);\n      Serial.println(\" characteristics discovered in battery service\");\n    } else {\n      Serial.println(\"Peripheral does NOT have battery service\");\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleService.hasCharacteristic()`\n\nQuery if the Bluetooth® Low Energy service has a particular characteristic.\n\n#### Syntax\n\n```\nbleService.hasCharacteristic(uuid)\nbleService.hasCharacteristic(uuid, index)\n\n```\n\n#### Parameters\n\n- **uuid**: uuid to check (as a **String**)\n- **index**: optional, index of characteristic to check if the device provides more than on. Defaults to 0, if not provided.\n\n#### Returns\n- **true**, if the service provides the characteristic,\n- **false** otherwise.\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    BLEService batteryService = peripheral.service(\"180f\");\n\n    if (batteryService) {\n      // use the service\n      if (batteryService.hasCharacteristic(\"2a19\")) {\n        Serial.println(\"Battery service has battery level characteristic\");\n      }\n    } else {\n      Serial.println(\"Peripheral does NOT have battery service\");\n    }\n\n    // ...\n  }\n\n\n```\n\n### `bleService.characteristic()`\n\nGet a BLECharacteristic representing a Bluetooth® Low Energy characteristic the service provides.\n\n#### Syntax\n\n```\nbleService.characteristic(index)\nbleService.characteristic(uuid)\nbleService.characteristic(uuid, index)\n\n```\n\n#### Parameters\n\n- **index**: index of characteristic\n- **uuid**: uuid (as a **String**)\n\n#### Returns\n- **BLECharacteristic** for provided parameters\n\n#### Example\n\n```arduino\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"BLE Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n\n\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // ...\n\n    Serial.println(\"Connecting ...\");\n\n    if (peripheral.connect()) {\n      Serial.println(\"Connected\");\n    } else {\n      Serial.println(\"Failed to connect!\");\n      return;\n    }\n\n    // discover peripheral attributes\n    Serial.println(\"Discovering attributes ...\");\n    if (peripheral.discoverAttributes()) {\n      Serial.println(\"Attributes discovered\");\n    } else {\n      Serial.println(\"Attribute discovery failed!\");\n      peripheral.disconnect();\n      return;\n    }\n\n    BLEService batteryService = peripheral.service(\"180f\");\n\n    if (batteryService) {\n      // use the service\n      BLECharacteristic batteryLevelCharacteristic = peripheral.characteristic(\"2a19\");\n\n      if (batteryLevelCharacteristic) {\n        // use the characteristic\n      } else {\n        Serial.println(\"Peripheral does NOT have battery level characteristic\");\n      }\n    } else {\n      Serial.println(\"Peripheral does NOT have battery service\");\n    }\n\n    // ...\n  }\n\n\n```\n\n## BLECharacteristic Class\n\nUsed to enable the characteristics board offers in a service or interact with characteristics a remote board provides.\n\n### `BLECharacteristic()`\n\nCreate a new Bluetooth® Low Energy characteristic.\n\n#### Syntax\n\n```\nBLECharacteristic(uuid, properties, valueSize)\nBLECharacteristic(uuid, properties, valueSize, fixedLength)\nBLECharacteristic(uuid, properties, stringValue)\n\nBLEBoolCharacteristic(uuid, properties)\nBLEBooleanCharacteristic(uuid, properties)\nBLECharCharacteristic(uuid, properties)\nBLEUnsignedCharCharacteristic(uuid, properties)\nBLEByteCharacteristic(uuid, properties)\nBLEShortCharacteristic(uuid, properties)\nBLEUnsignedShortCharacteristic(uuid, properties)\nBLEWordCharacteristic(uuid, properties)\nBLEIntCharacteristic(uuid, properties)\nBLEUnsignedIntCharacteristic(uuid, properties)\nBLELongCharacteristic(uuid, properties)\nBLEUnsignedLongCharacteristic(uuid, properties)\nBLEFloatCharacteristic(uuid, properties)\nBLEDoubleCharacteristic(uuid, properties)\n```\n\n#### Parameters\n\n- **uuid**: 16-bit or 128-bit UUID in **String** format\n- **properties**: mask of the properties (BLEBroadcast, BLERead, BLEWriteWithoutResponse, BLEWrite, BLENotify, BLEIndicate)\n- **valueSize**: (maximum) size of characteristic value\n- **fixedLength**: if true, size of characteristic value is fixed\n- **stringValue**: value as a string\n\n#### Returns\n- New **BLECharacteristic** with the specified **UUID** and value\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy Battery Level Characteristic\nBLEUnsignedCharCharacteristic batteryLevelChar(\"2A19\",  // standard 16-bit characteristic UUID\n    BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes\n\n\n\n```\n\n### `bleCharacteristic.uuid()`\n\nQuery the UUID of the specified BLECharacteristic.\n\n#### Syntax\n\n```\nbleCharacteristic.uuid()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **UUID** of the Bluetooth® Low Energy service as a **String**.\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\n\nSerial.print(\"Switch characteristic UUID = \");\nSerial.println(switchCharacteristic.uuid());\n\n\n\n```\n\n### `bleCharacteristic.properties()`\n\nQuery the property mask of the specified BLECharacteristic.\n\n#### Syntax\n\n```\nbleCharacteristic.properties()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **Properties of the characteristic masked** (BLEBroadcast, BLERead, BLEWriteWithoutResponse, BLEWrite, BLENotify, BLEIndicate)\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\n\nbyte properties = switchCharacteristic.properties();\n\nif (properties & BLERead) {\n  // characteristic is readable ...\n}\n\nif (properties & (BLEWrite | BLEWriteWithoutResponse)) {\n  // characteristic is writable ...\n}\n\n\n```\n\n### `bleCharacteristic.valueSize()`\n\nQuery the maximum value size of the specified BLECharacteristic.\n\n#### Syntax\n\n```\nbleCharacteristic.valueSize()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **maximum value** size of the characteristic (in bytes)\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\n\n\nSerial.print(\"value size = \");\nSerial.println(switchCharacteristic.valueSize());\n\n\n```\n\n### `bleCharacteristic.value()`\n\nQuery the current value of the specified BLECharacteristic.\n\n#### Syntax\n\n```\nbleCharacteristic.value()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **current value** of the characteristic, value type depends on the constructor used\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\n\n\n  if (switchCharacteristic.value()) {  // any value other than 0\n    Serial.println(\"LED on\");\n    digitalWrite(ledPin, HIGH);  // will turn the LED on\n  } else {                       // a 0 value\n    Serial.println(F(\"LED off\"));\n    digitalWrite(ledPin, LOW);  // will turn the LED off\n  }\n\n\n\n```\n\n### `bleCharacteristic.valueLength()`\n\nQuery the current value size of the specified BLECharacteristic.\n\n#### Syntax\n\n```\nbleCharacteristic.valueLength()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **current value** size of the characteristic (in bytes)\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\n\n\nSerial.print(\"value length = \");\nSerial.println(switchCharacteristic.valueLength());\n\n\n```\n\n### `bleCharacteristic.readValue()`\n\nRead the current value of the characteristic. If the characteristic is on a remote device, a read request will be sent.\n\n#### Syntax\n\n```\nbleCharacteristic.readValue(buffer, length)\nbleCharacteristic.readValue(value)\n\n```\n\n#### Parameters\n\n- **buffer:** byte array to read value into length: size of buffer argument in bytes\n- **value**: variable to read value into (by reference)\n\n#### Returns\n- **Number of bytes** read\n\n#### Example\n\n```arduino\n\n  while (peripheral.connected()) {\n    // while the peripheral is connected\n\n    // check if the value of the simple key characteristic has been updated\n    if (simpleKeyCharacteristic.valueUpdated()) {\n      // yes, get the value, characteristic is 1 byte so use byte value\n      byte value = 0;\n\n      simpleKeyCharacteristic.readValue(value);\n\n      if (value & 0x01) {\n        // first bit corresponds to the right button\n        Serial.println(\"Right button pressed\");\n      }\n\n      if (value & 0x02) {\n        // second bit corresponds to the left button\n        Serial.println(\"Left button pressed\");\n      }\n    }\n  }\n\n\n```\n\n### `bleCharacteristic.writeValue()`\n\nWrite the value of the characteristic. If the characteristic is on a remote device, a write request or command will be sent.\n\n#### Syntax\n\n```\nbleCharacteristic.writeValue(buffer, length)\nbleCharacteristic.writeValue(value)\n\n```\n\n#### Parameters\n\n- **buffer**: byte array to write value with\n- **length**: number of bytes of the buffer argument to write\n- **value**: value to write\n\n#### Returns\n- 1 on success,\n- 0 on failure\n\n#### Example\n\n```arduino\n\n    // read the button pin\n    int buttonState = digitalRead(buttonPin);\n\n    if (oldButtonState != buttonState) {\n      // button changed\n      oldButtonState = buttonState;\n\n      if (buttonState) {\n        Serial.println(\"button pressed\");\n\n        // button is pressed, write 0x01 to turn the LED on\n        ledCharacteristic.writeValue((byte)0x01);\n      } else {\n        Serial.println(\"button released\");\n\n        // button is released, write 0x00 to turn the LED off\n        ledCharacteristic.writeValue((byte)0x00);\n      }\n    }\n\n\n```\n\n### `bleCharacteristic.setEventHandler()`\n\nSet the event handler (callback) function that will be called when the specified event occurs.\n\n#### Syntax\n\n```\nbleCharacteristic.setEventHandler(eventType, callback)\n\n```\n\n#### Parameters\n\n- **eventType**: event type (BLESubscribed, BLEUnsubscribed, BLERead, BLEWritten)\n- **callback**: function to call when the event occurs\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n// create switch characteristic and allow remote device to read and write\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\n\n\n\n  // assign event handlers for characteristic\n  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);\n\n\n\nvoid switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {\n  // central wrote new value to characteristic, update LED\n  Serial.print(\"Characteristic event, written: \");\n\n  if (switchCharacteristic.value()) {\n    Serial.println(\"LED on\");\n    digitalWrite(ledPin, HIGH);\n  } else {\n    Serial.println(\"LED off\");\n    digitalWrite(ledPin, LOW);\n  }\n}\n\n\n```\n\n### `bleCharacteristic.broadcast()`\n\nBroadcast the characteristics value as service data when advertising.\n\n#### Syntax\n\n```\nbleCharacteristic.broadcast()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- 1 on success,\n- 0 on failure\n\n#### Example\n\n```arduino\n\n// create button characteristic and allow remote device to get notifications\nBLEByteCharacteristic buttonCharacteristic(\"19B10012-E8F2-537E-4F6C-D104768A1214\", BLERead | BLENotify | BLEBroadcast);\n\n\n\nbuttonCharacteristic.broadcast();\n\n\n\n```\n\n### `bleCharacteristic.written()`\n\nQuery if the characteristic value has been written by another Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleCharacteristic.written()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true** if the characteristic value has been written by another Bluetooth® Low Energy device,\n- **false** otherwise\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\n\n\n\n // listen for Bluetooth® Low Energy peripherals to connect:\n  BLEDevice central = BLE.central();\n\n  // if a central is connected to peripheral:\n  if (central) {\n    Serial.print(\"Connected to central: \");\n    // print the central's MAC address:\n    Serial.println(central.address());\n\n    // while the central is still connected to peripheral:\n    while (central.connected()) {\n      // if the remote device wrote to the characteristic,\n      // use the value to control the LED:\n      if (switchCharacteristic.written()) {\n        if (switchCharacteristic.value()) {   // any value other than 0\n          Serial.println(\"LED on\");\n          digitalWrite(ledPin, HIGH);         // will turn the LED on\n        } else {                              // a 0 value\n          Serial.println(F(\"LED off\"));\n          digitalWrite(ledPin, LOW);          // will turn the LED off\n        }\n      }\n    }\n\n    // when the central disconnects, print it out:\n    Serial.print(F(\"Disconnected from central: \"));\n    Serial.println(central.address());\n  }\n\n\n\n\n```\n\n### `bleCharacteristic.subscribed()`\n\nQuery if the characteristic has been subscribed to by another Bluetooth® Low Energy device.\n\n#### Syntax\n\n```\nbleCharacteristic.subscribed()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true** if the characteristic value has been subscribed to by another Bluetooth® Low Energy device,\n- **false** otherwise\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy Battery Level Characteristic\nBLEUnsignedCharCharacteristic batteryLevelChar(\"2A19\",  // standard 16-bit characteristic UUID\n    BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes\n\n\n\n\n\n  if (batteryLevelChar.subscribed()) {\n     // set a new value , that well be pushed to subscribed Bluetooth® Low Energy devices\n    batteryLevelChar.writeValue(0xab);\n  }\n\n\n```\n\n### `bleCharacteristic.addDescriptor()`\n\nAdd a BLEDescriptor to the characteristic.\n\n#### Syntax\n\n```\nbleCharacteristic.addDescriptor(bleDescriptor)\n\n```\n\n#### Parameters\n\n- **bleDescriptor**: descriptor to add to the characteristic\n\n#### Returns\nNothing\n\n#### Example\n\n```arduino\n\n// Bluetooth® Low Energy Battery Level Characteristic\nBLEUnsignedCharCharacteristic batteryLevelChar(\"2A19\",  // standard 16-bit characteristic UUID\n    BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes\n\nBLEDescriptor batteryLevelDescriptor(\"2901\", \"millis\");\n\n\n\n\n\n  batteryLevelChar.addDescriptor(batteryLevelDescriptor);\n\n\n```\n\n### `bleCharacteristic.descriptorCount()`\n\nQuery the number of Bluetooth® Low Energy descriptors discovered for the characteristic.\n\n#### Syntax\n\n```\nbleCharacteristic.descriptorCount()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- The **number of Bluetooth® Low Energy descriptors** discovered for the characteristic\n\n#### Example\n\n```arduino\n\n // loop the descriptors of the characteristic and explore each\n  for (int i = 0; i < characteristic.descriptorCount(); i++) {\n    BLEDescriptor descriptor = characteristic.descriptor(i);\n\n    // ...\n  }\n\n\n```\n\n### `bleCharacteristic.hasDescriptor()`\n\nCheck if a characteristic has a particular descriptor.\n\n#### Syntax\n\n```\nbleCharacteristic.hasDescriptor(uuid)\nbleCharacteristic.hasDescriptor(uuid, index)\n\n```\n\n#### Parameters\n\n- **index**: index of descriptor\n- **uuid**: uuid (as a **String**)\n\n#### Returns\n- **true**, if the characteristic has a matching descriptor,\n- otherwise **false**.\n\n#### Example\n\n```arduino\n\n  if (characteristic.hasDescriptor(\"2901\")) {\n    Serial.println(\"characteristic has description descriptor\");\n  }\n\n\n```\n\n### `bleCharacteristic.descriptor()`\n\nGet a BLEDescriptor that represents a characteristics Bluetooth® Low Energy descriptor.\n\n#### Syntax\n\n```\nbleCharacteristic.descriptor(index)\nbleCharacteristic.descriptor(uuid)\nbleCharacteristic.descriptor(uuid, index)\n\n```\n\n#### Parameters\n\n- **index**: index of descriptor\n- **uuid**: uuid (as a **String**)\n\n#### Returns\n- BLEDescriptor that represents a characteristics Bluetooth® Low Energy descriptor\n\n#### Example\n\n```arduino\n\n  if (characteristic.hasDescriptor(\"2901\")) {\n    Serial.println(\"characteristic has description descriptor\");\n  }\n\n\n```\n\n### `bleCharacteristic.canRead()`\n\nQuery if a Bluetooth® Low Energy characteristic is readable.\n\n#### Syntax\n\n```\nbleCharacteristic.canRead()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if characteristic is readable,\n- **false** otherwise\n\n#### Example\n\n```arduino\n\n  if (characteristic.canRead(\"2901\")) {\n    Serial.println(\"characteristic is readable\");\n  }\n\n\n```\n\nread\n\nPerform a read request for the characteristic.\n\n#### Syntax\n\n```\nbleCharacteristic.read()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if successful,\n- **false** on failure\n\n#### Example\n\n```arduino\n\n  if (characteristic.read()) {\n    Serial.println(\"characteristic value read\");\n\n    // ...\n  } else {\n    Serial.println(\"error reading characteristic value\");\n  }\n\n\n```\n\n### `bleCharacteristic.canWrite()`\n\nQuery if a Bluetooth® Low Energy characteristic is writable.\n\n#### Syntax\n\n```\nbleCharacteristic.canWrite()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if characteristic is writable,\n- **false** otherwise\n\n#### Example\n\n```arduino\n\n  if (characteristic.canWrite()) {\n    Serial.println(\"characteristic is writable\");\n  }\n\n\n```\n\n### `bleCharacteristic.canSubscribe()`\n\nQuery if a Bluetooth® Low Energy characteristic is subscribable.\n\n#### Syntax\n\n```\nbleCharacteristic.canSubscribe()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if characteristic is subscribable,\n- **false** otherwise\n\n#### Example\n\n```arduino\n\n  if (characteristic.canSubscribe()) {\n    Serial.println(\"characteristic is subscribable\");\n  }\n\n\n```\n\n### `bleCharacteristic.subscribe()`\n\nSubscribe to a Bluetooth® Low Energy characteristics notification or indications.\n\n#### Syntax\n\n```\nbleCharacteristic.subscribe()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, on success,\n- **false** on failure\n\n#### Example\n\n```arduino\n\n  // ...\n\n  // retrieve the simple key characteristic\n  BLECharacteristic simpleKeyCharacteristic = peripheral.characteristic(\"ffe1\");\n\n  // subscribe to the simple key characteristic\n  Serial.println(\"Subscribing to simple key characteristic ...\");\n  if (!simpleKeyCharacteristic) {\n    Serial.println(\"no simple key characteristic found!\");\n    peripheral.disconnect();\n    return;\n  } else if (!simpleKeyCharacteristic.canSubscribe()) {\n    Serial.println(\"simple key characteristic is not subscribable!\");\n    peripheral.disconnect();\n    return;\n  } else if (!simpleKeyCharacteristic.subscribe()) {\n    Serial.println(\"subscription failed!\");\n    peripheral.disconnect();\n    return;\n  }\n\n  // ...\n\n\n```\n\n### `bleCharacteristic.canUnsubscribe()`\n\nQuery if a Bluetooth® Low Energy characteristic is unsubscribable.\n\n#### Syntax\n\n```\nbleCharacteristic.canUnsubscribe()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if characteristic is unsubscribable,\n- **false** otherwise\n\n#### Example\n\n```arduino\n\n  if (characteristic.canUnsubscribe()) {\n    Serial.println(\"characteristic is unsubscribable\");\n  }\n\n\n```\n\n### `bleCharacteristic.unsubscribe()`\n\nUnsubscribe to a Bluetooth® Low Energy characteristics notifications or indications.\n\n#### Syntax\n\n```\nbleCharacteristic.unsubscribe()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, on success,\n- **false** on failure\n\n#### Example\n\n```arduino\n\n  // ...\n\n  // retrieve the simple key characteristic\n  BLECharacteristic simpleKeyCharacteristic = peripheral.characteristic(\"ffe1\");\n\n  // subscribe to the simple key characteristic\n  Serial.println(\"Subscribing to simple key characteristic ...\");\n  if (!simpleKeyCharacteristic) {\n    Serial.println(\"no simple key characteristic found!\");\n    peripheral.disconnect();\n    return;\n  } else if (!simpleKeyCharacteristic.canSubscribe()) {\n    Serial.println(\"simple key characteristic is not subscribable!\");\n    peripheral.disconnect();\n    return;\n  } else if (!simpleKeyCharacteristic.subscribe()) {\n    Serial.println(\"subscription failed!\");\n    peripheral.disconnect();\n    return;\n  }\n\n  // ...\n\n  simpleKeyCharacteristic.unsubscribe();\n\n\n```\n\n### `bleCharacteristic.valueUpdated()`\n\nHas the characteristics value been updated via a notification or indication.\n\n#### Syntax\n\n```\nbleCharacteristic.valueUpdated()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if the characteristics value been updated via a notification or indication\n\n#### Example\n\n```arduino\n\n  while (peripheral.connected()) {\n    // while the peripheral is connected\n\n    // check if the value of the simple key characteristic has been updated\n    if (simpleKeyCharacteristic.valueUpdated()) {\n      // yes, get the value, characteristic is 1 byte so use byte value\n      byte value = 0;\n\n      simpleKeyCharacteristic.readValue(value);\n\n      if (value & 0x01) {\n        // first bit corresponds to the right button\n        Serial.println(\"Right button pressed\");\n      }\n\n      if (value & 0x02) {\n        // second bit corresponds to the left button\n        Serial.println(\"Left button pressed\");\n      }\n    }\n  }\n\n\n```\n\n## BLEDescriptor Class\n\nUsed to describe a characteristic the board offers\n\n### `BLEDescriptor()`\n\nCreate a new Bluetooth® Low Energy descriptor.\n\n#### Syntax\n\n```\nBLEDescriptor(uuid, value, valueSize)\nBLEDescriptor(uuid, stringValue)\n\n```\n\n#### Parameters\n\n- **uuid**: 16-bit or 128-bit UUID in string format\n- **value**: byte array value\n- **valueSize**: size of byte array value\n- **stringValue**: value as a string\n\n#### Returns\n- New **BLEDescriptor** with the specified **UUID** and value\n\n#### Example\n\n```arduino\n\nBLEDescriptor millisLabelDescriptor(\"2901\", \"millis\");\n\n\n```\n\n### `bleDescriptor.uuid()`\n\nQuery the UUID of the specified BLEDescriptor.\n\n#### Syntax\n\n```\nbleDescriptor.uuid()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **UUID** of the Bluetooth® Low Energy descriptor (as a String).\n\n#### Example\n\n```arduino\n\nBLEDescriptor millisLabelDescriptor(\"2901\", \"millis\");\n\n\nSerial.print(\"millis label descriptor UUID = \");\nSerial.println(millisLabelDescriptor.uuid());\n\n\n\n```\n\n### `bleDescriptor.valueSize()`\n\nQuery the value size of the specified BLEDescriptor.\n\n#### Syntax\n\n```\nbleDescriptor.valueSize()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **Value size** (in bytes) of the Bluetooth® Low Energy descriptor.\n\n#### Example\n\n```arduino\n\nBLEDescriptor millisLabelDescriptor(\"2901\", \"millis\");\n\n\nSerial.print(\"millis label descriptor value size = \");\nSerial.println(millisLabelDescriptor.valueSize());\n\n\n\n```\n\n### `bleDescriptor.valueLength()`\n\nQuery the length, in bytes, of the descriptor current value.\n\n#### Syntax\n\n```\nbleDescriptor.valueLength()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **Length of descriptor** value in bytes.\n\n#### Example\n\n```arduino\n\n  // read the descriptor value\n  descriptor.read();\n\n  // print out the value of the descriptor\n  Serial.print(\", value 0x\");\n  printData(descriptor.value(), descriptor.valueLength());\n\n  // ...\n\n  void printData(const unsigned char data[], int length) {\n    for (int i = 0; i < length; i++) {\n      unsigned char b = data[i];\n\n      if (b < 16) {\n        Serial.print(\"0\");\n      }\n\n      Serial.print(b, HEX);\n    }\n  }\n\n\n```\n\n### `bleDescriptor.value()`\n\nQuery the value of the specified BLEDescriptor.\n\n#### Syntax\n\n```\nbleDescriptor.value()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- Value byte array of the **BLE descriptor**.\n\n#### Example\n\n```arduino\n\nBLEDescriptor millisLabelDescriptor(\"2901\", \"millis\");\n\n\n\n  int descriptorValueSize = millisLabelDescriptor.valueSize();\n  byte descriptorValue[descriptorValueSize];\n\n  for (int i = 0; i < descriptorValueSize; i++) {\n    descriptorValue[i] = millisLabelDescriptor.value()[i];\n  }\n\n\n\n```\n\n### `bleDescriptor.readValue()`\n\nRead the current value of the descriptor. If the descriptor is on a remote device, a read request will be sent.\n\n#### Syntax\n\n```\nbleDescriptor.readValue(buffer, length)\nbleDescriptor.readValue(value)\n\n```\n\n#### Parameters\n\n- **buffer**: byte array to read value into\n- **length**: size of buffer argument in bytes\n- **value**: variable to read value into (by reference)\n\n#### Returns\n- **Number of bytes** read\n\n#### Example\n\n\n```arduino\n\n  byte value = 0;\n\n  // get the value, descriptor is 1 byte so use byte value\n  descriptor.readValue(value);\n\n\n```\n\n### `bleDescriptor.read()`\n\nPerform a read request for the descriptor.\n\n#### Syntax\n\n```\nbleDescriptor.read()\n\n```\n\n#### Parameters\n\nNone\n\n#### Returns\n- **true**, if successful,\n- **false** on failure\n\n#### Example\n\n```arduino\n\n  if (descriptor.read()) {\n    Serial.println(\"descriptor value read\");\n\n    // ...\n  } else {\n    Serial.println(\"error reading descriptor value\");\n  }\n\n```\n"
  },
  {
    "path": "docs/readme.md",
    "content": "# ArduinoBLE library\n\nThis library supports all the Arduino boards that have the hardware enabled for Bluetooth® Low Energy and Bluetooth® 4.0 and above; these include Nano 33 BLE, Arduino NANO 33 IoT, Uno WiFi Rev2, MKR WiFi 1010, Nicla Sense ME.\n\nTo use this library\n``#include <ArduinoBLE.h>``\n\n## A quick introduction to BLE\n\nBluetooth® 4.0 includes both traditional Bluetooth®, now labeled \"Bluetooth® Classic\", and the Bluetooth® Low Energy. Bluetooth® Low Energy is optimized for low power use at low data rates, and was designed to operate from simple lithium coin cell batteries.\n\nUnlike standard Bluetooth® communication basically based on an asynchronous serial connection (UART) a Bluetooth® LE radio acts like a community bulletin board. The computers that connect to it are like community members that read the bulletin board. Each radio acts as either the bulletin board or the reader. If your radio is a bulletin board (called a peripheral device in Bluetooth® LE parlance) it posts data for all radios in the community to read. If your radio is a reader (called a central device in Bluetooth LE terms) it reads from any of the bulletin boards (peripheral devices) that have information about which it cares. You can also think of peripheral devices as the servers in a client-server transaction, because they contain the information that reader radios ask for. Similarly, central devices are the clients of the Bluetooth® LE world because they read information available from the peripherals.\n\n![Communication between central and peripheral devices](https://raw.githubusercontent.com/arduino-libraries/ArduinoBLE/master/docs/assets/ble-bulletin-board-model.png)\n\nThink of a Bluetooth® LE peripheral device as a bulletin board and central devices as viewers of the board. Central devices view the services, get the data, then move on. Each transaction is quick (a few milliseconds), so multiple central devices can get data from one peripheral.\n\nThe information presented by a peripheral is structured as **services**, each of which is subdivided into **characteristics**. You can think of services as the notices on a bulletin board, and characteristics as the individual paragraphs of those notices. If you're a peripheral device, you just update each service characteristic when it needs updating and don't worry about whether the central devices read them or not. If you're a central device, you connect to the peripheral then read the boxes you want. If a given characteristic is readable and writable, then the peripheral and central can both change it.\n\n## Notify\n\nThe Bluetooth® LE specification includes a mechanism known as **notify** that lets you know when data's changed. When notify on a characteristic is enabled and the sender writes to it, the new value is automatically sent to the receiver, without the receiver explicitly issuing a read command. This is commonly used for streaming data such as accelerometer or other sensor readings. There's a variation on this specification called **indicate** which works similarly, but in the indicate specification, the reader sends an acknowledgment of the pushed data.\n\nThe client-server structure of Bluetooth® LE, combined with the notify characteristic, is generally called a **publish-and-subscribe model**.\n\n## Update a characteristic\n\nYour peripheral should update characteristics when there's a significant change to them. For example, when a switch changes from off to on, update its characteristic. When an analog sensor changes by a significant amount, update its characteristic.\n\nJust as with writing to a characteristic, you could update your characteristics on a regular interval, but this wastes processing power and energy if the characteristic has not changed.\n\n## Central and Peripheral Devices\n\n**Central** devices are **clients**. They read and write data from peripheral devices. **Peripheral** devices are **servers**. They provide data from sensors as readable characteristics, and provide read/writable characteristics to control actuators like motors, lights, and so forth.\n\n## Services, characteristics, and UUIDs\n\nA Bluetooth® Low Energy peripheral will provide **services**, which in turn provide **characteristics**. You can define your own services, or use standard services (see section 3.4 in the [Assigned Numbers document](https://www.bluetooth.com/specifications/assigned-numbers/)).\n\nServices are identified by unique numbers known as UUIDs. You know about UUIDs from other contexts. Standard services have a 16-bit UUID and custom services have a 128-bit UUID. The ability to define services and characteristics depends on the radio you're using and its firmware.\n\n## Service design patterns\n\nA characteristic value can be up to 512 bytes long. This is a key constraint in designing services. Given this limit, you should consider how best to store data about your sensors and actuators most effectively for your application. The simplest design pattern is to store one sensor or actuator value per characteristic, in ASCII encoded values.\n\n|**Characteristic**|**Value**|\n|------------------|---------|\n|Accelerometer X|200|\n|Accelerometer Y|134|\n|Accelerometer Z|150|\n\nThis is also the most expensive in memory terms, and would take the longest to read. But it's the simplest for development and debugging.\n\nYou could also combine readings into a single characteristic, when a given sensor or actuator has multiple values associated with it.\n\n|**Characteristic**|**Value**|\n|------------------|---------|\n|Motor Speed, Direction|150,1|\n|Accelerometer X, Y, Z|200,133,150|\n\nThis is more efficient, but you need to be careful not to exceed the 512-byte limit. The accelerometer characteristic above, for example, takes 11 bytes as an ASCII-encoded string.\n\n## Read/write/notify/indicate\n\nThere are 4 things a central device can do with a characteristic:\n\n- **Read:** ask the peripheral to send back the current value of the characteristic. Often used for characteristics that don't change very often, for example characteristics used for configuration, version numbers, etc.\n- **Write:** modify the value of the characteristic. Often used for things that are like commands, for example telling the peripheral to turn a motor on or off.\n- **Indicate** and **Notify:** ask the peripheral to continuously send updated values of the characteristic, without the central having to constantly ask for it.\n\n## Advertising and GAP\n\nBLE devices let other devices know that they exist by advertising using the **General Advertising Profile (GAP)**. Advertising packets can contain a device name, some other information, and also a list of the services it provides.\n\nAdvertising packets have a limited size. You will only be able to fit a single 128-bit service UUID in the packet. Make sure the device name is not too long, or you won't even be able to fit that.\n\nYou can provide additional services that are not advertised. Central devices will learn about these through the connection/bonding process. Non-advertised services cannot be used to discover devices, though. Sometimes this is not an issue. For example, you may have a custom peripheral device with a custom service, but in your central device app you may know that it also provides the Battery Service and other services.\n\n## GATT\n\nThe Bluetooth LE protocol operates on multiple layers. **General Attribute Profile (GATT)** is the layer that defines services and characteristics and enables read/write/notify/indicate operations on them. When reading more about GATT, you may encounter GATT concepts of a \"server\" and \"client\". These don't always correspond to central and peripherals. In most cases, though, the peripheral is the GATT server (since it provides the services and characteristics), while the central is the GATT client.\n\n## Library structure\n\nAs the library enables multiple types of functionality, there are a number of different classes.\n\n- `BLE` used to enable the Bluetooth® Low Energy module.\n- `BLEDevice` used to get information about the devices connected or discovered while scanning.\n- `BLEService` used to enable the services board provides or interact with services a remote board provides.\n- `BLECharacteristic` used to enable the characteristics board offers in a service or interact with characteristics a remote board provides.\n- `BLEDescriptor` used to describe a characteristic the board offers.\n"
  },
  {
    "path": "examples/Central/LedControl/LedControl.ino",
    "content": "/*\n  LED Control\n\n  This example scans for Bluetooth® Low Energy peripherals until one with the advertised service\n  \"19b10000-e8f2-537e-4f6c-d104768a1214\" UUID is found. Once discovered and connected,\n  it will remotely control the Bluetooth® Low Energy peripheral's LED, when the button is pressed or released.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n  - Button with pull-up resistor connected to pin 2.\n\n  You can use it with another board that is compatible with this library and the\n  Peripherals -> LED example.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\n// variables for button\nconst int buttonPin = 2;\nint oldButtonState = LOW;\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  // configure the button pin as input\n  pinMode(buttonPin, INPUT);\n\n  // initialize the Bluetooth® Low Energy hardware\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"Bluetooth® Low Energy Central - LED control\");\n\n  // start scanning for peripherals\n  BLE.scanForUuid(\"19b10000-e8f2-537e-4f6c-d104768a1214\");\n}\n\nvoid loop() {\n  // check if a peripheral has been discovered\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // discovered a peripheral, print out address, local name, and advertised service\n    Serial.print(\"Found \");\n    Serial.print(peripheral.address());\n    Serial.print(\" '\");\n    Serial.print(peripheral.localName());\n    Serial.print(\"' \");\n    Serial.print(peripheral.advertisedServiceUuid());\n    Serial.println();\n\n    if (peripheral.localName() != \"LED\") {\n      return;\n    }\n\n    // stop scanning\n    BLE.stopScan();\n\n    controlLed(peripheral);\n\n    // peripheral disconnected, start scanning again\n    BLE.scanForUuid(\"19b10000-e8f2-537e-4f6c-d104768a1214\");\n  }\n}\n\nvoid controlLed(BLEDevice peripheral) {\n  // connect to the peripheral\n  Serial.println(\"Connecting ...\");\n\n  if (peripheral.connect()) {\n    Serial.println(\"Connected\");\n  } else {\n    Serial.println(\"Failed to connect!\");\n    return;\n  }\n\n  // discover peripheral attributes\n  Serial.println(\"Discovering attributes ...\");\n  if (peripheral.discoverAttributes()) {\n    Serial.println(\"Attributes discovered\");\n  } else {\n    Serial.println(\"Attribute discovery failed!\");\n    peripheral.disconnect();\n    return;\n  }\n\n  // retrieve the LED characteristic\n  BLECharacteristic ledCharacteristic = peripheral.characteristic(\"19b10001-e8f2-537e-4f6c-d104768a1214\");\n\n  if (!ledCharacteristic) {\n    Serial.println(\"Peripheral does not have LED characteristic!\");\n    peripheral.disconnect();\n    return;\n  } else if (!ledCharacteristic.canWrite()) {\n    Serial.println(\"Peripheral does not have a writable LED characteristic!\");\n    peripheral.disconnect();\n    return;\n  }\n\n  while (peripheral.connected()) {\n    // while the peripheral is connected\n\n    // read the button pin\n    int buttonState = digitalRead(buttonPin);\n\n    if (oldButtonState != buttonState) {\n      // button changed\n      oldButtonState = buttonState;\n\n      if (buttonState) {\n        Serial.println(\"button pressed\");\n\n        // button is pressed, write 0x01 to turn the LED on\n        ledCharacteristic.writeValue((byte)0x01);\n      } else {\n        Serial.println(\"button released\");\n\n        // button is released, write 0x00 to turn the LED off\n        ledCharacteristic.writeValue((byte)0x00);\n      }\n    }\n  }\n\n  Serial.println(\"Peripheral disconnected\");\n}\n"
  },
  {
    "path": "examples/Central/PeripheralExplorer/PeripheralExplorer.ino",
    "content": "/*\n  Peripheral Explorer\n\n  This example scans for Bluetooth® Low Energy peripherals until one with a particular name (\"LED\")\n  is found. Then connects, and discovers + prints all the peripheral's attributes.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n\n  You can use it with another board that is compatible with this library and the\n  Peripherals -> LED example.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"Bluetooth® Low Energy Central - Peripheral Explorer\");\n\n  // start scanning for peripherals\n  BLE.scan();\n}\n\nvoid loop() {\n  // check if a peripheral has been discovered\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // discovered a peripheral, print out address, local name, and advertised service\n    Serial.print(\"Found \");\n    Serial.print(peripheral.address());\n    Serial.print(\" '\");\n    Serial.print(peripheral.localName());\n    Serial.print(\"' \");\n    Serial.print(peripheral.advertisedServiceUuid());\n    Serial.println();\n\n    // see if peripheral is a LED\n    if (peripheral.localName() == \"LED\") {\n      // stop scanning\n      BLE.stopScan();\n\n      explorerPeripheral(peripheral);\n\n      // peripheral disconnected, we are done\n      while (1) {\n        // do nothing\n      }\n    }\n  }\n}\n\nvoid explorerPeripheral(BLEDevice peripheral) {\n  // connect to the peripheral\n  Serial.println(\"Connecting ...\");\n\n  if (peripheral.connect()) {\n    Serial.println(\"Connected\");\n  } else {\n    Serial.println(\"Failed to connect!\");\n    return;\n  }\n\n  // discover peripheral attributes\n  Serial.println(\"Discovering attributes ...\");\n  if (peripheral.discoverAttributes()) {\n    Serial.println(\"Attributes discovered\");\n  } else {\n    Serial.println(\"Attribute discovery failed!\");\n    peripheral.disconnect();\n    return;\n  }\n\n  // read and print device name of peripheral\n  Serial.println();\n  Serial.print(\"Device name: \");\n  Serial.println(peripheral.deviceName());\n  Serial.print(\"Appearance: 0x\");\n  Serial.println(peripheral.appearance(), HEX);\n  Serial.println();\n\n  // loop the services of the peripheral and explore each\n  for (int i = 0; i < peripheral.serviceCount(); i++) {\n    BLEService service = peripheral.service(i);\n\n    exploreService(service);\n  }\n\n  Serial.println();\n\n  // we are done exploring, disconnect\n  Serial.println(\"Disconnecting ...\");\n  peripheral.disconnect();\n  Serial.println(\"Disconnected\");\n}\n\nvoid exploreService(BLEService service) {\n  // print the UUID of the service\n  Serial.print(\"Service \");\n  Serial.println(service.uuid());\n\n  // loop the characteristics of the service and explore each\n  for (int i = 0; i < service.characteristicCount(); i++) {\n    BLECharacteristic characteristic = service.characteristic(i);\n\n    exploreCharacteristic(characteristic);\n  }\n}\n\nvoid exploreCharacteristic(BLECharacteristic characteristic) {\n  // print the UUID and properties of the characteristic\n  Serial.print(\"\\tCharacteristic \");\n  Serial.print(characteristic.uuid());\n  Serial.print(\", properties 0x\");\n  Serial.print(characteristic.properties(), HEX);\n\n  // check if the characteristic is readable\n  if (characteristic.canRead()) {\n    // read the characteristic value\n    characteristic.read();\n\n    if (characteristic.valueLength() > 0) {\n      // print out the value of the characteristic\n      Serial.print(\", value 0x\");\n      printData(characteristic.value(), characteristic.valueLength());\n    }\n  }\n  Serial.println();\n\n  // loop the descriptors of the characteristic and explore each\n  for (int i = 0; i < characteristic.descriptorCount(); i++) {\n    BLEDescriptor descriptor = characteristic.descriptor(i);\n\n    exploreDescriptor(descriptor);\n  }\n}\n\nvoid exploreDescriptor(BLEDescriptor descriptor) {\n  // print the UUID of the descriptor\n  Serial.print(\"\\t\\tDescriptor \");\n  Serial.print(descriptor.uuid());\n\n  // read the descriptor value\n  descriptor.read();\n\n  // print out the value of the descriptor\n  Serial.print(\", value 0x\");\n  printData(descriptor.value(), descriptor.valueLength());\n\n  Serial.println();\n}\n\nvoid printData(const unsigned char data[], int length) {\n  for (int i = 0; i < length; i++) {\n    unsigned char b = data[i];\n\n    if (b < 16) {\n      Serial.print(\"0\");\n    }\n\n    Serial.print(b, HEX);\n  }\n}\n"
  },
  {
    "path": "examples/Central/Scan/Scan.ino",
    "content": "/*\n  Scan\n\n  This example scans for Bluetooth® Low Energy peripherals and prints out their advertising details:\n  address, local name, advertised service UUID's.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"Bluetooth® Low Energy Central scan\");\n\n  // start scanning for peripheral\n  BLE.scan();\n}\n\nvoid loop() {\n  // check if a peripheral has been discovered\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // discovered a peripheral\n    Serial.println(\"Discovered a peripheral\");\n    Serial.println(\"-----------------------\");\n\n    // print address\n    Serial.print(\"Address: \");\n    Serial.println(peripheral.address());\n\n    // print the local name, if present\n    if (peripheral.hasLocalName()) {\n      Serial.print(\"Local Name: \");\n      Serial.println(peripheral.localName());\n    }\n\n    // print the advertised service UUIDs, if present\n    if (peripheral.hasAdvertisedServiceUuid()) {\n      Serial.print(\"Service UUIDs: \");\n      for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) {\n        Serial.print(peripheral.advertisedServiceUuid(i));\n        Serial.print(\" \");\n      }\n      Serial.println();\n    }\n\n    // print the RSSI\n    Serial.print(\"RSSI: \");\n    Serial.println(peripheral.rssi());\n\n    Serial.println();\n  }\n}\n"
  },
  {
    "path": "examples/Central/ScanCallback/ScanCallback.ino",
    "content": "/*\n  Scan Callback\n\n  This example scans for Bluetooth® Low Energy peripherals and prints out their advertising details:\n  address, local name, advertised service UUIDs. Unlike the Scan example, it uses\n  the callback style APIs and disables filtering so the peripheral discovery is\n  reported for every single advertisement it makes.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"Bluetooth® Low Energy Central scan callback\");\n\n  // set the discovered event handle\n  BLE.setEventHandler(BLEDiscovered, bleCentralDiscoverHandler);\n\n  // start scanning for peripherals with duplicates\n  BLE.scan(true);\n}\n\nvoid loop() {\n  // poll the central for events\n  BLE.poll();\n}\n\nvoid bleCentralDiscoverHandler(BLEDevice peripheral) {\n  // discovered a peripheral\n  Serial.println(\"Discovered a peripheral\");\n  Serial.println(\"-----------------------\");\n\n  // print address\n  Serial.print(\"Address: \");\n  Serial.println(peripheral.address());\n\n  // print the local name, if present\n  if (peripheral.hasLocalName()) {\n    Serial.print(\"Local Name: \");\n    Serial.println(peripheral.localName());\n  }\n\n  // print the advertised service UUIDs, if present\n  if (peripheral.hasAdvertisedServiceUuid()) {\n    Serial.print(\"Service UUIDs: \");\n    for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) {\n      Serial.print(peripheral.advertisedServiceUuid(i));\n      Serial.print(\" \");\n    }\n    Serial.println();\n  }\n\n  // print the RSSI\n  Serial.print(\"RSSI: \");\n  Serial.println(peripheral.rssi());\n\n  Serial.println();\n}\n"
  },
  {
    "path": "examples/Central/SensorTagButton/SensorTagButton.ino",
    "content": "/*\n  SensorTag Button\n\n  This example scans for Bluetooth® Low Energy peripherals until a TI SensorTag is discovered.\n  It then connects to it, discovers the attributes of the 0xffe0 service,\n  subscribes to the Simple Key Characteristic (UUID 0xffe1). When a button is\n  pressed on the SensorTag a notification is received and the button state is\n  outputted to the Serial Monitor when one is pressed.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n  - TI SensorTag\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  Serial.println(\"Bluetooth® Low Energy Central - SensorTag button\");\n  Serial.println(\"Make sure to turn on the device.\");\n\n  // start scanning for peripheral\n  BLE.scan();\n}\n\nvoid loop() {\n  // check if a peripheral has been discovered\n  BLEDevice peripheral = BLE.available();\n\n  if (peripheral) {\n    // discovered a peripheral, print out address, local name, and advertised service\n    Serial.print(\"Found \");\n    Serial.print(peripheral.address());\n    Serial.print(\" '\");\n    Serial.print(peripheral.localName());\n    Serial.print(\"' \");\n    Serial.print(peripheral.advertisedServiceUuid());\n    Serial.println();\n\n    // Check if the peripheral is a SensorTag, the local name will be:\n    // \"CC2650 SensorTag\"\n    if (peripheral.localName() == \"CC2650 SensorTag\") {\n      // stop scanning\n      BLE.stopScan();\n\n      monitorSensorTagButtons(peripheral);\n\n      // peripheral disconnected, start scanning again\n      BLE.scan();\n    }\n  }\n}\n\nvoid monitorSensorTagButtons(BLEDevice peripheral) {\n  // connect to the peripheral\n  Serial.println(\"Connecting ...\");\n  if (peripheral.connect()) {\n    Serial.println(\"Connected\");\n  } else {\n    Serial.println(\"Failed to connect!\");\n    return;\n  }\n\n  // discover peripheral attributes\n  Serial.println(\"Discovering service 0xffe0 ...\");\n  if (peripheral.discoverService(\"ffe0\")) {\n    Serial.println(\"Service discovered\");\n  } else {\n    Serial.println(\"Attribute discovery failed.\");\n    peripheral.disconnect();\n\n    while (1);\n    return;\n  }\n\n  // retrieve the simple key characteristic\n  BLECharacteristic simpleKeyCharacteristic = peripheral.characteristic(\"ffe1\");\n\n  // subscribe to the simple key characteristic\n  Serial.println(\"Subscribing to simple key characteristic ...\");\n  if (!simpleKeyCharacteristic) {\n    Serial.println(\"no simple key characteristic found!\");\n    peripheral.disconnect();\n    return;\n  } else if (!simpleKeyCharacteristic.canSubscribe()) {\n    Serial.println(\"simple key characteristic is not subscribable!\");\n    peripheral.disconnect();\n    return;\n  } else if (!simpleKeyCharacteristic.subscribe()) {\n    Serial.println(\"subscription failed!\");\n    peripheral.disconnect();\n    return;\n  } else {\n    Serial.println(\"Subscribed\");\n    Serial.println(\"Press the right and left buttons on your SensorTag.\");\n  }\n\n  while (peripheral.connected()) {\n    // while the peripheral is connected\n\n    // check if the value of the simple key characteristic has been updated\n    if (simpleKeyCharacteristic.valueUpdated()) {\n      // yes, get the value, characteristic is 1 byte so use byte value\n      byte value = 0;\n\n      simpleKeyCharacteristic.readValue(value);\n\n      if (value & 0x01) {\n        // first bit corresponds to the right button\n        Serial.println(\"Right button pressed\");\n      }\n\n      if (value & 0x02) {\n        // second bit corresponds to the left button\n        Serial.println(\"Left button pressed\");\n      }\n    }\n  }\n\n  Serial.println(\"SensorTag disconnected!\");\n}\n"
  },
  {
    "path": "examples/Peripheral/Advertising/EnhancedAdvertising/EnhancedAdvertising.ino",
    "content": "#include <ArduinoBLE.h>\n\nBLEService myService(\"fff0\");\nBLEIntCharacteristic myCharacteristic(\"fff1\", BLERead | BLEBroadcast);\n\n// Advertising parameters should have a global scope. Do NOT define them in 'setup' or in 'loop'\nconst uint8_t manufactData[4] = {0x01, 0x02, 0x03, 0x04};\nconst uint8_t serviceData[3] = {0x00, 0x01, 0x02};\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  myService.addCharacteristic(myCharacteristic);\n  BLE.addService(myService);\n\n  // Build scan response data packet\n  BLEAdvertisingData scanData;\n  // Set parameters for scan response packet\n  scanData.setLocalName(\"Test enhanced advertising\");\n  // Copy set parameters in the actual scan response packet\n  BLE.setScanResponseData(scanData);\n\n  // Build advertising data packet\n  BLEAdvertisingData advData;\n  // Set parameters for advertising packet\n  advData.setManufacturerData(0x004C, manufactData, sizeof(manufactData));\n  advData.setAdvertisedService(myService);\n  advData.setAdvertisedServiceData(0xfff0, serviceData, sizeof(serviceData));\n  // Copy set parameters in the actual advertising packet\n  BLE.setAdvertisingData(advData);\n\n  BLE.advertise();\n  Serial.println(\"advertising ...\");\n}\n\nvoid loop() {\n  BLE.poll();\n}\n"
  },
  {
    "path": "examples/Peripheral/Advertising/RawDataAdvertising/RawDataAdvertising.ino",
    "content": "#include <ArduinoBLE.h>\n\nBLEService myService(\"fff0\");\nBLEIntCharacteristic myCharacteristic(\"fff1\", BLERead | BLEBroadcast);\n\n// Advertising parameters should have a global scope. Do NOT define them in 'setup' or in 'loop'\nconst uint8_t completeRawAdvertisingData[] = {0x02,0x01,0x06,0x09,0xff,0x01,0x01,0x00,0x01,0x02,0x03,0x04,0x05};\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  myService.addCharacteristic(myCharacteristic);\n  BLE.addService(myService);\n\n  // Build advertising data packet\n  BLEAdvertisingData advData;\n  // If a packet has a raw data parameter, then all the other parameters of the packet will be ignored\n  advData.setRawData(completeRawAdvertisingData, sizeof(completeRawAdvertisingData));\n  // Copy set parameters in the actual advertising packet\n  BLE.setAdvertisingData(advData);\n\n  // Build scan response data packet\n  BLEAdvertisingData scanData;\n  scanData.setLocalName(\"Test advertising raw data\");\n  // Copy set parameters in the actual scan response packet\n  BLE.setScanResponseData(scanData);\n\n  BLE.advertise();\n\n  Serial.println(\"advertising ...\");\n}\n\nvoid loop() {\n  BLE.poll();\n}\n"
  },
  {
    "path": "examples/Peripheral/BatteryMonitor/BatteryMonitor.ino",
    "content": "/*\n  Battery Monitor\n\n  This example creates a Bluetooth® Low Energy peripheral with the standard battery service and\n  level characteristic. The A0 pin is used to calculate the battery level.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n\n  You can use a generic Bluetooth® Low Energy central app, like LightBlue (iOS and Android) or\n  nRF Connect (Android), to interact with the services and characteristics\n  created in this sketch.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\n // Bluetooth® Low Energy Battery Service\nBLEService batteryService(\"180F\");\n\n// Bluetooth® Low Energy Battery Level Characteristic\nBLEUnsignedCharCharacteristic batteryLevelChar(\"2A19\",  // standard 16-bit characteristic UUID\n    BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes\n\nint oldBatteryLevel = 0;  // last battery level reading from analog input\nlong previousMillis = 0;  // last time the battery level was checked, in ms\n\nvoid setup() {\n  Serial.begin(9600);    // initialize serial communication\n  while (!Serial);\n\n  pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  /* Set a local name for the Bluetooth® Low Energy device\n     This name will appear in advertising packets\n     and can be used by remote devices to identify this Bluetooth® Low Energy device\n     The name can be changed but maybe be truncated based on space left in advertisement packet\n  */\n  BLE.setLocalName(\"BatteryMonitor\");\n  BLE.setAdvertisedService(batteryService); // add the service UUID\n  batteryService.addCharacteristic(batteryLevelChar); // add the battery level characteristic\n  BLE.addService(batteryService); // Add the battery service\n  batteryLevelChar.writeValue(oldBatteryLevel); // set initial value for this characteristic\n\n  /* Start advertising Bluetooth® Low Energy.  It will start continuously transmitting Bluetooth® Low Energy\n     advertising packets and will be visible to remote Bluetooth® Low Energy central devices\n     until it receives a new connection */\n\n  // start advertising\n  BLE.advertise();\n\n  Serial.println(\"Bluetooth® device active, waiting for connections...\");\n}\n\nvoid loop() {\n  // wait for a Bluetooth® Low Energy central\n  BLEDevice central = BLE.central();\n\n  // if a central is connected to the peripheral:\n  if (central) {\n    Serial.print(\"Connected to central: \");\n    // print the central's BT address:\n    Serial.println(central.address());\n    // turn on the LED to indicate the connection:\n    digitalWrite(LED_BUILTIN, HIGH);\n\n    // check the battery level every 200 ms\n    // while the central is connected:\n    while (central.connected()) {\n      long currentMillis = millis();\n      // if 200 ms have passed, check the battery level:\n      if (currentMillis - previousMillis >= 200) {\n        previousMillis = currentMillis;\n        updateBatteryLevel();\n      }\n    }\n    // when the central disconnects, turn off the LED:\n    digitalWrite(LED_BUILTIN, LOW);\n    Serial.print(\"Disconnected from central: \");\n    Serial.println(central.address());\n  }\n}\n\nvoid updateBatteryLevel() {\n  /* Read the current voltage level on the A0 analog input pin.\n     This is used here to simulate the charge level of a battery.\n  */\n  int battery = analogRead(A0);\n  int batteryLevel = map(battery, 0, 1023, 0, 100);\n\n  if (batteryLevel != oldBatteryLevel) {      // if the battery level has changed\n    Serial.print(\"Battery Level % is now: \"); // print it\n    Serial.println(batteryLevel);\n    batteryLevelChar.writeValue(batteryLevel);  // and update the battery level characteristic\n    oldBatteryLevel = batteryLevel;           // save the level for next comparison\n  }\n}\n"
  },
  {
    "path": "examples/Peripheral/ButtonLED/ButtonLED.ino",
    "content": "/*\n  Button LED\n\n  This example creates a Bluetooth® Low Energy peripheral with service that contains a\n  characteristic to control an LED and another characteristic that\n  represents the state of the button.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n  - Button connected to pin 4\n\n  You can use a generic Bluetooth® Low Energy central app, like LightBlue (iOS and Android) or\n  nRF Connect (Android), to interact with the services and characteristics\n  created in this sketch.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\nconst int ledPin = LED_BUILTIN; // set ledPin to on-board LED\nconst int buttonPin = 4; // set buttonPin to digital pin 4\n\nBLEService ledService(\"19B10010-E8F2-537E-4F6C-D104768A1214\"); // create service\n\n// create switch characteristic and allow remote device to read and write\nBLEByteCharacteristic ledCharacteristic(\"19B10011-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n// create button characteristic and allow remote device to get notifications\nBLEByteCharacteristic buttonCharacteristic(\"19B10012-E8F2-537E-4F6C-D104768A1214\", BLERead | BLENotify);\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  pinMode(ledPin, OUTPUT); // use the LED as an output\n  pinMode(buttonPin, INPUT); // use button pin as an input\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // set the local name peripheral advertises\n  BLE.setLocalName(\"ButtonLED\");\n  // set the UUID for the service this peripheral advertises:\n  BLE.setAdvertisedService(ledService);\n\n  // add the characteristics to the service\n  ledService.addCharacteristic(ledCharacteristic);\n  ledService.addCharacteristic(buttonCharacteristic);\n\n  // add the service\n  BLE.addService(ledService);\n\n  ledCharacteristic.writeValue(0);\n  buttonCharacteristic.writeValue(0);\n\n  // start advertising\n  BLE.advertise();\n\n  Serial.println(\"Bluetooth® device active, waiting for connections...\");\n}\n\nvoid loop() {\n  // poll for Bluetooth® Low Energy events\n  BLE.poll();\n\n  // read the current button pin state\n  char buttonValue = digitalRead(buttonPin);\n\n  // has the value changed since the last read\n  bool buttonChanged = (buttonCharacteristic.value() != buttonValue);\n\n  if (buttonChanged) {\n    // button state changed, update characteristics\n    ledCharacteristic.writeValue(buttonValue);\n    buttonCharacteristic.writeValue(buttonValue);\n  }\n\n  if (ledCharacteristic.written() || buttonChanged) {\n    // update LED, either central has written to characteristic or button state has changed\n    if (ledCharacteristic.value()) {\n      Serial.println(\"LED on\");\n      digitalWrite(ledPin, HIGH);\n    } else {\n      Serial.println(\"LED off\");\n      digitalWrite(ledPin, LOW);\n    }\n  }\n}\n"
  },
  {
    "path": "examples/Peripheral/CallbackLED/CallbackLED.ino",
    "content": "/*\n  Callback LED\n\n  This example creates a Bluetooth® Low Energy peripheral with service that contains a\n  characteristic to control an LED. The callback features of the\n  library are used.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n\n  You can use a generic Bluetooth® Low Energy central app, like LightBlue (iOS and Android) or\n  nRF Connect (Android), to interact with the services and characteristics\n  created in this sketch.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\nBLEService ledService(\"19B10000-E8F2-537E-4F6C-D104768A1214\"); // create service\n\n// create switch characteristic and allow remote device to read and write\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\nconst int ledPin = LED_BUILTIN; // pin to use for the LED\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  pinMode(ledPin, OUTPUT); // use the LED pin as an output\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // set the local name peripheral advertises\n  BLE.setLocalName(\"LEDCallback\");\n  // set the UUID for the service this peripheral advertises\n  BLE.setAdvertisedService(ledService);\n\n  // add the characteristic to the service\n  ledService.addCharacteristic(switchCharacteristic);\n\n  // add service\n  BLE.addService(ledService);\n\n  // assign event handlers for connected, disconnected to peripheral\n  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);\n  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);\n\n  // assign event handlers for characteristic\n  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);\n  // set an initial value for the characteristic\n  switchCharacteristic.setValue(0);\n\n  // start advertising\n  BLE.advertise();\n\n  Serial.println((\"Bluetooth® device active, waiting for connections...\"));\n}\n\nvoid loop() {\n  // poll for Bluetooth® Low Energy events\n  BLE.poll();\n}\n\nvoid blePeripheralConnectHandler(BLEDevice central) {\n  // central connected event handler\n  Serial.print(\"Connected event, central: \");\n  Serial.println(central.address());\n}\n\nvoid blePeripheralDisconnectHandler(BLEDevice central) {\n  // central disconnected event handler\n  Serial.print(\"Disconnected event, central: \");\n  Serial.println(central.address());\n}\n\nvoid switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {\n  // unused parameters\n  (void)central;\n  (void)characteristic;\n\n  // central wrote new value to characteristic, update LED\n  Serial.print(\"Characteristic event, written: \");\n\n  if (switchCharacteristic.value()) {\n    Serial.println(\"LED on\");\n    digitalWrite(ledPin, HIGH);\n  } else {\n    Serial.println(\"LED off\");\n    digitalWrite(ledPin, LOW);\n  }\n}\n"
  },
  {
    "path": "examples/Peripheral/EncryptedBatteryMonitor/EncryptedBatteryMonitor.ino",
    "content": "/*\n  Battery Monitor\n\n  This example creates a BLE peripheral with the standard battery service and\n  level characteristic. The A0 pin is used to calculate the battery level.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n\n  You can use a generic BLE central app, like LightBlue (iOS and Android) or\n  nRF Connect (Android), to interact with the services and characteristics\n  created in this sketch.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\n\n#define PAIR_BUTTON 3         // button for pairing\n#define PAIR_LED 24           // LED used to signal pairing\n#define PAIR_LED_ON LOW       // Blue LED on Nano BLE has inverted logic\n#define PAIR_LED_OFF HIGH     // ... so these are inverted as well\n#define PAIR_INTERVAL 30000   // interval for pairing after button press in ms\n\n#define CTRL_LED LED_BUILTIN\n\n\n // BLE Battery Service\nBLEService batteryService(\"180F\");\n\n// BLE Battery Level Characteristic\nBLEUnsignedCharCharacteristic batteryLevelChar(\"2A19\",  // standard 16-bit characteristic UUID\n    BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes\nBLEStringCharacteristic stringcharacteristic(\"183E\", BLERead | BLEWrite, 31);\n\n\n// Add BLEEncryption tag to require pairing. This controls the LED.\nBLEUnsignedCharCharacteristic secretValue(\"2a3F\", BLERead | BLEWrite | BLEEncryption);\n\nint oldBatteryLevel = 0;  // last battery level reading from analog input\nunsigned long previousMillis = 0;  // last time the battery level was checked, in ms\nunsigned long pairingStarted = 0;  // pairing start time when button is pressed\nbool wasConnected = 0;\nbool acceptOrReject = true;\n\nvoid setup() {\n  Serial.begin(9600);    // initialize serial communication\n  while (!Serial);\n\n  pinMode(CTRL_LED, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected\n  pinMode(PAIR_LED, OUTPUT);\n  pinMode(PAIR_BUTTON, INPUT_PULLUP);\n\n\n  Serial.println(\"Serial connected\");\n\n  // Callback function with confirmation code when new device is pairing.\n  BLE.setDisplayCode([](uint32_t confirmCode){\n    Serial.println(\"New device pairing request.\");\n    Serial.print(\"Confirm code matches pairing device: \");\n    char code[7];\n    sprintf(code, \"%06d\", confirmCode);\n    Serial.println(code);\n  });\n\n  // Callback to allow accepting or rejecting pairing\n  BLE.setBinaryConfirmPairing([](){\n    Serial.print(\"Should we confirm pairing? \");\n    delay(5000);\n    if(acceptOrReject){\n      acceptOrReject = false;\n      Serial.println(\"yes\");\n      return true;\n    }else{\n      acceptOrReject = true;\n      Serial.println(\"no\");\n      return false;\n    }\n  });\n\n  // IRKs are keys that identify the true owner of a random mac address.\n  // Add IRKs of devices you are bonded with.\n  BLE.setGetIRKs([](uint8_t* nIRKs, uint8_t** BDaddrTypes, uint8_t*** BDAddrs, uint8_t*** IRKs){\n    // Set to number of devices\n    *nIRKs       = 2;\n\n    *BDAddrs     = new uint8_t*[*nIRKs];\n    *IRKs        = new uint8_t*[*nIRKs];\n    *BDaddrTypes = new uint8_t[*nIRKs];\n\n    // Set these to the mac and IRK for your bonded devices as printed in the serial console after bonding.\n    uint8_t device1Mac[6]    = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n    uint8_t device1IRK[16]   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n    uint8_t device2Mac[6]    = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n    uint8_t device2IRK[16]   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n\n    (*BDaddrTypes)[0] = 0; // Type 0 is for pubc address, type 1 is for static random\n    (*BDAddrs)[0] = new uint8_t[6];\n    (*IRKs)[0]    = new uint8_t[16];\n    memcpy((*IRKs)[0]   , device1IRK,16);\n    memcpy((*BDAddrs)[0], device1Mac, 6);\n\n\n    (*BDaddrTypes)[1] = 0;\n    (*BDAddrs)[1] = new uint8_t[6];\n    (*IRKs)[1]    = new uint8_t[16];\n    memcpy((*IRKs)[1]   , device2IRK,16);\n    memcpy((*BDAddrs)[1], device2Mac, 6);\n\n\n    return 1;\n  });\n  // The LTK is the secret key which is used to encrypt bluetooth traffic\n  BLE.setGetLTK([](uint8_t* address, uint8_t* LTK){\n    // address is input\n    Serial.print(\"Received request for address: \");\n    btct.printBytes(address,6);\n\n    // Set these to the MAC and LTK of your devices after bonding.\n    uint8_t device1Mac[6]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n    uint8_t device1LTK[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n    uint8_t device2Mac[6]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n    uint8_t device2LTK[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n\n    if(memcmp(device1Mac, address, 6) == 0) {\n      memcpy(LTK, device1LTK, 16);\n      return 1;\n    }else if(memcmp(device2Mac, address, 6) == 0) {\n      memcpy(LTK, device2LTK, 16);\n      return 1;\n    }\n    return 0;\n  });\n  BLE.setStoreIRK([](uint8_t* address, uint8_t* IRK){\n    Serial.print(F(\"New device with MAC : \"));\n    btct.printBytes(address,6);\n    Serial.print(F(\"Need to store IRK   : \"));\n    btct.printBytes(IRK,16);\n    return 1;\n  });\n  BLE.setStoreLTK([](uint8_t* address, uint8_t* LTK){\n    Serial.print(F(\"New device with MAC : \"));\n    btct.printBytes(address,6);\n    Serial.print(F(\"Need to store LTK   : \"));\n    btct.printBytes(LTK,16);\n    return 1;\n  });\n\n  while(1){\n    // begin initialization\n    if (!BLE.begin()) {\n      Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n      while (1);\n    }\n    Serial.println(\"BT init\");\n    delay(200);\n\n    /* Set a local name for the BLE device\n       This name will appear in advertising packets\n       and can be used by remote devices to identify this BLE device\n       The name can be changed but maybe be truncated based on space left in advertisement packet\n    */\n\n    BLE.setDeviceName(\"Arduino\");\n    BLE.setLocalName(\"BatteryMonitor\");\n\n    BLE.setAdvertisedService(batteryService); // add the service UUID\n    batteryService.addCharacteristic(batteryLevelChar); // add the battery level characteristic\n    batteryService.addCharacteristic(stringcharacteristic);\n    batteryService.addCharacteristic(secretValue);\n\n    BLE.addService(batteryService);               // Add the battery service\n    batteryLevelChar.writeValue(oldBatteryLevel); // set initial value for this characteristic\n    const char* stringCharValue = \"string\";\n    stringcharacteristic.writeValue(stringCharValue);\n    secretValue.writeValue(0);\n\n    delay(1000);\n\n    // prevent pairing until button is pressed (will show a pairing rejected message)\n    BLE.setPairable(false);\n\n    /* Start advertising BLE.  It will start continuously transmitting BLE\n       advertising packets and will be visible to remote BLE central devices\n       until it receives a new connection */\n\n    // start advertising\n    if(!BLE.advertise()){\n      Serial.println(\"failed to advertise bluetooth.\");\n      BLE.stopAdvertise();\n      delay(500);\n    }else{\n      Serial.println(\"advertising...\");\n      break;\n    }\n    BLE.end();\n    delay(100);\n  }\n}\n\n\nvoid loop() {\n  // wait for a BLE central\n  BLEDevice central = BLE.central();\n\n\n  // If button is pressed, allow pairing for 30 sec\n  if (!BLE.pairable() && digitalRead(PAIR_BUTTON) == LOW){\n    pairingStarted = millis();\n    BLE.setPairable(Pairable::ONCE);\n    Serial.println(\"Accepting pairing for 30 s\");\n  } else if (BLE.pairable() && millis() > pairingStarted + PAIR_INTERVAL){\n    BLE.setPairable(false);\n    Serial.println(\"No longer accepting pairing\");\n  }\n\n  // Make LED blink while pairing is allowed, steady ON when paired\n  bool led_status = BLE.pairable() ? (millis()%400)<200 : BLE.paired();\n  digitalWrite(PAIR_LED, led_status ? PAIR_LED_ON : PAIR_LED_OFF);\n\n  // if a central is connected to the peripheral:\n  if (central && central.connected()) {\n    if (!wasConnected){\n      wasConnected = true;\n      Serial.print(\"Connected to central: \");\n      // print the central's BT address:\n      Serial.println(central.address());\n    }\n\n    // check the battery level every 200ms\n    // while the central is connected:\n    long currentMillis = millis();\n    // if 200ms have passed, check the battery level:\n    if (currentMillis - previousMillis >= 1000) {\n      previousMillis = currentMillis;\n      updateBatteryLevel();\n      digitalWrite(CTRL_LED, secretValue.value()>0 ? HIGH : LOW);\n    }\n  } else if (wasConnected){\n    wasConnected = false;\n    Serial.print(\"Disconnected from central: \");\n    Serial.println(central.address());\n  }\n\n}\n\nvoid updateBatteryLevel() {\n  /* Read the current voltage level on the A0 analog input pin.\n     This is used here to simulate the charge level of a battery.\n  */\n  int battery = analogRead(A0);\n  int batteryLevel = map(battery, 0, 1023, 0, 100);\n\n  if (batteryLevel != oldBatteryLevel) {      // if the battery level has changed\n    // Serial.print(\"Battery Level % is now: \"); // print it\n    // Serial.println(batteryLevel);\n    batteryLevelChar.writeValue(batteryLevel);  // and update the battery level characteristic\n    oldBatteryLevel = batteryLevel;           // save the level for next comparison\n  }\n}\n"
  },
  {
    "path": "examples/Peripheral/LED/LED.ino",
    "content": "/*\n  LED\n\n  This example creates a Bluetooth® Low Energy peripheral with service that contains a\n  characteristic to control an LED.\n\n  The circuit:\n  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,\n    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.\n\n  You can use a generic Bluetooth® Low Energy central app, like LightBlue (iOS and Android) or\n  nRF Connect (Android), to interact with the services and characteristics\n  created in this sketch.\n\n  This example code is in the public domain.\n*/\n\n#include <ArduinoBLE.h>\n\nBLEService ledService(\"19B10000-E8F2-537E-4F6C-D104768A1214\"); // Bluetooth® Low Energy LED Service\n\n// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central\nBLEByteCharacteristic switchCharacteristic(\"19B10001-E8F2-537E-4F6C-D104768A1214\", BLERead | BLEWrite);\n\nconst int ledPin = LED_BUILTIN; // pin to use for the LED\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  // set LED pin to output mode\n  pinMode(ledPin, OUTPUT);\n\n  // begin initialization\n  if (!BLE.begin()) {\n    Serial.println(\"starting Bluetooth® Low Energy module failed!\");\n\n    while (1);\n  }\n\n  // set advertised local name and service UUID:\n  BLE.setLocalName(\"LED\");\n  BLE.setAdvertisedService(ledService);\n\n  // add the characteristic to the service\n  ledService.addCharacteristic(switchCharacteristic);\n\n  // add service\n  BLE.addService(ledService);\n\n  // set the initial value for the characteristic:\n  switchCharacteristic.writeValue(0);\n\n  // start advertising\n  BLE.advertise();\n\n  Serial.println(\"BLE LED Peripheral\");\n}\n\nvoid loop() {\n  // listen for Bluetooth® Low Energy peripherals to connect:\n  BLEDevice central = BLE.central();\n\n  // if a central is connected to peripheral:\n  if (central) {\n    Serial.print(\"Connected to central: \");\n    // print the central's MAC address:\n    Serial.println(central.address());\n\n    // while the central is still connected to peripheral:\n    while (central.connected()) {\n      // if the remote device wrote to the characteristic,\n      // use the value to control the LED:\n      if (switchCharacteristic.written()) {\n        if (switchCharacteristic.value()) {   // any value other than 0\n          Serial.println(\"LED on\");\n          digitalWrite(ledPin, HIGH);         // will turn the LED on\n        } else {                              // a 0 value\n          Serial.println(F(\"LED off\"));\n          digitalWrite(ledPin, LOW);          // will turn the LED off\n        }\n      }\n    }\n\n    // when the central disconnects, print it out:\n    Serial.print(F(\"Disconnected from central: \"));\n    Serial.println(central.address());\n  }\n}\n"
  },
  {
    "path": "extras/arduino-ble-parser.py",
    "content": "'''\nConvert ArduinoBLE debug files into Btsnoop files ready to be analyzed using wireshark or hcidump\nBtsnoop file format reference\n https://www.fte.com/WebHelpII/Sodera/Content/Technical_Information/BT_Snoop_File_Format.htm\n'''\n\nimport  os\nimport argparse\n\nDEBUG = False\n\nparser = argparse.ArgumentParser()\nparser.add_argument('-i', dest='inputPath', type=str, required=True, help='input file containing debug log')\nparser.add_argument('-o', dest='outputPath', type=str, required=True, help='result file that will contain the btsnoop encoded debug file')\nargs = parser.parse_args()\n\n# Extract only hci debug messages\ndef extractHCIDebugPrint(inputPath, outputPath):\n  inputFile = open(inputPath, 'r')\n  outputFile = open(outputPath, 'w')\n  for inputLine in inputFile:\n    lineItems = inputLine.split()\n    if (len(lineItems) < 7) or (lineItems[1] != \"->\") or (lineItems[2] != \"HCI\"):\n      if (len(lineItems) < 4) or (lineItems[0] != \"HCI\") or ((lineItems[3] != \"<-\") and (lineItems[3] != \"->\")):\n        continue\n    outputFile.write(inputLine)  \n  outputFile.close()\n\n# Return packet in btsnoop format\ndef buildBinaryPacket(hciMessage, hciDirection, hciType):\n  commandFlag = 1 if (hciType == \"COMMAND\" or hciType == \"EVENT\") else 0\n  directionFlag =  0 if (hciDirection == \"TX\") else 1\n  flagHex = (\"0\" * 7) + str((commandFlag * 2) + directionFlag)\n  timestampHex = \"0\" * 16\n  packetDropHex = \"0\" * 8\n  dataLengthHex = format( (int(len(hciMessage) / 2)), 'x')\n  packetLengthHex = (\"0\" * (8 - len(dataLengthHex))) + dataLengthHex\n  binaryPacket = bytearray.fromhex(packetLengthHex + packetLengthHex + flagHex + packetDropHex + timestampHex + hciMessage)\n  if DEBUG:\n    print(len(hciMessage))\n    print(dataLengthHex)\n    print(packetLengthHex)\n    print(flagHex)\n    print('\\n')\n  return binaryPacket\n\ndef buildBinaryHeader():\n  defaultHeader = \"6274736e6f6f700000000001000003ea\"\n  binaryHeader = bytearray.fromhex(defaultHeader)\n  return binaryHeader\n\ndef convertToBtsnoop(inputPath, outputPath):\n  # Open output file and write the Btsnoop header\n  outputFile = open(outputPath,'wb')\n  header = buildBinaryHeader()\n  outputFile.write(header)\n\n  # Open input file containing HCI debug packets\n  inputFile = open(inputPath, 'r')\n  for inputLine in inputFile:\n    lineItems = inputLine.split()\n    # For a safer script, do not use indexes but look for symbols in the line\n    baseIndex = lineItems.index(\"HCI\")\n    hciMessage = lineItems[baseIndex + 4]\n    hciDirection = lineItems[baseIndex + 2]\n    hciType = lineItems[baseIndex + 1]\n    # Build and write the encoded line\n    btsnoopPacket = buildBinaryPacket(hciMessage, hciDirection, hciType)\n    outputFile.write(btsnoopPacket)\n    if DEBUG:\n      print(hciDirection)\n      print(hciMessage)\n      print(hciType)\n      print('\\n')\n  outputFile.close()\n\ninputPath = args.inputPath\noutputPath = args.outputPath\ntempFile = \"temp-debug-print.txt\"\n# Run\nextractHCIDebugPrint(inputPath,tempFile)\nconvertToBtsnoop(tempFile, outputPath)\n# Delete temp file\nos.remove(tempFile) \n\n"
  },
  {
    "path": "extras/test/.gitignore",
    "content": "build\n### CMake ###\nCMakeLists.txt.user\nCMakeCache.txt\nCMakeFiles\nCMakeScripts\nTesting\nMakefile\ncmake_install.cmake\ninstall_manifest.txt\ncompile_commands.json\nCTestTestfile.cmake\n_deps\n\n### CMake Patch ###\n# External projects\n*-prefix/"
  },
  {
    "path": "extras/test/CMakeLists.txt",
    "content": "##########################################################################\n\nset(CMAKE_VERBOSE_MAKEFILE ON)\ncmake_minimum_required(VERSION 3.5)\n\n##########################################################################\n\nproject(testArduinoBLE)\n\nInclude(FetchContent)\n\nFetchContent_Declare(\n  Catch2\n  GIT_REPOSITORY https://github.com/catchorg/Catch2.git\n  GIT_TAG        v3.4.0\n)\n\nFetchContent_MakeAvailable(Catch2)\n\n##########################################################################\n\nset(CMAKE_CXX_STANDARD 11)\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n\n##########################################################################\n\nset(COMMON_TEST_SRCS\n  src/test_main.cpp\n  src/Arduino.cpp\n  src/util/itoa.c\n  src/util/TestUtil.cpp\n  src/util/String.cpp\n  src/util/Common.cpp\n)\n\nset(DUT_SRCS\n  ../../src/utility/BLEUuid.cpp\n  ../../src/BLEDevice.cpp\n  ../../src/BLECharacteristic.cpp\n  ../../src/BLEDescriptor.cpp\n  ../../src/BLEService.cpp\n  ../../src/BLEAdvertisingData.cpp\n  ../../src/utility/ATT.cpp\n  ../../src/utility/GAP.cpp\n  ../../src/utility/HCI.cpp\n  ../../src/utility/GATT.cpp\n  ../../src/utility/L2CAPSignaling.cpp\n  ../../src/utility/keyDistribution.cpp\n  ../../src/utility/bitDescriptions.cpp\n  ../../src/utility/btct.cpp\n  ../../src/local/BLELocalAttribute.cpp\n  ../../src/local/BLELocalCharacteristic.cpp\n  ../../src/local/BLELocalDescriptor.cpp\n  ../../src/local/BLELocalDevice.cpp\n  ../../src/local/BLELocalService.cpp\n  ../../src/remote/BLERemoteAttribute.cpp\n  ../../src/remote/BLERemoteCharacteristic.cpp\n  ../../src/remote/BLERemoteDescriptor.cpp\n  ../../src/remote/BLERemoteDevice.cpp\n  ../../src/remote/BLERemoteService.cpp\n  ../../src/BLEStringCharacteristic.cpp\n  ../../src/BLETypedCharacteristics.cpp\n)\n\nset(TEST_TARGET_UUID_SRCS\n  # Test files\n  ${COMMON_TEST_SRCS}\n  src/test_uuid/test_uuid.cpp\n  # DUT files\n  #${DUT_SRCS}\n  ../../src/utility/BLEUuid.cpp\n)\n\nset(TEST_TARGET_DISC_DEVICE_SRCS\n  # Test files\n  ${COMMON_TEST_SRCS}\n  src/test_discovered_device/test_discovered_device.cpp\n  # DUT files\n  ${DUT_SRCS}\n  # Fake classes files\n  src/util/HCIFakeTransport.cpp\n  src/test_discovered_device/FakeGAP.cpp\n)\n\nset(TEST_TARGET_ADVERTISING_DATA_SRCS\n  # Test files\n  ${COMMON_TEST_SRCS}\n  src/test_advertising_data/test_advertising_data.cpp\n  src/test_advertising_data/test_service.cpp\n  src/test_advertising_data/test_local_name.cpp\n  src/test_advertising_data/test_manufacturer.cpp\n  # DUT files\n  ${DUT_SRCS}\n  # Fake classes files\n  src/util/HCIFakeTransport.cpp\n  src/test_advertising_data/FakeBLELocalDevice.cpp\n)\n\nset(TEST_TARGET_CHARACTERISTIC_SRCS\n  # Test files\n  ${COMMON_TEST_SRCS}\n  src/test_characteristic/test_permissions.cpp\n  src/test_characteristic/test_writeValue.cpp\n  # DUT files\n  ${DUT_SRCS}\n  # Fake classes files\n  src/util/HCIFakeTransport.cpp\n  src/test_advertising_data/FakeBLELocalDevice.cpp\n)\n\n##########################################################################\n\nset(CMAKE_C_FLAGS   ${CMAKE_C_FLAGS}   \"--coverage\")\nset(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} \"--coverage\")\n\n##########################################################################\n\nadd_executable(TEST_TARGET_UUID ${TEST_TARGET_UUID_SRCS})\nadd_executable(TEST_TARGET_DISC_DEVICE ${TEST_TARGET_DISC_DEVICE_SRCS})\nadd_executable(TEST_TARGET_ADVERTISING_DATA ${TEST_TARGET_ADVERTISING_DATA_SRCS})\nadd_executable(TEST_TARGET_CHARACTERISTIC_DATA ${TEST_TARGET_CHARACTERISTIC_SRCS})\n\n##########################################################################\n\ninclude_directories(include)\ninclude_directories(include/util)\ninclude_directories(../../src)\ninclude_directories(../../src/local)\ninclude_directories(../../src/remote)\ninclude_directories(../../src/utility)\n\ntarget_include_directories(TEST_TARGET_DISC_DEVICE PUBLIC include/test_discovered_device)\ntarget_include_directories(TEST_TARGET_ADVERTISING_DATA PUBLIC include/test_advertising_data)\ntarget_include_directories(TEST_TARGET_CHARACTERISTIC_DATA PUBLIC include/test_advertising_data)\n\n##########################################################################\n\ntarget_compile_definitions(TEST_TARGET_DISC_DEVICE PUBLIC FAKE_GAP)\ntarget_compile_definitions(TEST_TARGET_ADVERTISING_DATA PUBLIC FAKE_BLELOCALDEVICE)\ntarget_compile_definitions(TEST_TARGET_CHARACTERISTIC_DATA PUBLIC FAKE_BLELOCALDEVICE)\n\n##########################################################################\n\n# Build unit tests as a post build step\nadd_custom_command(TARGET TEST_TARGET_UUID POST_BUILD\n  COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TEST_TARGET_UUID\n)\nadd_custom_command(TARGET TEST_TARGET_DISC_DEVICE POST_BUILD\n  COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TEST_TARGET_DISC_DEVICE\n)\nadd_custom_command(TARGET TEST_TARGET_ADVERTISING_DATA POST_BUILD\n  COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TEST_TARGET_ADVERTISING_DATA\n)\n\nadd_custom_command(TARGET TEST_TARGET_CHARACTERISTIC_DATA POST_BUILD\n  COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TEST_TARGET_CHARACTERISTIC_DATA\n)\n\n##########################################################################\n\ntarget_link_libraries( TEST_TARGET_UUID Catch2WithMain )\ntarget_link_libraries( TEST_TARGET_DISC_DEVICE Catch2WithMain )\ntarget_link_libraries( TEST_TARGET_ADVERTISING_DATA Catch2WithMain )\ntarget_link_libraries( TEST_TARGET_CHARACTERISTIC_DATA Catch2WithMain )\n"
  },
  {
    "path": "extras/test/include/Arduino.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef TEST_ARDUINO_H_\n#define TEST_ARDUINO_H_\n\n/******************************************************************************\n   INCLUDE\n ******************************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include \"String.h\"\n#include \"Stream.h\"\n#include \"itoa.h\"\n#include \"Common.h\"\n\n/******************************************************************************\n   TYPEDEF\n ******************************************************************************/\n\ntypedef arduino::String String;\ntypedef bool boolean;\n\n#if defined(__cplusplus)\n\n#undef F\n// C++11 F replacement declaration\ntemplate <typename T1>\nauto F(T1&& A)\n  -> const arduino::__FlashStringHelper*\n{\n  return (const arduino::__FlashStringHelper*)A;\n}\n\n#endif\n\n/******************************************************************************\n   FUNCTION PROTOTYPES\n ******************************************************************************/\n\n#endif /* TEST_ARDUINO_H_ */\n"
  },
  {
    "path": "extras/test/include/test_advertising_data/FakeBLELocalDevice.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _FAKE_BLELOCALDEVICE_H_\n#define _FAKE_BLELOCALDEVICE_H_\n\n#define private public\n#define protected public\n#include \"BLELocalDevice.h\"\n\nclass FakeBLELocalDevice : public BLELocalDevice {\n  public:\n    FakeBLELocalDevice();\n    virtual ~FakeBLELocalDevice();\n    \n    int advertise();\n};\n\n#endif\n"
  },
  {
    "path": "extras/test/include/test_discovered_device/FakeGAP.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _FAKE_GAP_H_\n#define _FAKE_GAP_H_\n\n#define private public\n#define protected public\n#include \"GAP.h\"\n\nclass FakeGAPClass : public GAPClass {\n  public:\n    FakeGAPClass();\n    virtual ~FakeGAPClass();\n};\n\n#endif\n"
  },
  {
    "path": "extras/test/include/util/Common.h",
    "content": "#pragma once\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\"{\n#endif\n\nvoid yield(void);\n\ntypedef enum {\n  LOW     = 0,\n  HIGH    = 1,\n  CHANGE  = 2,\n  FALLING = 3,\n  RISING  = 4,\n} PinStatus;\n\ntypedef enum {\n  INPUT           = 0x0,\n  OUTPUT          = 0x1,\n  INPUT_PULLUP    = 0x2,\n  INPUT_PULLDOWN  = 0x3,\n} PinMode;\n\ntypedef enum {\n  LSBFIRST = 0,\n  MSBFIRST = 1,\n} BitOrder;\n\n#define PI          3.1415926535897932384626433832795\n#define HALF_PI     1.5707963267948966192313216916398\n#define TWO_PI      6.283185307179586476925286766559\n#define DEG_TO_RAD  0.017453292519943295769236907684886\n#define RAD_TO_DEG  57.295779513082320876798154814105\n#define EULER       2.718281828459045235360287471352\n\n#define SERIAL      0x0\n#define DISPLAY     0x1\n\n#ifndef constrain\n#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))\n#endif\n\n#ifndef radians\n#define radians(deg) ((deg)*DEG_TO_RAD)\n#endif\n\n#ifndef degrees\n#define degrees(rad) ((rad)*RAD_TO_DEG)\n#endif\n\n#ifndef sq\n#define sq(x) ((x)*(x))\n#endif\n\ntypedef void (*voidFuncPtr)(void);\ntypedef void (*voidFuncPtrParam)(void*);\n\n// interrupts() / noInterrupts() must be defined by the core\n\n#define lowByte(w) ((uint8_t) ((w) & 0xff))\n#define highByte(w) ((uint8_t) ((w) >> 8))\n\n#define bitRead(value, bit) (((value) >> (bit)) & 0x01)\n#define bitSet(value, bit) ((value) |= (1UL << (bit)))\n#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))\n#define bitToggle(value, bit) ((value) ^= (1UL << (bit)))\n#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))\n\n#ifndef bit\n#define bit(b) (1UL << (b))\n#endif\n\n/* TODO: request for removal */\ntypedef bool      boolean;\ntypedef uint8_t   byte;\ntypedef uint16_t  word;\n\nvoid init(void);\nvoid initVariant(void);\n\nint atexit(void (*func)()) __attribute__((weak));\nint main() __attribute__((weak));\n\n#ifdef EXTENDED_PIN_MODE\n// Platforms who wnat to declare more than 256 pins need to define EXTENDED_PIN_MODE globally\ntypedef uint32_t pin_size_t;\n#else\ntypedef uint8_t pin_size_t;\n#endif\n\nvoid pinMode(pin_size_t pinNumber, PinMode pinMode);\nvoid digitalWrite(pin_size_t pinNumber, PinStatus status);\nPinStatus digitalRead(pin_size_t pinNumber);\nint analogRead(pin_size_t pinNumber);\nvoid analogReference(uint8_t mode);\nvoid analogWrite(pin_size_t pinNumber, int value);\n\nunsigned long millis(void);\nunsigned long micros(void);\nvoid delay(unsigned long);\nvoid delayMicroseconds(unsigned int us);\nunsigned long pulseIn(pin_size_t pin, uint8_t state, unsigned long timeout);\nunsigned long pulseInLong(pin_size_t pin, uint8_t state, unsigned long timeout);\n\nvoid shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder, uint8_t val);\npin_size_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder);\n\nvoid attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode);\nvoid attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void* param);\nvoid detachInterrupt(pin_size_t interruptNumber);\n\nvoid setup(void);\nvoid loop(void);\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n#ifdef __cplusplus\n  template<class T, class L> \n  auto min(const T& a, const L& b) -> decltype((b < a) ? b : a)\n  {\n    return (b < a) ? b : a;\n  }\n\n  template<class T, class L> \n  auto max(const T& a, const L& b) -> decltype((b < a) ? b : a)\n  {\n    return (a < b) ? b : a;\n  }\n#else\n#ifndef min\n#define min(a,b) \\\n   ({ __typeof__ (a) _a = (a); \\\n       __typeof__ (b) _b = (b); \\\n     _a < _b ? _a : _b; })\n#endif\n#ifndef max\n#define max(a,b) \\\n   ({ __typeof__ (a) _a = (a); \\\n       __typeof__ (b) _b = (b); \\\n     _a > _b ? _a : _b; })\n#endif\n#endif\n\n#ifdef __cplusplus\n\n/* C++ prototypes */\nuint16_t makeWord(uint16_t w);\nuint16_t makeWord(byte h, byte l);\n\n#define word(...) makeWord(__VA_ARGS__)\n\nunsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);\nunsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);\n\nvoid tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);\nvoid noTone(uint8_t _pin);\n\n// WMath prototypes\nlong random(long);\nlong random(long, long);\nvoid randomSeed(unsigned long);\nlong map(long, long, long, long, long);\n\n#endif // __cplusplus\n"
  },
  {
    "path": "extras/test/include/util/HCIFakeTransport.h",
    "content": "//#include \"Common.h\"\n#pragma once\n\n#include \"HCITransport.h\"\n\nclass HCIFakeTransportClass : public HCITransportInterface\n{\npublic:\n    HCIFakeTransportClass() {};\n    ~HCIFakeTransportClass() {};\n\n    int begin() {return 0;}\n    void end() {return;}\n    void wait(unsigned long timeout) {return;}\n    int available() {return 0;}\n    int peek() {return 0;}\n    int read() {return 0;}\n    size_t write(const uint8_t* data, size_t length) {return 0;}\n};"
  },
  {
    "path": "extras/test/include/util/Stream.h",
    "content": "//#include \"Common.h\"\n#pragma once\n\n#define DEC 10\n#define HEX 16\n#define OCT 8\n#define BIN 2\n\nclass Stream \n{\npublic:\n  Stream(const char *name = NULL);\n  ~Stream();\n\n  void flush() {}\n\n  size_t print(const char[]) { return 0; }\n  size_t print(char) { return 0; }\n  size_t print(unsigned char, int) { return 0; }\n  size_t print(int, int) { return 0; }\n  size_t print(unsigned int, int) { return 0; }\n  size_t print(long, int) { return 0; }\n  size_t print(unsigned long, int) { return 0; }\n  size_t print(long long, int) { return 0; }\n  size_t print(unsigned long long, int) { return 0; }\n  size_t print(double, int) { return 0; }\n  size_t print(void) { return 0; }\n\n  size_t println(const char[]) { return 0; }\n  size_t println(char) { return 0; }\n  size_t println(unsigned char, int) { return 0; }\n  size_t println(int, int) { return 0; }\n  size_t println(unsigned int, int) { return 0; }\n  size_t println(long, int) { return 0; }\n  size_t println(unsigned long, int) { return 0; }\n  size_t println(long long, int) { return 0; }\n  size_t println(unsigned long long, int) { return 0; }\n  size_t println(double, int) { return 0; }\n  size_t println(void) { return 0; }\n};\n"
  },
  {
    "path": "extras/test/include/util/String.h",
    "content": "/*\n  String library for Wiring & Arduino\n  ...mostly rewritten by Paul Stoffregen...\n  Copyright (c) 2009-10 Hernando Barragan.  All right reserved.\n  Copyright 2011, Paul Stoffregen, paul@pjrc.com\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifdef __cplusplus\n\n#ifndef __ARDUINO_STRINGS__\n#define __ARDUINO_STRINGS__\n\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n\nnamespace arduino {\n\n// When compiling programs with this class, the following gcc parameters\n// dramatically increase performance and memory (RAM) efficiency, typically\n// with little or no increase in code size.\n//     -felide-constructors\n//     -std=c++0x\n\nclass __FlashStringHelper;\n#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))\n\n// An inherited class for holding the result of a concatenation.  These\n// result objects are assumed to be writable by subsequent concatenations.\nclass StringSumHelper;\n\n// The string class\nclass String\n{\n\tfriend class StringSumHelper;\n\t// use a function pointer to allow for \"if (s)\" without the\n\t// complications of an operator bool(). for more information, see:\n\t// http://www.artima.com/cppsource/safebool.html\n\ttypedef void (String::*StringIfHelperType)() const;\n\tvoid StringIfHelper() const {}\n\npublic:\n\t// constructors\n\t// creates a copy of the initial value.\n\t// if the initial value is null or invalid, or if memory allocation\n\t// fails, the string will be marked as invalid (i.e. \"if (s)\" will\n\t// be false).\n\tString(const char *cstr = \"\");\n\tString(const String &str);\n\tString(const __FlashStringHelper *str);\n\t#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)\n\tString(String &&rval);\n\tString(StringSumHelper &&rval);\n\t#endif\n\texplicit String(char c);\n\texplicit String(unsigned char, unsigned char base=10);\n\texplicit String(int, unsigned char base=10);\n\texplicit String(unsigned int, unsigned char base=10);\n\texplicit String(long, unsigned char base=10);\n\texplicit String(unsigned long, unsigned char base=10);\n\t//explicit String(float, unsigned char decimalPlaces=2);\n\t//explicit String(double, unsigned char decimalPlaces=2);\n\t~String(void);\n\n\t// memory management\n\t// return true on success, false on failure (in which case, the string\n\t// is left unchanged).  reserve(0), if successful, will validate an\n\t// invalid string (i.e., \"if (s)\" will be true afterwards)\n\tunsigned char reserve(unsigned int size);\n\tinline unsigned int length(void) const {return len;}\n\n\t// creates a copy of the assigned value.  if the value is null or\n\t// invalid, or if the memory allocation fails, the string will be\n\t// marked as invalid (\"if (s)\" will be false).\n\tString & operator = (const String &rhs);\n\tString & operator = (const char *cstr);\n\t//String & operator = (const __FlashStringHelper *str);\n\t#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)\n\tString & operator = (String &&rval);\n\tString & operator = (StringSumHelper &&rval);\n\t#endif\n\n\t// concatenate (works w/ built-in types)\n\n\t// returns true on success, false on failure (in which case, the string\n\t// is left unchanged).  if the argument is null or invalid, the\n\t// concatenation is considered unsucessful.\n\tunsigned char concat(const String &str);\n\tunsigned char concat(const char *cstr);\n\tunsigned char concat(char c);\n\tunsigned char concat(unsigned char c);\n\tunsigned char concat(int num);\n\tunsigned char concat(unsigned int num);\n\tunsigned char concat(long num);\n\tunsigned char concat(unsigned long num);\n\tunsigned char concat(float num);\n\t//unsigned char concat(double num);\n\tunsigned char concat(const __FlashStringHelper * str);\n\n\t// if there's not enough memory for the concatenated value, the string\n\t// will be left unchanged (but this isn't signalled in any way)\n\tString & operator += (const String &rhs)\t{concat(rhs); return (*this);}\n\tString & operator += (const char *cstr)\t\t{concat(cstr); return (*this);}\n\tString & operator += (char c)\t\t\t{concat(c); return (*this);}\n\tString & operator += (unsigned char num)\t\t{concat(num); return (*this);}\n\tString & operator += (int num)\t\t\t{concat(num); return (*this);}\n\tString & operator += (unsigned int num)\t\t{concat(num); return (*this);}\n\tString & operator += (long num)\t\t\t{concat(num); return (*this);}\n\tString & operator += (unsigned long num)\t{concat(num); return (*this);}\n\tString & operator += (float num)\t\t{concat(num); return (*this);}\n\t//String & operator += (double num)\t\t{concat(num); return (*this);}\n\tString & operator += (const __FlashStringHelper *str){concat(str); return (*this);}\n\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, char c);\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, int num);\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, long num);\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);\n\tfriend StringSumHelper & operator + (const StringSumHelper &lhs, float num);\n\t//friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);\n\t//friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs);\n\n\t// comparison (only works w/ Strings and \"strings\")\n\toperator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }\n\tint compareTo(const String &s) const;\n\tint compareTo(const char *cstr) const;\n\tunsigned char equals(const String &s) const;\n\tunsigned char equals(const char *cstr) const;\n\n\tfriend unsigned char operator == (const String &a, const String &b) { return a.equals(b); }\n\tfriend unsigned char operator == (const String &a, const char   *b) { return a.equals(b); }\n\tfriend unsigned char operator == (const char   *a, const String &b) { return b == a; }\n\tfriend unsigned char operator <  (const String &a, const String &b) { return a.compareTo(b) < 0; }\n\tfriend unsigned char operator <  (const String &a, const char   *b) { return a.compareTo(b) < 0; }\n\tfriend unsigned char operator <  (const char   *a, const String &b) { return b.compareTo(a) > 0; }\n\n\tfriend unsigned char operator != (const String &a, const String &b) { return !(a == b); }\n\tfriend unsigned char operator != (const String &a, const char   *b) { return !(a == b); }\n\tfriend unsigned char operator != (const char   *a, const String &b) { return !(a == b); }\n\tfriend unsigned char operator >  (const String &a, const String &b) { return b < a; }\n\tfriend unsigned char operator >  (const String &a, const char   *b) { return b < a; }\n\tfriend unsigned char operator >  (const char   *a, const String &b) { return b < a; }\n\tfriend unsigned char operator <= (const String &a, const String &b) { return !(b < a); }\n\tfriend unsigned char operator <= (const String &a, const char   *b) { return !(b < a); }\n\tfriend unsigned char operator <= (const char   *a, const String &b) { return !(b < a); }\n\tfriend unsigned char operator >= (const String &a, const String &b) { return !(a < b); }\n\tfriend unsigned char operator >= (const String &a, const char   *b) { return !(a < b); }\n\tfriend unsigned char operator >= (const char   *a, const String &b) { return !(a < b); }\n\n\tunsigned char equalsIgnoreCase(const String &s) const;\n\tunsigned char startsWith( const String &prefix) const;\n\tunsigned char startsWith(const String &prefix, unsigned int offset) const;\n\tunsigned char endsWith(const String &suffix) const;\n\n\t// character acccess\n\tchar charAt(unsigned int index) const;\n\tvoid setCharAt(unsigned int index, char c);\n\tchar operator [] (unsigned int index) const;\n\tchar& operator [] (unsigned int index);\n\tvoid getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;\n\tvoid toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const\n\t\t{ getBytes((unsigned char *)buf, bufsize, index); }\n\tconst char* c_str() const { return buffer; }\n\tchar* begin() { return buffer; }\n\tchar* end() { return buffer + length(); }\n\tconst char* begin() const { return c_str(); }\n\tconst char* end() const { return c_str() + length(); }\n\n\t// search\n\tint indexOf( char ch ) const;\n\tint indexOf( char ch, unsigned int fromIndex ) const;\n\tint indexOf( const String &str ) const;\n\tint indexOf( const String &str, unsigned int fromIndex ) const;\n\tint lastIndexOf( char ch ) const;\n\tint lastIndexOf( char ch, unsigned int fromIndex ) const;\n\tint lastIndexOf( const String &str ) const;\n\tint lastIndexOf( const String &str, unsigned int fromIndex ) const;\n\tString substring( unsigned int beginIndex ) const { return substring(beginIndex, len); };\n\tString substring( unsigned int beginIndex, unsigned int endIndex ) const;\n\n\t// modification\n\tvoid replace(char find, char replace);\n\tvoid replace(const String& find, const String& replace);\n\tvoid remove(unsigned int index);\n\tvoid remove(unsigned int index, unsigned int count);\n\tvoid toLowerCase(void);\n\tvoid toUpperCase(void);\n\tvoid trim(void);\n\n\t// parsing/conversion\n\tlong toInt(void) const;\n\tfloat toFloat(void) const;\n\tdouble toDouble(void) const;\n\nprotected:\n\tchar *buffer;\t        // the actual char array\n\tunsigned int capacity;  // the array length minus one (for the '\\0')\n\tunsigned int len;       // the String length (not counting the '\\0')\nprotected:\n\tvoid init(void);\n\tvoid invalidate(void);\n\tunsigned char changeBuffer(unsigned int maxStrLen);\n\tunsigned char concat(const char *cstr, unsigned int length);\n\n\t// copy and move\n\tString & copy(const char *cstr, unsigned int length);\n\tString & copy(const __FlashStringHelper *pstr, unsigned int length);\n\t#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)\n\tvoid move(String &rhs);\n\t#endif\n};\n\nclass StringSumHelper : public String\n{\npublic:\n    StringSumHelper(const String &s) : String(s) {}\n    StringSumHelper(const char *p) : String(p) {}\n    StringSumHelper(char c) : String(c) {}\n    StringSumHelper(unsigned char num) : String(num) {}\n    StringSumHelper(int num) : String(num) {}\n    StringSumHelper(unsigned int num) : String(num) {}\n    StringSumHelper(long num) : String(num) {}\n    StringSumHelper(unsigned long num) : String(num) {}\n    //StringSumHelper(float num) : String(num) {}\n    //StringSumHelper(double num) : String(num) {}\n};\n\n} // namespace arduino\n\n#endif  // __cplusplus\n#endif  // __ARDUINO_STRINGS__\n"
  },
  {
    "path": "extras/test/include/util/TestUtil.h",
    "content": "/*\n * Copyright (c) 2020 Arduino.  All rights reserved.\n */\n"
  },
  {
    "path": "extras/test/include/util/itoa.h",
    "content": "/*\n  Copyright (c) 2016 Arduino LLC.  All right reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n  See the GNU Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#pragma once\n\n// Standard C functions required in Arduino API\n// If these functions are not provided by the standard library, the\n// core should supply an implementation of them.\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern char* itoa(int value, char *string, int radix);\nextern char* ltoa(long value, char *string, int radix);\nextern char* utoa(unsigned value, char *string, int radix);\nextern char* ultoa(unsigned long value, char *string, int radix);\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n"
  },
  {
    "path": "extras/test/src/Arduino.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n/******************************************************************************\n   INCLUDE\n ******************************************************************************/\n\n#include <Arduino.h>\n\n/******************************************************************************\n   GLOBAL VARIABLES\n ******************************************************************************/\n\nstatic unsigned long current_millis = 0;\n\n/******************************************************************************\n   PUBLIC FUNCTIONS\n ******************************************************************************/\n\nvoid set_millis(unsigned long const millis)\n{\n  current_millis = millis;\n}\n\nunsigned long millis()\n{\n  return current_millis;\n}\n"
  },
  {
    "path": "extras/test/src/test_advertising_data/FakeBLELocalDevice.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"FakeBLELocalDevice.h\"\n\nFakeBLELocalDevice::FakeBLELocalDevice()\n{\n\n}\n\nFakeBLELocalDevice::~FakeBLELocalDevice()\n{\n\n}\n\nint FakeBLELocalDevice::advertise()\n{\n  _advertisingData.updateData();\n  _scanResponseData.updateData();\n  return 1;\n}\n\nFakeBLELocalDevice FakeBLEObj;\nBLELocalDevice& BLE = FakeBLEObj;\n"
  },
  {
    "path": "extras/test/src/test_advertising_data/test_advertising_data.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <catch2/catch_test_macros.hpp>\n\n#define private public\n#define protected public\n\n#include \"FakeBLELocalDevice.h\"\n#include \"BLEAdvertisingData.h\"\n\nTEST_CASE(\"Test flags override\", \"[ArduinoBLE::BLEAdvertisingData]\")\n{\n  // Mocking advertisement packet\n  BLEAdvertisingData advData;\n  // Expected results\n  const uint8_t defaultData[] = {0x02, BLEFieldFlags, 0x06};\n  const uint8_t goldenFlags[] = {0x02, 0x01, BLEFlagsBREDRNotSupported};\n\n  WHEN(\"Default options for flags\")\n  {\n    BLE.advertise();\n    REQUIRE( 0 == (memcmp(defaultData, BLE.getAdvertisingData().data(), sizeof(defaultData))) );\n    REQUIRE( BLE.getScanResponseData().dataLength() == 0 );\n  }\n\n  WHEN(\"Setting external advertising data which has flags\")\n  {\n    advData.setFlags(BLEFlagsBREDRNotSupported);\n    advData.updateData();\n    BLE.setAdvertisingData(advData);\n    BLE.advertise();\n    REQUIRE( 3 == BLE.getAdvertisingData().dataLength());\n    REQUIRE( 0 == (memcmp(goldenFlags, advData.data(), sizeof(goldenFlags))) );\n    REQUIRE( 0 == (memcmp(goldenFlags, BLE.getAdvertisingData().data(), sizeof(goldenFlags))) );\n    REQUIRE( 0 != (memcmp(defaultData, BLE.getAdvertisingData().data(), sizeof(defaultData))) );\n  }\n\n  WHEN(\"Setting external advertising data without flags\")\n  {\n    advData.clear();\n    BLE.setAdvertisingData(advData);\n    BLE.advertise();\n    REQUIRE( 0 == (memcmp(defaultData, BLE.getAdvertisingData().data(), sizeof(defaultData))) );\n  }\n\n  // Clear BLE advertising data\n  advData.clear();\n  BLE.setAdvertisingData(advData);\n}\n\nTEST_CASE(\"Set default flags in an already full advertising data packet\", \"[ArduinoBLE::BLEAdvertisingData]\")\n{\n    BLEAdvertisingData advData;\n    bool retVal;\n\n    const char* name = \"tes\";\n    const uint8_t manufacturerData[24] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n                                          17, 18, 19, 20, 21, 22, 23};\n\n    const uint8_t defaultFlags[3] = {0x02, 0x01, 0x06}; \n\n    const uint8_t goldenData[31] = { \n       (sizeof(manufacturerData) + 1), BLEFieldManufacturerData, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n                                                                17, 18, 19, 20, 21, 22, 23,\n        ((uint8_t)(strlen(name) + 1)), BLEFieldCompleteLocalName, 't', 'e', 's'\n    }; \n\n  WHEN(\"Test flags when advertising data is full\")\n  {\n    retVal = advData.setLocalName(\"tes\");\n    retVal = advData.setManufacturerData(manufacturerData, sizeof(manufacturerData));\n\n    BLE.setAdvertisingData(advData);\n    BLE.advertise();\n    REQUIRE(0 != memcmp(defaultFlags, BLE.getAdvertisingData().data(), sizeof(defaultFlags)));\n    REQUIRE(0 == memcmp(goldenData, BLE.getAdvertisingData().data(), sizeof(goldenData)));\n  }\n\n  // Clear BLE advertising data\n  advData.clear();\n  BLE.setAdvertisingData(advData);\n}\n\nTEST_CASE(\"BLE overwrite a full internal advertising data with an external built one\", \"[ArduinoBLE::BLEAdvertisingData]\")\n{\n  bool verify;\n  BLEAdvertisingData advData;\n  BLEAdvertisingData internalData;\n\n  WHEN(\"Copy empty external advertising data\")\n  {\n    BLE.setLocalName(\"test\");\n    BLE.setAdvertisedServiceUuid(\"1818\");\n    BLE.advertise();\n\n    THEN(\"Check that BLE advertising data has been set\") \n    {\n      verify = (BLE.getAdvertisingData().dataLength() == (3 + (2+2)));\n      REQUIRE(verify);\n    }\n\n    THEN(\"Check that BLE scan response data has been set\") \n    {\n      verify = (BLE.getScanResponseData().dataLength() == (4+2));\n      REQUIRE(verify);\n    }\n\n    // Copy external empty adv data into advertising data\n    BLE.setAdvertisingData(advData);\n    BLE.advertise();\n    THEN(\"BLE advertising data should be erased\") \n    {\n      verify = (BLE.getAdvertisingData().dataLength() == 3);\n      REQUIRE(verify);\n    }\n\n    // Copy external empty adv data into scan response data\n    BLE.setScanResponseData(advData);\n    BLE.advertise();\n    THEN(\"BLE scan response data should be erased\") \n    {\n      verify = (BLE.getScanResponseData().dataLength() == 0);\n      REQUIRE(verify);\n    }\n  }\n\n  // Clear BLE advertising data\n  advData.clear();\n  BLE.setAdvertisingData(advData);\n}\n\nTEST_CASE(\"BLE test raw data\", \"[ArduinoBLE::BLEAdvertisingData]\")\n{\n  BLEAdvertisingData advData;\n  bool retVal;\n\n  WHEN(\"Set too large raw data\")\n  {\n    const uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n                      11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n                      21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };\n    retVal = advData.setRawData(data, sizeof(data));\n    THEN(\"Set raw data should return false. The parameter should not be set\")\n    {\n      REQUIRE(!retVal);\n    }\n    advData.clear();\n  }\n\n  WHEN(\"Set correct raw data\")\n  {\n    const uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n                      11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n                      21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};\n    retVal = advData.setRawData(data, sizeof(data));\n    THEN(\"Set raw data should return true. The parameter should be correctly set\")\n    {\n      REQUIRE(retVal);\n    }\n    advData.updateData();\n    REQUIRE( 0 == memcmp(data, advData.data(), sizeof(data)) );\n    advData.clear();\n  }\n\n  WHEN(\"Hide other parameters by setting raw data\")\n  {\n    const uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\n    advData.setLocalName(\"test\");\n    advData.setRawData(data, sizeof(data));\n\n    advData.updateData();\n    REQUIRE( 0 == memcmp(data, advData.data(), sizeof(data)) );\n\n    advData.setLocalName(\"test\");\n    advData.updateData();\n    REQUIRE( 0 == memcmp(data, advData.data(), sizeof(data)) );\n    \n    advData.clear();\n    advData.setLocalName(\"test\");\n    advData.updateData();\n    REQUIRE( 0 != memcmp(data, advData.data(), sizeof(data)) );\n  }\n\n  // Clear BLE advertising data\n  advData.clear();\n  BLE.setAdvertisingData(advData);\n}\n"
  },
  {
    "path": "extras/test/src/test_advertising_data/test_local_name.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <catch2/catch_test_macros.hpp>\n\n#define private public\n#define protected public\n\n#include \"FakeBLELocalDevice.h\"\n#include \"BLEAdvertisingData.h\"\n\nTEST_CASE(\"Test local name setting\", \"[ArduinoBLE::BLEAdvertisingData]\")\n{\n  BLEAdvertisingData advData;\n  int oldRemainingLength = advData.remainingLength();\n  bool retVal;\n\n  WHEN(\"Set correct local name\")\n  {\n    const char* name = \"test\";\n    retVal = advData.setLocalName(name);\n    THEN(\"Set local name should return true. The name parameter should be correctly set\")\n    {\n      REQUIRE(retVal);\n    }\n\n    THEN(\"Check the exact number of bytes occupied by the name just set\")\n    {\n      REQUIRE( (strlen(name) + 2) == (oldRemainingLength - advData.remainingLength()) );\n    }\n    oldRemainingLength = advData.remainingLength();\n\n    advData.updateData();\n    REQUIRE(advData.dataLength() == (strlen(name) + 2));\n  }\n\n  WHEN(\"Set too long local name\")\n  {\n    const char* name = \"way too long local name (len 32)\";\n    retVal = advData.setLocalName(name);\n    THEN(\"Set local name should return false. The name parameter should not be set\")\n    {\n      REQUIRE(!retVal);\n      REQUIRE( oldRemainingLength == advData.remainingLength() );\n      advData.updateData();\n      REQUIRE( advData.dataLength() == (MAX_AD_DATA_LENGTH - oldRemainingLength) );\n    }\n  }\n\n  WHEN(\"Overwrite local name with a name as long as max data length\")\n  {\n    const char* name = \"local name with full length  \";\n    retVal = advData.setLocalName(name);\n    THEN(\"The name parameter should be correctly overwritten. The remaining length should be 0\")\n    {\n      REQUIRE(retVal);\n      REQUIRE( (strlen(name) + 2) == (oldRemainingLength - advData.remainingLength()) );\n      oldRemainingLength = advData.remainingLength();\n\n      advData.updateData();\n      REQUIRE(advData.dataLength() == (strlen(name) + 2));\n      // advData should be full now\n      REQUIRE( 0 == advData.remainingLength() );\n      REQUIRE( 0 == advData.availableForWrite() );\n    }\n  }\n\n  WHEN(\"Check consistency when setting the external advertising data\")\n  {\n    const auto goldenData = advData.data();\n    BLE.setAdvertisingData(advData);\n    BLE.advertise();\n    REQUIRE( 0 == memcmp(goldenData, BLE.getAdvertisingData().data(), advData.dataLength()) );\n  }\n\n  // Clear BLE advertising data\n  advData.clear();\n  BLE.setAdvertisingData(advData);\n}\n"
  },
  {
    "path": "extras/test/src/test_advertising_data/test_manufacturer.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <catch2/catch_test_macros.hpp>\n\n#define private public\n#define protected public\n\n#include \"FakeBLELocalDevice.h\"\n#include \"BLEAdvertisingData.h\"\n\nTEST_CASE(\"Test manufacturer data setting\", \"[ArduinoBLE::BLEAdvertisingData]\")\n{\n  BLEAdvertisingData advData;\n  int oldRemainingLength = advData.remainingLength();\n  const uint16_t companyId = 0x1100;\n  bool retVal;\n\n  WHEN(\"Set correct manufacturer data without id\")\n  {\n    const uint8_t data[] = {0x00, 0x11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    const uint8_t goldenData[] = {(sizeof(data) + 1), BLEFieldManufacturerData, \n                                  0x00, 0x11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    retVal = advData.setManufacturerData(data, sizeof(data));\n    THEN(\"Check that the manufacturer data has been correctly set\")\n    {\n      REQUIRE(retVal);\n      REQUIRE( (sizeof(data) + 2) == (oldRemainingLength - advData.remainingLength()) );\n    }\n    oldRemainingLength = advData.remainingLength();\n\n    advData.updateData();\n    REQUIRE(advData.dataLength() == sizeof(goldenData));\n    REQUIRE( 0 == memcmp(goldenData, advData.data(), sizeof(goldenData)) );\n  }\n\n  WHEN(\"Set correct manufacturer data given a manufacturer id\")\n  {\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    const uint8_t goldenData[] = {(sizeof(data) + sizeof(companyId) + 1), BLEFieldManufacturerData, \n                                  0x00, 0x11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    retVal = advData.setManufacturerData(companyId, data, sizeof(data));\n    THEN(\"Check that the manufacturer data has been correctly set\")\n    {\n      REQUIRE(retVal);\n      REQUIRE( (sizeof(data) + sizeof(companyId) + 2) == (oldRemainingLength - advData.remainingLength()) );\n    }\n    oldRemainingLength = advData.remainingLength();\n\n    advData.updateData();\n    REQUIRE(advData.dataLength() == sizeof(goldenData));\n    REQUIRE( 0 == memcmp(goldenData, advData.data(), sizeof(goldenData)) );\n  }\n\n  WHEN(\"Set too long manufacturer data given id\")\n  {\n    // extreme case, 1 byte more than the maximum\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};\n    retVal = advData.setManufacturerData(companyId, data, sizeof(data));\n    THEN(\"Manufacturer data was too long, check that it has not been set\")\n    {\n      REQUIRE(!retVal);\n      REQUIRE( oldRemainingLength == advData.remainingLength() );\n    }\n    advData.updateData();\n    REQUIRE( advData.dataLength() == (MAX_AD_DATA_LENGTH - oldRemainingLength) );\n  }\n\n  WHEN(\"Set too long manufacturer data without id\")\n  {\n    // extreme case, 1 byte more than the maximum\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29};\n    retVal = advData.setManufacturerData(data, sizeof(data));\n    THEN(\"Manufacturer data was too long, check that it has not been set\")\n    {\n      REQUIRE(!retVal);\n      REQUIRE( oldRemainingLength == advData.remainingLength() );\n    }\n    advData.updateData();\n    REQUIRE( advData.dataLength() == (MAX_AD_DATA_LENGTH - oldRemainingLength) );\n  }\n\n  WHEN(\"Set manufacturer data without id after setting manufacturer data given id\")\n  {\n    advData.clear();\n    const uint8_t dataGivenId[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                                  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28};\n    THEN(\"Check that first insertion of manufacturer data given id is correctly done\")\n    {\n      retVal = advData.setManufacturerData(companyId, dataGivenId, sizeof(dataGivenId));\n      REQUIRE(retVal);\n    }\n    THEN(\"Check that the insertion of manufacturer data without after one with id is correctly done\")\n    {\n      retVal = advData.setManufacturerData(data, sizeof(data));\n      REQUIRE(retVal);\n      REQUIRE( 0 == advData.remainingLength() );\n      advData.updateData();\n      REQUIRE( advData.dataLength() == (MAX_AD_DATA_LENGTH) );\n    }\n  }\n\n  WHEN(\"Set manufacturer data given id after setting manufacturer data without id\")\n  {\n    advData.clear();\n    // dataGivenId is too long!! it should not pass\n    const uint8_t dataGivenId[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                                  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28};\n    THEN(\"Check that first insertion of manufacturer data WITHOUT id is correctly done\")\n    {\n      retVal = advData.setManufacturerData(data, sizeof(data));\n      REQUIRE(retVal);\n    }\n    THEN(\"Check that the insertion of manufacturer data given id after one without id is correctly done\")\n    {\n      retVal = advData.setManufacturerData(companyId, dataGivenId, sizeof(dataGivenId));\n      REQUIRE(!retVal);\n    }\n  }\n\n  WHEN(\"Overwrite manufacturer data with one as long as max data length\")\n  {\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};\n    const uint8_t goldenData[] = {(sizeof(data) + sizeof(companyId) + 1), BLEFieldManufacturerData, \n                                  0x00, 0x11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\n                                  12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};\n    retVal = advData.setManufacturerData(companyId, data, sizeof(data));\n    THEN(\"Manufacturer data should be set correctly\")\n    {\n      REQUIRE(retVal);\n\n      advData.updateData();\n      REQUIRE( 0 == advData.remainingLength() );\n      REQUIRE( 0 == advData.availableForWrite() );\n      REQUIRE( 0 == memcmp(goldenData, advData.data(), sizeof(goldenData)) );\n    }\n  }\n\n  WHEN(\"Check consistency when setting the external advertising data\")\n  {\n    const auto goldenData = advData.data();\n    BLE.setAdvertisingData(advData);\n    BLE.advertise();\n    REQUIRE( 0 == memcmp(goldenData, BLE.getAdvertisingData().data(), advData.dataLength()) );\n  }\n\n  // Clear BLE advertising data\n  advData.clear();\n  BLE.setAdvertisingData(advData);\n}\n"
  },
  {
    "path": "extras/test/src/test_advertising_data/test_service.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <catch2/catch_test_macros.hpp>\n\n#define private public\n#define protected public\n\n#include \"FakeBLELocalDevice.h\"\n#include \"BLEAdvertisingData.h\"\n\nTEST_CASE(\"Test advertised service id setting\", \"[ArduinoBLE::BLEAdvertisingData]\")\n{\n  BLEAdvertisingData advData;\n  int oldRemainingLength = advData.remainingLength();\n  bool retVal;\n\n  WHEN(\"Set correct advertised service\")\n  {\n    const char* service = \"00112233445566770011223344556677\";\n    retVal = advData.setAdvertisedServiceUuid(service);\n    REQUIRE(retVal);\n    REQUIRE( (16 + 2) == (oldRemainingLength - advData.remainingLength()) );\n    oldRemainingLength = advData.remainingLength();\n\n    advData.updateData();\n    REQUIRE(advData.dataLength() == (16 + 2));\n  }\n\n  WHEN(\"Set an advertised id too long with respect to the remaining length\")\n  {\n    advData.clear();\n    const char* name = \"12 chars str\";\n    const char* service = \"00112233445566770011223344556677\";\n    advData.setLocalName(name);\n    oldRemainingLength = advData.remainingLength();\n    THEN(\"Check that the too long parameter has not been set\")\n    {\n      REQUIRE(!advData.setAdvertisedServiceUuid(service)); \n      REQUIRE( oldRemainingLength == advData.remainingLength() );\n      advData.updateData();\n      REQUIRE( advData.dataLength() == (MAX_AD_DATA_LENGTH - oldRemainingLength) );\n    }\n  }\n\n  WHEN(\"Fill to maximum an advertising packet with a service id\")\n  {\n    advData.clear();\n    const char* name = \"11 char str\";\n    const char* service = \"00112233445566770011223344556677\";\n    advData.setLocalName(name);\n    REQUIRE(advData.setAdvertisedServiceUuid(service));\n\n    advData.updateData();\n    REQUIRE(advData.dataLength() == (MAX_AD_DATA_LENGTH));\n    // advData should be full now\n    REQUIRE( 0 == advData.remainingLength() );\n    REQUIRE( 0 == advData.availableForWrite() );\n  }\n\n  WHEN(\"Check consistency when setting the external advertising data\")\n  {\n    const auto goldenData = advData.data();\n    BLE.setAdvertisingData(advData);\n    BLE.advertise();\n    REQUIRE( 0 == memcmp(goldenData, BLE.getAdvertisingData().data(), advData.dataLength()) );\n  }\n\n  // Clear BLE advertising data\n  advData.clear();\n  BLE.setAdvertisingData(advData);\n}\n\nTEST_CASE(\"Test service data setting\", \"[ArduinoBLE::BLEAdvertisingData]\")\n{\n  BLEAdvertisingData advData;\n  int oldRemainingLength = advData.remainingLength();\n  const uint16_t uuid = 0x1100;\n  bool retVal;\n\n  WHEN(\"Set correct service data\")\n  {\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    const uint8_t goldenData[] = {(sizeof(data) + sizeof(uuid) + 1), BLEFieldServiceData, \n                                  0x00, 0x11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    retVal = advData.setAdvertisedServiceData(uuid, data, sizeof(data));\n    THEN(\"Correctly set parameter\")\n    {\n      REQUIRE(retVal);\n      REQUIRE( (sizeof(data) + 2 + sizeof(uuid)) == (oldRemainingLength - advData.remainingLength()) );\n    }\n    oldRemainingLength = advData.remainingLength();\n\n    advData.updateData();\n    THEN(\"Check parameter analyzing advertising raw data\")\n    {\n      REQUIRE(advData.dataLength() == (sizeof(data) + 2 + sizeof(uuid)));\n      REQUIRE(advData.dataLength() == sizeof(goldenData));\n      REQUIRE( 0 == memcmp(goldenData, advData.data(), sizeof(goldenData)) );\n    }\n  }\n\n  WHEN(\"Set too long service data\")\n  {\n    // extreme case, 1 byte more than the maximum\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};\n    retVal = advData.setAdvertisedServiceData(uuid, data, sizeof(data));\n    THEN(\"Check that the too long parameter has not been set\")\n    {\n      REQUIRE(!retVal);\n    }\n    REQUIRE( oldRemainingLength == advData.remainingLength() );\n    advData.updateData();\n    REQUIRE( advData.dataLength() == (MAX_AD_DATA_LENGTH - oldRemainingLength) );\n  }\n\n  WHEN(\"Overwrite service data with one as long as max data length\")\n  {\n    const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n                            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};\n    retVal = advData.setAdvertisedServiceData(uuid, data, sizeof(data));\n    THEN(\"Check correctly set parameter\")\n    {\n      REQUIRE(retVal);\n    }\n\n    advData.updateData();\n    // advData should be full now\n    THEN(\"advData should be full now\")\n    {\n      REQUIRE( 0 == advData.remainingLength() );\n      REQUIRE( 0 == advData.availableForWrite() );\n    }\n  }\n\n  WHEN(\"Check consistency when setting the external advertising data\")\n  {\n    const auto goldenData = advData.data();\n    BLE.setAdvertisingData(advData);\n    BLE.advertise();\n    REQUIRE( 0 == memcmp(goldenData, BLE.getAdvertisingData().data(), advData.dataLength()) );\n  }\n\n  // Clear BLE advertising data\n  advData.clear();\n  BLE.setAdvertisingData(advData);\n}\n"
  },
  {
    "path": "extras/test/src/test_characteristic/test_permissions.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <catch2/catch_test_macros.hpp>\n\n#define private public\n#define protected public\n\n#include \"FakeBLELocalDevice.h\"\n#include \"BLEAdvertisingData.h\"\n#include \"BLETypedCharacteristics.h\"\n#include \"BLELocalCharacteristic.h\"\n#include \"BLEStringCharacteristic.h\"\n#include \"BLEProperty.h\"\n#include <memory>\n\nint property[] = {\n  BLEBroadcast,\n  BLERead,\n  BLEWriteWithoutResponse,\n  BLEWrite,\n  BLENotify,\n  BLEIndicate,\n  BLEAuthSignedWrite,\n  BLEExtProp,\n  BLERead | BLEWrite | BLENotify\n};\n\nint permission[] = {\n  BLEEncryption,\n  BLEAuthentication,\n  BLEAuthorization,\n  BLEEncryption | BLEAuthentication\n};\n\nconst char uuid[][31] = {\n  \"1 Bool\",\n  \"2 Char\",\n  \"3 UnsignedChar\",\n  \"4 Byte\",\n  \"5 Short\",\n  \"6 UnsignedShort\",\n  \"7 Word\",\n  \"8 Int\",\n  \"9 UnsignedInt\",\n  \"A Long\",\n  \"B UnsignedLong\",\n  \"C Float\",\n  \"D Double\",\n  \"E String\"\n};\n\nstd::unique_ptr<BLECharacteristic> createCharacteristic(const char* uuid, unsigned int properties)\n{\n  switch(uuid[0])\n  {\n    case '1':\n      return std::unique_ptr<BLECharacteristic>(new BLEBoolCharacteristic(uuid, properties));\n    case '2':\n      return std::unique_ptr<BLECharacteristic>(new BLECharCharacteristic(uuid, properties));\n    case '3':\n      return std::unique_ptr<BLECharacteristic>(new BLEUnsignedCharCharacteristic(uuid, properties));\n    case '4':\n      return std::unique_ptr<BLECharacteristic>(new BLEByteCharacteristic(uuid, properties));\n    case '5':\n      return std::unique_ptr<BLECharacteristic>(new BLEShortCharacteristic(uuid, properties));\n    case '6':\n      return std::unique_ptr<BLECharacteristic>(new BLEUnsignedShortCharacteristic(uuid, properties));\n    case '7':\n      return std::unique_ptr<BLECharacteristic>(new BLEWordCharacteristic(uuid, properties));\n    case '8':\n      return std::unique_ptr<BLECharacteristic>(new BLEIntCharacteristic(uuid, properties));\n    case '9':\n      return std::unique_ptr<BLECharacteristic>(new BLEUnsignedIntCharacteristic(uuid, properties));\n    case 'A':\n      return std::unique_ptr<BLECharacteristic>(new BLELongCharacteristic(uuid, properties));\n    case 'B':\n      return std::unique_ptr<BLECharacteristic>(new BLEUnsignedLongCharacteristic(uuid, properties));\n    case 'C':\n      return std::unique_ptr<BLECharacteristic>(new BLEFloatCharacteristic(uuid, properties));\n    case 'D':\n      return std::unique_ptr<BLECharacteristic>(new BLEDoubleCharacteristic(uuid, properties));\n    case 'E':\n      return std::unique_ptr<BLECharacteristic>(new BLEStringCharacteristic(uuid, properties, 2));\n    default:\n      break;\n  }\n  return nullptr;\n}\n\nTEST_CASE(\"Test characteristic properties and permissions\", \"[ArduinoBLE::BLECharacteristic]\")\n{\n  WHEN(\"Create a characteristic\")\n  {\n    for(int i = 0; i < sizeof(property)/sizeof(int); i++)\n    {\n      for(int j = 0; j < sizeof(permission)/sizeof(int); j++)\n      {\n        for(int k = 0; k < 14; k++)\n        {\n          std::unique_ptr<BLECharacteristic> ptr = createCharacteristic(uuid[k], property[i] | permission[j]);\n          REQUIRE(ptr != nullptr);\n          REQUIRE(ptr->properties() == (property[i]));\n          BLELocalCharacteristic * local  = ptr->local();\n          REQUIRE(local->permissions() == (permission[j] >> 8));\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "extras/test/src/test_characteristic/test_writeValue.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <catch2/catch_test_macros.hpp>\n\n#define private public\n#define protected public\n\n#include \"FakeBLELocalDevice.h\"\n#include \"BLEAdvertisingData.h\"\n#include \"BLETypedCharacteristics.h\"\n#include \"BLELocalCharacteristic.h\"\n#include \"BLEStringCharacteristic.h\"\n#include \"BLEProperty.h\"\n\n\nTEST_CASE(\"Test characteristic writeValue\", \"[ArduinoBLE::BLECharacteristic]\")\n{\n  WHEN(\"Create a bool characteristic\")\n  {\n    BLEBoolCharacteristic boolCharacteristic(\"Bool\", BLEBroadcast| BLEIndicate | BLENotify );\n    bool v = false;;\n    int written = boolCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(bool) );\n\n    boolCharacteristic.broadcast();\n    written = boolCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(bool) );\n\n    BLEDevice device;\n    boolCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = boolCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    boolCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = boolCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a boolean characteristic\")\n  {\n    BLEBooleanCharacteristic booleanCharacteristic(\"Boolean\", BLEBroadcast| BLEIndicate | BLENotify);\n    bool v = false;\n    int written = booleanCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(bool) );\n\n    booleanCharacteristic.broadcast();\n    written = booleanCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(bool) );\n\n    BLEDevice device;\n    booleanCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = booleanCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    booleanCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = booleanCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a char characteristic\")\n  {\n    BLECharCharacteristic charCharacteristic(\"Char\", BLEBroadcast| BLEIndicate | BLENotify);\n    char v = 'a';\n    int written = charCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(char) );\n\n    charCharacteristic.broadcast();\n    written = charCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(char) );\n\n    BLEDevice device;\n    charCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = charCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    charCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = charCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a unsigned char characteristic\")\n  {\n    BLEUnsignedCharCharacteristic unsignedCharCharacteristic(\"UnsignedChar\", BLEBroadcast| BLEIndicate | BLENotify);\n    unsigned char v = 0x01;\n    int written = unsignedCharCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(unsigned char) );\n\n    unsignedCharCharacteristic.broadcast();\n    written = unsignedCharCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(unsigned char) );\n\n    BLEDevice device;\n    unsignedCharCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = unsignedCharCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    unsignedCharCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = unsignedCharCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a byte characteristic\")\n  {\n    BLEByteCharacteristic byteCharacteristic(\"Byte\", BLEBroadcast| BLEIndicate | BLENotify);\n    byte v = 0x01;\n    int written = byteCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(byte) );\n\n    byteCharacteristic.broadcast();\n    written = byteCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(byte) );\n\n    BLEDevice device;\n    byteCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = byteCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    byteCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = byteCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a short characteristic\")\n  {\n    BLEShortCharacteristic shortCharacteristic(\"Short\", BLEBroadcast| BLEIndicate | BLENotify);\n    short v = -1;\n    int written = shortCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(short) );\n\n    shortCharacteristic.broadcast();\n    written = shortCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(short) );\n\n    BLEDevice device;\n    shortCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = shortCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    shortCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = shortCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a unsigned short characteristic\")\n  {\n    BLEUnsignedShortCharacteristic unsignedShortCharacteristic(\"UnsignedShort\", BLEBroadcast| BLEIndicate | BLENotify);\n    unsigned short v = 1;\n    int written = unsignedShortCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(unsigned short) );\n\n    unsignedShortCharacteristic.broadcast();\n    written = unsignedShortCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(unsigned short) );\n\n    BLEDevice device;\n    unsignedShortCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = unsignedShortCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    unsignedShortCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = unsignedShortCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a word characteristic\")\n  {\n    BLEWordCharacteristic wordCharacteristic(\"Word\", BLEBroadcast| BLEIndicate | BLENotify);\n    word v = -1;\n    int written = wordCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(word) );\n\n    wordCharacteristic.broadcast();\n    written = wordCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(word) );\n\n    BLEDevice device;\n    wordCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = wordCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    wordCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = wordCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a int characteristic\")\n  {\n    BLEIntCharacteristic intCharacteristic(\"Int\", BLEBroadcast| BLEIndicate | BLENotify);\n    int v = -1;\n    int written = intCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(int) );\n\n    intCharacteristic.broadcast();\n    written = intCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(int) );\n\n    BLEDevice device;\n    intCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = intCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    intCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = intCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a unsigned int characteristic\")\n  {\n    BLEUnsignedIntCharacteristic unsignedIntCharacteristic(\"UnsignedInt\", BLEBroadcast| BLEIndicate | BLENotify);\n    unsigned int v = 1;\n    int written = unsignedIntCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(unsigned int) );\n\n    unsignedIntCharacteristic.broadcast();\n    written = unsignedIntCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(unsigned int) );\n\n    BLEDevice device;\n    unsignedIntCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = unsignedIntCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    unsignedIntCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = unsignedIntCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a long characteristic\")\n  {\n    BLELongCharacteristic longCharacteristic(\"Long\", BLEBroadcast| BLEIndicate | BLENotify);\n    long v = -1;\n    int written = longCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(long) );\n\n    longCharacteristic.broadcast();\n    written = longCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(long) );\n\n    BLEDevice device;\n    longCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = longCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    longCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = longCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a unsigned long characteristic\")\n  {\n    BLEUnsignedLongCharacteristic unsignedLongCharacteristic(\"UnsignedLong\", BLEBroadcast| BLEIndicate | BLENotify);\n    unsigned long v = 1;\n    int written = unsignedLongCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(unsigned long) );\n\n    unsignedLongCharacteristic.broadcast();\n    written = unsignedLongCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(unsigned long) );\n\n    BLEDevice device;\n    unsignedLongCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = unsignedLongCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    unsignedLongCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = unsignedLongCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a float characteristic\")\n  {\n    BLEFloatCharacteristic floatCharacteristic(\"Float\", BLEBroadcast| BLEIndicate | BLENotify);\n    float v = -1.0f;\n    int written = floatCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(float) );\n\n    floatCharacteristic.broadcast();\n    written = floatCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(float) );\n\n    BLEDevice device;\n    floatCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = floatCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    floatCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = floatCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a double characteristic\")\n  {\n    BLEDoubleCharacteristic doubleCharacteristic(\"Double\", BLEBroadcast| BLEIndicate | BLENotify);\n    double v = -1.0;\n    int written = doubleCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(double) );\n\n    doubleCharacteristic.broadcast();\n    written = doubleCharacteristic.writeValue(v);\n    REQUIRE( written == sizeof(double) );\n\n    BLEDevice device;\n    doubleCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = doubleCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    doubleCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = doubleCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a string characteristic\")\n  {\n    const int maxStringLength = 64;\n    BLEStringCharacteristic stringCharacteristic(\"String\", BLEBroadcast| BLEIndicate | BLENotify, maxStringLength);\n    const char* v = \"Hello\";\n    int written = stringCharacteristic.writeValue(v);\n    REQUIRE( written == min(strlen(v), maxStringLength) );\n\n    stringCharacteristic.broadcast();\n    written = stringCharacteristic.writeValue(v);\n    REQUIRE( written == min(strlen(v), maxStringLength) );\n\n    BLEDevice device;\n    stringCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = stringCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    stringCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = stringCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n  WHEN(\"Create a too long string characteristic\")\n  {\n    const int maxStringLength = 4;\n    BLEStringCharacteristic stringCharacteristic(\"String\", BLEBroadcast| BLEIndicate | BLENotify, maxStringLength);\n    const char* v = \"Hello\";\n    int written = stringCharacteristic.writeValue(v);\n    REQUIRE( written == min(strlen(v), maxStringLength) );\n\n    stringCharacteristic.broadcast();\n    written = stringCharacteristic.writeValue(v);\n    REQUIRE( written == min(strlen(v), maxStringLength) );\n\n    BLEDevice device;\n    stringCharacteristic.local()->writeCccdValue(device, 0x002);\n    written = stringCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n    stringCharacteristic.local()->writeCccdValue(device, 0x001);\n    written = stringCharacteristic.writeValue(v);\n    /* No peers connected */\n    REQUIRE( written == 0 );\n  }\n\n}\n"
  },
  {
    "path": "extras/test/src/test_discovered_device/FakeGAP.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"FakeGAP.h\"\n\nFakeGAPClass::FakeGAPClass()\n{\n}\n\nFakeGAPClass::~FakeGAPClass()\n{\n}\n\nFakeGAPClass GAPFakeObj;\nGAPClass& GAP = GAPFakeObj;\n"
  },
  {
    "path": "extras/test/src/test_discovered_device/test_discovered_device.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <catch2/catch_test_macros.hpp>\n\n#define private public\n#define protected public\n#include \"BLEDevice.h\"\n\nTEST_CASE(\"BLE discovered device test\", \"[ArduinoBLE::BLEDevice]\")\n{\n\n  WHEN(\"Retrieve local name from advertisement packet\")\n  {\n    // Mocking advertisement packet\n    uint8_t advType = 0x03;\n    uint8_t eirLength = 6;\n    uint8_t eirData[] = {0x05, 0x09, 't', 'e', 's', 't'};\n    uint8_t rssi = 0;\n\n    // Expected results\n    String goldenName = \"test\";\n\n    // Simulate device discovery\n    BLEDevice device = BLEDevice();\n    device.setAdvertisementData(0x03, eirLength, eirData, rssi); \n\n    bool hasName = device.hasLocalName();\n    REQUIRE(hasName);\n\n    String name = device.localName();\n    REQUIRE(goldenName == name);\n\n  }\n\n}\n"
  },
  {
    "path": "extras/test/src/test_main.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#define CATCH_CONFIG_MAIN /* This tells Catch to provide a main() - only do this in one cpp file */\n#include <catch2/catch_test_macros.hpp>\n"
  },
  {
    "path": "extras/test/src/test_uuid/test_uuid.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <catch2/catch_test_macros.hpp>\n\n#include \"utility/BLEUuid.h\"\n\nTEST_CASE(\"BLE uuid test\", \"[ArduinoBLE::BLEUuid]\")\n{\n  WHEN(\"Set and retrieve uuid\")\n  {\n    bool verify;\n\n    const char* goldenUuid = \"19b10010-e8f2-537e-4f6c-d104768a1214\";\n    // little-endian order\n    const uint8_t goldenData[] = {0x14,0x12,0x8A,0x76,0x04,0xD1,0x6C,0x4F,0x7E,0x53,0xF2,0xE8,0x10,0x00,0xB1,0x19};\n    uint8_t goldenLength = 16;\n\n    BLEUuid test(goldenUuid);\n\n    uint8_t testLength = test.length();\n    verify = (goldenLength == testLength);\n    REQUIRE(verify);\n\n    const uint8_t *testData = test.data();\n    verify = ( 0 == (memcmp(goldenData, testData, sizeof(goldenData))) );\n    REQUIRE(verify);\n\n    const char *testUuid = test.uuidToString(testData, testLength);\n    verify = ( 0 == strcmp(testUuid, goldenUuid) );\n    REQUIRE(verify);\n\n    // print the uuid\n    //WARN(\"test: \" << testUuid << \",  golden: \" << goldenUuid);\n  }\n}"
  },
  {
    "path": "extras/test/src/util/Common.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"Common.h\"\n\nvoid delay(unsigned long)\n{\n\n}\n\n/* C++ prototypes */\nlong map(long x, long in_min, long in_max, long out_min, long out_max)\n{\n  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;\n}\n\nuint16_t makeWord(uint16_t w) { return w; }\nuint16_t makeWord(uint8_t h, uint8_t l) { return (h << 8) | l; }"
  },
  {
    "path": "extras/test/src/util/HCIFakeTransport.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"HCIFakeTransport.h\"\n\nHCIFakeTransportClass HCIFakeTransport;\nHCITransportInterface& HCITransport = HCIFakeTransport;"
  },
  {
    "path": "extras/test/src/util/String.cpp",
    "content": "/*\n  String library for Wiring & Arduino\n  ...mostly rewritten by Paul Stoffregen...\n  Copyright (c) 2009-10 Hernando Barragan.  All rights reserved.\n  Copyright 2011, Paul Stoffregen, paul@pjrc.com\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"String.h\"\n#include \"itoa.h\"\n\n/*********************************************/\n/*  Constructors                             */\n/*********************************************/\n\nnamespace arduino {\n\nString::String(const char *cstr)\n{\n\tinit();\n\tif (cstr) copy(cstr, strlen(cstr));\n}\n\nString::String(const String &value)\n{\n\tinit();\n\t*this = value;\n}\n\nString::String(const __FlashStringHelper *pstr)\n{\n\tinit();\n\t*this = pstr;\n}\n\n#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)\nString::String(String &&rval)\n{\n\tinit();\n\tmove(rval);\n}\nString::String(StringSumHelper &&rval)\n{\n\tinit();\n\tmove(rval);\n}\n#endif\n\nString::String(char c)\n{\n\tinit();\n\tchar buf[2];\n\tbuf[0] = c;\n\tbuf[1] = 0;\n\t*this = buf;\n}\n\nString::String(unsigned char value, unsigned char base)\n{\n\tinit();\n\tchar buf[1 + 8 * sizeof(unsigned char)];\n\tutoa(value, buf, base);\n\t*this = buf;\n}\n\nString::String(int value, unsigned char base)\n{\n\tinit();\n\tchar buf[2 + 8 * sizeof(int)];\n\titoa(value, buf, base);\n\t*this = buf;\n}\n\nString::String(unsigned int value, unsigned char base)\n{\n\tinit();\n\tchar buf[1 + 8 * sizeof(unsigned int)];\n\tutoa(value, buf, base);\n\t*this = buf;\n}\n\nString::String(long value, unsigned char base)\n{\n\tinit();\n\tchar buf[2 + 8 * sizeof(long)];\n\tltoa(value, buf, base);\n\t*this = buf;\n}\n\nString::String(unsigned long value, unsigned char base)\n{\n\tinit();\n\tchar buf[1 + 8 * sizeof(unsigned long)];\n\tultoa(value, buf, base);\n\t*this = buf;\n}\n\n/*\nString::String(float value, unsigned char decimalPlaces)\n{\n\tinit();\n\tchar buf[33];\n\t*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);\n}\n\nString::String(double value, unsigned char decimalPlaces)\n{\n\tinit();\n\tchar buf[33];\n\t*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);\n}\n*/\n\nString::~String()\n{\n\tif (buffer) free(buffer);\n}\n\n/*********************************************/\n/*  Memory Management                        */\n/*********************************************/\n\ninline void String::init(void)\n{\n\tbuffer = NULL;\n\tcapacity = 0;\n\tlen = 0;\n}\n\nvoid String::invalidate(void)\n{\n\tif (buffer) free(buffer);\n\tbuffer = NULL;\n\tcapacity = len = 0;\n}\n\nunsigned char String::reserve(unsigned int size)\n{\n\tif (buffer && capacity >= size) return 1;\n\tif (changeBuffer(size)) {\n\t\tif (len == 0) buffer[0] = 0;\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nunsigned char String::changeBuffer(unsigned int maxStrLen)\n{\n\tchar *newbuffer = (char *)realloc(buffer, maxStrLen + 1);\n\tif (newbuffer) {\n\t\tbuffer = newbuffer;\n\t\tcapacity = maxStrLen;\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n/*********************************************/\n/*  Copy and Move                            */\n/*********************************************/\n\nString & String::copy(const char *cstr, unsigned int length)\n{\n\tif (!reserve(length)) {\n\t\tinvalidate();\n\t\treturn *this;\n\t}\n\tlen = length;\n\tstrcpy(buffer, cstr);\n\treturn *this;\n}\n\n/*\nString & String::copy(const __FlashStringHelper *pstr, unsigned int length)\n{\n\tif (!reserve(length)) {\n\t\tinvalidate();\n\t\treturn *this;\n\t}\n\tlen = length;\n\tstrcpy_P(buffer, (PGM_P)pstr);\n\treturn *this;\n}\n*/\n\n#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)\nvoid String::move(String &rhs)\n{\n\tif (buffer) {\n\t\tif (rhs && capacity >= rhs.len) {\n\t\t\tstrcpy(buffer, rhs.buffer);\n\t\t\tlen = rhs.len;\n\t\t\trhs.len = 0;\n\t\t\treturn;\n\t\t} else {\n\t\t\tfree(buffer);\n\t\t}\n\t}\n\tbuffer = rhs.buffer;\n\tcapacity = rhs.capacity;\n\tlen = rhs.len;\n\trhs.buffer = NULL;\n\trhs.capacity = 0;\n\trhs.len = 0;\n}\n#endif\n\nString & String::operator = (const String &rhs)\n{\n\tif (this == &rhs) return *this;\n\t\n\tif (rhs.buffer) copy(rhs.buffer, rhs.len);\n\telse invalidate();\n\t\n\treturn *this;\n}\n\n#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)\nString & String::operator = (String &&rval)\n{\n\tif (this != &rval) move(rval);\n\treturn *this;\n}\n\nString & String::operator = (StringSumHelper &&rval)\n{\n\tif (this != &rval) move(rval);\n\treturn *this;\n}\n#endif\n\nString & String::operator = (const char *cstr)\n{\n\tif (cstr) copy(cstr, strlen(cstr));\n\telse invalidate();\n\t\n\treturn *this;\n}\n\n/*\nString & String::operator = (const __FlashStringHelper *pstr)\n{\n\tif (pstr) copy(pstr, strlen_P((PGM_P)pstr));\n\telse invalidate();\n\n\treturn *this;\n}\n*/\n\n/*********************************************/\n/*  concat                                   */\n/*********************************************/\n\nunsigned char String::concat(const String &s)\n{\n\treturn concat(s.buffer, s.len);\n}\n\nunsigned char String::concat(const char *cstr, unsigned int length)\n{\n\tunsigned int newlen = len + length;\n\tif (!cstr) return 0;\n\tif (length == 0) return 1;\n\tif (!reserve(newlen)) return 0;\n\tstrcpy(buffer + len, cstr);\n\tlen = newlen;\n\treturn 1;\n}\n\nunsigned char String::concat(const char *cstr)\n{\n\tif (!cstr) return 0;\n\treturn concat(cstr, strlen(cstr));\n}\n\nunsigned char String::concat(char c)\n{\n\tchar buf[2];\n\tbuf[0] = c;\n\tbuf[1] = 0;\n\treturn concat(buf, 1);\n}\n\nunsigned char String::concat(unsigned char num)\n{\n\tchar buf[1 + 3 * sizeof(unsigned char)];\n\titoa(num, buf, 10);\n\treturn concat(buf, strlen(buf));\n}\n\nunsigned char String::concat(int num)\n{\n\tchar buf[2 + 3 * sizeof(int)];\n\titoa(num, buf, 10);\n\treturn concat(buf, strlen(buf));\n}\n\nunsigned char String::concat(unsigned int num)\n{\n\tchar buf[1 + 3 * sizeof(unsigned int)];\n\tutoa(num, buf, 10);\n\treturn concat(buf, strlen(buf));\n}\n\nunsigned char String::concat(long num)\n{\n\tchar buf[2 + 3 * sizeof(long)];\n\tltoa(num, buf, 10);\n\treturn concat(buf, strlen(buf));\n}\n\nunsigned char String::concat(unsigned long num)\n{\n\tchar buf[1 + 3 * sizeof(unsigned long)];\n\tultoa(num, buf, 10);\n\treturn concat(buf, strlen(buf));\n}\n\n/*\nunsigned char String::concat(float num)\n{\n\tchar buf[20];\n\tchar* string = dtostrf(num, 4, 2, buf);\n\treturn concat(string, strlen(string));\n}\n\nunsigned char String::concat(double num)\n{\n\tchar buf[20];\n\tchar* string = dtostrf(num, 4, 2, buf);\n\treturn concat(string, strlen(string));\n}\n\nunsigned char String::concat(const __FlashStringHelper * str)\n{\n\tif (!str) return 0;\n\tint length = strlen_P((const char *) str);\n\tif (length == 0) return 1;\n\tunsigned int newlen = len + length;\n\tif (!reserve(newlen)) return 0;\n\tstrcpy_P(buffer + len, (const char *) str);\n\tlen = newlen;\n\treturn 1;\n}\n*/\n\n/*********************************************/\n/*  Concatenate                              */\n/*********************************************/\n\nStringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(rhs.buffer, rhs.len)) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, char c)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(c)) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(num)) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, int num)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(num)) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(num)) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, long num)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(num)) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(num)) a.invalidate();\n\treturn a;\n}\n\n/*\nStringSumHelper & operator + (const StringSumHelper &lhs, float num)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(num)) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, double num)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(num)) a.invalidate();\n\treturn a;\n}\n\nStringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)\n{\n\tStringSumHelper &a = const_cast<StringSumHelper&>(lhs);\n\tif (!a.concat(rhs))\ta.invalidate();\n\treturn a;\n}\n*/\n\n/*********************************************/\n/*  Comparison                               */\n/*********************************************/\n\nint String::compareTo(const String &s) const\n{\n\tif (!buffer || !s.buffer) {\n\t\tif (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;\n\t\tif (buffer && len > 0) return *(unsigned char *)buffer;\n\t\treturn 0;\n\t}\n\treturn strcmp(buffer, s.buffer);\n}\n\nint String::compareTo(const char *cstr) const\n{\n\tif (!buffer || !cstr) {\n\t\tif (cstr && !*cstr) return 0 - *(unsigned char *)cstr;\n\t\tif (buffer && len > 0) return *(unsigned char *)buffer;\n\t\treturn 0;\n\t}\n\treturn strcmp(buffer, cstr);\n}\n\nunsigned char String::equals(const String &s2) const\n{\n\treturn (len == s2.len && compareTo(s2) == 0);\n}\n\nunsigned char String::equals(const char *cstr) const\n{\n\tif (len == 0) return (cstr == NULL || *cstr == 0);\n\tif (cstr == NULL) return buffer[0] == 0;\n\treturn strcmp(buffer, cstr) == 0;\n}\n\nunsigned char String::equalsIgnoreCase( const String &s2 ) const\n{\n\tif (this == &s2) return 1;\n\tif (len != s2.len) return 0;\n\tif (len == 0) return 1;\n\tconst char *p1 = buffer;\n\tconst char *p2 = s2.buffer;\n\twhile (*p1) {\n\t\tif (tolower(*p1++) != tolower(*p2++)) return 0;\n\t} \n\treturn 1;\n}\n\nunsigned char String::startsWith( const String &s2 ) const\n{\n\tif (len < s2.len) return 0;\n\treturn startsWith(s2, 0);\n}\n\nunsigned char String::startsWith( const String &s2, unsigned int offset ) const\n{\n\tif (offset > len - s2.len || !buffer || !s2.buffer) return 0;\n\treturn strncmp( &buffer[offset], s2.buffer, s2.len ) == 0;\n}\n\nunsigned char String::endsWith( const String &s2 ) const\n{\n\tif ( len < s2.len || !buffer || !s2.buffer) return 0;\n\treturn strcmp(&buffer[len - s2.len], s2.buffer) == 0;\n}\n\n/*********************************************/\n/*  Character Access                         */\n/*********************************************/\n\nchar String::charAt(unsigned int loc) const\n{\n\treturn operator[](loc);\n}\n\nvoid String::setCharAt(unsigned int loc, char c) \n{\n\tif (loc < len) buffer[loc] = c;\n}\n\nchar & String::operator[](unsigned int index)\n{\n\tstatic char dummy_writable_char;\n\tif (index >= len || !buffer) {\n\t\tdummy_writable_char = 0;\n\t\treturn dummy_writable_char;\n\t}\n\treturn buffer[index];\n}\n\nchar String::operator[]( unsigned int index ) const\n{\n\tif (index >= len || !buffer) return 0;\n\treturn buffer[index];\n}\n\nvoid String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const\n{\n\tif (!bufsize || !buf) return;\n\tif (index >= len) {\n\t\tbuf[0] = 0;\n\t\treturn;\n\t}\n\tunsigned int n = bufsize - 1;\n\tif (n > len - index) n = len - index;\n\tstrncpy((char *)buf, buffer + index, n);\n\tbuf[n] = 0;\n}\n\n/*********************************************/\n/*  Search                                   */\n/*********************************************/\n\nint String::indexOf(char c) const\n{\n\treturn indexOf(c, 0);\n}\n\nint String::indexOf( char ch, unsigned int fromIndex ) const\n{\n\tif (fromIndex >= len) return -1;\n\tconst char* temp = strchr(buffer + fromIndex, ch);\n\tif (temp == NULL) return -1;\n\treturn temp - buffer;\n}\n\nint String::indexOf(const String &s2) const\n{\n\treturn indexOf(s2, 0);\n}\n\nint String::indexOf(const String &s2, unsigned int fromIndex) const\n{\n\tif (fromIndex >= len) return -1;\n\tconst char *found = strstr(buffer + fromIndex, s2.buffer);\n\tif (found == NULL) return -1;\n\treturn found - buffer;\n}\n\nint String::lastIndexOf( char theChar ) const\n{\n\treturn lastIndexOf(theChar, len - 1);\n}\n\nint String::lastIndexOf(char ch, unsigned int fromIndex) const\n{\n\tif (fromIndex >= len) return -1;\n\tchar tempchar = buffer[fromIndex + 1];\n\tbuffer[fromIndex + 1] = '\\0';\n\tchar* temp = strrchr( buffer, ch );\n\tbuffer[fromIndex + 1] = tempchar;\n\tif (temp == NULL) return -1;\n\treturn temp - buffer;\n}\n\nint String::lastIndexOf(const String &s2) const\n{\n\treturn lastIndexOf(s2, len - s2.len);\n}\n\nint String::lastIndexOf(const String &s2, unsigned int fromIndex) const\n{\n\tif (s2.len == 0 || len == 0 || s2.len > len) return -1;\n\tif (fromIndex >= len) fromIndex = len - 1;\n\tint found = -1;\n\tfor (char *p = buffer; p <= buffer + fromIndex; p++) {\n\t\tp = strstr(p, s2.buffer);\n\t\tif (!p) break;\n\t\tif ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer;\n\t}\n\treturn found;\n}\n\nString String::substring(unsigned int left, unsigned int right) const\n{\n\tif (left > right) {\n\t\tunsigned int temp = right;\n\t\tright = left;\n\t\tleft = temp;\n\t}\n\tString out;\n\tif (left >= len) return out;\n\tif (right > len) right = len;\n\tchar temp = buffer[right];  // save the replaced character\n\tbuffer[right] = '\\0';\t\n\tout = buffer + left;  // pointer arithmetic\n\tbuffer[right] = temp;  //restore character\n\treturn out;\n}\n\n/*********************************************/\n/*  Modification                             */\n/*********************************************/\n\nvoid String::replace(char find, char replace)\n{\n\tif (!buffer) return;\n\tfor (char *p = buffer; *p; p++) {\n\t\tif (*p == find) *p = replace;\n\t}\n}\n\nvoid String::replace(const String& find, const String& replace)\n{\n\tif (len == 0 || find.len == 0) return;\n\tint diff = replace.len - find.len;\n\tchar *readFrom = buffer;\n\tchar *foundAt;\n\tif (diff == 0) {\n\t\twhile ((foundAt = strstr(readFrom, find.buffer)) != NULL) {\n\t\t\tmemcpy(foundAt, replace.buffer, replace.len);\n\t\t\treadFrom = foundAt + replace.len;\n\t\t}\n\t} else if (diff < 0) {\n\t\tchar *writeTo = buffer;\n\t\twhile ((foundAt = strstr(readFrom, find.buffer)) != NULL) {\n\t\t\tunsigned int n = foundAt - readFrom;\n\t\t\tmemcpy(writeTo, readFrom, n);\n\t\t\twriteTo += n;\n\t\t\tmemcpy(writeTo, replace.buffer, replace.len);\n\t\t\twriteTo += replace.len;\n\t\t\treadFrom = foundAt + find.len;\n\t\t\tlen += diff;\n\t\t}\n\t\tstrcpy(writeTo, readFrom);\n\t} else {\n\t\tunsigned int size = len; // compute size needed for result\n\t\twhile ((foundAt = strstr(readFrom, find.buffer)) != NULL) {\n\t\t\treadFrom = foundAt + find.len;\n\t\t\tsize += diff;\n\t\t}\n\t\tif (size == len) return;\n\t\tif (size > capacity && !changeBuffer(size)) return; // XXX: tell user!\n\t\tint index = len - 1;\n\t\twhile (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {\n\t\t\treadFrom = buffer + index + find.len;\n\t\t\tmemmove(readFrom + diff, readFrom, len - (readFrom - buffer));\n\t\t\tlen += diff;\n\t\t\tbuffer[len] = 0;\n\t\t\tmemcpy(buffer + index, replace.buffer, replace.len);\n\t\t\tindex--;\n\t\t}\n\t}\n}\n\nvoid String::remove(unsigned int index){\n\t// Pass the biggest integer as the count. The remove method\n\t// below will take care of truncating it at the end of the\n\t// string.\n\tremove(index, (unsigned int)-1);\n}\n\nvoid String::remove(unsigned int index, unsigned int count){\n\tif (index >= len) { return; }\n\tif (count <= 0) { return; }\n\tif (count > len - index) { count = len - index; }\n\tchar *writeTo = buffer + index;\n\tlen = len - count;\n\tmemmove(writeTo, buffer + index + count,len - index);\n\tbuffer[len] = 0;\n}\n\nvoid String::toLowerCase(void)\n{\n\tif (!buffer) return;\n\tfor (char *p = buffer; *p; p++) {\n\t\t*p = tolower(*p);\n\t}\n}\n\nvoid String::toUpperCase(void)\n{\n\tif (!buffer) return;\n\tfor (char *p = buffer; *p; p++) {\n\t\t*p = toupper(*p);\n\t}\n}\n\nvoid String::trim(void)\n{\n\tif (!buffer || len == 0) return;\n\tchar *begin = buffer;\n\twhile (isspace(*begin)) begin++;\n\tchar *end = buffer + len - 1;\n\twhile (isspace(*end) && end >= begin) end--;\n\tlen = end + 1 - begin;\n\tif (begin > buffer) memmove(buffer, begin, len);\n\tbuffer[len] = 0;\n}\n\n/*********************************************/\n/*  Parsing / Conversion                     */\n/*********************************************/\n\nlong String::toInt(void) const\n{\n\tif (buffer) return atol(buffer);\n\treturn 0;\n}\n\nfloat String::toFloat(void) const\n{\n\treturn float(toDouble());\n}\n\ndouble String::toDouble(void) const\n{\n\tif (buffer) return atof(buffer);\n\treturn 0;\n}\n\n} // namespace arduino\n"
  },
  {
    "path": "extras/test/src/util/TestUtil.cpp",
    "content": "/*\n * Copyright (c) 2020 Arduino.  All rights reserved.\n */\n"
  },
  {
    "path": "extras/test/src/util/itoa.c",
    "content": "/*\n  Copyright (c) 2014 Arduino LLC.  All right reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n  See the GNU Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <itoa.h>\n#include <string.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern char* itoa( int value, char *string, int radix )\n{\n  return ltoa( value, string, radix ) ;\n}\n\nextern char* ltoa( long value, char *string, int radix )\n{\n  char tmp[33];\n  char *tp = tmp;\n  long i;\n  unsigned long v;\n  int sign;\n  char *sp;\n\n  if ( string == NULL )\n  {\n    return 0 ;\n  }\n\n  if (radix > 36 || radix <= 1)\n  {\n    return 0 ;\n  }\n\n  sign = (radix == 10 && value < 0);\n  if (sign)\n  {\n    v = -value;\n  }\n  else\n  {\n    v = (unsigned long)value;\n  }\n\n  while (v || tp == tmp)\n  {\n    i = v % radix;\n    v = v / radix;\n    if (i < 10)\n      *tp++ = i+'0';\n    else\n      *tp++ = i + 'a' - 10;\n  }\n\n  sp = string;\n\n  if (sign)\n    *sp++ = '-';\n  while (tp > tmp)\n    *sp++ = *--tp;\n  *sp = 0;\n\n  return string;\n}\n\nextern char* utoa( unsigned int value, char *string, int radix )\n{\n  return ultoa( value, string, radix ) ;\n}\n\nextern char* ultoa( unsigned long value, char *string, int radix )\n{\n  char tmp[33];\n  char *tp = tmp;\n  long i;\n  unsigned long v = value;\n  char *sp;\n\n  if ( string == NULL )\n  {\n    return 0;\n  }\n\n  if (radix > 36 || radix <= 1)\n  {\n    return 0;\n  }\n\n  while (v || tp == tmp)\n  {\n    i = v % radix;\n    v = v / radix;\n    if (i < 10)\n      *tp++ = i+'0';\n    else\n      *tp++ = i + 'a' - 10;\n  }\n\n  sp = string;\n\n\n  while (tp > tmp)\n    *sp++ = *--tp;\n  *sp = 0;\n\n  return string;\n}\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif\n"
  },
  {
    "path": "keywords.txt",
    "content": "#######################################\n# Syntax Coloring Map For ArduinoBLE\n#######################################\n\n#######################################\n# Datatypes (KEYWORD1)\n#######################################\n\nArduinoBLE\tKEYWORD1\nBLE\tKEYWORD1\n\nBLEDevice\tKEYWORD1\nBLECharacteristic\tKEYWORD1\nBLEDescriptor\tKEYWORD1\nBLEService\tKEYWORD1\n\nBLEBoolCharacteristic\tKEYWORD1\nBLEBooleanCharacteristic\tKEYWORD1\nBLECharCharacteristic\tKEYWORD1\nBLEUnsignedCharCharacteristic\tKEYWORD1\nBLEByteCharacteristic\tKEYWORD1\nBLEShortCharacteristic\tKEYWORD1\nBLEUnsignedShortCharacteristic\tKEYWORD1\nBLEWordCharacteristic\tKEYWORD1\nBLEIntCharacteristic\tKEYWORD1\nBLEUnsignedIntCharacteristic\tKEYWORD1\nBLELongCharacteristic\tKEYWORD1\nBLEUnsignedLongCharacteristic\tKEYWORD1\nBLEFloatCharacteristic\tKEYWORD1\nBLEDoubleCharacteristic\tKEYWORD1\nBLEStringCharacteristic\tKEYWORD1\n\n#######################################\n# Methods and Functions (KEYWORD2)\n#######################################\n\nbegin\tKEYWORD2\npoll\tKEYWORD2\nend\tKEYWORD2\n\nconnected\tKEYWORD2\ndisconnect\tKEYWORD2\naddress\tKEYWORD2\nhasLocalName\tKEYWORD2\nhasAdvertisedServiceUuid\tKEYWORD2\nadvertisedServiceUuidCount\tKEYWORD2\nlocalName\tKEYWORD2\nadvertisedServiceUuid\tKEYWORD2\nrssi\tKEYWORD2\nconnect\tKEYWORD2\ndiscoverAttributes\tKEYWORD2\ndiscoverService\tKEYWORD2\ndeviceName\tKEYWORD2\nappearance\tKEYWORD2\nserviceCount\tKEYWORD2\nhasService\tKEYWORD2\nservice\tKEYWORD2\ncharacteristicCount\tKEYWORD2\ncharacteristic\tKEYWORD2\n\nsetAdvertisedServiceUuid\tKEYWORD2\nsetManufacturerData\tKEYWORD2\nsetLocalName\tKEYWORD2\nsetDeviceName\tKEYWORD2\nsetAppearance\tKEYWORD2\naddService\tKEYWORD2\nadvertise\tKEYWORD2\nstopAdvertise\tKEYWORD2\nscan\tKEYWORD2\nscanForName\tKEYWORD2\nscanForUuid\tKEYWORD2\nscanForAddress\tKEYWORD2\nstopScan\tKEYWORD2\ncentral\tKEYWORD2\navailable\tKEYWORD2\nsetEventHandler\tKEYWORD2\nsetAdvertisingInterval\tKEYWORD2\nsetConnectionInterval\tKEYWORD2\nsetConnectable\tKEYWORD2\nsetPairable\tKEYWORD2\nsetTimeout\tKEYWORD2\ndebug\tKEYWORD2\nnoDebug\tKEYWORD2\npairable\tKEYWORD2\npaired\tKEYWORD2\n\nproperties\tKEYWORD2\nvalueSize\tKEYWORD2\nvalue\tKEYWORD2\nvalueLength\tKEYWORD2\nreadValue\tKEYWORD2\nwriteValue\tKEYWORD2\nsetValue\tKEYWORD2\nbroadcast\tKEYWORD2\nwritten\tKEYWORD2\nsubscribed\tKEYWORD2\nvalueUpdated\tKEYWORD2\naddDescriptor\tKEYWORD2\ndescriptorCount\tKEYWORD2\nhasDescriptor\tKEYWORD2\ndescriptor\tKEYWORD2\ncanRead\tKEYWORD2\nread\tKEYWORD2\ncanWrite\tKEYWORD2\ncanSubscribe\tKEYWORD2\nsubscribe\tKEYWORD2\ncanUnsubscribe\tKEYWORD2\nunsubscribe\tKEYWORD2\nwriteValueLE\tKEYWORD2\nsetValueLE\tKEYWORD2\nvalueLE\tKEYWORD2\nwriteValueBE\tKEYWORD2\nsetValueBE\tKEYWORD2\nvalueBE\tKEYWORD2\n\nuuid\tKEYWORD2\naddCharacteristic\tKEYWORD2\n\n#######################################\n# Constants (LITERAL1)\n#######################################\n\nBLEConnected\tLITERAL1\nBLEDisconnected\tLITERAL1\nBLEDiscovered\tLITERAL1\n\nBLEBroadcast\tLITERAL1\nBLERead\tLITERAL1\nBLEWriteWithoutResponse\tLITERAL1\nBLEWrite\tLITERAL1\nBLENotify\tLITERAL1\nBLEIndicate\tLITERAL1\n\nBLESubscribed\tLITERAL1\nBLEUnsubscribed\tLITERAL1\nBLEWritten\tLITERAL1\nBLEUpdated\tLITERAL1\n\n"
  },
  {
    "path": "library.properties",
    "content": "name=ArduinoBLE\nversion=2.0.1\nauthor=Arduino\nmaintainer=Arduino <info@arduino.cc>\nsentence=Enables Bluetooth® Low Energy connectivity on the Arduino MKR WiFi 1010, Arduino UNO WiFi Rev2, Arduino Nano 33 IoT, Arduino Nano 33 BLE, Nicla Sense ME and UNO R4 WiFi.\nparagraph=This library supports creating a Bluetooth® Low Energy peripheral & central mode.\ncategory=Communication\nurl=https://www.arduino.cc/en/Reference/ArduinoBLE\narchitectures=*\nincludes=ArduinoBLE.h\ndepends=Arduino_SpiNINA\n"
  },
  {
    "path": "src/ArduinoBLE.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _ARDUINO_BLE_H_\n#define _ARDUINO_BLE_H_\n\n#include \"local/BLELocalDevice.h\"\n#include \"BLEProperty.h\"\n#include \"BLEStringCharacteristic.h\"\n#include \"BLETypedCharacteristics.h\"\n#include \"utility/btct.h\"\n\n#endif\n"
  },
  {
    "path": "src/BLEAdvertisingData.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLEAdvertisingData.h\"\n\n#define AD_FIELD_OVERHEAD (2)\n\nBLEAdvertisingData::BLEAdvertisingData() :\n  _dataLength(0),\n  _remainingLength(MAX_AD_DATA_LENGTH),\n  _rawData(NULL),\n  _rawDataLength(0),\n  _flags(0),\n  _hasFlags(false),\n  _localName(NULL),\n  _manufacturerData(NULL),\n  _manufacturerDataLength(0),\n  _manufacturerCompanyId(0),\n  _hasManufacturerCompanyId(false),\n  _advertisedServiceUuid(NULL),\n  _advertisedServiceUuidLength(0),\n  _serviceData(NULL),\n  _serviceDataLength(0)\n{\n}\n\nBLEAdvertisingData::~BLEAdvertisingData()\n{\n}\n\ninline bool BLEAdvertisingData::updateRemainingLength(int oldFieldLength, int newFieldLength)\n{\n  int updatedRemaining = _remainingLength + (oldFieldLength - newFieldLength);\n  if (updatedRemaining >= 0) {\n    _remainingLength = updatedRemaining;\n    return true;\n  }\n  return false;\n}\n\nint BLEAdvertisingData::remainingLength() const\n{\n  return _remainingLength;\n}\n\nint BLEAdvertisingData::availableForWrite()\n{\n  int available = (_remainingLength - AD_FIELD_OVERHEAD);\n  if (available < 0) available = 0;\n  return available; \n}\n\nvoid BLEAdvertisingData::clear()\n{\n  _remainingLength = MAX_AD_DATA_LENGTH;\n  _rawData = NULL;\n  _rawDataLength = 0;\n  _hasFlags = false;\n  _localName = NULL;\n  _manufacturerData = NULL;\n  _manufacturerDataLength = 0;\n  _hasManufacturerCompanyId = false;\n  _advertisedServiceUuid = NULL;\n  _advertisedServiceUuidLength = 0;\n  _serviceData = NULL;\n  _serviceDataLength = 0;\n}\n\nvoid BLEAdvertisingData::copy(const BLEAdvertisingData& adv)\n{\n  _remainingLength = adv._remainingLength;\n  _rawData = adv._rawData;\n  _rawDataLength = adv._rawDataLength;\n  _flags = adv._flags;\n  _hasFlags = adv._hasFlags;\n  _localName = adv._localName;\n  _manufacturerData = adv._manufacturerData;\n  _manufacturerDataLength = adv._manufacturerDataLength;\n  _manufacturerCompanyId = adv._manufacturerCompanyId;\n  _hasManufacturerCompanyId = adv._hasManufacturerCompanyId;\n  _advertisedServiceUuid = adv._advertisedServiceUuid;\n  _advertisedServiceUuidLength = adv._advertisedServiceUuidLength;\n  _serviceDataUuid = adv._serviceDataUuid;\n  _serviceData = adv._serviceData;\n  _serviceDataLength = adv._serviceDataLength;\n}\n\nBLEAdvertisingData& BLEAdvertisingData::operator=(const BLEAdvertisingData &other) \n{\n  copy(other);\n  return *this;\n}\n\nbool BLEAdvertisingData::setAdvertisedServiceUuid(const char* advertisedServiceUuid)\n{\n  BLEUuid uuid(advertisedServiceUuid);\n  int previousLength = (_advertisedServiceUuidLength > 0) ? (_advertisedServiceUuidLength + AD_FIELD_OVERHEAD) : 0;\n  bool success = updateRemainingLength(previousLength, (uuid.length() + AD_FIELD_OVERHEAD));\n  if (success) {\n    _advertisedServiceUuid = advertisedServiceUuid;\n    _advertisedServiceUuidLength = uuid.length();\n  }\n  return success;\n}\n\nbool BLEAdvertisingData::setAdvertisedService(const BLEService& service)\n{\n  return setAdvertisedServiceUuid(service.uuid());\n}\n\nbool BLEAdvertisingData::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength)\n{\n  int previousLength = 0;\n  if (_manufacturerDataLength) {\n    previousLength = _manufacturerDataLength + AD_FIELD_OVERHEAD;\n    if (_hasManufacturerCompanyId) {\n      previousLength += sizeof(_manufacturerCompanyId);\n    }\n  }\n  bool success = updateRemainingLength(previousLength, (manufacturerDataLength + AD_FIELD_OVERHEAD));\n  if (success) {\n    _manufacturerData = manufacturerData;\n    _manufacturerDataLength = manufacturerDataLength;\n    _hasManufacturerCompanyId = false;\n  }\n  return success;\n}\n\nbool BLEAdvertisingData::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength)\n{\n  int previousLength = 0;\n  if (_manufacturerDataLength) {\n    previousLength = _manufacturerDataLength + AD_FIELD_OVERHEAD;\n    if (_hasManufacturerCompanyId) {\n      previousLength += sizeof(_manufacturerCompanyId);\n    }\n  }\n  bool success = updateRemainingLength(previousLength, (manufacturerDataLength + sizeof(companyId) + AD_FIELD_OVERHEAD));\n  if (success) {\n    _manufacturerData = manufacturerData;\n    _manufacturerDataLength = manufacturerDataLength;\n    _manufacturerCompanyId = companyId;\n    _hasManufacturerCompanyId = true;\n  }\n  return success;\n}\n\nbool BLEAdvertisingData::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length)\n{\n  int previousLength = (_serviceDataLength > 0) ? (_serviceDataLength + sizeof(uuid) + AD_FIELD_OVERHEAD) : 0;\n  bool success = updateRemainingLength(previousLength, (length + sizeof(uuid) + AD_FIELD_OVERHEAD));\n  if (success) {\n    _serviceDataUuid = uuid;\n    _serviceData = data;\n    _serviceDataLength = length;\n  }\n  return success;\n}\n\nbool BLEAdvertisingData::setLocalName(const char *localName)\n{\n  int previousLength = (_localName && strlen(_localName) > 0) ? (strlen(_localName) + AD_FIELD_OVERHEAD) : 0;\n  bool success = updateRemainingLength(previousLength, (strlen(localName) + AD_FIELD_OVERHEAD));\n  if (success) {\n    _localName = localName;\n  }\n  return success;\n}\n\nbool BLEAdvertisingData::setRawData(const uint8_t* data, int length)\n{\n  if (length > MAX_AD_DATA_LENGTH) {\n    return false;\n  }\n  _rawData = data;\n  _rawDataLength = length;\n  return true;\n}\n\nbool BLEAdvertisingData::setRawData(const BLEAdvertisingRawData& rawData)\n{\n  if (rawData.length > MAX_AD_DATA_LENGTH) {\n    return false;\n  }\n  _rawData = rawData.data;\n  _rawDataLength = rawData.length;\n  return true;\n}\n\nbool BLEAdvertisingData::setFlags(uint8_t flags)\n{\n  int previousLength = (_hasFlags) ? (sizeof(_flags) + AD_FIELD_OVERHEAD) : 0;\n  bool success = updateRemainingLength(previousLength, (sizeof(flags) + AD_FIELD_OVERHEAD));\n  if (success) {\n    _hasFlags = true;\n    _flags = flags;\n  }\n  return success;\n}\n\nbool BLEAdvertisingData::updateData()\n{\n  // Success indicates whether all the fields have been inserted\n  bool success = true;\n  // Reset data \n  _dataLength = 0;\n  // If rawData is present, then only rawData is inserted in the advertising packet\n  if (_rawData && _rawDataLength) {\n    return addRawData(_rawData, _rawDataLength);\n  }\n  // Try to add flags into the current advertising packet\n  if (_hasFlags) {\n    success &= addFlags(_flags);\n  }\n  // Try to add Advertised service uuid into the current advertising packet\n  if (_advertisedServiceUuid) {\n    success &= addAdvertisedServiceUuid(_advertisedServiceUuid);\n  }\n  // Try to add Manufacturer data into the current advertising packet\n  if (_manufacturerData && _manufacturerDataLength) {\n    if (_hasManufacturerCompanyId) {\n      success &= addManufacturerData(_manufacturerCompanyId, _manufacturerData, _manufacturerDataLength);\n    } else {\n      success &= addManufacturerData(_manufacturerData, _manufacturerDataLength);\n    }\n  }\n  // Try to add Service data into the current advertising packet\n  if (_serviceData && _serviceDataLength) {\n    success &= addAdvertisedServiceData(_serviceDataUuid, _serviceData, _serviceDataLength);\n  }\n  // Try to add Local name into the current advertising packet\n  if (_localName) {\n    success &= addLocalName(_localName);\n  }\n  return success;\n}\n\nuint8_t* BLEAdvertisingData::data() \n{\n  return _data;\n}\n\nint BLEAdvertisingData::dataLength() const\n{\n  return _dataLength;\n}\n\nbool BLEAdvertisingData::hasFlags() const\n{\n  return _hasFlags;\n}\n\nbool BLEAdvertisingData::addLocalName(const char *localName)\n{\n  bool success = false;\n  if (strlen(localName) > (MAX_AD_DATA_LENGTH - AD_FIELD_OVERHEAD)) {\n    success = addField(BLEFieldShortLocalName, (uint8_t*)localName, (MAX_AD_DATA_LENGTH - AD_FIELD_OVERHEAD));\n  } else {\n    success = addField(BLEFieldCompleteLocalName, localName);\n  }\n  return success;\n}\n\nbool BLEAdvertisingData::addAdvertisedServiceUuid(const char* advertisedServiceUuid)\n{\n  BLEUuid uuid(advertisedServiceUuid);\n  int uuidLen = uuid.length();\n  BLEAdField advField;\n  if (uuidLen > 2) {\n    advField = BLEFieldIncompleteAdvertisedService128;\n  } else {\n    advField = BLEFieldIncompleteAdvertisedService16;\n  }\n  return addField(advField, uuid.data(), uuidLen);\n}\n\nbool BLEAdvertisingData::addManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength)\n{\n  return addField(BLEFieldManufacturerData, manufacturerData, manufacturerDataLength);\n}\n\nbool BLEAdvertisingData::addManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength)\n{\n  int tempDataLength = manufacturerDataLength + sizeof(companyId);\n  uint8_t tempData[MAX_AD_DATA_LENGTH];\n  memcpy(tempData, &companyId, sizeof(companyId));\n  memcpy(&tempData[sizeof(companyId)], manufacturerData, manufacturerDataLength);\n  return addField(BLEFieldManufacturerData, tempData, tempDataLength);\n}\n\nbool BLEAdvertisingData::addAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length)\n{\n  int tempDataLength = length + sizeof(uuid);\n  uint8_t tempData[MAX_AD_DATA_LENGTH];\n  memcpy(tempData, &uuid, sizeof(uuid));\n  memcpy(&tempData[sizeof(uuid)], data, length);\n  return addField(BLEFieldServiceData, tempData, tempDataLength);\n}\n\nbool BLEAdvertisingData::addRawData(const uint8_t* data, int length)\n{\n  // Bypass addField to add the integral raw data\n  if (length > (MAX_AD_DATA_LENGTH - _dataLength)) {\n    // Not enough space \n    return false;\n  }\n  memcpy(&_data[_dataLength], data, length);\n  _dataLength += length;\n  return true;\n}\n\nbool BLEAdvertisingData::addFlags(uint8_t flags)\n{\n  return addField(BLEFieldFlags, &flags, sizeof(flags));\n}\n\nbool BLEAdvertisingData::addField(BLEAdField field, const char* data)\n{\n  int dataLength = strlen(data);\n  return addField(field, (uint8_t *)data, dataLength);\n}\n\nbool BLEAdvertisingData::addField(BLEAdField field, const uint8_t* data, int length)\n{\n  int fieldLength = length + AD_FIELD_OVERHEAD; // Considering data TYPE and LENGTH fields\n  if (fieldLength > (MAX_AD_DATA_LENGTH - _dataLength)) {\n    // Not enough space for storing this field\n    return false;\n  }\n  // Insert field into advertising data of the instance\n  _data[_dataLength++] = length + 1;\n  _data[_dataLength++] = field;\n  memcpy(&_data[_dataLength], data, length);\n  _dataLength += length;\n  return true;\n}\n"
  },
  {
    "path": "src/BLEAdvertisingData.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_ADVERTISING_DATA_H_\n#define _BLE_ADVERTISING_DATA_H_\n\n#include <Arduino.h>\n#include \"utility/BLEUuid.h\"\n#include \"BLEService.h\"\n\n#define MAX_AD_DATA_LENGTH (31)\n\nenum BLEFlags {\n  BLEFlagsLimitedDiscoverable = 0x01,\n  BLEFlagsGeneralDiscoverable = 0x02,\n  BLEFlagsBREDRNotSupported   = 0x04\n};\n\nenum BLEAdField {\n  BLEFieldFlags = 0x01,\n  BLEFieldIncompleteAdvertisedService16 = 0x02,\n  BLEFieldCompleteAdvertisedService16 = 0x03,\n  BLEFieldIncompleteAdvertisedService128 = 0x06,\n  BLEFieldCompleteAdvertisedService128 = 0x07,\n  BLEFieldShortLocalName = 0x08,\n  BLEFieldCompleteLocalName = 0x09,\n  BLEFieldServiceData = 0x16,\n  BLEFieldManufacturerData = 0xFF,\n\n  BLEAdFieldLast\n};\n\nstruct BLEAdvertisingRawData {\n  uint8_t data[MAX_AD_DATA_LENGTH];\n  int length;\n};\n\nclass BLEAdvertisingData {\npublic:\n  BLEAdvertisingData(); \n  virtual ~BLEAdvertisingData();\n\n  int availableForWrite(); \n  void clear();\n  void copy(const BLEAdvertisingData& adv);\n  BLEAdvertisingData& operator=(const BLEAdvertisingData &other);\n\n  bool setAdvertisedService(const BLEService& service);\n  bool setAdvertisedServiceUuid(const char* advertisedServiceUuid);\n  bool setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength);\n  bool setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength);\n  bool setLocalName(const char *localName);\n  bool setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length);\n  bool setRawData(const uint8_t* data, int length);\n  bool setRawData(const BLEAdvertisingRawData& data);\n  bool setFlags(uint8_t flags);\n\nprotected:\n  friend class BLELocalDevice;\n  bool updateData();\n  uint8_t* data();\n  int dataLength() const;\n  int remainingLength() const;\n  bool hasFlags() const;\n\nprivate:\n  bool updateRemainingLength(int oldFieldLength, int newFieldLength);\n\n  bool addAdvertisedServiceUuid(const char* advertisedServiceUuid);\n  bool addManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength);\n  bool addManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength);\n  bool addLocalName(const char *localName);\n  bool addAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length);\n  bool addRawData(const uint8_t* data, int length);\n  bool addFlags(uint8_t flags);\n\n  bool addField(BLEAdField field, const char* data);\n  bool addField(BLEAdField field, const uint8_t* data, int length);\n\n  uint8_t _data[MAX_AD_DATA_LENGTH];\n  int _dataLength;\n\n  int _remainingLength;\n\n  const uint8_t* _rawData;\n  int _rawDataLength;\n\n  uint8_t _flags;\n  bool _hasFlags;\n  const char* _localName;\n\n  const uint8_t* _manufacturerData;\n  int _manufacturerDataLength;\n  uint16_t _manufacturerCompanyId;\n  bool _hasManufacturerCompanyId;\n\n  const char* _advertisedServiceUuid; \n  int _advertisedServiceUuidLength;\n  uint16_t _serviceDataUuid;\n  const uint8_t* _serviceData;\n  int _serviceDataLength;\n};\n\n#endif\n"
  },
  {
    "path": "src/BLECharacteristic.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLEProperty.h\"\n\n#include \"local/BLELocalCharacteristic.h\"\n#include \"remote/BLERemoteCharacteristic.h\"\n\n#include \"BLECharacteristic.h\"\n\nextern \"C\" int strcasecmp(char const *a, char const *b);\n\nBLECharacteristic::BLECharacteristic() :\n  BLECharacteristic((BLELocalCharacteristic*)NULL)\n{\n}\n\nBLECharacteristic::BLECharacteristic(BLELocalCharacteristic* local) :\n  _local(local),\n  _remote(NULL)\n{\n  if (_local) {\n    _local->retain();\n  }\n}\n\nBLECharacteristic::BLECharacteristic(BLERemoteCharacteristic* remote) :\n  _local(NULL),\n  _remote(remote)\n{\n  if (_remote) {\n    _remote->retain();\n  }\n}\n\nBLECharacteristic::BLECharacteristic(const char* uuid, uint16_t permissions, int valueSize, bool fixedLength) :\n  BLECharacteristic(new BLELocalCharacteristic(uuid, permissions, valueSize, fixedLength))\n{\n}\n\nBLECharacteristic::BLECharacteristic(const char* uuid, uint16_t permissions, const char* value) :\n  BLECharacteristic(new BLELocalCharacteristic(uuid, permissions, value))\n{\n}\n\nBLECharacteristic::BLECharacteristic(const BLECharacteristic& other)\n{\n  _local = other._local;\n  if (_local) {\n    _local->retain();\n  }\n\n  _remote = other._remote;\n  if (_remote) {\n    _remote->retain();\n  }\n}\n\nBLECharacteristic::~BLECharacteristic()\n{\n  if (_local && _local->release() == 0) {\n    delete _local;\n  }\n\n  if (_remote && _remote->release() == 0) {\n    delete _remote;\n  }\n}\n\nconst char* BLECharacteristic::uuid() const\n{\n  if (_local) {\n    return _local->uuid();\n  }\n\n  if (_remote) {\n    return _remote->uuid();\n  }\n\n  return \"\";\n}\n\nuint8_t BLECharacteristic::properties() const\n{\n  if (_local) {\n    return _local->properties();\n  }\n\n  if (_remote) {\n    return _remote->properties();\n  }\n\n  return 0;\n}\n\nint BLECharacteristic::valueSize() const\n{\n  if (_local) {\n    return _local->valueSize();\n  }\n\n  if (_remote) {\n    return _remote->valueLength();\n  }\n\n  return 0;\n}\n\nconst uint8_t* BLECharacteristic::value() const\n{\n  if (_local) {\n    return _local->value();\n  }\n\n  if (_remote) {\n    return _remote->value();\n  }\n\n  return NULL;\n}\n\nint BLECharacteristic::valueLength() const\n{\n  if (_local) {\n    return _local->valueLength();\n  }\n\n  if (_remote) {\n    return _remote->valueLength();\n  }\n\n  return 0;\n}\n\nuint8_t BLECharacteristic::operator[] (int offset) const\n{\n  if (_local) {\n    return (*_local)[offset];\n  }\n\n  if (_remote) {\n    return (*_remote)[offset];\n  }\n\n  return 0;\n}\n\nint BLECharacteristic::readValue(uint8_t value[], int length)\n{\n  int bytesRead = 0;\n\n  if (_local) {\n    bytesRead = min(length, _local->valueLength());\n\n    memcpy(value, _local->value(), bytesRead);\n  }\n\n  if (_remote) {\n    // trigger a read if the updated value (notification/indication)\n    // has already been read and the characteristic is readable\n    if (_remote->updatedValueRead() && canRead()) {\n      if (!read()) {\n        // read failed\n        return 0;\n      }\n    }\n\n    bytesRead = min(length, _remote->valueLength());\n\n    memcpy(value, _remote->value(), bytesRead);\n  }\n\n  return bytesRead;\n}\n\nint BLECharacteristic::readValue(void* value, int length)\n{\n  return readValue((uint8_t*)value, length);\n}\n\nint BLECharacteristic::readValue(uint8_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLECharacteristic::readValue(int8_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLECharacteristic::readValue(uint16_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLECharacteristic::readValue(int16_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLECharacteristic::readValue(uint32_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLECharacteristic::readValue(int32_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLECharacteristic::writeValue(const uint8_t value[], int length, bool withResponse)\n{\n  if (_local) {\n    return _local->writeValue(value, length);\n  }\n\n  if (_remote) {\n    return _remote->writeValue(value, length, withResponse);\n  }\n\n  return 0;\n}\n\nint BLECharacteristic::writeValue(const void* value, int length, bool withResponse)\n{\n  return writeValue((const uint8_t*)value, length, withResponse);\n}\n\nint BLECharacteristic::writeValue(const char* value, bool withResponse)\n{\n  if (_local) {\n    return _local->writeValue(value);\n  }\n\n  if (_remote) {\n    return _remote->writeValue(value, withResponse);\n  }\n\n  return 0;\n}\n\nint BLECharacteristic::writeValue(uint8_t value, bool withResponse)\n{\n  return writeValue((uint8_t*)&value, sizeof(value), withResponse);\n}\n\nint BLECharacteristic::writeValue(int8_t value, bool withResponse)\n{\n  return writeValue((uint8_t*)&value, sizeof(value), withResponse);\n}\n\nint BLECharacteristic::writeValue(uint16_t value, bool withResponse)\n{\n  return writeValue((uint8_t*)&value, sizeof(value), withResponse);\n}\n\nint BLECharacteristic::writeValue(int16_t value, bool withResponse)\n{\n  return writeValue((uint8_t*)&value, sizeof(value), withResponse);\n}\n\nint BLECharacteristic::writeValue(uint32_t value, bool withResponse)\n{\n  return writeValue((uint8_t*)&value, sizeof(value), withResponse);\n}\n\nint BLECharacteristic::writeValue(int32_t value, bool withResponse)\n{\n  return writeValue((uint8_t*)&value, sizeof(value), withResponse);\n}\n\nint BLECharacteristic::broadcast()\n{\n  if (_local) {\n    return _local->broadcast();\n  }\n\n  return 0;\n}\n\nbool BLECharacteristic::written()\n{\n  if (_local) {\n    return _local->written();\n  }\n\n  return false;\n}\n\nbool BLECharacteristic::subscribed()\n{\n  if (_local) {\n    return _local->subscribed();\n  }\n\n  return false;\n}\n\nbool BLECharacteristic::valueUpdated()\n{\n  if (_remote) {\n    return _remote->valueUpdated();\n  }\n\n  return false; \n}\n\nvoid BLECharacteristic::addDescriptor(BLEDescriptor& descriptor)\n{\n  if (_local) {\n    return _local->addDescriptor(descriptor);\n  }\n}\n\nBLECharacteristic::operator bool() const\n{\n  return (_local != NULL) || (_remote != NULL);\n}\n\nBLELocalCharacteristic* BLECharacteristic::local()\n{\n  return _local;\n}\n\nvoid BLECharacteristic::setEventHandler(int event, BLECharacteristicEventHandler eventHandler)\n{\n  if (_local) {\n    _local->setEventHandler((BLECharacteristicEvent)event, eventHandler);\n  }\n\n  if (_remote) {\n    _remote->setEventHandler((BLECharacteristicEvent)event, eventHandler);\n  }\n}\n\nint BLECharacteristic::descriptorCount() const\n{\n  if (_remote) {\n    return _remote->descriptorCount();\n  }\n\n  return 0;\n}\n\nbool BLECharacteristic::hasDescriptor(const char* uuid) const\n{\n  return hasDescriptor(uuid, 0);\n}\n\nbool BLECharacteristic::hasDescriptor(const char* uuid, int index) const\n{\n  if (_remote) {\n    int count = 0;\n    int numDescriptors = _remote->descriptorCount();\n\n    for (int i = 0; i < numDescriptors; i++) {\n      BLERemoteDescriptor* d = _remote->descriptor(i);\n\n      if (strcasecmp(uuid, d->uuid()) == 0) {\n        if (count == index) {\n          return true;\n        }\n\n        count++;\n      }\n    }\n  }\n\n  return false;\n}\n\nBLEDescriptor BLECharacteristic::descriptor(int index) const\n{\n  if (_remote) {\n    return BLEDescriptor(_remote->descriptor(index));\n  }\n\n  return BLEDescriptor();\n}\n\nBLEDescriptor BLECharacteristic::descriptor(const char * uuid) const\n{\n  return descriptor(uuid, 0);\n}\n\nBLEDescriptor BLECharacteristic::descriptor(const char * uuid, int index) const\n{\n  if (_remote) {\n    int count = 0;\n    int numDescriptors = _remote->descriptorCount();\n\n    for (int i = 0; i < numDescriptors; i++) {\n      BLERemoteDescriptor* d = _remote->descriptor(i);\n\n      if (strcasecmp(uuid, d->uuid()) == 0) {\n        if (count == index) {\n          return BLEDescriptor(d);\n        }\n\n        count++;\n      }\n    }\n  }\n\n  return BLEDescriptor();\n}\n\nbool BLECharacteristic::canRead()\n{\n  if (_remote) {\n    return (properties() & BLERead) != 0;\n  }\n\n  return false;\n}\n\nbool BLECharacteristic::read()\n{\n  if (_remote) {\n    return _remote->read();\n  }\n\n  return false;\n}\n\nbool BLECharacteristic::canWrite()\n{\n  if (_remote) {\n    return (properties() & (BLEWrite | BLEWriteWithoutResponse)) != 0;\n  }\n\n  return false;\n}\n\nbool BLECharacteristic::canSubscribe()\n{\n  if (_remote) {\n    return (properties() & (BLENotify | BLEIndicate)) != 0;\n  }\n\n  return false;\n}\n\nbool BLECharacteristic::subscribe()\n{\n  if (_remote) {\n    return _remote->writeCccd((properties() & BLEIndicate) ? 0x0002 : 0x0001);\n  }\n\n  return false;\n}\n\nbool BLECharacteristic::canUnsubscribe()\n{\n  return canSubscribe();\n}\n\nbool BLECharacteristic::unsubscribe()\n{\n  if (_remote) {\n    return _remote->writeCccd(0x0000);\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "src/BLECharacteristic.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_CHARACTERISTIC_H_\n#define _BLE_CHARACTERISTIC_H_\n\n#include <stdint.h>\n\n#include \"BLEDescriptor.h\"\n\nenum BLECharacteristicEvent {\n  BLESubscribed = 0,\n  BLEUnsubscribed = 1,\n//BLERead = 2, // defined in BLEProperties.h\n  BLEWritten = 3,\n  BLEUpdated = BLEWritten, // alias\n\n  BLECharacteristicEventLast\n};\n\nclass BLECharacteristic;\nclass BLEDevice;\n\ntypedef void (*BLECharacteristicEventHandler)(BLEDevice device, BLECharacteristic characteristic);\n\nclass BLELocalCharacteristic;\nclass BLERemoteCharacteristic;\n\nclass BLECharacteristic  {\npublic:\n  BLECharacteristic();\n  BLECharacteristic(const char* uuid, uint16_t permissions, int valueSize, bool fixedLength = false);\n  BLECharacteristic(const char* uuid, uint16_t permissions, const char* value);\n  BLECharacteristic(const BLECharacteristic& other);\n  virtual ~BLECharacteristic();\n\n  const char* uuid() const;\n\n  uint8_t properties() const;\n\n  int valueSize() const;\n  const uint8_t* value() const;\n  int valueLength() const;\n  uint8_t operator[] (int offset) const;\n\n  int readValue(uint8_t value[], int length);\n  int readValue(void* value, int length);\n  int readValue(uint8_t& value);\n  int readValue(int8_t& value);\n  int readValue(uint16_t& value);\n  int readValue(int16_t& value);\n  int readValue(uint32_t& value);\n  int readValue(int32_t& value);\n\n  int writeValue(const uint8_t value[], int length, bool withResponse = true);\n  int writeValue(const void* value, int length, bool withResponse = true);\n  int writeValue(const char* value, bool withResponse = true);\n  int writeValue(uint8_t value, bool withResponse = true);\n  int writeValue(int8_t value, bool withResponse = true);\n  int writeValue(uint16_t value, bool withResponse = true);\n  int writeValue(int16_t value, bool withResponse = true);\n  int writeValue(uint32_t value, bool withResponse = true);\n  int writeValue(int32_t value, bool withResponse = true);\n\n  // deprecated, use writeValue(...)\n  int setValue(const uint8_t value[], int length) { return writeValue(value, length); }\n  int setValue(const char* value) { return writeValue(value); }\n\n  int broadcast();\n\n  bool written();\n  bool subscribed();\n  bool valueUpdated();\n\n  void addDescriptor(BLEDescriptor& descriptor);\n\n  operator bool() const;\n\n  void setEventHandler(int event, BLECharacteristicEventHandler eventHandler);\n\n  int descriptorCount() const;\n  bool hasDescriptor(const char* uuid) const;\n  bool hasDescriptor(const char* uuid, int index) const;\n  BLEDescriptor descriptor(int index) const;\n  BLEDescriptor descriptor(const char * uuid) const;\n  BLEDescriptor descriptor(const char * uuid, int index) const;\n\n  bool canRead();\n  bool read();\n  bool canWrite();\n  bool canSubscribe();\n  bool subscribe();\n  bool canUnsubscribe();\n  bool unsubscribe();\n\nprotected:\n  friend class BLELocalCharacteristic;\n  friend class BLELocalService;\n\n  BLECharacteristic(BLELocalCharacteristic* local);\n\n  BLELocalCharacteristic* local();\n\nprotected:\n  friend class BLEDevice;\n  friend class BLEService;\n  friend class BLERemoteCharacteristic;\n\n  BLECharacteristic(BLERemoteCharacteristic* remote);\n\nprivate:\n  BLELocalCharacteristic* _local;\n  BLERemoteCharacteristic* _remote;\n};\n\n#endif\n"
  },
  {
    "path": "src/BLEDescriptor.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <stddef.h>\n\n#include \"local/BLELocalDescriptor.h\"\n#include \"remote/BLERemoteDescriptor.h\"\n\n#include \"BLEDescriptor.h\"\n\nBLEDescriptor::BLEDescriptor() :\n  BLEDescriptor((BLELocalDescriptor*)NULL)\n{\n}\n\nBLEDescriptor::BLEDescriptor(BLELocalDescriptor* local) :\n  _local(local),\n  _remote(NULL)\n{\n  if (_local) {\n    _local->retain();\n  }\n}\n\nBLEDescriptor::BLEDescriptor(BLERemoteDescriptor* remote) :\n  _local(NULL),\n  _remote(remote)\n{\n  if (_remote) {\n    _remote->retain();\n  }\n}\n\nBLEDescriptor::BLEDescriptor(const char* uuid, const uint8_t value[], int valueSize) :\n  BLEDescriptor(new BLELocalDescriptor(uuid, value, valueSize))\n{\n}\n\nBLEDescriptor::BLEDescriptor(const char* uuid, const char* value) :\n  BLEDescriptor(new BLELocalDescriptor(uuid, value))\n{\n}\n\nBLEDescriptor::BLEDescriptor(const BLEDescriptor& other)\n{\n  _local = other._local;\n  if (_local) {\n    _local->retain();\n  }\n\n  _remote = other._remote;\n  if (_remote) {\n    _remote->retain();\n  }\n}\n\nBLEDescriptor::~BLEDescriptor()\n{\n  if (_local && _local->release() == 0) {\n    delete _local;\n  }\n\n  if (_remote && _remote->release() == 0) {\n    delete _remote;\n  }\n}\n\nconst char* BLEDescriptor::uuid() const\n{\n  if (_local) {\n    return _local->uuid();\n  }\n\n  if (_remote) {\n    return _remote->uuid();\n  }\n\n  return \"\";\n}\n\nint BLEDescriptor::valueSize() const\n{\n  if (_local) {\n    return _local->valueSize();\n  }\n\n  if (_remote) {\n    return _remote->valueLength();\n  }\n\n  return 0;\n}\n\nconst uint8_t* BLEDescriptor::value() const\n{\n  if (_local) {\n    return _local->value();\n  }\n\n  if (_remote) {\n    return _remote->value();\n  }\n\n  return NULL;\n}\n\nint BLEDescriptor::valueLength() const\n{\n  return valueSize(); \n}\n\nuint8_t BLEDescriptor::operator[] (int offset) const\n{\n  if (_local) {\n    return (*_local)[offset];\n  }\n\n  if (_remote) {\n    return (*_remote)[offset];\n  }\n\n  return 0;\n}\n\nint BLEDescriptor::readValue(uint8_t value[], int length)\n{\n  int bytesRead = 0;\n\n  if (_local) {\n    bytesRead = min(length, _local->valueSize());\n\n    memcpy(value, _local->value(), bytesRead);\n  }\n\n  if (_remote) {\n    if (!read()) {\n      // read failed\n      return 0;\n    }\n\n    bytesRead = min(length, _remote->valueLength());\n\n    memcpy(value, _remote->value(), bytesRead);\n  }\n\n  return bytesRead;\n}\n\nint BLEDescriptor::readValue(void* value, int length)\n{\n  return readValue((uint8_t*)value, length);\n}\n\nint BLEDescriptor::readValue(uint8_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLEDescriptor::readValue(int8_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLEDescriptor::readValue(uint16_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLEDescriptor::readValue(int16_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLEDescriptor::readValue(uint32_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nint BLEDescriptor::readValue(int32_t& value)\n{\n  value = 0;\n\n  return readValue((uint8_t*)&value, sizeof(value));\n}\n\nBLEDescriptor::operator bool() const\n{\n  return (_local != NULL) || (_remote != NULL); \n}\n\nbool BLEDescriptor::read()\n{\n  if (_remote) {\n    return _remote->read();\n  }\n\n  return false;\n}\n\nBLELocalDescriptor* BLEDescriptor::local()\n{\n  return _local;\n}\n"
  },
  {
    "path": "src/BLEDescriptor.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_DESCRIPTOR_H_\n#define _BLE_DESCRIPTOR_H_\n\n#include <stdint.h>\n\nclass BLELocalDescriptor;\nclass BLERemoteDescriptor;\n\nclass BLEDescriptor {\npublic:\n  BLEDescriptor();\n  BLEDescriptor(const BLEDescriptor& other);\n  BLEDescriptor(const char* uuid, const uint8_t value[], int valueSize);\n  BLEDescriptor(const char* uuid, const char* value);\n  virtual ~BLEDescriptor();\n\n  const char* uuid() const;\n\n  int valueSize() const;\n  const uint8_t* value() const;\n  int valueLength() const;\n  uint8_t operator[] (int offset) const;\n\n  int readValue(uint8_t value[], int length);\n  int readValue(void* value, int length);\n  int readValue(uint8_t& value);\n  int readValue(int8_t& value);\n  int readValue(uint16_t& value);\n  int readValue(int16_t& value);\n  int readValue(uint32_t& value);\n  int readValue(int32_t& value);\n\n  operator bool() const;\n\n  bool read();\n\nprotected:\n  friend class BLELocalCharacteristic;\n\n  BLEDescriptor(BLELocalDescriptor* local);\n\n  BLELocalDescriptor* local();\n\nprotected:\n  friend class BLECharacteristic;\n\n  BLEDescriptor(BLERemoteDescriptor* remote);\n\nprivate:\n  BLELocalDescriptor* _local;\n  BLERemoteDescriptor* _remote;\n};\n\n#endif\n"
  },
  {
    "path": "src/BLEDevice.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"utility/ATT.h\"\n#include \"utility/BLEUuid.h\"\n#include \"utility/HCI.h\"\n\n#include \"remote/BLERemoteDevice.h\"\n\n#include \"BLEDevice.h\"\n\nextern \"C\" int strcasecmp(char const *a, char const *b);\n\nBLEDevice::BLEDevice() :\n  _advertisementTypeMask(0),\n  _eirDataLength(0),\n  _rssi(127)\n{\n  memset(_address, 0x00, sizeof(_address));\n}\n\nBLEDevice::BLEDevice(uint8_t addressType, uint8_t address[6]) :\n  _addressType(addressType),\n  _advertisementTypeMask(0),\n  _eirDataLength(0),\n  _rssi(127)\n{\n  memcpy(_address, address, sizeof(_address));\n}\n\nBLEDevice::~BLEDevice()\n{\n}\n\nvoid BLEDevice::poll()\n{\n  HCI.poll();\n}\n\nvoid BLEDevice::poll(unsigned long timeout)\n{\n  HCI.poll(timeout);\n}\n\nbool BLEDevice::connected() const\n{\n  HCI.poll();\n\n  if (!(*this)) {\n    return false;\n  }\n\n  return ATT.connected(_addressType, _address);\n}\n\nbool BLEDevice::disconnect()\n{\n  return ATT.disconnect(_addressType, _address);\n}\n\nString BLEDevice::address() const\n{\n  char result[18];\n  sprintf(result, \"%02x:%02x:%02x:%02x:%02x:%02x\", _address[5], _address[4], _address[3], _address[2], _address[1], _address[0]);\n\n  return result;\n}\n\nbool BLEDevice::hasLocalName() const\n{\n  return (localName().length() > 0);\n}\n\nbool BLEDevice::hasAdvertisedServiceUuid() const\n{\n  return hasAdvertisedServiceUuid(0);\n}\n\nbool BLEDevice::hasAdvertisedServiceUuid(int index) const\n{\n  return (advertisedServiceUuid(index).length() > 0);\n}\n\nint BLEDevice::advertisedServiceUuidCount() const\n{\n  int advertisedServiceCount = 0;\n\n  for (unsigned char i = 0; i < _eirDataLength;) {\n    int eirLength = _eirData[i++];\n    int eirType = _eirData[i++];\n\n    if (eirType == 0x02 || eirType == 0x03 || eirType == 0x06 || eirType == 0x07) {\n      int uuidLength;\n\n      if (eirType == 0x02 || eirType == 0x03) {\n        uuidLength = 2;\n      } else /*if (eirType == 0x06 || eirType == 0x07)*/ {\n        uuidLength = 16;\n      }\n\n      for (int j = 0; j < (eirLength - 1); j += uuidLength) {\n        advertisedServiceCount++;\n      }\n    }\n\n    i += (eirLength - 1);\n  }\n\n  return advertisedServiceCount;\n}\n\nString BLEDevice::localName() const\n{\n  String localName = \"\";\n\n  for (int i = 0; i < _eirDataLength;) {\n    int eirLength = _eirData[i++];\n    int eirType = _eirData[i++];\n\n    if (eirType == 0x08 || eirType == 0x09) {\n      localName.reserve(eirLength - 1);\n\n      for (int j = 0; j < (eirLength - 1); j++) {\n        localName += (char)_eirData[i + j];\n      }\n      break;\n    }\n\n    i += (eirLength - 1);\n  }\n\n  return localName;\n}\n\nString BLEDevice::advertisedServiceUuid() const\n{\n  return advertisedServiceUuid(0);\n}\n\nString BLEDevice::advertisedServiceUuid(int index) const\n{\n  String serviceUuid;\n  int uuidIndex = 0;\n\n  for (unsigned char i = 0; i < _eirDataLength;) {\n    int eirLength = _eirData[i++];\n    int eirType = _eirData[i++];\n\n    if (eirType == 0x02 || eirType == 0x03 || eirType == 0x06 || eirType == 0x07) {\n      int uuidLength;\n\n      if (eirType == 0x02 || eirType == 0x03) {\n        uuidLength = 2;\n      } else /*if (eirType == 0x06 || eirType == 0x07)*/ {\n        uuidLength = 16;\n      }\n\n      for (int j = 0; j < (eirLength - 1); j += uuidLength) {\n        if (uuidIndex == index) {\n          serviceUuid = BLEUuid::uuidToString(&_eirData[i + j * uuidLength], uuidLength);\n        }\n\n        uuidIndex++;\n      }\n    }\n\n    i += (eirLength - 1);\n  }\n\n  return serviceUuid;\n}\n\nbool BLEDevice::hasAdvertisementData() const\n{\n  return (_eirDataLength > 0);\n}\n\nint BLEDevice::advertisementDataLength() const\n{\n  return _eirDataLength;\n}\n\nint BLEDevice::advertisementData(uint8_t value[], int length) const\n{\n  if (length > _eirDataLength) length = _eirDataLength;\n\n  if (length) {\n    memcpy(value, _eirData, length);\n  }\n\n  return length;\n}\n\nbool BLEDevice::hasManufacturerData() const\n{\n  return (manufacturerDataLength() > 0);\n}\n\nint BLEDevice::manufacturerDataLength() const\n{\n  int length = 0;\n\n  for (int i = 0; i < _eirDataLength;) {\n    int eirLength = _eirData[i++];\n    int eirType = _eirData[i++];\n\n    if (eirType == 0xFF) {\n      length = (eirLength - 1);\n      break;\n    }\n\n    i += (eirLength - 1);\n  }\n\n  return length;\n}\n\nint BLEDevice::manufacturerData(uint8_t value[], int length) const\n{\n  for (int i = 0; i < _eirDataLength;) {\n    int eirLength = _eirData[i++];\n    int eirType = _eirData[i++];\n\n    if (eirType == 0xFF) {\n      if (length > (eirLength - 1)) length = (eirLength - 1);\n\n      memcpy(value, &_eirData[i], length);\n      break;\n    }\n\n    i += (eirLength - 1);\n  }\n\n  return length;\n}\n\nint BLEDevice::rssi()\n{\n  uint16_t handle = ATT.connectionHandle(_addressType, _address);\n\n  if (handle != 0xffff) {\n    return HCI.readRssi(handle);\n  }\n\n  return _rssi;\n}\n\nbool BLEDevice::connect()\n{\n  return ATT.connect(_addressType, _address);\n}\n\nbool BLEDevice::discoverAttributes()\n{\n  return ATT.discoverAttributes(_addressType, _address, NULL);\n}\n\nbool BLEDevice::discoverService(const char* serviceUuid)\n{\n  return ATT.discoverAttributes(_addressType, _address, serviceUuid);\n}\n\nBLEDevice::operator bool() const\n{\n  uint8_t zeros[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,};\n\n  return (memcmp(_address, zeros, sizeof(zeros)) != 0);\n}\n\nbool BLEDevice::operator==(const BLEDevice& rhs) const\n{\n  return ((_addressType == rhs._addressType) && memcmp(_address, rhs._address, sizeof(_address)) == 0);\n}\n\nbool BLEDevice::operator!=(const BLEDevice& rhs) const\n{\n  return ((_addressType != rhs._addressType) || memcmp(_address, rhs._address, sizeof(_address)) != 0);\n}\n\nString BLEDevice::deviceName()\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    BLEService genericAccessService = service(\"1800\");\n\n    if (genericAccessService) {\n      BLECharacteristic deviceNameCharacteristic = genericAccessService.characteristic(\"2a00\");\n\n      if (deviceNameCharacteristic) {\n        deviceNameCharacteristic.read();\n\n        String result;\n        int valueLength = deviceNameCharacteristic.valueLength();\n        const char* value = (const char*)deviceNameCharacteristic.value();\n\n        result.reserve(valueLength);\n\n        for (int i = 0; i < valueLength; i++) {\n          result += value[i];\n        }\n\n        return result;\n      }\n    }\n  }\n\n  return \"\";\n}\n\nint BLEDevice::appearance()\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    BLEService genericAccessService = service(\"1801\");\n\n    if (genericAccessService) {\n      BLECharacteristic appearanceCharacteristic = genericAccessService.characteristic(\"2a01\");\n\n      if (appearanceCharacteristic) {\n        appearanceCharacteristic.read();\n\n        uint16_t result = 0;\n\n        memcpy  (&result, appearanceCharacteristic.value(), min((int)sizeof(result), appearanceCharacteristic.valueLength()));\n\n        return result;\n      }\n    }\n  }\n\n  return 0;\n}\n\nint BLEDevice::serviceCount() const\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    return device->serviceCount();\n  }\n\n  return 0;\n}\n\nbool BLEDevice::hasService(const char* uuid) const\n{\n  return hasService(uuid, 0);\n}\n\nbool BLEDevice::hasService(const char* uuid, int index) const\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    int count = 0;\n    int numServices = device->serviceCount();\n\n    for (int i = 0; i < numServices; i++) {\n      BLERemoteService* s = device->service(i);\n\n      if (strcasecmp(uuid, s->uuid()) == 0) {\n        if (count == index) {\n          return true;\n        }\n\n        count++;\n      }\n    }\n  }\n\n  return false;\n}\n\nBLEService BLEDevice::service(int index) const\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    if (index < (int)device->serviceCount()) {\n      return BLEService(device->service(index));\n    }\n  }\n\n  return BLEService();\n}\n\nBLEService BLEDevice::service(const char * uuid) const\n{\n  return service(uuid, 0);\n}\n\nBLEService BLEDevice::service(const char * uuid, int index) const\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    int count = 0;\n    int numServices = device->serviceCount();\n\n    for (int i = 0; i < numServices; i++) {\n      BLERemoteService* s = device->service(i);\n\n      if (strcasecmp(uuid, s->uuid()) == 0) {\n        if (count == index) {\n          return BLEService(s);\n        }\n\n        count++;\n      }\n    }\n  }\n\n  return BLEService();\n}\n\nint BLEDevice::characteristicCount() const\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    int result = 0;\n    int numServices = device->serviceCount();\n\n    for (int i = 0; i < numServices; i++) {\n      result += device->service(i)->characteristicCount();\n    }\n\n    return result;\n  }\n\n  return 0;\n}\n\nbool BLEDevice::hasCharacteristic(const char* uuid) const\n{\n  return hasCharacteristic(uuid, 0);\n}\n\nbool BLEDevice::hasCharacteristic(const char* uuid, int index) const\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    int count = 0;\n    int numServices = device->serviceCount();\n\n    for (int i = 0; i < numServices; i++) {\n      BLERemoteService* s = device->service(i);\n\n      int numCharacteristics = s->characteristicCount();\n\n      for (int j = 0; j < numCharacteristics; j++) {\n        BLERemoteCharacteristic* c = s->characteristic(j);\n\n\n        if (strcasecmp(c->uuid(), uuid) == 0) {\n          if (count == index) {\n            return true;\n          }\n        }\n\n        count++;\n      }\n    }\n  }\n\n  return false;\n}\n\nBLECharacteristic BLEDevice::characteristic(int index) const\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    int count = 0;\n    int numServices = device->serviceCount();\n\n    for (int i = 0; i < numServices; i++) {\n      BLERemoteService* s = device->service(i);\n\n      int numCharacteristics = s->characteristicCount();\n\n      for (int j = 0; j < numCharacteristics; j++) {\n        if (count == index) {\n          BLERemoteCharacteristic* c = s->characteristic(j);\n\n          return BLECharacteristic(c);\n        }\n\n        count++;\n      }\n    }\n  }\n\n  return BLECharacteristic();\n}\n\nBLECharacteristic BLEDevice::characteristic(const char * uuid) const\n{\n  return characteristic(uuid, 0);\n}\n\nBLECharacteristic BLEDevice::characteristic(const char * uuid, int index) const\n{\n  BLERemoteDevice* device = ATT.device(_addressType, _address);\n\n  if (device) {\n    int count = 0;\n    int numServices = device->serviceCount();\n\n    for (int i = 0; i < numServices; i++) {\n      BLERemoteService* s = device->service(i);\n\n      int numCharacteristics = s->characteristicCount();\n\n      for (int j = 0; j < numCharacteristics; j++) {\n        BLERemoteCharacteristic* c = s->characteristic(j);\n\n        if (strcasecmp(c->uuid(), uuid) == 0) {\n          if (count == index) {\n\n            return BLECharacteristic(c);\n          }\n\n          count++;\n        }\n      }\n    }\n  }\n\n  return BLECharacteristic();\n}\n\nbool BLEDevice::hasAddress(uint8_t addressType, uint8_t address[6])\n{\n  return (_addressType == addressType) && (memcmp(_address, address, sizeof(_address)) == 0);\n}\n\nvoid BLEDevice::setAdvertisementData(uint8_t type, uint8_t eirDataLength, uint8_t eirData[], int8_t rssi)\n{\n  _advertisementTypeMask = (1 << type);\n  _eirDataLength = eirDataLength;\n  memcpy(_eirData, eirData, eirDataLength);\n  _rssi = rssi;\n}\n\nvoid BLEDevice::setScanResponseData(uint8_t eirDataLength, uint8_t eirData[], int8_t rssi)\n{\n  _advertisementTypeMask |= (1 << 0x04);\n  memcpy(&_eirData[_eirDataLength], eirData, eirDataLength);\n  _eirDataLength += eirDataLength;\n  _rssi = rssi;\n}\n\nbool BLEDevice::discovered()\n{\n  // expect, 0x03 or 0x04 flag to be set\n  return (_advertisementTypeMask & 0x18) != 0;\n}\n\n"
  },
  {
    "path": "src/BLEDevice.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_DEVICE_H_\n#define _BLE_DEVICE_H_\n\n#include <Arduino.h>\n\n#include \"BLEService.h\"\n\nenum BLEDeviceEvent {\n  BLEConnected = 0,\n  BLEDisconnected = 1,\n  BLEDiscovered = 2,\n\n  BLEDeviceLastEvent\n};\n\nclass BLEDevice;\n\ntypedef void (*BLEDeviceEventHandler)(BLEDevice device);\n\nclass BLEDevice {\npublic:\n  BLEDevice();\n  virtual ~BLEDevice();\n\n  virtual void poll();\n  virtual void poll(unsigned long timeout);\n\n  virtual bool connected() const;\n  virtual bool disconnect();\n\n  virtual String address() const;\n\n  bool hasLocalName() const;\n    \n  bool hasAdvertisedServiceUuid() const;\n  bool hasAdvertisedServiceUuid(int index) const;\n  int advertisedServiceUuidCount() const;\n\n  String localName() const;\n  String advertisedServiceUuid() const;\n  String advertisedServiceUuid(int index) const;\n\n  bool hasAdvertisementData() const;\n  int advertisementDataLength() const;\n  int advertisementData(uint8_t value[], int length) const;\n\n  bool hasManufacturerData() const;\n  int manufacturerDataLength() const;\n  int manufacturerData(uint8_t value[], int length) const;\n\n  virtual int rssi();\n\n  bool connect();\n  bool discoverAttributes();\n  bool discoverService(const char* serviceUuid);\n\n  virtual operator bool() const;\n  virtual bool operator==(const BLEDevice& rhs) const;\n  virtual bool operator!=(const BLEDevice& rhs) const;\n\n  String deviceName();\n  int appearance();\n\n  int serviceCount() const; \n  bool hasService(const char* uuid) const;\n  bool hasService(const char* uuid, int index) const;\n  BLEService service(int index) const;\n  BLEService service(const char * uuid) const;\n  BLEService service(const char * uuid, int index) const;\n  int characteristicCount() const;\n  bool hasCharacteristic(const char* uuid) const;\n  bool hasCharacteristic(const char* uuid, int index) const;\n  BLECharacteristic characteristic(int index) const;\n  BLECharacteristic characteristic(const char * uuid) const;\n  BLECharacteristic characteristic(const char * uuid, int index) const;\n\nprotected:\n  friend class ATTClass;\n  friend class GAPClass;\n\n  BLEDevice(uint8_t addressType, uint8_t address[6]);\n\nprotected:\n  friend class GAPClass;\n\n  bool hasAddress(uint8_t addressType, uint8_t address[6]);\n\n  void setAdvertisementData(uint8_t type, uint8_t eirDataLength, uint8_t eirData[], int8_t rssi);\n  void setScanResponseData(uint8_t eirDataLength, uint8_t eirData[], int8_t rssi);\n\n  bool discovered();\n\nprivate:\n  uint8_t _addressType;\n  uint8_t _address[6];\n  uint8_t _advertisementTypeMask;\n  uint8_t _eirDataLength;\n  uint8_t _eirData[31 * 2];\n  int8_t _rssi;\n};\n\n#endif\n"
  },
  {
    "path": "src/BLEProperty.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n// #include <stdint.h>\n\n#ifndef _BLE_PROPERTY_H_\n#define _BLE_PROPERTY_H_\n\nenum BLEProperty {\n  BLEBroadcast            = 0x01,\n  BLERead                 = 0x02,\n  BLEWriteWithoutResponse = 0x04,\n  BLEWrite                = 0x08,\n  BLENotify               = 0x10,\n  BLEIndicate             = 0x20,\n  BLEAuthSignedWrite      = 1 << 6,\n  BLEExtProp              = 1 << 7,\n};\n\nenum BLEPermission {\n  BLEEncryption         = 1 << 9,\n  BLEAuthentication     = 1 << 10,\n  BLEAuthorization      = 1 << 11,\n  // BLEWriteEncryption        = 1 << 11,\n  // BLEWriteAuthentication    = 1 << 12,\n  // BLEWriteAuthorization     = 1 << 13,\n};\n\n#define    ESP_GATT_CHAR_PROP_BIT_BROADCAST    (1 << 0)       /* 0x01 */    /* relate to BTA_GATT_CHAR_PROP_BIT_BROADCAST in bta/bta_gatt_api.h */\n#define    ESP_GATT_CHAR_PROP_BIT_READ         (1 << 1)       /* 0x02 */    /* relate to BTA_GATT_CHAR_PROP_BIT_READ in bta/bta_gatt_api.h */\n#define    ESP_GATT_CHAR_PROP_BIT_WRITE_NR     (1 << 2)       /* 0x04 */    /* relate to BTA_GATT_CHAR_PROP_BIT_WRITE_NR in bta/bta_gatt_api.h */\n#define    ESP_GATT_CHAR_PROP_BIT_WRITE        (1 << 3)       /* 0x08 */    /* relate to BTA_GATT_CHAR_PROP_BIT_WRITE in bta/bta_gatt_api.h */\n#define    ESP_GATT_CHAR_PROP_BIT_NOTIFY       (1 << 4)       /* 0x10 */    /* relate to BTA_GATT_CHAR_PROP_BIT_NOTIFY in bta/bta_gatt_api.h */\n#define    ESP_GATT_CHAR_PROP_BIT_INDICATE     (1 << 5)       /* 0x20 */    /* relate to BTA_GATT_CHAR_PROP_BIT_INDICATE in bta/bta_gatt_api.h */\n#define    ESP_GATT_CHAR_PROP_BIT_AUTH         (1 << 6)       /* 0x40 */    /* relate to BTA_GATT_CHAR_PROP_BIT_AUTH in bta/bta_gatt_api.h */\n#define    ESP_GATT_CHAR_PROP_BIT_EXT_PROP     (1 << 7)       /* 0x80 */    /* relate to BTA_GATT_CHAR_PROP_BIT_EXT_PROP in bta/bta_gatt_api.h */\n\n#define    ESP_GATT_PERM_READ                  (1 << 0)   /* bit 0 -  0x0001 */    /* relate to BTA_GATT_PERM_READ in bta/bta_gatt_api.h */\n#define    ESP_GATT_PERM_READ_ENCRYPTED        (1 << 1)   /* bit 1 -  0x0002 */    /* relate to BTA_GATT_PERM_READ_ENCRYPTED in bta/bta_gatt_api.h */\n#define    ESP_GATT_PERM_READ_ENC_MITM         (1 << 2)   /* bit 2 -  0x0004 */    /* relate to BTA_GATT_PERM_READ_ENC_MITM in bta/bta_gatt_api.h */\n#define    ESP_GATT_PERM_WRITE                 (1 << 4)   /* bit 4 -  0x0010 */    /* relate to BTA_GATT_PERM_WRITE in bta/bta_gatt_api.h */\n#define    ESP_GATT_PERM_WRITE_ENCRYPTED       (1 << 5)   /* bit 5 -  0x0020 */    /* relate to BTA_GATT_PERM_WRITE_ENCRYPTED in bta/bta_gatt_api.h */\n#define    ESP_GATT_PERM_WRITE_ENC_MITM        (1 << 6)   /* bit 6 -  0x0040 */    /* relate to BTA_GATT_PERM_WRITE_ENC_MITM in bta/bta_gatt_api.h */\n#define    ESP_GATT_PERM_WRITE_SIGNED          (1 << 7)   /* bit 7 -  0x0080 */    /* relate to BTA_GATT_PERM_WRITE_SIGNED in bta/bta_gatt_api.h */\n#define    ESP_GATT_PERM_WRITE_SIGNED_MITM     (1 << 8)   /* bit 8 -  0x0100 */    /* relate to BTA_GATT_PERM_WRITE_SIGNED_MITM in bta/bta_gatt_api.h */\n#define    ESP_GATT_PERM_READ_AUTHORIZATION    (1 << 9)   /* bit 9 -  0x0200 */\n#define    ESP_GATT_PERM_WRITE_AUTHORIZATION   (1 << 10)  /* bit 10 - 0x0400 */\n\nenum BLE_GATT_PERM_ {\n  BLE_GATT_READ       = 1 << 0,\n  READ_ENCRYPTED      = 1 << 1,\n  READ_ENC_MITM       = 1 << 2,\n  BLE_GATT_WRITE      = 1 << 4,\n  WRITE_ENCRYPTED     = 1 << 5,\n  WRITE_ENC_MITM      = 1 << 6,\n  WRITE_SIGNED        = 1 << 7,\n  WRITE_SIGNED_MITM   = 1 << 8,\n  READ_AUTHORIZATION  = 1 << 9,\n  WRITE_AUTHORIZATION = 1 << 10,\n};\n\n\n#endif\n"
  },
  {
    "path": "src/BLEService.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"local/BLELocalService.h\"\n#include \"remote/BLERemoteService.h\"\n\n#include \"BLEService.h\"\n\nextern \"C\" int strcasecmp(char const *a, char const *b);\n\nBLEService::BLEService() :\n  BLEService((BLELocalService*)NULL)\n{\n}\n\nBLEService::BLEService(BLELocalService* local) :\n  _local(local),\n  _remote(NULL)\n{\n  if (_local) {\n    _local->retain();\n  }\n}\n\nBLEService::BLEService(BLERemoteService* remote) :\n  _local(NULL),\n  _remote(remote)\n{\n  if (_remote) {\n    _remote->retain();\n  }\n}\n\nBLEService::BLEService(const char* uuid) :\n  BLEService(new BLELocalService(uuid))\n{\n}\n\nBLEService::BLEService(const BLEService& other)\n{\n  _local = other._local;\n  if (_local) {\n    _local->retain();\n  }\n\n  _remote = other._remote;\n  if (_remote) {\n    _remote->retain();\n  }\n}\n\nvoid BLEService::clear()\n{\n  if (_local) {\n    _local->clear();\n  }\n}\n\nBLEService::~BLEService()\n{\n  if (_local && _local->release() == 0) {\n    delete _local;\n  }\n\n  if (_remote && _remote->release() == 0) {\n    delete _remote;\n  }\n}\n\nconst char* BLEService::uuid() const\n{\n  if (_local) {\n    return _local->uuid();\n  }\n\n  if (_remote) {\n    return _remote->uuid();\n  }\n\n  return \"\";\n}\n\nvoid BLEService::addCharacteristic(BLECharacteristic& characteristic)\n{\n  if (_local) {\n    _local->addCharacteristic(characteristic);\n  }\n}\n\nBLEService::operator bool() const\n{\n  return (_local != NULL) || (_remote != NULL);\n}\n\nint BLEService::characteristicCount() const\n{\n  if (_remote) {\n    return _remote->characteristicCount();\n  }\n\n  return 0;\n}\n\nbool BLEService::hasCharacteristic(const char* uuid) const\n{\n  return hasCharacteristic(uuid, 0);\n}\n\nbool BLEService::hasCharacteristic(const char* uuid, int index) const\n{\n  if (_remote) {\n    int count = 0;\n    int numCharacteristics = _remote->characteristicCount();\n\n    for (int i = 0; i < numCharacteristics; i++) {\n      BLERemoteCharacteristic* c = _remote->characteristic(i);\n\n      if (strcasecmp(uuid, c->uuid()) == 0) {\n        if (count == index) {\n          return true;\n        }\n\n        count++;\n      }\n    }\n  }\n\n  return false;\n}\n\nBLECharacteristic BLEService::characteristic(int index) const\n{\n  if (_remote) {\n    return BLECharacteristic(_remote->characteristic(index));\n  }\n\n  return BLECharacteristic();\n}\n\nBLECharacteristic BLEService::characteristic(const char * uuid) const\n{\n  return characteristic(uuid, 0);\n}\n\nBLECharacteristic BLEService::characteristic(const char * uuid, int index) const\n{\n  if (_remote) {\n    int count = 0;\n    int numCharacteristics = _remote->characteristicCount();\n\n    for (int i = 0; i < numCharacteristics; i++) {\n      BLERemoteCharacteristic* c = _remote->characteristic(i);\n\n      if (strcasecmp(uuid, c->uuid()) == 0) {\n        if (count == index) {\n          return BLECharacteristic(c);\n        }\n\n        count++;\n      }\n    }\n  }\n\n  return BLECharacteristic();\n}\n\nBLELocalService* BLEService::local()\n{\n  return _local;\n}\n"
  },
  {
    "path": "src/BLEService.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_SERVICE_H_\n#define _BLE_SERVICE_H_\n\n#include \"BLECharacteristic.h\"\n\nclass BLELocalService;\nclass BLERemoteService;\n\nclass BLEService {\npublic:\n  BLEService();\n  BLEService(const char* uuid);\n  BLEService(const BLEService& other);\n  virtual ~BLEService();\n\n  const char* uuid() const;\n  void clear();\n\n  void addCharacteristic(BLECharacteristic& characteristic);\n\n  operator bool() const;\n\n  int characteristicCount() const;\n  bool hasCharacteristic(const char* uuid) const;\n  bool hasCharacteristic(const char* uuid, int index) const;\n  BLECharacteristic characteristic(int index) const;\n  BLECharacteristic characteristic(const char * uuid) const;\n  BLECharacteristic characteristic(const char * uuid, int index) const;\n\nprotected:\n  friend class GATTClass;\n\n  BLEService(BLELocalService* local);\n\n  BLELocalService* local();\n\n  void addCharacteristic(BLELocalCharacteristic* characteristic);\n\nprotected:\n  friend class BLEDevice;\n\n  BLEService(BLERemoteService* remote);\n\nprivate:\n  BLELocalService* _local;\n  BLERemoteService* _remote;\n};\n\n#endif\n"
  },
  {
    "path": "src/BLEStringCharacteristic.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLEStringCharacteristic.h\"\n\nBLEStringCharacteristic::BLEStringCharacteristic(const char* uuid, unsigned int properties, int valueSize) :\n  BLECharacteristic(uuid, properties, valueSize)\n{\n}\n\nint BLEStringCharacteristic::writeValue(const String& value)\n{\n  return BLECharacteristic::writeValue(value.c_str());\n}\n\nString BLEStringCharacteristic::value(void)\n{\n  String str;\n  int length = BLECharacteristic::valueLength();\n  const uint8_t* val = BLECharacteristic::value();\n\n  str.reserve(length);\n\n  for (int i = 0; i < length; i++) {\n    str += (char)val[i];\n  }\n\n  return str;\n}\n"
  },
  {
    "path": "src/BLEStringCharacteristic.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_STRING_CHARACTERISTIC_H_\n#define _BLE_STRING_CHARACTERISTIC_H_\n\n#include <Arduino.h>\n\n#include \"BLECharacteristic.h\"\n\nclass BLEStringCharacteristic : public BLECharacteristic\n{\npublic:\n  BLEStringCharacteristic(const char* uuid, unsigned int properties, int valueSize);\n\n  int writeValue(const String& value);\n  int setValue(const String& value) { return writeValue(value); }\n  String value(void);\n\nprivate:\n};\n\n#endif\n"
  },
  {
    "path": "src/BLETypedCharacteristic.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_TYPED_CHARACTERISTIC_H_\n#define _BLE_TYPED_CHARACTERISTIC_H_\n\n#include \"BLECharacteristic.h\"\n\ntemplate<typename T> class BLETypedCharacteristic : public BLECharacteristic\n{\npublic:\n  BLETypedCharacteristic(const char* uuid, unsigned int permissions);\n\n  int writeValue(T value);\n  int setValue(T value) { return writeValue(value); }\n  T value(void);\n\n  int writeValueLE(T value);\n  int setValueLE(T value) { return writeValueLE(value); }\n  T valueLE(void);\n\n  int writeValueBE(T value);\n  int setValueBE(T value) { return writeValueBE(value); }\n  T valueBE(void);\n\nprivate:\n  T byteSwap(T value);\n};\n\ntemplate<typename T> BLETypedCharacteristic<T>::BLETypedCharacteristic(const char* uuid, unsigned int permissions) :\n  BLECharacteristic(uuid, permissions, sizeof(T), true)\n{\n  T value;\n  memset(&value, 0x00, sizeof(value));\n\n  writeValue(value);\n}\n\ntemplate<typename T> int BLETypedCharacteristic<T>::writeValue(T value)\n{\n  return BLECharacteristic::writeValue((uint8_t*)&value, sizeof(T));\n}\n\ntemplate<typename T> T BLETypedCharacteristic<T>::value()\n{\n  T value;\n\n  memcpy(&value, (unsigned char*)BLECharacteristic::value(), BLECharacteristic::valueSize());\n\n  return value;\n}\n\ntemplate<typename T> int BLETypedCharacteristic<T>::writeValueLE(T value)\n{\n  return writeValue(value);\n}\n\ntemplate<typename T> T BLETypedCharacteristic<T>::valueLE()\n{\n  return value();\n}\n\ntemplate<typename T> int BLETypedCharacteristic<T>::writeValueBE(T value)\n{\n  return writeValue(byteSwap(value));\n}\n\ntemplate<typename T> T BLETypedCharacteristic<T>::valueBE()\n{\n  return byteSwap(value());\n}\n\ntemplate<typename T> T BLETypedCharacteristic<T>::byteSwap(T value)\n{\n  T result;\n  unsigned char* src = (unsigned char*)&value;\n  unsigned char* dst = (unsigned char*)&result;\n\n  for (int i = 0; i < sizeof(T); i++) {\n    dst[i] = src[sizeof(T) - i - 1];\n  }\n\n  return result;\n}\n\n#endif\n"
  },
  {
    "path": "src/BLETypedCharacteristics.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <Arduino.h>\n\n#include \"BLETypedCharacteristics.h\"\n\nBLEBoolCharacteristic::BLEBoolCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<bool>(uuid, properties)\n{\n}\n\nBLEBooleanCharacteristic::BLEBooleanCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<bool>(uuid, properties)\n{\n}\n\nBLECharCharacteristic::BLECharCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<char>(uuid, properties)\n{\n}\n\nBLEUnsignedCharCharacteristic::BLEUnsignedCharCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<unsigned char>(uuid, properties)\n{\n}\n\nBLEByteCharacteristic::BLEByteCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<byte>(uuid, properties)\n{\n}\n\nBLEShortCharacteristic::BLEShortCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<short>(uuid, properties)\n{\n}\n\nBLEUnsignedShortCharacteristic::BLEUnsignedShortCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<unsigned short>(uuid, properties)\n{\n}\n\nBLEWordCharacteristic::BLEWordCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<word>(uuid, properties)\n{\n}\n\nBLEIntCharacteristic::BLEIntCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<int>(uuid, properties) \n{\n}\n\nBLEUnsignedIntCharacteristic::BLEUnsignedIntCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<unsigned int>(uuid, properties)\n{\n}\n\nBLELongCharacteristic::BLELongCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<long>(uuid, properties)\n{\n}\n\nBLEUnsignedLongCharacteristic::BLEUnsignedLongCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<unsigned long>(uuid, properties)\n{\n}\n\nBLEFloatCharacteristic::BLEFloatCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<float>(uuid, properties)\n{\n}\n\nBLEDoubleCharacteristic::BLEDoubleCharacteristic(const char* uuid, unsigned int properties) :\n  BLETypedCharacteristic<double>(uuid, properties)\n{\n}\n"
  },
  {
    "path": "src/BLETypedCharacteristics.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_TYPED_CHARACTERISTICS_H_\n#define _BLE_TYPED_CHARACTERISTICS_H_\n\n#include \"BLETypedCharacteristic.h\"\n\nclass BLEBoolCharacteristic : public BLETypedCharacteristic<bool> {\npublic:\n  BLEBoolCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEBooleanCharacteristic : public BLETypedCharacteristic<bool> {\npublic:\n  BLEBooleanCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLECharCharacteristic : public BLETypedCharacteristic<char> {\npublic:\n  BLECharCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEUnsignedCharCharacteristic : public BLETypedCharacteristic<unsigned char> {\npublic:\n  BLEUnsignedCharCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEByteCharacteristic : public BLETypedCharacteristic<byte> {\npublic:\n  BLEByteCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEShortCharacteristic : public BLETypedCharacteristic<short> {\npublic:\n  BLEShortCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEUnsignedShortCharacteristic : public BLETypedCharacteristic<unsigned short> {\npublic:\n  BLEUnsignedShortCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEWordCharacteristic : public BLETypedCharacteristic<word> {\npublic:\n  BLEWordCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEIntCharacteristic : public BLETypedCharacteristic<int> {\npublic:\n  BLEIntCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEUnsignedIntCharacteristic : public BLETypedCharacteristic<unsigned int> {\npublic:\n  BLEUnsignedIntCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLELongCharacteristic : public BLETypedCharacteristic<long> {\npublic:\n  BLELongCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEUnsignedLongCharacteristic : public BLETypedCharacteristic<unsigned long> {\npublic:\n  BLEUnsignedLongCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEFloatCharacteristic : public BLETypedCharacteristic<float> {\npublic:\n  BLEFloatCharacteristic(const char* uuid, unsigned int permissions);\n};\n\nclass BLEDoubleCharacteristic : public BLETypedCharacteristic<double> {\npublic:\n  BLEDoubleCharacteristic(const char* uuid, unsigned int permissions);\n};\n\n#endif\n"
  },
  {
    "path": "src/local/BLELocalAttribute.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLELocalAttribute.h\"\n\nBLELocalAttribute::BLELocalAttribute(const char* uuid) :\n  _uuid(uuid),\n  _refCount(0)\n{\n}\n\nBLELocalAttribute::~BLELocalAttribute()\n{\n}\n\nconst char* BLELocalAttribute::uuid() const\n{\n  return _uuid.str();\n}\n\nconst uint8_t* BLELocalAttribute::uuidData() const\n{\n  return _uuid.data();\n}\n\nuint8_t BLELocalAttribute::uuidLength() const\n{\n  return _uuid.length();\n}\n\nenum BLEAttributeType BLELocalAttribute::type() const\n{\n  return BLETypeUnknown;\n}\n\nint BLELocalAttribute::retain()\n{\n  _refCount++;\n\n  return _refCount;\n}\n\nbool BLELocalAttribute::active()\n{\n  return _refCount > 0;\n}\n\nint BLELocalAttribute::release()\n{\n  _refCount--;\n\n  return _refCount;\n}\n"
  },
  {
    "path": "src/local/BLELocalAttribute.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_LOCAL_ATTRIBUTE_H_\n#define _BLE_LOCAL_ATTRIBUTE_H_\n\n#include \"utility/BLEUuid.h\"\n\n#define BLE_ATTRIBUTE_TYPE_SIZE 2\n\nenum BLEAttributeType {\n  BLETypeUnknown        = 0x0000,\n\n  BLETypeService        = 0x2800,\n  BLETypeCharacteristic = 0x2803,\n  BLETypeDescriptor     = 0x2900\n};\n\nclass BLELocalAttribute\n{\npublic:\n  BLELocalAttribute(const char* uuid);\n  virtual ~BLELocalAttribute();\n\n  const char* uuid() const;\n\n  virtual enum BLEAttributeType type() const;\n\n  int retain();\n  int release();\n  bool active();\n\nprotected:\n  friend class ATTClass;\n  friend class GATTClass;\n\n  const uint8_t* uuidData() const;\n  uint8_t uuidLength() const;\n\nprivate:\n  BLEUuid _uuid;\n  int _refCount;\n};\n\n#endif\n"
  },
  {
    "path": "src/local/BLELocalCharacteristic.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <Arduino.h>\n#include \"BLELocalDevice.h\"\n\n#include \"utility/ATT.h\"\n#include \"utility/GAP.h\"\n#include \"utility/GATT.h\"\n\n#include \"BLELocalDescriptor.h\"\n#include \"BLEProperty.h\"\n\n#include \"BLELocalCharacteristic.h\"\n\nBLELocalCharacteristic::BLELocalCharacteristic(const char* uuid, uint16_t permissions, int valueSize, bool fixedLength) :\n  BLELocalAttribute(uuid),\n  _properties((uint8_t)(permissions&0x000FF)),\n  _permissions((uint8_t)((permissions&0xFF00)>>8)),\n  _valueSize(min(valueSize, 512)),\n  _valueLength(0),\n  _fixedLength(fixedLength),\n  _handle(0x0000),\n  _broadcast(false),\n  _written(false),\n  _cccdValue(0x0000)\n{\n  memset(_eventHandlers, 0x00, sizeof(_eventHandlers));\n\n  if (permissions & (BLENotify | BLEIndicate)) {\n    BLELocalDescriptor* cccd = new BLELocalDescriptor(\"2902\", (uint8_t*)&_cccdValue, sizeof(_cccdValue));\n  \n    cccd->retain();\n    _descriptors.add(cccd);\n  }\n\n  _value = (uint8_t*)malloc(valueSize);\n}\n\nBLELocalCharacteristic::BLELocalCharacteristic(const char* uuid, uint16_t permissions, const char* value) :\n  BLELocalCharacteristic(uuid, permissions, strlen(value))\n{\n  writeValue(value);\n}\nBLELocalCharacteristic::~BLELocalCharacteristic()\n{\n  for (unsigned int i = 0; i < descriptorCount(); i++) {\n    BLELocalDescriptor* d = descriptor(i);\n\n    if (d->release() == 0) {\n      delete d;\n    }\n  }\n\n  _descriptors.clear();\n\n  if (_value) {\n    free(_value);\n  }\n}\n\nenum BLEAttributeType BLELocalCharacteristic::type() const\n{\n  return BLETypeCharacteristic;\n}\n\nuint8_t BLELocalCharacteristic::properties() const\n{\n  return _properties;\n}\n\nuint8_t BLELocalCharacteristic::permissions() const {\n  return _permissions;\n}\n\nint BLELocalCharacteristic::valueSize() const\n{\n  return _valueSize;\n}\n\nconst uint8_t* BLELocalCharacteristic::value() const\n{\n  return _value;\n}\n\nint BLELocalCharacteristic::valueLength() const\n{\n  return _valueLength;\n}\n\nuint8_t BLELocalCharacteristic::operator[] (int offset) const\n{\n  return _value[offset];\n}\n\nint BLELocalCharacteristic::writeValue(const uint8_t value[], int length)\n{\n  _valueLength = min(length, _valueSize);\n  memcpy(_value, value, _valueLength);\n\n  if (_fixedLength) {\n    _valueLength = _valueSize;\n  }\n\n  if ((_properties & BLEIndicate) && (_cccdValue & 0x0002)) {\n    return ATT.handleInd(valueHandle(), _value, _valueLength);\n  } else if ((_properties & BLENotify) && (_cccdValue & 0x0001)) {\n    return ATT.handleNotify(valueHandle(), _value, _valueLength);\n  }\n\n  if (_broadcast) {\n    uint16_t serviceUuid = GATT.serviceUuidForCharacteristic(this);\n    BLE.setAdvertisedServiceData(serviceUuid, value, _valueLength);\n    if (!ATT.connected() && GAP.advertising()) {\n      BLE.advertise();\n    }\n  }\n\n  return _valueLength;\n}\n\nint BLELocalCharacteristic::writeValue(const char* value)\n{\n  return writeValue((uint8_t*)value, strlen(value));\n}\n\nint BLELocalCharacteristic::broadcast()\n{\n  if (_properties & BLEBroadcast) {\n    _broadcast = true;\n\n    return 1;\n  }\n\n  return 0;\n}\n\nbool BLELocalCharacteristic::written()\n{\n  bool written = _written;\n\n  _written = false;\n\n  return written;\n}\n\nbool BLELocalCharacteristic::subscribed()\n{\n  return (_cccdValue != 0x0000);\n}\n\nvoid BLELocalCharacteristic::addDescriptor(BLEDescriptor& descriptor)\n{\n  BLELocalDescriptor* localDescriptor = descriptor.local();\n\n  if (localDescriptor) {\n    localDescriptor->retain();\n\n    _descriptors.add(localDescriptor);\n  }\n}\n\nvoid BLELocalCharacteristic::setEventHandler(BLECharacteristicEvent event, BLECharacteristicEventHandler eventHandler)\n{\n  if (event < (sizeof(_eventHandlers) / sizeof(_eventHandlers[0]))) {\n    _eventHandlers[event] = eventHandler;\n  }\n}\n\nvoid BLELocalCharacteristic::setHandle(uint16_t handle)\n{\n  _handle = handle;\n}\n\nuint16_t BLELocalCharacteristic::handle() const\n{\n  return _handle;\n}\n\nuint16_t BLELocalCharacteristic::valueHandle() const\n{\n  return (_handle + 1);\n}\n\nunsigned int BLELocalCharacteristic::descriptorCount() const\n{\n  return _descriptors.size();\n}\n\nBLELocalDescriptor* BLELocalCharacteristic::descriptor(unsigned int index) const\n{\n  return _descriptors.get(index);\n}\n\nvoid BLELocalCharacteristic::readValue(BLEDevice device, uint16_t offset, uint8_t value[], int length)\n{\n  if (_eventHandlers[BLERead]) {\n    _eventHandlers[BLERead](device, BLECharacteristic(this));\n  }\n\n  memcpy(value, _value + offset, length);\n}\n\nvoid BLELocalCharacteristic::writeValue(BLEDevice device, const uint8_t value[], int length)\n{\n  _written = true;\n\n  writeValue(value, length);\n\n  if (_eventHandlers[BLEWritten]) {\n    _eventHandlers[BLEWritten](device, BLECharacteristic(this));\n  }\n}\n\nvoid BLELocalCharacteristic::writeCccdValue(BLEDevice device, uint16_t value)\n{\n  value &= 0x0003;\n\n  if (_cccdValue != value) {\n    _cccdValue = value;\n\n    BLECharacteristicEvent event = (_cccdValue) ? BLESubscribed : BLEUnsubscribed;\n\n    if (_eventHandlers[event]) {\n      _eventHandlers[event](device, BLECharacteristic(this));\n    }\n  }\n}\n"
  },
  {
    "path": "src/local/BLELocalCharacteristic.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_LOCAL_CHARACTERISTIC_H_\n#define _BLE_LOCAL_CHARACTERISTIC_H_\n\n#include <stdint.h>\n\n#include \"BLECharacteristic.h\"\n#include \"BLEDescriptor.h\"\n\n#include \"BLELocalAttribute.h\"\n\n#include \"utility/BLELinkedList.h\"\n\nclass BLELocalDescriptor;\n\nclass BLELocalCharacteristic : public BLELocalAttribute {\npublic:\n  BLELocalCharacteristic(const char* uuid, uint16_t permissions, int valueSize, bool fixedLength = false);\n  BLELocalCharacteristic(const char* uuid, uint16_t permissions, const char* value);\n  virtual ~BLELocalCharacteristic();\n\n  virtual enum BLEAttributeType type() const;\n\n  uint8_t properties() const;\n  uint8_t permissions() const;\n\n  int valueSize() const;\n  const uint8_t* value() const;\n  int valueLength() const;\n  uint8_t operator[] (int offset) const;\n\n  int writeValue(const uint8_t value[], int length);\n  int writeValue(const char* value);\n\n  int broadcast();\n\n  bool written();\n  bool subscribed();\n\n  void addDescriptor(BLEDescriptor& descriptor);\n\n  void setEventHandler(BLECharacteristicEvent event, BLECharacteristicEventHandler eventHandler);\n\nprotected:\n  friend class ATTClass;\n  friend class GATTClass;\n\n  void setHandle(uint16_t handle);\n  uint16_t handle() const;\n  uint16_t valueHandle() const;\n\n  unsigned int descriptorCount() const;\n  BLELocalDescriptor* descriptor(unsigned int index) const;\n\n  void readValue(BLEDevice device, uint16_t offset, uint8_t value[], int length);\n  void writeValue(BLEDevice device, const uint8_t value[], int length);\n  void writeCccdValue(BLEDevice device, uint16_t value);\n\nprivate:\n  uint8_t  _properties;\n  uint8_t  _permissions;\n  int      _valueSize;\n  uint8_t* _value;\n  uint16_t  _valueLength;\n  bool _fixedLength;\n\n  uint16_t _handle;\n\n  bool _broadcast;\n  bool _written;\n\n  uint16_t _cccdValue;\n  BLELinkedList<BLELocalDescriptor*> _descriptors;\n\n  BLECharacteristicEventHandler _eventHandlers[BLECharacteristicEventLast];\n};\n\n#endif\n"
  },
  {
    "path": "src/local/BLELocalDescriptor.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <Arduino.h>\n\n#include \"BLELocalDescriptor.h\"\n\nBLELocalDescriptor::BLELocalDescriptor(const char* uuid, const uint8_t value[], int valueSize) :\n  BLELocalAttribute(uuid),\n  _value(value),\n  _valueSize(min(valueSize, 512)),\n  _handle(0x0000)\n{\n}\n\nBLELocalDescriptor::BLELocalDescriptor(const char* uuid, const char* value) :\n  BLELocalDescriptor(uuid, (const uint8_t*)value, strlen(value))\n{\n}\n\nBLELocalDescriptor::~BLELocalDescriptor()\n{\n}\n\nenum BLEAttributeType BLELocalDescriptor::type() const\n{\n  return BLETypeDescriptor;\n}\n\nint BLELocalDescriptor::valueSize() const\n{\n  return _valueSize;\n}\n\nconst uint8_t* BLELocalDescriptor::value() const\n{\n  return _value;\n}\n\nuint8_t BLELocalDescriptor::operator[] (int offset) const\n{\n  return _value[offset];\n}\n\nvoid BLELocalDescriptor::setHandle(uint16_t handle)\n{\n  _handle = handle;\n}\n\nuint16_t BLELocalDescriptor::handle() const\n{\n  return _handle;\n}\n"
  },
  {
    "path": "src/local/BLELocalDescriptor.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_LOCAL_DESCRIPTOR_H_\n#define _BLE_LOCAL_DESCRIPTOR_H_\n\n#include <stdint.h>\n\n#include \"BLELocalAttribute.h\"\n\nclass BLELocalDescriptor : public BLELocalAttribute {\npublic:\n  BLELocalDescriptor(const char* uuid, const uint8_t value[], int valueSize);\n  BLELocalDescriptor(const char* uuid, const char* value);\n  virtual ~BLELocalDescriptor();\n\n  virtual enum BLEAttributeType type() const;\n\n  int valueSize() const;\n  const uint8_t* value() const;\n  uint8_t operator[] (int offset) const;\n\nprotected:\n  friend class GATTClass;\n\n  void setHandle(uint16_t handle);\n  uint16_t handle() const;\n\nprivate:\n  const uint8_t* _value;\n  int            _valueSize;\n\n  uint16_t       _handle;\n};\n\n#endif\n"
  },
  {
    "path": "src/local/BLELocalDevice.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"utility/ATT.h\"\n#include \"utility/HCI.h\"\n#include \"utility/GAP.h\"\n#include \"utility/GATT.h\"\n#include \"utility/L2CAPSignaling.h\"\n\n#include \"BLELocalDevice.h\"\n\n#ifdef __ZEPHYR__\n#undef ARDUINO_PORTENTA_H7_M7\n#undef ARDUINO_OPTA\n#undef ARDUINO_GIGA\n#undef ARDUINO_NICLA_VISION\n#undef ARDUINO_PORTENTA_C33\n#undef ARDUINO_UNO_Q\n#endif\n\n#if defined(ARDUINO_PORTENTA_C33)\n#include <EspChipManager.h>\n#endif\n\n#if defined(PORTENTA_H7_PINS) || defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_OPTA)\n#ifndef BT_REG_ON\n#define BT_REG_ON PJ_12\n#endif\n#elif defined(ARDUINO_NICLA_VISION)\n#ifndef BT_REG_ON\n#define BT_REG_ON PF_14\n#endif\n#elif defined(ARDUINO_GIGA)\n#ifndef BT_REG_ON\n#define BT_REG_ON PA_10\n#endif\n#endif\n\nBLELocalDevice::BLELocalDevice()\n{\n  _advertisingData.setFlags(BLEFlagsGeneralDiscoverable | BLEFlagsBREDRNotSupported);\n}\n\nBLELocalDevice::~BLELocalDevice()\n{\n}\n\nint BLELocalDevice::begin()\n{\n#if defined(PORTENTA_H7_PINS) || defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_GIGA) || defined(ARDUINO_OPTA)\n  // BT_REG_ON -> HIGH\n  pinMode(BT_REG_ON, OUTPUT);\n  digitalWrite(BT_REG_ON, LOW);\n  delay(500);\n  digitalWrite(BT_REG_ON, HIGH);\n  delay(500);\n#elif defined(ARDUINO_PORTENTA_C33)\n\n  Serial5.begin(921600);\n  CEspChipManager::getInstance().initialize();\n  auto _start = millis();\n  while (millis() - _start < 500) {\n    if (Serial5.available()) {\n      Serial5.read();\n    }\n  }\n  //pinMode(94, OUTPUT);\n  //digitalWrite(94, LOW);\n#endif\n\n\n#ifdef ARDUINO_AVR_UNO_WIFI_REV2\n  // set SS HIGH\n  digitalWrite(SPIWIFI_SS, HIGH);\n\n  // set RTS HIGH\n  pinMode(NINA_RTS, OUTPUT);\n  digitalWrite(NINA_RTS, HIGH);\n\n  // set CTS as input\n  pinMode(NINA_CTS, INPUT);\n#endif\n\n  if (!HCI.begin()) {\n    end();\n    return 0;\n  }\n\n  delay(100);\n\n  if (HCI.reset() != 0) {\n    end();\n#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(TARGET_NANO_RP2040_CONNECT)\n    Serial.println(\"The initialization of the Bluetooth® Low Energy module failed.\");\n    Serial.println(\"Please ensure your NINA firmware is version 3.0.0 or higher.\");\n#endif\n    return 0;\n  }\n\n  uint8_t hciVer;\n  uint16_t hciRev;\n  uint8_t lmpVer;\n  uint16_t manufacturer;\n  uint16_t lmpSubVer;\n\n  if (HCI.readLocalVersion(hciVer, hciRev, lmpVer, manufacturer, lmpSubVer) != 0) {\n    end();\n    return 0;\n  }\n\n  if (HCI.setEventMask(0x3FFFFFFFFFFFFFFF) != 0) {\n    end();\n    return 0;\n  }\n  if (HCI.setLeEventMask(0x00000000000003FF) != 0) {\n    end();\n    return 0;\n  }\n\n  uint16_t pktLen;\n  uint8_t maxPkt;\n\n  if (HCI.readLeBufferSize(pktLen, maxPkt) != 0) {\n    end();\n    return 0;\n  }\n\n  /// The HCI should allow automatic address resolution.\n\n  // // If we have callbacks to remember bonded devices:\n  // if(HCI._getIRKs!=0){\n  //   uint8_t nIRKs = 0;\n  //   uint8_t** BADDR_Type = new uint8_t*;\n  //   uint8_t*** BADDRs = new uint8_t**;\n  //   uint8_t*** IRKs = new uint8_t**;\n  //   uint8_t* memcheck;\n\n\n  //   if(!HCI._getIRKs(&nIRKs, BADDR_Type, BADDRs, IRKs)){\n  //     Serial.println(\"error\");\n  //   }\n  //   for(int i=0; i<nIRKs; i++){\n  //     Serial.print(\"Baddr type: \");\n  //     Serial.println((*BADDR_Type)[i]);\n  //     Serial.print(\"BADDR:\");\n  //     for(int k=0; k<6; k++){\n  //       Serial.print(\", 0x\");\n  //       Serial.print((*BADDRs)[i][k],HEX);\n  //     }\n  //     Serial.println();\n  //     Serial.print(\"IRK:\");\n  //     for(int k=0; k<16; k++){\n  //       Serial.print(\", 0x\");\n  //       Serial.print((*IRKs)[i][k],HEX);\n  //     }\n  //     Serial.println();\n\n  //     // save this\n  //     uint8_t zeros[16];\n  //     for(int k=0; k<16; k++) zeros[15-k] = 0;\n\n  //     // HCI.leAddResolvingAddress((*BADDR_Type)[i],(*BADDRs)[i],(*IRKs)[i], zeros);\n\n  //     delete[] (*BADDRs)[i];\n  //     delete[] (*IRKs)[i];\n  //   }\n  //   delete[] (*BADDR_Type);\n  //   delete BADDR_Type;\n  //   delete[] (*BADDRs);\n  //   delete BADDRs;\n  //   delete[] (*IRKs);\n  //   delete IRKs;\n\n  //   memcheck = new uint8_t[1];\n  //   Serial.print(\"nIRK location: 0x\");\n  //   Serial.println((int)memcheck,HEX);\n  //   delete[] memcheck;\n\n  // }\n\n  GATT.begin();\n\n  return 1;\n}\n\nvoid BLELocalDevice::end()\n{\n  GATT.end();\n\n  HCI.end();\n\n#if defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_GIGA) || defined(ARDUINO_OPTA)\n  digitalWrite(BT_REG_ON, LOW);\n#endif\n  _advertisingData.clear();\n  _scanResponseData.clear();\n}\n\nvoid BLELocalDevice::poll()\n{\n  HCI.poll();\n}\n\nvoid BLELocalDevice::poll(unsigned long timeout)\n{\n  HCI.poll(timeout);\n}\n\nbool BLELocalDevice::connected() const\n{\n  HCI.poll();\n\n  return ATT.connected();\n}\n\n/*\n * Whether there is at least one paired device\n */\nbool BLELocalDevice::paired()\n{\n  HCI.poll();\n\n  return ATT.paired();\n}\n\nbool BLELocalDevice::disconnect()\n{\n  return ATT.disconnect();\n}\n\nString BLELocalDevice::address() const\n{\n  uint8_t addr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n  HCI.readBdAddr(addr);\n\n  char result[18];\n  sprintf(result, \"%02x:%02x:%02x:%02x:%02x:%02x\", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);\n\n  return result;\n}\n\nint BLELocalDevice::rssi()\n{\n  BLEDevice central = ATT.central();\n\n  if (central) {\n    return central.rssi();\n  }\n\n  return 127;\n}\n\nbool BLELocalDevice::setAdvertisedServiceUuid(const char* advertisedServiceUuid)\n{\n  return _advertisingData.setAdvertisedServiceUuid(advertisedServiceUuid);\n}\n\nbool BLELocalDevice::setAdvertisedService(const BLEService& service)\n{\n  return setAdvertisedServiceUuid(service.uuid());\n}\n\nbool BLELocalDevice::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length)\n{\n  return _advertisingData.setAdvertisedServiceData(uuid, data, length);\n}\n\nbool BLELocalDevice::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength)\n{\n  return _advertisingData.setManufacturerData(manufacturerData, manufacturerDataLength);\n}\n\nbool BLELocalDevice::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength)\n{\n  return _advertisingData.setManufacturerData(companyId, manufacturerData, manufacturerDataLength);\n}\n\nbool BLELocalDevice::setLocalName(const char *localName)\n{\n  return _scanResponseData.setLocalName(localName);\n}\n\nvoid BLELocalDevice::setAdvertisingData(BLEAdvertisingData& advertisingData)\n{\n  _advertisingData = advertisingData;\n  if (!_advertisingData.hasFlags()) {\n    _advertisingData.setFlags(BLEFlagsGeneralDiscoverable | BLEFlagsBREDRNotSupported);\n  }\n}\n\nvoid BLELocalDevice::setScanResponseData(BLEAdvertisingData& scanResponseData)\n{\n  _scanResponseData = scanResponseData;\n}\n\nBLEAdvertisingData& BLELocalDevice::getAdvertisingData()\n{\n  return _advertisingData;\n}\n\nBLEAdvertisingData& BLELocalDevice::getScanResponseData()\n{\n  return _scanResponseData;\n}\n\nvoid BLELocalDevice::setDeviceName(const char* deviceName)\n{\n  GATT.setDeviceName(deviceName);\n}\n\nvoid BLELocalDevice::setAppearance(uint16_t appearance)\n{\n  GATT.setAppearance(appearance);\n}\n\nvoid BLELocalDevice::addService(BLEService& service)\n{\n  GATT.addService(service);\n}\n\nint BLELocalDevice::advertise()\n{\n  _advertisingData.updateData();\n  _scanResponseData.updateData();\n  return GAP.advertise( _advertisingData.data(), _advertisingData.dataLength(),\n                        _scanResponseData.data(), _scanResponseData.dataLength());\n}\n\nvoid BLELocalDevice::stopAdvertise()\n{\n  GAP.stopAdvertise();\n}\n\nint BLELocalDevice::scan(bool withDuplicates)\n{\n  return GAP.scan(withDuplicates);\n}\n\nint BLELocalDevice::scanForName(String name, bool withDuplicates)\n{\n  return GAP.scanForName(name, withDuplicates);\n}\n\nint BLELocalDevice::scanForUuid(String uuid, bool withDuplicates)\n{\n  return GAP.scanForUuid(uuid, withDuplicates);\n}\n\nint BLELocalDevice::scanForAddress(String address, bool withDuplicates)\n{\n  return GAP.scanForAddress(address, withDuplicates);\n}\n\nvoid BLELocalDevice::stopScan()\n{\n  GAP.stopScan();\n}\n\nBLEDevice BLELocalDevice::central()\n{\n  HCI.poll();\n\n  return ATT.central();\n}\n\nBLEDevice BLELocalDevice::available()\n{\n  HCI.poll();\n\n  return GAP.available();\n}\n\nvoid BLELocalDevice::setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler)\n{\n  if (event == BLEDiscovered) {\n    GAP.setEventHandler(event, eventHandler);\n  } else {\n    ATT.setEventHandler(event, eventHandler);\n  }\n}\n\nvoid BLELocalDevice::setAdvertisingInterval(uint16_t advertisingInterval)\n{\n  GAP.setAdvertisingInterval(advertisingInterval);\n}\n\nvoid BLELocalDevice::setConnectionInterval(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval)\n{\n  L2CAPSignaling.setConnectionInterval(minimumConnectionInterval, maximumConnectionInterval);\n}\n\nvoid BLELocalDevice::setSupervisionTimeout(uint16_t supervisionTimeout)\n{\n  L2CAPSignaling.setSupervisionTimeout(supervisionTimeout);\n}\n\nvoid BLELocalDevice::setConnectable(bool connectable)\n{\n  GAP.setConnectable(connectable);\n}\n\nvoid BLELocalDevice::setTimeout(unsigned long timeout)\n{\n  ATT.setTimeout(timeout);\n}\n\n/*\n * Control whether pairing is allowed or rejected\n * Use true/false or the Pairable enum\n */\nvoid BLELocalDevice::setPairable(uint8_t pairable)\n{\n  L2CAPSignaling.setPairingEnabled(pairable);\n}\n\n/*\n * Whether pairing is currently allowed\n */\nbool BLELocalDevice::pairable()\n{\n  return L2CAPSignaling.isPairingEnabled();\n}\n\nvoid BLELocalDevice::setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs)){\n  HCI._getIRKs = getIRKs;\n}\nvoid BLELocalDevice::setGetLTK(int (*getLTK)(uint8_t* BADDR, uint8_t* LTK)){\n  HCI._getLTK = getLTK;\n}\nvoid BLELocalDevice::setStoreLTK(int (*storeLTK)(uint8_t*, uint8_t*)){\n  HCI._storeLTK = storeLTK;\n}\nvoid BLELocalDevice::setStoreIRK(int (*storeIRK)(uint8_t*, uint8_t*)){\n  HCI._storeIRK = storeIRK;\n}\nvoid BLELocalDevice::setDisplayCode(void (*displayCode)(uint32_t confirmationCode)){\n  HCI._displayCode = displayCode;\n}\nvoid BLELocalDevice::setBinaryConfirmPairing(bool (*binaryConfirmPairing)()){\n  HCI._binaryConfirmPairing = binaryConfirmPairing;\n}\n\nvoid BLELocalDevice::debug(Stream& stream)\n{\n  HCI.debug(stream);\n}\n\nvoid BLELocalDevice::noDebug()\n{\n  HCI.noDebug();\n}\n\n#if !defined(FAKE_BLELOCALDEVICE)\nBLELocalDevice BLEObj;\nBLELocalDevice& BLE = BLEObj;\n#endif\n"
  },
  {
    "path": "src/local/BLELocalDevice.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_LOCAL_DEVICE_H_\n#define _BLE_LOCAL_DEVICE_H_\n\n#include \"BLEDevice.h\"\n#include \"BLEService.h\"\n#include \"BLEAdvertisingData.h\"\n\nenum Pairable {\n  NO = 0,\n  YES = 1,\n  ONCE = 2,\n};\n\nclass BLELocalDevice {\npublic:\n  BLELocalDevice();\n  virtual ~BLELocalDevice();\n\n  virtual int begin();\n  virtual void end();\n\n  virtual void poll();\n  virtual void poll(unsigned long timeout);\n\n  virtual bool connected() const;\n  virtual bool disconnect();\n\n  virtual String address() const;\n\n  virtual int rssi();\n\n  virtual bool setAdvertisedServiceUuid(const char* advertisedServiceUuid);\n  virtual bool setAdvertisedService(const BLEService& service);\n  virtual bool setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length);\n  virtual bool setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength);\n  virtual bool setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength);\n  virtual bool setLocalName(const char *localName);\n\n  virtual void setAdvertisingData(BLEAdvertisingData& advertisingData);\n  virtual void setScanResponseData(BLEAdvertisingData& scanResponseData);\n\n  virtual void setDeviceName(const char* deviceName);\n  virtual void setAppearance(uint16_t appearance);\n\n  virtual void addService(BLEService& service);\n\n  virtual int advertise();\n  virtual void stopAdvertise();\n\n  virtual int scan(bool withDuplicates = false);\n  virtual int scanForName(String name, bool withDuplicates = false);\n  virtual int scanForUuid(String uuid, bool withDuplicates = false);\n  virtual int scanForAddress(String address, bool withDuplicates = false);\n  virtual void stopScan();\n\n  virtual BLEDevice central();\n  virtual BLEDevice available();\n\n  virtual void setAdvertisingInterval(uint16_t advertisingInterval);\n  virtual void setConnectionInterval(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval);\n  virtual void setSupervisionTimeout(uint16_t supervisionTimeout);\n  virtual void setConnectable(bool connectable); \n\n  virtual void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler);\n\n  virtual void setTimeout(unsigned long timeout);\n\n  virtual void debug(Stream& stream);\n  virtual void noDebug();\n  \n  virtual void setPairable(uint8_t pairable);\n  virtual bool pairable();\n  virtual bool paired();\n\n  // address - The mac to store\n  // IRK - The IRK to store with this mac\n  virtual void setStoreIRK(int (*storeIRK)(uint8_t* address, uint8_t* IRK));\n  // nIRKs      - the number of IRKs being provided.\n  // BDAddrType - an array containing the type of each address (0 public, 1 static random)\n  // BDAddrs    - an array containing the list of addresses\n  virtual void setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BDAddrType, uint8_t*** BDAddrs, uint8_t*** IRKs));\n  // address - the address to store [6 bytes]\n  // LTK - the LTK to store with this mac [16 bytes]\n  virtual void setStoreLTK(int (*storeLTK)(uint8_t* address, uint8_t* LTK));\n  // address - The mac address needing its LTK\n  // LTK - 16 octet LTK for the mac address\n  virtual void setGetLTK(int (*getLTK)(uint8_t* address, uint8_t* LTK));\n\n  virtual void setDisplayCode(void (*displayCode)(uint32_t confirmationCode));\n  virtual void setBinaryConfirmPairing(bool (*binaryConfirmPairing)());\n  uint8_t BDaddress[6];\n  \nprotected:\n  virtual BLEAdvertisingData& getAdvertisingData();\n  virtual BLEAdvertisingData& getScanResponseData();\n\nprivate:\n  BLEAdvertisingData _advertisingData;\n  BLEAdvertisingData _scanResponseData;\n};\n\nextern BLELocalDevice& BLE;\n\n#endif\n"
  },
  {
    "path": "src/local/BLELocalService.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLELocalCharacteristic.h\"\n\n#include \"BLELocalService.h\"\n\nBLELocalService::BLELocalService(const char* uuid) :\n  BLELocalAttribute(uuid),\n  _startHandle(0x0000),\n  _endHandle(0x0000)\n{\n}\n\nvoid BLELocalService::clear() {\n  _characteristics.clear();\n  _startHandle = 0;\n  _endHandle = 0;\n}\n\nBLELocalService::~BLELocalService()\n{\n  for (unsigned int i = 0; i < characteristicCount(); i++) {\n    BLELocalCharacteristic* c = characteristic(i);\n\n    if (c->release() == 0) {\n      delete c;\n    }\n  }\n  clear();\n}\n\nenum BLEAttributeType BLELocalService::type() const\n{\n  return BLETypeService;\n}\n\nvoid BLELocalService::addCharacteristic(BLECharacteristic& characteristic)\n{\n  BLELocalCharacteristic* localCharacteristic = characteristic.local();\n\n  if (localCharacteristic) {\n    addCharacteristic(localCharacteristic);\n  }\n}\n\nvoid BLELocalService::setHandles(uint16_t start, uint16_t end)\n{\n  _startHandle = start;\n  _endHandle = end;\n}\n\nuint16_t BLELocalService::startHandle() const\n{\n  return _startHandle;\n}\n\nuint16_t BLELocalService::endHandle() const\n{\n  return _endHandle;\n}\n\nunsigned int BLELocalService::characteristicCount() const\n{\n  return _characteristics.size();\n}\n\nBLELocalCharacteristic* BLELocalService::characteristic(unsigned int index) const\n{\n  return _characteristics.get(index);\n}\n\nvoid BLELocalService::addCharacteristic(BLELocalCharacteristic* characteristic)\n{\n  characteristic->retain();\n\n  _characteristics.add(characteristic);\n}\n"
  },
  {
    "path": "src/local/BLELocalService.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_LOCAL_SERVICE_H_\n#define _BLE_LOCAL_SERVICE_H_\n\n#include \"BLECharacteristic.h\"\n\n#include \"BLELocalAttribute.h\"\n\n#include \"utility/BLELinkedList.h\"\n\nclass BLELocalCharacteristic;\n\nclass BLELocalService : public BLELocalAttribute {\npublic:\n  BLELocalService(const char* uuid);\n  virtual ~BLELocalService();\n\n  virtual enum BLEAttributeType type() const;\n\n  void addCharacteristic(BLECharacteristic& characteristic);\n  void clear();\n\nprotected:\n  friend class ATTClass;\n  friend class GATTClass;\n\n  void setHandles(uint16_t start, uint16_t end);\n  uint16_t startHandle() const;\n  uint16_t endHandle() const;\n\n  unsigned int characteristicCount() const;\n  BLELocalCharacteristic* characteristic(unsigned int index) const;\n\n  void addCharacteristic(BLELocalCharacteristic* characteristic);\n\nprivate:\n  uint16_t _startHandle;\n  uint16_t _endHandle;\n\n  BLELinkedList<BLELocalCharacteristic*> _characteristics;\n};\n\n#endif\n"
  },
  {
    "path": "src/remote/BLERemoteAttribute.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"utility/BLEUuid.h\"\n\n#include \"BLERemoteAttribute.h\"\n\nBLERemoteAttribute::BLERemoteAttribute(const uint8_t uuid[], uint8_t uuidLen) :\n  _uuid(BLEUuid::uuidToString(uuid, uuidLen)),\n  _refCount(0)\n{\n}\n\nBLERemoteAttribute::~BLERemoteAttribute()\n{\n}\n\nconst char* BLERemoteAttribute::uuid() const\n{\n  return _uuid.c_str();\n}\n\nint BLERemoteAttribute::retain()\n{\n  _refCount++;\n\n  return _refCount;\n}\n\nint BLERemoteAttribute::release()\n{\n  _refCount--;\n\n  return _refCount;\n}\n"
  },
  {
    "path": "src/remote/BLERemoteAttribute.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_REMOTE_ATTRIBUTE_H_\n#define _BLE_REMOTE_ATTRIBUTE_H_\n\n#include <Arduino.h>\n\nclass BLERemoteAttribute\n{\npublic:\n  BLERemoteAttribute(const uint8_t uuid[], uint8_t uuidLen);\n  virtual ~BLERemoteAttribute();\n\n  const char* uuid() const;\n\n  int retain();\n  int release();\n\nprivate:\n  String _uuid;\n  int _refCount;\n};\n\n#endif\n"
  },
  {
    "path": "src/remote/BLERemoteCharacteristic.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLEProperty.h\"\n\n#include \"utility/ATT.h\"\n\n#include \"BLERemoteCharacteristic.h\"\n\nBLERemoteCharacteristic::BLERemoteCharacteristic(const uint8_t uuid[], uint8_t uuidLen, uint16_t connectionHandle,\n                                                  uint16_t startHandle, uint16_t permissions, uint16_t valueHandle) :\n  BLERemoteAttribute(uuid, uuidLen),\n  _connectionHandle(connectionHandle),\n  _startHandle(startHandle),\n  _properties((uint8_t)(permissions & 0x00FF)),\n  _permissions((uint8_t)((permissions & 0xFF00)>>8)),\n  _valueHandle(valueHandle),\n  _value(NULL),\n  _valueLength(0),\n  _valueUpdated(false),\n  _updatedValueRead(true),\n  _valueUpdatedEventHandler(NULL)\n{\n}\n\nBLERemoteCharacteristic::~BLERemoteCharacteristic()\n{\n  for (unsigned int i = 0; i < descriptorCount(); i++) {\n    BLERemoteDescriptor* d = descriptor(i);\n\n    if (d->release() == 0) {\n      delete d;\n    }\n  }\n\n  _descriptors.clear();\n\n  if (_value) {\n    free(_value);\n    _value = NULL;\n  }\n}\n\nuint16_t BLERemoteCharacteristic::startHandle() const\n{\n  return _startHandle;\n}\n\nuint8_t BLERemoteCharacteristic::properties() const\n{\n  return _properties;\n}\n\nconst uint8_t* BLERemoteCharacteristic::value() const\n{\n  return _value;\n}\n\nint BLERemoteCharacteristic::valueLength() const\n{\n  return _valueLength;\n}\n\nuint8_t BLERemoteCharacteristic::operator[] (int offset) const\n{\n  if (_value) {\n    return _value[offset];\n  }\n\n  return 0;\n}\n\nint BLERemoteCharacteristic::writeValue(const uint8_t value[], int length, bool withResponse)\n{\n  if (!ATT.connected(_connectionHandle)) {\n    return false;\n  }\n\n  uint16_t maxLength = ATT.mtu(_connectionHandle) - 3;\n\n  if (length > (int)maxLength) {\n    // cap to MTU max length\n    length = maxLength;\n  }\n\n  _value = (uint8_t*)realloc(_value, length);\n  if (_value == NULL) {\n    // realloc failed\n    return 0;\n  }\n\n  if ((_properties & BLEWrite) && withResponse) {\n    uint8_t resp[4];\n    int respLength = ATT.writeReq(_connectionHandle, _valueHandle, value, length, resp);\n\n    if (!respLength) {\n      return 0;\n    }\n\n    if (resp[0] == 0x01) {\n      // error\n      return 0;\n    }\n\n    memcpy(_value, value, length);\n    _valueLength = length;\n\n    return 1;\n  } else if (_properties & BLEWriteWithoutResponse) {\n    ATT.writeCmd(_connectionHandle, _valueHandle, value, length);\n\n    memcpy(_value, value, length);\n    _valueLength = length;\n\n    return 1;\n  }\n\n  return 0;\n}\n\nint BLERemoteCharacteristic::writeValue(const char* value, bool withResponse)\n{\n  return writeValue((uint8_t*)value, strlen(value), withResponse);\n}\n\nbool BLERemoteCharacteristic::valueUpdated()\n{\n  ATT.connected(_connectionHandle); // to force a poll\n\n  bool result = _valueUpdated;\n\n  _valueUpdated = false;\n\n  return result;\n}\n\nbool BLERemoteCharacteristic::updatedValueRead()\n{\n  bool result = _updatedValueRead;\n\n  _updatedValueRead = true;\n\n  return result;\n}\n\nbool BLERemoteCharacteristic::read()\n{\n  if (!ATT.connected(_connectionHandle)) {\n    return false;\n  }\n  \n  uint8_t resp[256];\n\n  int respLength = ATT.readReq(_connectionHandle, _valueHandle, resp);\n\n  if (!respLength) {\n    _valueLength = 0;\n    return false;\n  }\n\n  if (resp[0] == 0x01) {\n    // error\n    _valueLength = 0;\n    return false;\n  }\n\n  _valueLength = respLength - 1;\n  _value = (uint8_t*)realloc(_value, _valueLength);\n\n  if (_value == NULL) {\n    _valueLength = 0;\n    return false;\n  }\n\n  memcpy(_value, &resp[1], _valueLength); \n\n  return true;\n}\n\nbool BLERemoteCharacteristic::writeCccd(uint16_t value)\n{\n  int numDescriptors = descriptorCount();\n\n  for (int i = 0; i < numDescriptors; i++) {\n    BLERemoteDescriptor* d = descriptor(i);\n\n    if (strcmp(d->uuid(), \"2902\") == 0) {\n      return d->writeValue((uint8_t*)&value, sizeof(value));\n    }\n  }\n\n  if (_properties & (BLENotify | BLEIndicate)) {\n    // no CCCD descriptor found, fallback to _valueHandle + 1\n    BLERemoteDescriptor cccd(NULL, 0, _connectionHandle, _valueHandle + 1);\n\n    return cccd.writeValue((uint8_t*)&value, sizeof(value));\n  }\n\n  return false;\n}\n\nuint16_t BLERemoteCharacteristic::valueHandle() const\n{\n  return _valueHandle;\n}\n\nunsigned int BLERemoteCharacteristic::descriptorCount() const\n{\n  return _descriptors.size();\n}\n\nBLERemoteDescriptor* BLERemoteCharacteristic::descriptor(unsigned int index) const\n{\n  return _descriptors.get(index);\n}\n\nvoid BLERemoteCharacteristic::setEventHandler(BLECharacteristicEvent event, BLECharacteristicEventHandler eventHandler)\n{\n  if (event == BLEUpdated) {\n    _valueUpdatedEventHandler = eventHandler;\n  }\n}\n\nvoid BLERemoteCharacteristic::addDescriptor(BLERemoteDescriptor* descriptor)\n{\n  descriptor->retain();\n\n  _descriptors.add(descriptor);\n}\n\nvoid BLERemoteCharacteristic::writeValue(BLEDevice device, const uint8_t value[], int length)\n{\n  _valueLength = length;\n  _value = (uint8_t*)realloc(_value, _valueLength);\n\n  if (_value == NULL) {\n    _valueLength = 0;\n    return;\n  }\n\n  _valueUpdated = true;\n  _updatedValueRead = false;\n  memcpy(_value, value, _valueLength);\n\n  if (_valueUpdatedEventHandler) {\n    _valueUpdatedEventHandler(device, BLECharacteristic(this));\n  }\n}\n"
  },
  {
    "path": "src/remote/BLERemoteCharacteristic.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_REMOTE_CHARACTERISTIC_H_\n#define _BLE_REMOTE_CHARACTERISTIC_H_\n\n#include \"BLECharacteristic.h\"\n\n#include \"BLERemoteAttribute.h\"\n#include \"BLERemoteDescriptor.h\"\n\n#include \"utility/BLELinkedList.h\"\n\nclass BLERemoteCharacteristic : public BLERemoteAttribute {\npublic:\n  BLERemoteCharacteristic(const uint8_t uuid[], uint8_t uuidLen, uint16_t connectionHandle, uint16_t startHandle, uint16_t permissions, uint16_t valueHandle);\n  virtual ~BLERemoteCharacteristic();\n\n  uint8_t properties() const;\n  uint8_t permissions() const;\n\n  const uint8_t* value() const;\n  int valueLength() const;\n  uint8_t operator[] (int offset) const;\n\n  int writeValue(const uint8_t value[], int length, bool withResponse = true);\n  int writeValue(const char* value, bool withResponse = true);\n\n  bool valueUpdated();\n  bool updatedValueRead();\n\n  bool read();\n  bool writeCccd(uint16_t value);\n\n  unsigned int descriptorCount() const;\n  BLERemoteDescriptor* descriptor(unsigned int index) const;\n\n  void setEventHandler(BLECharacteristicEvent event, BLECharacteristicEventHandler eventHandler);\n\nprotected:\n  friend class ATTClass;\n\n  uint16_t startHandle() const;\n  uint16_t valueHandle() const;\n\n  void addDescriptor(BLERemoteDescriptor* descriptor);\n\n  void writeValue(BLEDevice device, const uint8_t value[], int length);\n\nprivate:\n  uint16_t _connectionHandle;\n  uint16_t _startHandle;\n  uint8_t _properties;\n  uint8_t _permissions;\n  uint16_t _valueHandle;\n\n  uint8_t* _value;\n  int _valueLength;\n\n  bool _valueUpdated;\n  bool _updatedValueRead;\n\n  BLELinkedList<BLERemoteDescriptor*> _descriptors;\n\n  BLECharacteristicEventHandler _valueUpdatedEventHandler;\n};\n\n#endif\n"
  },
  {
    "path": "src/remote/BLERemoteDescriptor.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"utility/ATT.h\"\n\n#include \"BLERemoteDescriptor.h\"\n\nBLERemoteDescriptor::BLERemoteDescriptor(const uint8_t uuid[], uint8_t uuidLen, uint16_t connectionHandle, uint16_t handle) :\n  BLERemoteAttribute(uuid, uuidLen),\n  _connectionHandle(connectionHandle),\n  _handle(handle),\n  _value(NULL),\n  _valueLength(0)\n{\n}\n\nBLERemoteDescriptor::~BLERemoteDescriptor()\n{\n  if (_value) {\n    free(_value);\n    _value = NULL;\n  }\n}\n\nconst uint8_t* BLERemoteDescriptor::value() const\n{\n  return _value;\n}\n\nint BLERemoteDescriptor::valueLength() const\n{\n  return _valueLength;\n}\n\nuint8_t BLERemoteDescriptor::operator[] (int offset) const\n{\n  if (_value) {\n    return _value[offset];\n  }\n\n  return 0;\n}\n\nint BLERemoteDescriptor::writeValue(const uint8_t value[], int length)\n{\n  if (!ATT.connected(_connectionHandle)) {\n    return false;\n  }\n\n  uint16_t maxLength = ATT.mtu(_connectionHandle) - 3;\n\n  if (length > (int)maxLength) {\n    // cap to MTU max length\n    length = maxLength;\n  }\n\n  _value = (uint8_t*)realloc(_value, length);\n  if (_value == NULL) {\n    // realloc failed\n    return 0;\n  }  \n\n  uint8_t resp[4];\n  int respLength = ATT.writeReq(_connectionHandle, _handle, value, length, resp);\n\n  if (!respLength) {\n    return 0;\n  }\n\n  if (resp[0] == 0x01) {\n    // error\n    return 0;\n  }\n\n  memcpy(_value, value, length);\n  _valueLength = length;\n\n  return 1;\n}\n\nbool BLERemoteDescriptor::read()\n{\n  if (!ATT.connected(_connectionHandle)) {\n    return false;\n  }\n\n  uint8_t resp[256];\n\n  int respLength = ATT.readReq(_connectionHandle, _handle, resp);\n\n  if (!respLength) {\n    _valueLength = 0;\n    return false;\n  }\n\n  if (resp[0] == 0x01) {\n    // error\n    _valueLength = 0;\n    return false;\n  }\n\n  _valueLength = respLength - 1;\n  _value = (uint8_t*)realloc(_value, _valueLength);\n\n  if (_value == NULL) {\n    _valueLength = 0;\n    return false;\n  }\n\n  memcpy(_value, &resp[1], _valueLength); \n\n  return true;\n}\n\nuint16_t BLERemoteDescriptor::handle() const\n{\n  return _handle;\n}\n"
  },
  {
    "path": "src/remote/BLERemoteDescriptor.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_REMOTE_DESCRIPTOR_H_\n#define _BLE_REMOTE_DESCRIPTOR_H_\n\n#include \"BLERemoteAttribute.h\"\n\nclass BLERemoteDescriptor : public BLERemoteAttribute {\npublic:\n  BLERemoteDescriptor(const uint8_t uuid[], uint8_t uuidLen, uint16_t connectionHandle, uint16_t handle);\n  virtual ~BLERemoteDescriptor();\n\n  const uint8_t* value() const;\n  int valueLength() const;\n  uint8_t operator[] (int offset) const;\n\n  int writeValue(const uint8_t value[], int length);\n\n  bool read();\n\nprotected:\n  friend class ATTClass;\n  uint16_t handle() const;\n\nprivate:\n  uint16_t _connectionHandle;\n  uint16_t _handle;\n\n  uint8_t* _value;\n  int _valueLength;\n};\n\n#endif\n"
  },
  {
    "path": "src/remote/BLERemoteDevice.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLERemoteDevice.h\"\n\nBLERemoteDevice::BLERemoteDevice()\n{\n}\n\nBLERemoteDevice::~BLERemoteDevice()\n{\n  clearServices();\n}\n\nvoid BLERemoteDevice::addService(BLERemoteService* service)\n{\n  service->retain();\n\n  _services.add(service);\n}\n\nunsigned int BLERemoteDevice::serviceCount() const\n{\n  return _services.size();\n}\n\nBLERemoteService* BLERemoteDevice::service(unsigned int index) const\n{\n  return _services.get(index);\n}\n\nvoid BLERemoteDevice::clearServices()\n{\n  for (unsigned int i = 0; i < serviceCount(); i++) {\n    BLERemoteService* s = service(i);\n\n    if (s->release() == 0) {\n      delete s;\n    }\n  }\n\n  _services.clear();\n}\n"
  },
  {
    "path": "src/remote/BLERemoteDevice.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_REMOTE_DEVICE_H_\n#define _BLE_REMOTE_DEVICE_H_\n\n#include \"utility/BLELinkedList.h\"\n\n#include \"BLERemoteService.h\"\n\nclass BLERemoteDevice /*: public BLEDevice*/ {\npublic:\n  BLERemoteDevice();\n  virtual ~BLERemoteDevice();\n\n  void addService(BLERemoteService* service);\n\n  unsigned int serviceCount() const;\n  BLERemoteService* service(unsigned int index) const;\n\n  void clearServices();\n\nprivate:\n  BLELinkedList<BLERemoteService*> _services;\n};\n\n#endif\n"
  },
  {
    "path": "src/remote/BLERemoteService.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLERemoteService.h\"\n\nBLERemoteService::BLERemoteService(const uint8_t uuid[], uint8_t uuidLen, uint16_t startHandle, uint16_t endHandle) :\n  BLERemoteAttribute(uuid, uuidLen),\n  _startHandle(startHandle),\n  _endHandle(endHandle)\n{\n}\n\nBLERemoteService::~BLERemoteService()\n{\n  for (unsigned int i = 0; i < characteristicCount(); i++) {\n    BLERemoteCharacteristic* c = characteristic(i);\n\n    if (c->release() == 0) {\n      delete c;\n    }\n  }\n\n  _characteristics.clear();\n}\n\nuint16_t BLERemoteService::startHandle() const\n{\n  return _startHandle;\n}\n\nuint16_t BLERemoteService::endHandle() const\n{\n  return _endHandle;\n}\n\nunsigned int BLERemoteService::characteristicCount() const\n{\n  return _characteristics.size();\n}\n\nBLERemoteCharacteristic* BLERemoteService::characteristic(unsigned int index) const\n{\n  return _characteristics.get(index);\n}\n\nvoid BLERemoteService::addCharacteristic(BLERemoteCharacteristic* characteristic)\n{\n  characteristic-> retain();\n\n  _characteristics.add(characteristic);\n}\n"
  },
  {
    "path": "src/remote/BLERemoteService.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_REMOTE_SERVICE_H_\n#define _BLE_REMOTE_SERVICE_H_\n\n#include \"BLERemoteAttribute.h\"\n#include \"BLERemoteCharacteristic.h\"\n\n#include \"utility/BLELinkedList.h\"\n\nclass BLERemoteService : public BLERemoteAttribute {\npublic:\n  BLERemoteService(const uint8_t uuid[], uint8_t uuidLen, uint16_t startHandle, uint16_t endHandle);\n  virtual ~BLERemoteService();\n\n  unsigned int characteristicCount() const;\n  BLERemoteCharacteristic* characteristic(unsigned int index) const;\n\nprotected:\n  friend class ATTClass;\n\n  uint16_t startHandle() const;\n  uint16_t endHandle() const;\n\n  void addCharacteristic(BLERemoteCharacteristic* characteristic);\n\nprivate:\n  uint16_t _startHandle;\n  uint16_t _endHandle;\n\n  String _uuid;\n\n  BLELinkedList<BLERemoteCharacteristic*> _characteristics;\n};\n\n#endif\n"
  },
  {
    "path": "src/utility/ATT.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <Arduino.h>\n\n#include \"HCI.h\"\n#include \"GATT.h\"\n\n#include \"local/BLELocalAttribute.h\"\n#include \"local/BLELocalCharacteristic.h\"\n#include \"local/BLELocalDescriptor.h\"\n#include \"local/BLELocalService.h\"\n\n#include \"remote/BLERemoteDevice.h\"\n#include \"remote/BLERemoteService.h\"\n\n#include \"BLEProperty.h\"\n\n#include \"ATT.h\"\n\nextern \"C\" int strcasecmp(char const *a, char const *b);\n\n#define ATT_OP_ERROR              0x01\n#define ATT_OP_MTU_REQ            0x02\n#define ATT_OP_MTU_RESP           0x03\n#define ATT_OP_FIND_INFO_REQ      0x04\n#define ATT_OP_FIND_INFO_RESP     0x05\n#define ATT_OP_FIND_BY_TYPE_REQ   0x06\n#define ATT_OP_FIND_BY_TYPE_RESP  0x07\n#define ATT_OP_READ_BY_TYPE_REQ   0x08\n#define ATT_OP_READ_BY_TYPE_RESP  0x09\n#define ATT_OP_READ_REQ           0x0a\n#define ATT_OP_READ_RESP          0x0b\n#define ATT_OP_READ_BLOB_REQ      0x0c\n#define ATT_OP_READ_BLOB_RESP     0x0d\n#define ATT_OP_READ_MULTI_REQ     0x0e\n#define ATT_OP_READ_MULTI_RESP    0x0f\n#define ATT_OP_READ_BY_GROUP_REQ  0x10\n#define ATT_OP_READ_BY_GROUP_RESP 0x11\n#define ATT_OP_WRITE_REQ          0x12\n#define ATT_OP_WRITE_RESP         0x13\n#define ATT_OP_WRITE_CMD          0x52\n#define ATT_OP_PREP_WRITE_REQ     0x16\n#define ATT_OP_PREP_WRITE_RESP    0x17\n#define ATT_OP_EXEC_WRITE_REQ     0x18\n#define ATT_OP_EXEC_WRITE_RESP    0x19\n#define ATT_OP_HANDLE_NOTIFY      0x1b\n#define ATT_OP_HANDLE_IND         0x1d\n#define ATT_OP_HANDLE_CNF         0x1e\n#define ATT_OP_SIGNED_WRITE_CMD   0xd2\n\n#define ATT_ECODE_INVALID_HANDLE       0x01\n#define ATT_ECODE_READ_NOT_PERM        0x02\n#define ATT_ECODE_WRITE_NOT_PERM       0x03\n#define ATT_ECODE_INVALID_PDU          0x04\n#define ATT_ECODE_AUTHENTICATION       0x05\n#define ATT_ECODE_REQ_NOT_SUPP         0x06\n#define ATT_ECODE_INVALID_OFFSET       0x07\n#define ATT_ECODE_AUTHORIZATION        0x08\n#define ATT_ECODE_PREP_QUEUE_FULL      0x09\n#define ATT_ECODE_ATTR_NOT_FOUND       0x0a\n#define ATT_ECODE_ATTR_NOT_LONG        0x0b\n#define ATT_ECODE_INSUFF_ENCR_KEY_SIZE 0x0c\n#define ATT_ECODE_INVAL_ATTR_VALUE_LEN 0x0d\n#define ATT_ECODE_UNLIKELY             0x0e\n#define ATT_ECODE_INSUFF_ENC           0x0f\n#define ATT_ECODE_UNSUPP_GRP_TYPE      0x10\n#define ATT_ECODE_INSUFF_RESOURCES     0x11\n\n// #define _BLE_TRACE_\n\nATTClass::ATTClass() :\n  _maxMtu(23),\n  _timeout(5000),\n  _longWriteHandle(0x0000),\n  _longWriteValue(NULL),\n  _longWriteValueLength(0)\n{\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    _peers[i].connectionHandle = 0xffff;\n    _peers[i].role = 0x00;\n    _peers[i].addressType = 0x00;\n    memset(_peers[i].address, 0x00, sizeof(_peers[i].address));\n    _peers[i].mtu = 23;\n    _peers[i].device = NULL;\n    _peers[i].encryption = 0x0;\n  }\n\n  memset(_eventHandlers, 0x00, sizeof(_eventHandlers));\n}\n\nATTClass::~ATTClass()\n{\n  if (_longWriteValue) {\n    free(_longWriteValue);\n  }\n}\n\nbool ATTClass::connect(uint8_t peerBdaddrType, uint8_t peerBdaddr[6])\n{\n  if (HCI.leCreateConn(0x0060, 0x0030, 0x00, peerBdaddrType, peerBdaddr, 0x00,\n                        0x0006, 0x000c, 0x0000, 0x00c8, 0x0004, 0x0006) != 0) {\n    return false;\n  }\n\n  bool isConnected = false;\n\n  for (unsigned long start = millis(); (millis() - start) < _timeout;) {\n    HCI.poll();\n\n    isConnected = connected(peerBdaddrType, peerBdaddr);\n\n    if (isConnected) {\n      break;\n    }\n  }\n\n  if (!isConnected) {\n    HCI.leCancelConn();\n  }\n\n  return isConnected;\n}\n\nbool ATTClass::disconnect(uint8_t peerBdaddrType, uint8_t peerBdaddr[6])\n{\n  uint16_t connHandle = connectionHandle(peerBdaddrType, peerBdaddr);\n  if (connHandle == 0xffff) {\n    return false;\n  }\n\n  HCI.disconnect(connHandle);\n\n  for (unsigned long start = millis(); (millis() - start) < _timeout;) {\n    HCI.poll();\n\n    if (!connected(connHandle)) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\nbool ATTClass::discoverAttributes(uint8_t peerBdaddrType, uint8_t peerBdaddr[6], const char* serviceUuidFilter)\n{\n  uint16_t connHandle = connectionHandle(peerBdaddrType, peerBdaddr);\n  if (connHandle == 0xffff) {\n    return false;\n  }\n\n  // send MTU request\n  if (!exchangeMtu(connHandle)) {\n    return false;\n  }\n\n  // find the device entry for the peeer\n  BLERemoteDevice* device = NULL;\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == connHandle) {\n      if (_peers[i].device == NULL) {\n        _peers[i].device = new BLERemoteDevice();\n      }\n\n      device = _peers[i].device;\n\n      break;\n    }\n  }\n\n  if (device == NULL) {\n    return false;\n  }\n\n  if (serviceUuidFilter == NULL) {\n    // clear existing services\n    device->clearServices();\n  } else {\n    int serviceCount = device->serviceCount();\n  \n    for (int i = 0; i < serviceCount; i++) {\n      BLERemoteService* service = device->service(i);\n\n      if (strcasecmp(service->uuid(), serviceUuidFilter) == 0) {\n        // found an existing service with same UUID\n        return true;\n      }\n    }\n  }\n\n  // discover services\n  if (!discoverServices(connHandle, device, serviceUuidFilter)) {\n    return false;\n  }\n\n  // discover characteristics\n  if (!discoverCharacteristics(connHandle, device)) {\n    return false;\n  }\n\n  // discover descriptors\n  if (!discoverDescriptors(connHandle, device)) {\n    return false;\n  }\n\n  return true;\n}\n\nvoid ATTClass::setMaxMtu(uint16_t maxMtu)\n{\n  _maxMtu = maxMtu;\n}\n\nvoid ATTClass::setTimeout(unsigned long timeout)\n{\n  _timeout = timeout;\n}\n\nvoid ATTClass::addConnection(uint16_t handle, uint8_t role, uint8_t peerBdaddrType,\n                              uint8_t peerBdaddr[6], uint16_t /*interval*/,\n                              uint16_t /*latency*/, uint16_t /*supervisionTimeout*/,\n                              uint8_t /*masterClockAccuracy*/)\n{\n  int peerIndex = -1;\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == 0xffff) {\n      peerIndex = i;\n      break;\n    }\n  }\n\n  if (peerIndex == -1) {\n    // bail, no space\n    return;\n  }\n\n  _peers[peerIndex].connectionHandle = handle;\n  _peers[peerIndex].role = role;\n  _peers[peerIndex].mtu = 23;\n  _peers[peerIndex].addressType = peerBdaddrType;\n  memcpy(_peers[peerIndex].address, peerBdaddr, sizeof(_peers[peerIndex].address));\n  uint8_t BDADDr[6];\n  for(int i=0; i<6; i++) BDADDr[5-i] = peerBdaddr[i];\n  if(HCI.tryResolveAddress(BDADDr,_peers[peerIndex].resolvedAddress)){\n#ifdef _BLE_TRACE_\n    Serial.println(\"Found match.\");\n#endif\n  }else{\n#ifdef _BLE_TRACE_\n    Serial.println(\"No matching MAC\");\n#endif\n    memset(&_peers[peerIndex].resolvedAddress, 0, 6);\n  }\n\n  if (_eventHandlers[BLEConnected]) {\n    _eventHandlers[BLEConnected](BLEDevice(peerBdaddrType, peerBdaddr));\n  }\n}\n\nvoid ATTClass::handleData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  uint8_t opcode = data[0];\n\n  dlen--;\n  data++;\n\n  uint16_t mtu = this->mtu(connectionHandle);\n\n#ifdef _BLE_TRACE_\n  Serial.print(\"data opcode: 0x\");\n  Serial.println(opcode, HEX);\n#endif\n  switch (opcode) {\n    case ATT_OP_ERROR:\n#ifdef _BLE_TRACE_\n      Serial.println(\"[Info] data error\");\n      // Serial.print(\"Error: \");\n      // btct.printBytes(data, dlen);\n#endif\n      error(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_MTU_REQ:\n#ifdef _BLE_TRACE_\n      Serial.println(\"MTU\");\n#endif\n      mtuReq(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_MTU_RESP:\n      mtuResp(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_FIND_INFO_REQ:\n#ifdef _BLE_TRACE_\n      Serial.println(\"Find info\");\n#endif\n      findInfoReq(connectionHandle, mtu, dlen, data);\n      break;\n\n    case ATT_OP_FIND_INFO_RESP:\n      findInfoResp(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_FIND_BY_TYPE_REQ:\n      findByTypeReq(connectionHandle, mtu, dlen, data);\n      break;\n\n    case ATT_OP_READ_BY_TYPE_REQ:\n#ifdef _BLE_TRACE_\n      Serial.println(\"By type\");\n#endif\n      readByTypeReq(connectionHandle, mtu, dlen, data);\n      break;\n\n    case ATT_OP_READ_BY_TYPE_RESP:\n      readByTypeResp(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_READ_BY_GROUP_REQ:\n      readByGroupReq(connectionHandle, mtu, dlen, data);\n      break;\n\n    case ATT_OP_READ_BY_GROUP_RESP:\n      readByGroupResp(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_READ_REQ:\n    case ATT_OP_READ_BLOB_REQ:\n      readOrReadBlobReq(connectionHandle, mtu, opcode, dlen, data);\n      break;\n\n    case ATT_OP_READ_RESP:\n      readResp(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_WRITE_REQ:\n    case ATT_OP_WRITE_CMD:\n#ifdef _BLE_TRACE_\n      Serial.println(\"Write req\");\n#endif\n      writeReqOrCmd(connectionHandle, mtu, opcode, dlen, data);\n      break;\n\n    case ATT_OP_WRITE_RESP:\n      writeResp(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_PREP_WRITE_REQ:\n      prepWriteReq(connectionHandle, mtu, dlen, data);\n      break;\n\n    case ATT_OP_EXEC_WRITE_REQ:\n      execWriteReq(connectionHandle, mtu, dlen, data);\n      break;\n\n    case ATT_OP_HANDLE_NOTIFY:\n    case ATT_OP_HANDLE_IND:\n      handleNotifyOrInd(connectionHandle, opcode, dlen, data);\n      break;\n\n    case ATT_OP_HANDLE_CNF:\n      handleCnf(connectionHandle, dlen, data);\n      break;\n\n    case ATT_OP_READ_MULTI_REQ:\n    case ATT_OP_SIGNED_WRITE_CMD:\n    default:\n#ifdef _BLE_TRACE_\n      Serial.println(\"[Info] Unhandled dara\");\n#endif\n      sendError(connectionHandle, opcode, 0x00, ATT_ECODE_REQ_NOT_SUPP);\n      break;\n  }\n}\n\nvoid ATTClass::removeConnection(uint16_t handle, uint8_t /*reason*/)\n{\n  int peerIndex = -1;\n  int peerCount = 0;\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == handle) {\n      peerIndex = i;\n    }\n\n    if (_peers[i].connectionHandle != 0xffff) {\n      peerCount++;\n    }\n  }\n\n  if (peerIndex == -1) {\n    // bail not found\n    return;\n  }\n\n  BLEDevice bleDevice(_peers[peerIndex].addressType, _peers[peerIndex].address);\n\n  if (peerCount == 1) {\n    // clear CCCD values on disconnect\n    for (uint16_t i = 0; i < GATT.attributeCount(); i++) {\n      BLELocalAttribute* attribute = GATT.attribute(i);\n\n      if (attribute->type() == BLETypeCharacteristic) {\n        BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n\n        characteristic->writeCccdValue(bleDevice, 0x0000);\n      }\n    }\n\n    _longWriteHandle = 0x0000;\n    _longWriteValueLength = 0;\n  }\n\n  if (_eventHandlers[BLEDisconnected]) {\n    _eventHandlers[BLEDisconnected](bleDevice);\n  }\n\n  _peers[peerIndex].connectionHandle = 0xffff;\n  _peers[peerIndex].role = 0x00;\n  _peers[peerIndex].addressType = 0x00;\n  memset(_peers[peerIndex].address, 0x00, sizeof(_peers[peerIndex].address));\n  _peers[peerIndex].mtu = 23;\n  _peers[peerIndex].encryption = PEER_ENCRYPTION::NO_ENCRYPTION;\n  _peers[peerIndex].IOCap[0] = 0;\n  _peers[peerIndex].IOCap[1] = 0;\n  _peers[peerIndex].IOCap[2] = 0;\n\n  if (_peers[peerIndex].device) {\n    delete _peers[peerIndex].device;\n  }\n  _peers[peerIndex].device = NULL;\n}\n\nuint16_t ATTClass::connectionHandle(uint8_t addressType, const uint8_t address[6]) const\n{\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].addressType == addressType && memcmp(_peers[i].address, address, 6) == 0) {\n      return _peers[i].connectionHandle;\n    }\n  }\n\n  return 0xffff;\n}\n\nBLERemoteDevice* ATTClass::device(uint8_t addressType, const uint8_t address[6]) const\n{\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].addressType == addressType && memcmp(_peers[i].address, address, 6) == 0) {\n      return _peers[i].device;\n    }\n  }\n\n  return NULL;\n}\n\nbool ATTClass::connected() const\n{\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle != 0xffff) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\nbool ATTClass::connected(uint8_t addressType, const uint8_t address[6]) const\n{\n  return (connectionHandle(addressType, address) != 0xffff);\n}\n\nbool ATTClass::connected(uint16_t handle) const\n{\n  HCI.poll();\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == handle) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\n/*\n * Return true if any of the known devices is paired (peer encrypted)\n * Does not check if the paired device is also connected\n */\nbool ATTClass::paired() const\n{\n  for(int i=0; i<ATT_MAX_PEERS; i++){\n    if((_peers[i].encryption & PEER_ENCRYPTION::ENCRYPTED_AES) > 0){\n      return true;\n    }\n  }\n  return false;\n}\n\n/*\n * Return true if the specified device is paired (peer encrypted)\n */\nbool ATTClass::paired(uint16_t handle) const\n{  \n  for(int i=0; i<ATT_MAX_PEERS; i++){\n    if(_peers[i].connectionHandle != handle){continue;}\n    return (_peers[i].encryption & PEER_ENCRYPTION::ENCRYPTED_AES) > 0;\n  }\n  return false; // unknown handle\n}\n\nuint16_t ATTClass::mtu(uint16_t handle) const\n{\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == handle) {\n      return _peers[i].mtu;\n    }\n  }\n\n  return 23;\n}\n\nbool ATTClass::disconnect()\n{\n  int numDisconnects = 0;\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == 0xffff) {\n      continue;\n    }\n\n    if (HCI.disconnect(_peers[i].connectionHandle) != 0) {\n      continue;\n    }\n\n    numDisconnects++;\n\n    BLEDevice bleDevice(_peers[i].addressType, _peers[i].address);\n\n    // clear CCCD values on disconnect\n    for (uint16_t att = 0; att < GATT.attributeCount(); att++) {\n      BLELocalAttribute* attribute = GATT.attribute(att);\n\n      if (attribute->type() == BLETypeCharacteristic) {\n        BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n\n        characteristic->writeCccdValue(bleDevice, 0x0000);\n      }\n    }\n\n    _longWriteHandle = 0x0000;\n    _longWriteValueLength = 0;\n\n    _peers[i].connectionHandle = 0xffff;\n    _peers[i].role = 0x00;\n    _peers[i].addressType = 0x00;\n    memset(_peers[i].address, 0x00, sizeof(_peers[i].address));\n    memset(_peers[i].resolvedAddress, 0x00, sizeof(_peers[i].resolvedAddress));\n    _peers[i].mtu = 23;\n\n    if (_peers[i].device) {\n      delete _peers[i].device;\n    }\n    _peers[i].device = NULL;\n  }\n\n  return (numDisconnects > 0);\n}\n\nBLEDevice ATTClass::central()\n{\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == 0xffff || _peers[i].role != 0x01) {\n      continue;\n    }\n\n    return BLEDevice(_peers[i].addressType, _peers[i].address);\n  }\n\n  return BLEDevice();\n}\n\nint ATTClass::handleNotify(uint16_t handle, const uint8_t* value, int length)\n{\n  int numNotifications = 0;\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == 0xffff) {\n      continue;\n    }\n\n    uint8_t notification[_peers[i].mtu];\n    uint16_t notificationLength = 0;\n\n    notification[0] = ATT_OP_HANDLE_NOTIFY;\n    notificationLength++;\n\n    memcpy(&notification[1], &handle, sizeof(handle));\n    notificationLength += sizeof(handle);\n\n    length = min((uint16_t)(_peers[i].mtu - notificationLength), (uint16_t)length);\n    memcpy(&notification[notificationLength], value, length);\n    notificationLength += length;\n\n    /// TODO: Set encryption requirement on notify.\n    HCI.sendAclPkt(_peers[i].connectionHandle, ATT_CID, notificationLength, notification);\n\n    numNotifications++;\n  }\n\n  return (numNotifications > 0) ? length : 0;\n}\n\nint ATTClass::handleInd(uint16_t handle, const uint8_t* value, int length)\n{\n  int numIndications = 0;\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == 0xffff) {\n      continue;\n    }\n\n    uint8_t indication[_peers[i].mtu];\n    uint16_t indicationLength = 0;\n\n    indication[0] = ATT_OP_HANDLE_IND;\n    indicationLength++;\n\n    memcpy(&indication[1], &handle, sizeof(handle));\n    indicationLength += sizeof(handle);\n\n    length = min((uint16_t)(_peers[i].mtu - indicationLength), (uint16_t)length);\n    memcpy(&indication[indicationLength], value, length);\n    indicationLength += length;\n\n    _cnf = false;\n\n    HCI.sendAclPkt(_peers[i].connectionHandle, ATT_CID, indicationLength, indication);\n\n    while (!_cnf) {\n      HCI.poll();\n\n      if (!connected(_peers[i].addressType, _peers[i].address)) {\n        break;\n      }\n    }\n\n    numIndications++;\n  }\n\n  return (numIndications > 0) ? length : 0;\n}\n\nvoid ATTClass::error(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  if (dlen != 4) {\n    // drop\n    return;\n  } \n\n  struct __attribute__ ((packed)) AttError {\n    uint8_t opcode;\n    uint16_t handle;\n    uint8_t code;\n  } *attError = (AttError*)data;\n\n  if (_pendingResp.connectionHandle == connectionHandle && (_pendingResp.op - 1) == attError->opcode) {\n    _pendingResp.buffer[0] = ATT_OP_ERROR;\n    memcpy(&_pendingResp.buffer[1], data, dlen);\n    _pendingResp.length = dlen + 1;\n  }\n}\n\nvoid ATTClass::mtuReq(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  uint16_t mtu = *(uint16_t*)data;\n\n  if (dlen != 2) {\n    sendError(connectionHandle, ATT_OP_MTU_REQ, 0x0000, ATT_ECODE_INVALID_PDU);\n    return;\n  }\n\n  if (mtu > _maxMtu) {\n    mtu = _maxMtu;\n  }\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == connectionHandle) {\n      _peers[i].mtu = mtu;\n      break;\n    }\n  }\n\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint16_t mtu;\n  } mtuResp = { ATT_OP_MTU_RESP, mtu };\n\n  HCI.sendAclPkt(connectionHandle, ATT_CID, sizeof(mtuResp), &mtuResp);\n}\n\nint ATTClass::mtuReq(uint16_t connectionHandle, uint16_t mtu, uint8_t responseBuffer[])\n{\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint16_t mtu;\n  } mtuReq = { ATT_OP_MTU_REQ, mtu };\n\n  return sendReq(connectionHandle, &mtuReq, sizeof(mtuReq), responseBuffer);\n}\n\nvoid ATTClass::mtuResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  uint16_t mtu = *(uint16_t*)data;\n\n  if (dlen != 2) {\n    return;\n  }\n\n  for (int i = 0; i < ATT_MAX_PEERS; i++) {\n    if (_peers[i].connectionHandle == connectionHandle) {\n      _peers[i].mtu = mtu;\n      break;\n    }\n  }\n\n  if (connectionHandle == _pendingResp.connectionHandle && _pendingResp.op == ATT_OP_MTU_RESP) {\n    _pendingResp.buffer[0] = ATT_OP_MTU_RESP;\n    memcpy(&_pendingResp.buffer[1], data, dlen);\n    _pendingResp.length = dlen + 1;\n  }\n}\n\nvoid ATTClass::findInfoReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[])\n{\n  struct __attribute__ ((packed)) FindInfoReq {\n    uint16_t startHandle;\n    uint16_t endHandle;\n  } *findInfoReq = (FindInfoReq*)data;\n\n  if (dlen != sizeof(FindInfoReq)) {\n    sendError(connectionHandle, ATT_OP_FIND_INFO_REQ, findInfoReq->startHandle, ATT_ECODE_INVALID_PDU);\n    return;\n  }\n\n  uint8_t response[mtu];\n  uint16_t responseLength;\n\n  response[0] = ATT_OP_FIND_INFO_RESP;\n  response[1] = 0x00;\n  responseLength = 2;\n\n  for (uint16_t i = (findInfoReq->startHandle - 1); i < GATT.attributeCount() && i <= (findInfoReq->endHandle - 1); i++) {\n    BLELocalAttribute* attribute = GATT.attribute(i);\n    uint16_t handle = (i + 1);\n    bool isValueHandle = (attribute->type() == BLETypeCharacteristic) && (((BLELocalCharacteristic*)attribute)->valueHandle() == handle);\n    bool isDescriptor = attribute->type() == BLETypeDescriptor;\n    int uuidLen = (isValueHandle || isDescriptor) ? attribute->uuidLength() : BLE_ATTRIBUTE_TYPE_SIZE;\n    int infoType = (uuidLen == 2) ? 0x01 : 0x02;\n\n    if (response[1] == 0) {\n      response[1] = infoType;\n    }\n\n    if (response[1] != infoType) {\n      // different type\n      break;\n    }\n\n    // add the handle\n    memcpy(&response[responseLength], &handle, sizeof(handle));\n    responseLength += sizeof(handle);\n\n    if (isValueHandle || isDescriptor) {\n      // add the UUID\n      memcpy(&response[responseLength], attribute->uuidData(), uuidLen);\n      responseLength += uuidLen;\n    } else {\n      // add the type\n      uint16_t type = attribute->type();\n\n      memcpy(&response[responseLength], &type, sizeof(type));\n      responseLength += sizeof(type);\n    }\n\n    if ((responseLength + (2 + uuidLen)) > mtu) {\n      break;\n    }\n  }\n\n  if (responseLength == 2) {\n    sendError(connectionHandle, ATT_OP_FIND_INFO_REQ, findInfoReq->startHandle, ATT_ECODE_ATTR_NOT_FOUND);\n  } else {\n    HCI.sendAclPkt(connectionHandle, ATT_CID, responseLength, response);\n  }\n}\n\nint ATTClass::findInfoReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint8_t responseBuffer[])\n{\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint16_t startHandle;\n    uint16_t endHandle;\n  } findInfoReq = { ATT_OP_FIND_INFO_REQ, startHandle, endHandle };\n\n  return sendReq(connectionHandle, &findInfoReq, sizeof(findInfoReq), responseBuffer);\n}\n\nvoid ATTClass::findInfoResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  if (dlen < 2) {\n    return; // invalid, drop\n  }\n\n  if (connectionHandle == _pendingResp.connectionHandle && _pendingResp.op == ATT_OP_FIND_INFO_RESP) {\n    _pendingResp.buffer[0] = ATT_OP_FIND_INFO_RESP;\n    memcpy(&_pendingResp.buffer[1], data, dlen);\n    _pendingResp.length = dlen + 1;\n  }\n}\n\nvoid ATTClass::findByTypeReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[])\n{\n  struct __attribute__ ((packed)) FindByTypeReq {\n    uint16_t startHandle;\n    uint16_t endHandle;\n    uint16_t type;\n  } *findByTypeReq = (FindByTypeReq*)data;\n\n  if (dlen < sizeof(FindByTypeReq)) {\n    sendError(connectionHandle, ATT_OP_FIND_BY_TYPE_REQ, findByTypeReq->startHandle, ATT_ECODE_INVALID_PDU);\n    return;\n  }\n\n  uint16_t valueLength = dlen - sizeof(*findByTypeReq);\n  uint8_t* value = &data[sizeof(*findByTypeReq)];\n\n  uint8_t response[mtu];\n  uint16_t responseLength;\n\n  response[0] = ATT_OP_FIND_BY_TYPE_RESP;\n  responseLength = 1;\n\n  if (findByTypeReq->type == BLETypeService) {\n    for (uint16_t i = (findByTypeReq->startHandle - 1); i < GATT.attributeCount() && i <= (findByTypeReq->endHandle - 1); i++) {\n      BLELocalAttribute* attribute = GATT.attribute(i);\n\n      if ((attribute->type() == findByTypeReq->type) && (attribute->uuidLength() == valueLength) && memcmp(attribute->uuidData(), value, valueLength) == 0) {\n        BLELocalService* service = (BLELocalService*)attribute;\n\n        // add the start handle\n        uint16_t startHandle = service->startHandle();\n        memcpy(&response[responseLength], &startHandle, sizeof(startHandle));\n        responseLength += sizeof(startHandle);\n\n        // add the end handle\n        uint16_t endHandle = service->endHandle();\n        memcpy(&response[responseLength], &endHandle, sizeof(endHandle));\n        responseLength += sizeof(endHandle);\n      }\n\n      if ((responseLength + 4) > mtu) {\n        break;\n      }\n    }\n  }\n\n  if (responseLength == 1) {\n    sendError(connectionHandle, ATT_OP_FIND_BY_TYPE_REQ, findByTypeReq->startHandle, ATT_ECODE_ATTR_NOT_FOUND);\n  } else {\n    HCI.sendAclPkt(connectionHandle, ATT_CID, responseLength, response);\n  }\n}\n\nvoid ATTClass::readByGroupReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[])\n{\n  struct __attribute__ ((packed)) ReadByGroupReq {\n    uint16_t startHandle;\n    uint16_t endHandle;\n    uint16_t uuid;\n  } *readByGroupReq = (ReadByGroupReq*)data;\n#ifdef _BLE_TRACE_\n  Serial.print(\"readByGroupReq: start: 0x\");\n  Serial.println(readByGroupReq->startHandle,HEX);\n  Serial.print(\"readByGroupReq: end: 0x\");\n  Serial.println(readByGroupReq->endHandle,HEX);\n  Serial.print(\"readByGroupReq: UUID: 0x\");\n  Serial.println(readByGroupReq->uuid,HEX);\n#endif\n\n  if (dlen != sizeof(ReadByGroupReq) || (readByGroupReq->uuid != BLETypeService && readByGroupReq->uuid != 0x2801)) {\n    sendError(connectionHandle, ATT_OP_READ_BY_GROUP_REQ, readByGroupReq->startHandle, ATT_ECODE_UNSUPP_GRP_TYPE);\n    return;\n  }\n\n  uint8_t response[mtu];\n  uint16_t responseLength;\n\n  response[0] = ATT_OP_READ_BY_GROUP_RESP;\n  response[1] = 0x00;\n  responseLength = 2;\n#ifdef _BLE_TRACE_\n  Serial.print(\"readByGroupReq: attrcount: \");\n  Serial.println(GATT.attributeCount());\n#endif\n  for (uint16_t i = (readByGroupReq->startHandle - 1); i < GATT.attributeCount() && i <= (readByGroupReq->endHandle - 1); i++) {\n    BLELocalAttribute* attribute = GATT.attribute(i);\n\n    if (readByGroupReq->uuid != attribute->type()) {\n      // not the type\n      continue;\n    }\n\n    int uuidLen = attribute->uuidLength();\n    int infoSize = (uuidLen == 2) ? 6 : 20;\n\n    if (response[1] == 0) {\n      response[1] = infoSize;\n    }\n\n    if (response[1] != infoSize) {\n      // different size\n      break;\n    }\n\n    BLELocalService* service = (BLELocalService*)attribute;\n\n    // add the start handle\n    uint16_t startHandle = service->startHandle();\n    memcpy(&response[responseLength], &startHandle, sizeof(startHandle));\n    responseLength += sizeof(startHandle);\n\n    // add the end handle\n    uint16_t endHandle = service->endHandle();\n    memcpy(&response[responseLength], &endHandle, sizeof(endHandle));\n    responseLength += sizeof(endHandle);\n\n    // add the UUID\n    memcpy(&response[responseLength], service->uuidData(), uuidLen);\n    responseLength += uuidLen;\n\n    if ((responseLength + infoSize) > mtu) {\n      break;\n    }\n  }\n\n  if (responseLength == 2) {\n    sendError(connectionHandle, ATT_OP_READ_BY_GROUP_REQ, readByGroupReq->startHandle, ATT_ECODE_ATTR_NOT_FOUND);\n  } else {\n    HCI.sendAclPkt(connectionHandle, ATT_CID, responseLength, response);\n  }\n}\n\nint ATTClass::readByGroupReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint16_t uuid, uint8_t responseBuffer[])\n{\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint16_t startHandle;\n    uint16_t endHandle;\n    uint16_t uuid;\n  } readByGroupReq = { ATT_OP_READ_BY_GROUP_REQ, startHandle, endHandle, uuid };\n\n  return sendReq(connectionHandle, &readByGroupReq, sizeof(readByGroupReq), responseBuffer);\n}\n\nvoid ATTClass::readByGroupResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  if (dlen < 2) {\n    return; // invalid, drop\n  }\n\n  if (connectionHandle == _pendingResp.connectionHandle && _pendingResp.op == ATT_OP_READ_BY_GROUP_RESP) {\n    _pendingResp.buffer[0] = ATT_OP_READ_BY_GROUP_RESP;\n    memcpy(&_pendingResp.buffer[1], data, dlen);\n    _pendingResp.length = dlen + 1;\n  }\n}\n\nvoid ATTClass::readOrReadBlobReq(uint16_t connectionHandle, uint16_t mtu, uint8_t opcode, uint8_t dlen, uint8_t data[])\n{\n  if (opcode == ATT_OP_READ_REQ) {\n    if (dlen != sizeof(uint16_t)) {\n      sendError(connectionHandle, ATT_OP_READ_REQ, 0x0000, ATT_ECODE_INVALID_PDU);\n      return;\n    }\n  } else {\n    if (dlen != (sizeof(uint16_t) + sizeof(uint16_t))) {\n      sendError(connectionHandle, ATT_OP_READ_BLOB_REQ, 0x0000, ATT_ECODE_INVALID_PDU);\n      return;\n    }\n  }\n  /// if auth error, hold the response in a buffer.\n  bool holdResponse = false;\n  uint16_t handle;\n  memcpy(&handle, data, sizeof(handle));\n  uint16_t offset = (opcode == ATT_OP_READ_REQ) ? 0 : *(uint16_t*)&data[sizeof(handle)];\n\n  if ((uint16_t)(handle - 1) > GATT.attributeCount()) {\n    sendError(connectionHandle, opcode, handle, ATT_ECODE_ATTR_NOT_FOUND);\n    return;\n  }\n\n  uint8_t response[mtu];\n  uint16_t responseLength;\n\n  response[0] = (opcode == ATT_OP_READ_REQ) ? ATT_OP_READ_RESP : ATT_OP_READ_BLOB_RESP;\n  responseLength = 1;\n\n  BLELocalAttribute* attribute = GATT.attribute(handle - 1);\n  enum BLEAttributeType attributeType = attribute->type();\n\n  if (attributeType == BLETypeService) {\n    if (offset) {\n      sendError(connectionHandle, ATT_ECODE_ATTR_NOT_LONG, handle, ATT_ECODE_INVALID_PDU);\n      return;\n    }\n\n    BLELocalService* service = (BLELocalService*)attribute;\n\n    // add the UUID\n    uint8_t uuidLen = service->uuidLength();\n    memcpy(&response[responseLength], service->uuidData(), uuidLen);\n    responseLength += uuidLen;\n  } else if (attributeType == BLETypeCharacteristic) {\n    BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n\n    if (characteristic->handle() == handle) {\n      if (offset) {\n        sendError(connectionHandle, opcode, handle, ATT_ECODE_ATTR_NOT_LONG);\n        return;\n      }\n\n      // add the properties\n      response[responseLength++] = characteristic->properties();\n\n      // add the value handle\n      uint16_t valueHandle = characteristic->valueHandle();\n      memcpy(&response[responseLength], &valueHandle, sizeof(valueHandle));\n      responseLength += sizeof(valueHandle);\n\n      // add the UUID\n      uint8_t uuidLen = characteristic->uuidLength();\n      memcpy(&response[responseLength], characteristic->uuidData(), uuidLen);\n      responseLength += uuidLen;\n    } else {\n      if ((characteristic->properties() & BLERead) == 0) {\n        sendError(connectionHandle, opcode, handle, ATT_ECODE_READ_NOT_PERM);\n        return;\n      }\n      // If characteristic requires encryption send error & hold response until encrypted\n      if ((characteristic->permissions() & (BLEPermission::BLEEncryption >> 8)) > 0 &&\n          (getPeerEncryption(connectionHandle) & PEER_ENCRYPTION::ENCRYPTED_AES)==0 ) {\n        holdResponse = true;\n        sendError(connectionHandle, opcode, handle, ATT_ECODE_INSUFF_ENC);\n      }\n\n      uint16_t valueLength = characteristic->valueLength();\n\n      if (offset >= valueLength) {\n        sendError(connectionHandle, opcode, handle, ATT_ECODE_INVALID_OFFSET);\n        return;\n      }\n\n      valueLength = min(mtu - responseLength, valueLength - offset);\n\n      for (int i = 0; i < ATT_MAX_PEERS; i++) {\n        if (_peers[i].connectionHandle == connectionHandle) {\n          characteristic->readValue(BLEDevice(_peers[i].addressType, _peers[i].address), offset, &response[responseLength], valueLength);\n          responseLength += valueLength;\n        }\n      }\n    }\n  } else if (attributeType == BLETypeDescriptor) {\n    BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute;\n    \n    uint16_t valueLength = descriptor->valueSize();\n\n    if (offset >= valueLength) {\n      sendError(connectionHandle, opcode, handle, ATT_ECODE_INVALID_OFFSET);\n      return;\n    }\n\n    valueLength = min(mtu - responseLength, valueLength - offset);\n\n    memcpy(&response[responseLength], descriptor->value() + offset, valueLength);\n    responseLength += valueLength;\n  }\n  if(holdResponse){\n    memcpy(holdBuffer, response, responseLength);\n    holdBufferSize = responseLength;\n  }else{\n    HCI.sendAclPkt(connectionHandle, ATT_CID, responseLength, response);\n  }\n}\n\nvoid ATTClass::readResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  if (connectionHandle == _pendingResp.connectionHandle && _pendingResp.op == ATT_OP_READ_RESP) {\n    _pendingResp.buffer[0] = ATT_OP_READ_RESP;\n    memcpy(&_pendingResp.buffer[1], data, dlen);\n    _pendingResp.length = dlen + 1;\n  }\n}\n\nvoid ATTClass::readByTypeReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[])\n{\n  struct __attribute__ ((packed)) ReadByTypeReq {\n    uint16_t startHandle;\n    uint16_t endHandle;\n    uint16_t uuid;\n  } *readByTypeReq = (ReadByTypeReq*)data;\n\n  if (dlen != sizeof(ReadByTypeReq)) {\n    sendError(connectionHandle, ATT_OP_READ_BY_TYPE_REQ, readByTypeReq->startHandle, ATT_ECODE_INVALID_PDU);\n    return;\n  }\n\n  uint8_t response[mtu];\n  uint16_t responseLength;\n\n  response[0] = ATT_OP_READ_BY_TYPE_RESP;\n  response[1] = 0x00;\n  responseLength = 2;\n\n  for (uint16_t i = (readByTypeReq->startHandle - 1); i < GATT.attributeCount() && i <= (readByTypeReq->endHandle - 1); i++) {\n    BLELocalAttribute* attribute = GATT.attribute(i);\n    uint16_t handle = (i + 1);\n\n    if (attribute->type() == readByTypeReq->uuid) {\n      if (attribute->type() == BLETypeCharacteristic) {\n        BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n\n        if (characteristic->valueHandle() == handle) {\n          // value handle, skip\n          continue;\n        }\n\n        int uuidLen = attribute->uuidLength();\n        int typeSize = (uuidLen == 2) ? 7 : 21;\n\n        if (response[1] == 0) {\n          response[1] = typeSize;\n        }\n\n        if (response[1] != typeSize) {\n          // all done, wrong size\n          break;\n        }\n\n        // add the handle\n        memcpy(&response[responseLength], &handle, sizeof(handle));\n        responseLength += sizeof(handle);\n\n        // add the properties\n        response[responseLength++] = characteristic->properties();\n\n        // add the value handle\n        uint16_t valueHandle = (handle + 1);\n        memcpy(&response[responseLength], &valueHandle, sizeof(valueHandle));\n        responseLength += sizeof(valueHandle);\n\n        // add the UUID\n        memcpy(&response[responseLength], characteristic->uuidData(), uuidLen);\n        responseLength += uuidLen;\n\n        // skip the next handle, it's a value handle\n        i++;\n\n        if ((responseLength + typeSize) > mtu) {\n          break;\n        }\n      } else if (attribute->type() == 0x2902) {\n        BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute;\n\n        // add the handle\n        memcpy(&response[responseLength], &handle, sizeof(handle));\n        responseLength += sizeof(handle);\n\n        // add the value\n        int valueSize = min((uint16_t)(mtu - responseLength), (uint16_t)descriptor->valueSize());\n        memcpy(&response[responseLength], descriptor->value(), valueSize);\n        responseLength += valueSize;\n\n        response[1] = 2 + valueSize;\n\n        break; // all done\n      }\n    } else if (attribute->type() == BLETypeCharacteristic && attribute->uuidLength() == 2 && memcmp(&readByTypeReq->uuid, attribute->uuidData(), 2) == 0) {\n      BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n\n      // add the handle\n      memcpy(&response[responseLength], &handle, sizeof(handle));\n      responseLength += sizeof(handle);\n\n      // add the value\n      int valueLength = min((uint16_t)(mtu - responseLength), (uint16_t)characteristic->valueLength());\n      memcpy(&response[responseLength], characteristic->value(), valueLength);\n      responseLength += valueLength;\n\n      response[1] = 2 + valueLength;\n\n      break; // all done\n    }\n  }\n\n  if (responseLength == 2) {\n    sendError(connectionHandle, ATT_OP_READ_BY_TYPE_REQ, readByTypeReq->startHandle, ATT_ECODE_ATTR_NOT_FOUND);\n  } else {\n    HCI.sendAclPkt(connectionHandle, ATT_CID, responseLength, response);\n  }\n}\n\nint ATTClass::readByTypeReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint16_t type, uint8_t responseBuffer[])\n{\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint16_t startHandle;\n    uint16_t endHandle;\n    uint16_t type;\n  } readByTypeReq = { ATT_OP_READ_BY_TYPE_REQ, startHandle, endHandle, type };\n\n  return sendReq(connectionHandle, &readByTypeReq, sizeof(readByTypeReq), responseBuffer);\n}\n\nvoid ATTClass::readByTypeResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  if (dlen < 1) {\n    return; // invalid, drop\n  }\n\n  if (connectionHandle == _pendingResp.connectionHandle && _pendingResp.op == ATT_OP_READ_BY_TYPE_RESP) {\n    _pendingResp.buffer[0] = ATT_OP_READ_BY_TYPE_RESP;\n    memcpy(&_pendingResp.buffer[1], data, dlen);\n    _pendingResp.length = dlen + 1;\n  }\n}\n\nvoid ATTClass::writeReqOrCmd(uint16_t connectionHandle, uint16_t mtu, uint8_t op, uint8_t dlen, uint8_t data[])\n{\n  bool withResponse = (op == ATT_OP_WRITE_REQ);\n\n  if (dlen < sizeof(uint16_t)) {\n    if (withResponse) {\n      sendError(connectionHandle, ATT_OP_WRITE_REQ, 0x0000, ATT_ECODE_INVALID_PDU);\n    }\n    return;\n  }\n\n  uint16_t handle;\n  memcpy(&handle, data, sizeof(handle));\n\n  if ((uint16_t)(handle - 1) > GATT.attributeCount()) {\n    if (withResponse) {\n      sendError(connectionHandle, ATT_OP_WRITE_REQ, handle, ATT_ECODE_ATTR_NOT_FOUND);\n    }\n    return;\n  }\n\n  uint8_t valueLength = dlen - sizeof(handle);\n  uint8_t* value = &data[sizeof(handle)];\n\n  BLELocalAttribute* attribute = GATT.attribute(handle - 1);\n  bool holdResponse = false;\n\n  if (attribute->type() == BLETypeCharacteristic) {\n    BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n    \n    if (handle != characteristic->valueHandle() || \n      withResponse ? ((characteristic->properties() & BLEWrite) == 0) : \n                     ((characteristic->properties() & BLEWriteWithoutResponse) == 0)) {\n      if (withResponse) {\n        sendError(connectionHandle, ATT_OP_WRITE_REQ, handle, ATT_ECODE_WRITE_NOT_PERM);\n      }\n      return;\n    }\n    // Check permission\n    if((characteristic->permissions() &( BLEPermission::BLEEncryption >> 8)) > 0 && \n       (getPeerEncryption(connectionHandle) & PEER_ENCRYPTION::ENCRYPTED_AES) == 0){\n      holdResponse = true;\n      sendError(connectionHandle, ATT_OP_WRITE_REQ, handle, ATT_ECODE_INSUFF_ENC);\n    }\n\n    for (int i = 0; i < ATT_MAX_PEERS; i++) {\n      if (_peers[i].connectionHandle == connectionHandle) {\n        if(holdResponse){\n          \n          writeBufferSize = 0;\n          memcpy(writeBuffer, &handle, 2);\n          writeBufferSize+=2;\n\n          writeBuffer[writeBufferSize++] = _peers[i].addressType;\n\n          memcpy(&writeBuffer[writeBufferSize], _peers[i].address, sizeof(_peers[i].address));\n          writeBufferSize += sizeof(_peers[i].address);\n          \n          writeBuffer[writeBufferSize] = valueLength;\n          writeBufferSize += sizeof(valueLength);\n\n          memcpy(&writeBuffer[writeBufferSize], value, valueLength);\n          writeBufferSize += valueLength;\n        }else{\n          characteristic->writeValue(BLEDevice(_peers[i].addressType, _peers[i].address), value, valueLength);\n        }\n        break;\n      }\n    }\n  } else if (attribute->type() == BLETypeDescriptor) {\n    BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute;\n\n    // only CCCD's are writable\n    if (descriptor->uuidLength() != 2 || *((uint16_t*)(descriptor->uuidData())) != 0x2902) {\n      if (withResponse) {\n        sendError(connectionHandle, ATT_OP_WRITE_REQ, handle, ATT_ECODE_WRITE_NOT_PERM);\n      }\n      return;\n    }\n\n    // get the previous handle, should be the characteristic for the CCCD\n    attribute = GATT.attribute(handle - 2);\n\n    if (attribute->type() != BLETypeCharacteristic) {\n      if (withResponse) {\n        sendError(connectionHandle, ATT_OP_WRITE_REQ, handle, ATT_ECODE_WRITE_NOT_PERM);\n      }\n      return;\n    }\n\n    BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n\n    for (int i = 0; i < ATT_MAX_PEERS; i++) {\n      if (_peers[i].connectionHandle == connectionHandle) {\n        characteristic->writeCccdValue(BLEDevice(_peers[i].addressType, _peers[i].address), *((uint16_t*)value));\n        break;\n      }\n    }\n  } else {\n    if (withResponse) {\n      sendError(connectionHandle, ATT_OP_WRITE_REQ, handle, ATT_ECODE_WRITE_NOT_PERM);\n    }\n    return;\n  }\n\n  if (withResponse) {\n    uint8_t response[mtu];\n    uint16_t responseLength;\n\n    response[0] = ATT_OP_WRITE_RESP;\n    responseLength = 1;\n\n    if(holdResponse){\n      memcpy(holdBuffer, response, responseLength);\n      holdBufferSize = responseLength;\n    }else{\n      HCI.sendAclPkt(connectionHandle, ATT_CID, responseLength, response);\n    }\n  }\n}\nint ATTClass::processWriteBuffer(){\n  if(writeBufferSize==0){\n    return 0;\n  }\n\n  struct __attribute__ ((packed)) WriteBuffer {\n    uint16_t handle;\n    uint8_t addressType;\n    uint8_t address[6];\n    uint8_t valueLength;\n    uint8_t value[];\n  } *writeBufferStruct = (WriteBuffer*)&ATT.writeBuffer;\n  // uint8_t value[writeBufferStruct->valueLength];\n  // memcpy(value, writeBufferStruct->value, writeBufferStruct->valueLength);\n  BLELocalAttribute* attribute = GATT.attribute(writeBufferStruct->handle-1);\n  BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n#ifdef _BLE_TRACE_\n  Serial.println(\"Writing value\");\n#endif\n  characteristic->writeValue(BLEDevice(writeBufferStruct->addressType, writeBufferStruct->address), writeBufferStruct->value, writeBufferStruct->valueLength);\n  writeBufferSize = 0;\n  return 1;\n}\n\nvoid ATTClass::writeResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  if (dlen != 0) {\n    return; // drop\n  }\n\n  if (connectionHandle == _pendingResp.connectionHandle && _pendingResp.op == ATT_OP_WRITE_RESP) {\n    _pendingResp.buffer[0] = ATT_OP_WRITE_RESP;\n    memcpy(&_pendingResp.buffer[1], data, dlen);\n    _pendingResp.length = dlen + 1;\n  }\n}\n\nvoid ATTClass::prepWriteReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[])\n{\n  struct __attribute__ ((packed)) PrepWriteReq {\n    uint16_t handle;\n    uint16_t offset;\n  } *prepWriteReq = (PrepWriteReq*)data;\n\n  if (dlen < sizeof(PrepWriteReq)) {\n    sendError(connectionHandle, ATT_OP_PREP_WRITE_REQ, 0x0000, ATT_ECODE_INVALID_PDU);\n    return;\n  }\n\n  uint16_t handle = prepWriteReq->handle;\n  uint16_t offset = prepWriteReq->offset;\n\n  if ((uint16_t)(handle - 1) > GATT.attributeCount()) {\n    sendError(connectionHandle, ATT_OP_PREP_WRITE_REQ, handle, ATT_ECODE_ATTR_NOT_FOUND);\n    return;\n  }\n\n  BLELocalAttribute* attribute = GATT.attribute(handle - 1);\n\n  if (attribute->type() != BLETypeCharacteristic) {\n    sendError(connectionHandle, ATT_OP_PREP_WRITE_REQ, handle, ATT_ECODE_ATTR_NOT_LONG);\n    return;\n  }\n\n  BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;\n\n  if (handle != characteristic->valueHandle()) {\n    sendError(connectionHandle, ATT_OP_PREP_WRITE_REQ, handle, ATT_ECODE_ATTR_NOT_LONG);\n    return;\n  }\n\n  if ((characteristic->properties() & BLEWrite) == 0) {\n    sendError(connectionHandle, ATT_OP_PREP_WRITE_REQ, handle, ATT_ECODE_WRITE_NOT_PERM);\n    return;\n  }\n\n  if (_longWriteHandle == 0) {\n    int valueSize = characteristic->valueSize();\n\n    _longWriteValue = (uint8_t*)realloc(_longWriteValue, valueSize);\n    _longWriteValueLength = 0;\n    _longWriteHandle = handle;\n\n    memset(_longWriteValue, 0x00, valueSize);\n  } else if (_longWriteHandle != handle) {\n    sendError(connectionHandle, ATT_OP_PREP_WRITE_REQ, handle, ATT_ECODE_UNLIKELY);\n    return;\n  }\n\n  uint8_t valueLength = dlen - sizeof(PrepWriteReq);\n  uint8_t* value = &data[sizeof(PrepWriteReq)];\n\n  if ((offset != _longWriteValueLength) || ((offset + valueLength) > (uint16_t)characteristic->valueSize())) {\n    sendError(connectionHandle, ATT_OP_PREP_WRITE_REQ, handle, ATT_ECODE_INVALID_OFFSET);\n    return;\n  }\n\n  memcpy(_longWriteValue + offset, value, valueLength);\n  _longWriteValueLength += valueLength;\n\n  uint8_t response[mtu];\n  uint16_t responseLength;\n\n  response[0] = ATT_OP_PREP_WRITE_RESP;\n  memcpy(&response[1], data, dlen);\n  responseLength = dlen + 1;\n\n  HCI.sendAclPkt(connectionHandle, ATT_CID, responseLength, response);\n}\n\nvoid ATTClass::execWriteReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[])\n{\n  if (dlen != sizeof(uint8_t)) {\n    sendError(connectionHandle, ATT_OP_EXEC_WRITE_REQ, 0x0000, ATT_ECODE_INVALID_PDU);\n    return;\n  }\n\n  uint8_t flag = data[0];\n\n  if (_longWriteHandle && (flag & 0x01)) {\n    BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)GATT.attribute(_longWriteHandle - 1);\n\n    for (int i = 0; i < ATT_MAX_PEERS; i++) {\n      if (_peers[i].connectionHandle == connectionHandle) {\n        characteristic->writeValue(BLEDevice(_peers[i].addressType, _peers[i].address), _longWriteValue, _longWriteValueLength);\n        break;\n      }\n    }\n  }\n\n  _longWriteHandle = 0x0000;\n  _longWriteValueLength = 0;\n\n  uint8_t response[mtu];\n  uint16_t responseLength;\n\n  response[0] = ATT_OP_EXEC_WRITE_RESP;\n  responseLength = 1;\n\n  HCI.sendAclPkt(connectionHandle, ATT_CID, responseLength, response);\n}\n\nvoid ATTClass::handleNotifyOrInd(uint16_t connectionHandle, uint8_t opcode, uint8_t dlen, uint8_t data[])\n{\n  if (dlen < 2) {\n    return; // drop\n  }\n\n  struct __attribute__ ((packed)) HandleNotifyOrInd {\n    uint16_t handle;\n  } *handleNotifyOrInd = (HandleNotifyOrInd*)data;\n\n  uint16_t handle = handleNotifyOrInd->handle;\n\n  for (int peer = 0; peer < ATT_MAX_PEERS; peer++) {\n    if (_peers[peer].connectionHandle != connectionHandle) {\n      continue;\n    }\n\n    BLERemoteDevice* device = _peers[peer].device;\n\n    if (!device) {\n      break;\n    }\n\n    int serviceCount = device->serviceCount();\n\n    for (int i = 0; i < serviceCount; i++) {\n      BLERemoteService* s = device->service(i);\n\n      if (s->startHandle() < handle && s->endHandle() >= handle) {\n        int characteristicCount = s->characteristicCount();\n\n        for (int j = 0; j < characteristicCount; j++) {\n          BLERemoteCharacteristic* c = s->characteristic(j);\n\n          if (c->valueHandle() == handle) {\n            c->writeValue(BLEDevice(_peers[peer].addressType, _peers[peer].address), &data[2], dlen - 2);\n          }\n        }\n\n        break;\n      }\n    }\n  }\n\n  if (opcode == ATT_OP_HANDLE_IND) {\n    // send CNF for IND\n\n    uint8_t cnf = ATT_OP_HANDLE_CNF;\n\n    HCI.sendAclPkt(connectionHandle, ATT_CID, sizeof(cnf), &cnf);\n  }\n}\n\nvoid ATTClass::handleCnf(uint16_t /*connectionHandle*/, uint8_t /*dlen*/, uint8_t /*data*/[])\n{\n  _cnf = true;\n}\n\nvoid ATTClass::sendError(uint16_t connectionHandle, uint8_t opcode, uint16_t handle, uint8_t code)\n{\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint8_t opcode;\n    uint16_t handle;\n    uint8_t code;\n  } attError = { ATT_OP_ERROR, opcode, handle, code };\n\n  HCI.sendAclPkt(connectionHandle, ATT_CID, sizeof(attError), &attError);\n}\n\n\nbool ATTClass::exchangeMtu(uint16_t connectionHandle)\n{\n  uint8_t responseBuffer[_maxMtu];\n\n  if (!mtuReq(connectionHandle, _maxMtu, responseBuffer)) {\n    return false;\n  }\n\n  return true;\n}\n\nbool ATTClass::discoverServices(uint16_t connectionHandle, BLERemoteDevice* device, const char* serviceUuidFilter)\n{\n  uint16_t reqStartHandle = 0x0001;\n  uint16_t reqEndHandle = 0xffff;\n\n  uint8_t responseBuffer[_maxMtu];\n\n  BLEUuid serviceUuid(serviceUuidFilter);\n\n  while (reqEndHandle == 0xffff) {\n    int respLength = readByGroupReq(connectionHandle, reqStartHandle, reqEndHandle, BLETypeService, responseBuffer);\n\n    if (respLength == 0) {\n      return false;\n    }\n\n    if (responseBuffer[0] == ATT_OP_READ_BY_GROUP_RESP) {\n      uint16_t lengthPerService = responseBuffer[1];\n      uint8_t uuidLen = lengthPerService - 4;\n\n      for (int i = 2; i < respLength; i += lengthPerService) {\n        struct __attribute__ ((packed)) RawService {\n          uint16_t startHandle;\n          uint16_t endHandle;\n          uint8_t uuid[16];\n        } *rawService = (RawService*)&responseBuffer[i];\n\n        if (serviceUuidFilter == NULL || \n            (uuidLen == serviceUuid.length() && memcmp(rawService->uuid, serviceUuid.data(), uuidLen) == 0)) {\n        \n          BLERemoteService* service = new BLERemoteService(rawService->uuid, uuidLen,\n                                                            rawService->startHandle,\n                                                            rawService->endHandle);\n\n          if (service == NULL) {\n            return false;\n          }\n\n          device->addService(service);\n\n        }\n\n        reqStartHandle = rawService->endHandle + 1;\n\n        if (reqStartHandle == 0x0000) {\n          reqEndHandle = 0x0000;\n        }\n      }\n    } else {\n      reqEndHandle = 0x0000;\n    }\n  }\n\n  return true;\n}\n\nbool ATTClass::discoverCharacteristics(uint16_t connectionHandle, BLERemoteDevice* device)\n{\n  uint16_t reqStartHandle = 0x0001;\n  uint16_t reqEndHandle = 0xffff;\n\n  uint8_t responseBuffer[_maxMtu];\n\n  int serviceCount = device->serviceCount();\n  \n  for (int i = 0; i < serviceCount; i++) {\n    BLERemoteService* service = device->service(i);\n\n    reqStartHandle = service->startHandle();\n    reqEndHandle = service->endHandle();\n\n    while (1) {\n      int respLength = readByTypeReq(connectionHandle, reqStartHandle, reqEndHandle, BLETypeCharacteristic, responseBuffer);\n\n      if (respLength == 0) {\n        return false;\n      }\n\n      if (responseBuffer[0] == ATT_OP_READ_BY_TYPE_RESP) {\n        uint16_t lengthPerCharacteristic = responseBuffer[1];\n        uint8_t uuidLen = lengthPerCharacteristic - 5;\n\n        for (int i = 2; i < respLength; i += lengthPerCharacteristic) {\n          struct __attribute__ ((packed)) RawCharacteristic {\n            uint16_t startHandle;\n            uint8_t properties;\n            uint16_t valueHandle;\n            uint8_t uuid[16];\n          } *rawCharacteristic = (RawCharacteristic*)&responseBuffer[i];\n\n          BLERemoteCharacteristic* characteristic = new BLERemoteCharacteristic(rawCharacteristic->uuid, uuidLen,\n                                                                                connectionHandle,\n                                                                                rawCharacteristic->startHandle,\n                                                                                rawCharacteristic->properties,\n                                                                                rawCharacteristic->valueHandle);\n\n          if (characteristic == NULL) {\n            return false;\n          }\n\n          service->addCharacteristic(characteristic);\n\n          reqStartHandle = rawCharacteristic->valueHandle + 1;\n        }\n      } else {\n        break;\n      }\n    }\n  }\n\n  return true;\n}\n\nbool ATTClass::discoverDescriptors(uint16_t connectionHandle, BLERemoteDevice* device)\n{\n  uint16_t reqStartHandle = 0x0001;\n  uint16_t reqEndHandle = 0xffff;\n\n  uint8_t responseBuffer[_maxMtu];\n\n  int serviceCount = device->serviceCount();  \n\n  for (int i = 0; i < serviceCount; i++) {\n    BLERemoteService* service = device->service(i);\n\n    uint16_t serviceEndHandle = service->endHandle();\n\n    int characteristicCount = service->characteristicCount();\n\n    for (int j = 0; j < characteristicCount; j++) {\n      BLERemoteCharacteristic* characteristic = service->characteristic(j);\n      BLERemoteCharacteristic* nextCharacteristic = (j == (characteristicCount - 1)) ? NULL : service->characteristic(j + 1);\n\n      reqStartHandle = characteristic->valueHandle() + 1;\n      reqEndHandle = nextCharacteristic ? nextCharacteristic->valueHandle() : serviceEndHandle;\n\n      if (reqStartHandle > reqEndHandle) {\n        continue;\n      }\n\n      while (1) {\n        int respLength = findInfoReq(connectionHandle, reqStartHandle, reqEndHandle, responseBuffer);\n\n        if (respLength == 0) {\n          return false;\n        }\n\n        if (responseBuffer[0] == ATT_OP_FIND_INFO_RESP) {\n          uint16_t lengthPerDescriptor = responseBuffer[1] * 4;\n          uint8_t uuidLen = 2;\n\n          for (int i = 2; i < respLength; i += lengthPerDescriptor) {\n            struct __attribute__ ((packed)) RawDescriptor {\n              uint16_t handle;\n              uint8_t uuid[16];\n            } *rawDescriptor = (RawDescriptor*)&responseBuffer[i];\n\n            BLERemoteDescriptor* descriptor = new BLERemoteDescriptor(rawDescriptor->uuid, uuidLen,\n                                                                      connectionHandle,\n                                                                      rawDescriptor->handle);\n\n            if (descriptor == NULL) {\n              return false;\n            }\n\n            characteristic->addDescriptor(descriptor);\n\n            reqStartHandle = rawDescriptor->handle + 1;\n          }\n        } else {\n          break;\n        }\n      }\n    }\n  }\n\n  return true;\n}\n\nint ATTClass::sendReq(uint16_t connectionHandle, void* requestBuffer, int requestLength, uint8_t responseBuffer[])\n{\n  _pendingResp.connectionHandle = connectionHandle;\n  _pendingResp.op = ((uint8_t*)requestBuffer)[0] + 1;\n  _pendingResp.buffer = responseBuffer;\n  _pendingResp.length = 0;\n\n  HCI.sendAclPkt(connectionHandle, ATT_CID, requestLength, requestBuffer);\n\n  if (responseBuffer == NULL) {\n    // not waiting response\n    return 0;\n  } \n\n  for (unsigned long start = millis(); (millis() - start) < _timeout;) {\n    HCI.poll();\n\n    if (!connected(connectionHandle)) {\n      break;\n    }\n\n    if (_pendingResp.length != 0) {\n      _pendingResp.connectionHandle = 0xffff;\n      return _pendingResp.length;\n    }\n  }\n\n  _pendingResp.connectionHandle = 0xffff;\n  return 0;\n}\n\nvoid ATTClass::setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler)\n{\n  if (event < (sizeof(_eventHandlers) / (sizeof(_eventHandlers[0])))) {\n    _eventHandlers[event] = eventHandler;\n  }\n}\n\nint ATTClass::readReq(uint16_t connectionHandle, uint16_t handle, uint8_t responseBuffer[])\n{\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint16_t handle;\n  } readReq = { ATT_OP_READ_REQ, handle };\n\n  return sendReq(connectionHandle, &readReq, sizeof(readReq), responseBuffer);\n}\n\nint ATTClass::writeReq(uint16_t connectionHandle, uint16_t handle, const uint8_t* data, uint8_t dataLen, uint8_t responseBuffer[])\n{\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint16_t handle;\n    uint8_t data[255];\n  } writeReq;\n\n  writeReq.op = ATT_OP_WRITE_REQ;\n  writeReq.handle = handle;\n  memcpy(writeReq.data, data, dataLen);\n\n  return sendReq(connectionHandle, &writeReq, 3 + dataLen, responseBuffer);\n}\n\nvoid ATTClass::writeCmd(uint16_t connectionHandle, uint16_t handle, const uint8_t* data, uint8_t dataLen)\n{\n  struct __attribute__ ((packed)) {\n    uint8_t op;\n    uint16_t handle;\n    uint8_t data[255];\n  } writeReq;\n\n  writeReq.op = ATT_OP_WRITE_CMD;\n  writeReq.handle = handle;\n  memcpy(writeReq.data, data, dataLen);\n\n  sendReq(connectionHandle, &writeReq, 3 + dataLen, NULL);\n}\n\n// Set encryption state for a peer\nint ATTClass::setPeerEncryption(uint16_t connectionHandle, uint8_t encryption){\n  for(int i=0; i<ATT_MAX_PEERS; i++){\n    if(_peers[i].connectionHandle != connectionHandle){\n      continue;\n    }\n    _peers[i].encryption = encryption;\n    return 1;\n  }\n  return 0;\n}\n// Set the IO capabilities for a peer\nint ATTClass::setPeerIOCap(uint16_t connectionHandle, uint8_t IOCap[3]){\n  for(int i=0; i<ATT_MAX_PEERS; i++){\n    if(_peers[i].connectionHandle != connectionHandle){\n      continue;\n    }\n    memcpy(_peers[i].IOCap, IOCap, 3);\n    return 1;\n  }\n  return 0;\n}\n// Return the connection handle for the first peer that is requesting encryption\nuint16_t ATTClass::getPeerEncrptingConnectionHandle(){\n  for(int i=0; i<ATT_MAX_PEERS; i++){\n    if((_peers[i].encryption & PEER_ENCRYPTION::REQUESTED_ENCRYPTION) > 0){\n      return _peers[i].connectionHandle;\n    }\n  }\n  return ATT_MAX_PEERS + 1;\n}\n// Get the encryption state for a particular peer / connection handle\nuint8_t ATTClass::getPeerEncryption(uint16_t connectionHandle) {\n  for(int i=0; i<ATT_MAX_PEERS; i++){\n    if(_peers[i].connectionHandle != connectionHandle){continue;}\n    return _peers[i].encryption;\n  }\n  return 0;\n}\n// Get the IOCapabilities for a peer\nint ATTClass::getPeerIOCap(uint16_t connectionHandle, uint8_t IOCap[3]) {\n  for(int i=0; i<ATT_MAX_PEERS; i++){\n    if(_peers[i].connectionHandle != connectionHandle){continue;}\n    // return _peers[i].encryption;\n    memcpy(IOCap, _peers[i].IOCap, 3);\n  }\n  return 0;\n}\n// Get the BD_ADDR for a peer\nint ATTClass::getPeerAddr(uint16_t connectionHandle, uint8_t peerAddr[])\n{\n  for(int i=0; i<ATT_MAX_PEERS; i++)\n  {\n    if(_peers[i].connectionHandle != connectionHandle){continue;}\n    memcpy(peerAddr, _peers[i].address,6);\n    return 1;\n  }\n  return 0;\n}\n// Get the BD_ADDR for a peer in the format needed by f6 for pairing.\nint ATTClass::getPeerAddrWithType(uint16_t connectionHandle, uint8_t peerAddr[])\n{\n  for(int i=0; i<ATT_MAX_PEERS; i++)\n  {\n    if(_peers[i].connectionHandle != connectionHandle){continue;}\n    for(int k=0; k<6; k++){\n      peerAddr[6-k] = _peers[i].address[k];\n    }\n    if(_peers[i].addressType){\n      peerAddr[0] = _peers[i].addressType;\n    }else{\n      peerAddr[0] = 0x00;\n    }\n    return 1;\n  }\n  return 0;\n}\n// Get the resolved address for a peer if it exists\nint ATTClass::getPeerResolvedAddress(uint16_t connectionHandle, uint8_t resolvedAddress[]){\n  for(int i=0; i<ATT_MAX_PEERS; i++)\n  {\n    if(_peers[i].connectionHandle != connectionHandle){continue;}\n\n    bool allZero=true;\n    for(int k=0; k<6; k++){\n      if(_peers[i].resolvedAddress[k] == 0){\n        continue;\n      }else{\n        allZero = false;\n        break;\n      }\n    }\n\n    if(allZero){\n      return 0;\n    }\n\n    memcpy(resolvedAddress, _peers[i].resolvedAddress, 6);\n    return 1;\n  }\n  return 0;\n}\n\n#if !defined(FAKE_ATT)\nATTClass ATTObj;\nATTClass& ATT = ATTObj;\n#endif\n"
  },
  {
    "path": "src/utility/ATT.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _ATT_H_\n#define _ATT_H_\n\n#include <Arduino.h>\n\n#include \"BLEDevice.h\"\n#include \"keyDistribution.h\"\n\n#define ATT_CID       0x0004\n#define BLE_CTL       0x0008\n\n#if DM_CONN_MAX\n#define ATT_MAX_PEERS DM_CONN_MAX // Mbed + Cordio\n#elif __AVR__\n#define ATT_MAX_PEERS 3\n#else\n#define ATT_MAX_PEERS 8\n#endif\n\nenum PEER_ENCRYPTION {\n  NO_ENCRYPTION         = 0,\n  PAIRING_REQUEST       = 1 << 0,\n  REQUESTED_ENCRYPTION  = 1 << 1,\n  SENT_PUBKEY           = 1 << 2,\n  DH_KEY_CALULATED      = 1 << 3,\n  RECEIVED_DH_CHECK     = 1 << 4,\n  SENT_DH_CHECK         = 1 << 5,\n  ENCRYPTED_AES         = 1 << 7\n};\n\nclass BLERemoteDevice;\n\nclass ATTClass {\npublic:\n  ATTClass();\n  virtual ~ATTClass();\n\n  virtual void setMaxMtu(uint16_t maxMtu);\n  virtual void setTimeout(unsigned long timeout);\n\n  virtual bool connect(uint8_t peerBdaddrType, uint8_t peerBdaddr[6]);\n  virtual bool disconnect(uint8_t peerBdaddrType, uint8_t peerBdaddr[6]);\n  virtual bool discoverAttributes(uint8_t peerBdaddrType, uint8_t peerBdaddr[6], const char* serviceUuidFilter);\n\n  virtual void addConnection(uint16_t handle, uint8_t role, uint8_t peerBdaddrType,\n                    uint8_t peerBdaddr[6], uint16_t interval,\n                    uint16_t latency, uint16_t supervisionTimeout,\n                    uint8_t masterClockAccuracy);\n\n  virtual void handleData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n\n  virtual void removeConnection(uint16_t handle, uint8_t reason);\n\n  virtual uint16_t connectionHandle(uint8_t addressType, const uint8_t address[6]) const;\n  virtual BLERemoteDevice* device(uint8_t addressType, const uint8_t address[6]) const;\n  virtual bool connected() const;\n  virtual bool connected(uint8_t addressType, const uint8_t address[6]) const;\n  virtual bool connected(uint16_t handle) const;\n  virtual bool paired() const;\n  virtual bool paired(uint16_t handle) const;\n  virtual uint16_t mtu(uint16_t handle) const;\n\n  virtual bool disconnect();\n\n  virtual BLEDevice central();\n\n  virtual int handleNotify(uint16_t handle, const uint8_t* value, int length);\n  virtual int handleInd(uint16_t handle, const uint8_t* value, int length);\n\n  virtual void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler);\n\n  virtual int readReq(uint16_t connectionHandle, uint16_t handle, uint8_t responseBuffer[]);\n  virtual int writeReq(uint16_t connectionHandle, uint16_t handle, const uint8_t* data, uint8_t dataLen, uint8_t responseBuffer[]);\n  virtual void writeCmd(uint16_t connectionHandle, uint16_t handle, const uint8_t* data, uint8_t dataLen);\n  virtual int setPeerEncryption(uint16_t connectionHandle, uint8_t encryption);\n  uint8_t getPeerEncryption(uint16_t connectionHandle);\n  uint16_t getPeerEncrptingConnectionHandle();\n  virtual int getPeerAddr(uint16_t connectionHandle, uint8_t peerAddr[]);\n  virtual int getPeerAddrWithType(uint16_t connectionHandle, uint8_t peerAddr[]);\n  virtual int setPeerIOCap(uint16_t connectionHandle, uint8_t IOCap[]);\n  virtual int getPeerIOCap(uint16_t connectionHandle, uint8_t IOCap[]);\n  virtual int getPeerResolvedAddress(uint16_t connectionHandle, uint8_t* resolvedAddress);\n  uint8_t holdBuffer[64];\n  uint8_t writeBuffer[64];\n  uint8_t holdBufferSize;\n  uint8_t writeBufferSize;\n  virtual int processWriteBuffer();\n  KeyDistribution remoteKeyDistribution;\n  KeyDistribution localKeyDistribution;\n  uint8_t peerIRK[16];\n  /// This is just a random number... Not sure it has use unless privacy mode is active.\n  uint8_t localIRK[16] = {0x54,0x83,0x63,0x7c,0xc5,0x1e,0xf7,0xec,0x32,0xdd,0xad,0x51,0x89,0x4b,0x9e,0x07};\nprivate:\n  virtual void error(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual void mtuReq(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual int mtuReq(uint16_t connectionHandle, uint16_t mtu, uint8_t responseBuffer[]);\n  virtual void mtuResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual void findInfoReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]);\n  virtual int findInfoReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint8_t responseBuffer[]);\n  virtual void findInfoResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual void findByTypeReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]);\n  virtual void readByTypeReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]);\n  virtual int readByTypeReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint16_t type, uint8_t responseBuffer[]);\n  virtual void readByTypeResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual void readOrReadBlobReq(uint16_t connectionHandle, uint16_t mtu, uint8_t opcode, uint8_t dlen, uint8_t data[]);\n  virtual void readResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual void readByGroupReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]);\n  virtual int readByGroupReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint16_t uuid, uint8_t responseBuffer[]);\n  virtual void readByGroupResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual void writeReqOrCmd(uint16_t connectionHandle, uint16_t mtu, uint8_t op, uint8_t dlen, uint8_t data[]);\n  virtual void writeResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual void prepWriteReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]);\n  virtual void execWriteReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]);\n  virtual void handleNotifyOrInd(uint16_t connectionHandle, uint8_t opcode, uint8_t dlen, uint8_t data[]);\n  virtual void handleCnf(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n  virtual void sendError(uint16_t connectionHandle, uint8_t opcode, uint16_t handle, uint8_t code);\n\n  virtual bool exchangeMtu(uint16_t connectionHandle);\n  virtual bool discoverServices(uint16_t connectionHandle, BLERemoteDevice* device, const char* serviceUuidFilter);\n  virtual bool discoverCharacteristics(uint16_t connectionHandle, BLERemoteDevice* device);\n  virtual bool discoverDescriptors(uint16_t connectionHandle, BLERemoteDevice* device);\n\n  virtual int sendReq(uint16_t connectionHandle, void* requestBuffer, int requestLength, uint8_t responseBuffer[]);\n\nprivate:\n  uint16_t _maxMtu;\n  unsigned long _timeout;\n  struct {\n    uint16_t connectionHandle;\n    uint8_t role;\n    uint8_t addressType;\n    uint8_t address[6];\n    uint8_t resolvedAddress[6];\n    uint16_t mtu;\n    BLERemoteDevice* device;\n    uint8_t encryption;\n    uint8_t IOCap[3];\n  } _peers[ATT_MAX_PEERS];\n\n  volatile bool _cnf;\n\n  uint16_t _longWriteHandle;\n  uint8_t* _longWriteValue;\n  uint16_t _longWriteValueLength;\n\n  struct {\n    uint16_t connectionHandle;\n    uint8_t op;\n    uint8_t* buffer;\n    uint8_t length;\n  } _pendingResp;\n\n  BLEDeviceEventHandler _eventHandlers[2];\n};\n\nextern ATTClass& ATT;\n\n#endif\n"
  },
  {
    "path": "src/utility/BLELinkedList.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_LINKED_LIST_\n#define _BLE_LINKED_LIST_\n\n#include <stddef.h>\n\ntemplate<class T> struct BLELinkedListNode\n{\n  T data;\n  BLELinkedListNode<T>* next;\n};\n\ntemplate <typename T> class BLELinkedList {\npublic:\n  BLELinkedList();\n  ~BLELinkedList();\n\n  void add(T);\n  T get(unsigned int index) const;\n  void clear();\n  T remove(unsigned int index);\n\n  unsigned int size() const;\n\nprivate:\n  unsigned int _size;\n  BLELinkedListNode<T>* _root;\n  BLELinkedListNode<T>* _last;\n};\n\ntemplate <typename T> BLELinkedList<T>::BLELinkedList() :\n  _size(0),\n  _root(NULL),\n  _last(NULL)\n{\n}\n\ntemplate <typename T> BLELinkedList<T>::~BLELinkedList()\n{\n  clear();\n}\n\ntemplate <typename T> void BLELinkedList<T>::add(T item)\n{\n  BLELinkedListNode<T>* itemNode = new BLELinkedListNode<T>();\n\n  itemNode->data = item;\n  itemNode->next = NULL;\n\n  if (_root == NULL) {\n    _root = itemNode;\n  } else {\n    _last->next = itemNode;\n  }\n  _last = itemNode;\n\n  _size++;\n}\n\ntemplate <typename T> T BLELinkedList<T>::get(unsigned int index) const\n{\n  if (index >= _size) {\n    return T();\n  }\n\n  BLELinkedListNode<T>* itemNode = _root;\n\n  for (unsigned int i = 0; i < index; i++) {\n    itemNode = itemNode->next;\n  }\n\n  return itemNode->data;\n}\n\ntemplate <typename T> void BLELinkedList<T>::clear()\n{\n  BLELinkedListNode<T>* itemNode = _root;\n\n  for (unsigned int i = 0; i < _size; i++) {\n    BLELinkedListNode<T>* n = itemNode;\n\n    itemNode = itemNode->next;\n\n    delete n;\n  }\n\n  _size = 0;\n  _root = NULL;\n  _last = NULL;\n}\n\ntemplate <typename T> unsigned int BLELinkedList<T>::size() const\n{\n  return _size;\n}\n\ntemplate <typename T> T BLELinkedList<T>::remove(unsigned int index)\n{\n  if (index >= _size) {\n    return T();\n  }\n\n  BLELinkedListNode<T>* previousItemNode = NULL;\n  BLELinkedListNode<T>* itemNode = _root;\n\n  for (unsigned int i = 0; i < index; i++) {\n    previousItemNode = itemNode;\n    itemNode = itemNode->next;\n  }\n\n  T result = itemNode->data;\n\n  if (previousItemNode == NULL) {\n    _root = itemNode->next;\n  } else {\n    previousItemNode->next = itemNode->next;\n  }\n\n  if (_last == itemNode) {\n    _last = previousItemNode;\n  }\n\n  delete itemNode;\n  _size--;\n\n  return result;\n}\n\n#endif\n"
  },
  {
    "path": "src/utility/BLEUuid.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"BLEUuid.h\"\n\nBLEUuid::BLEUuid(const char * str) :\n  _str(str)\n{\n  char temp[] = {0, 0, 0};\n\n  memset(_data, 0x00, sizeof(_data));\n\n  _length = 0;\n\n  if (str == NULL) {\n    return;\n  }\n\n  for (int i = strlen(str) - 1; i >= 0 && _length < BLE_UUID_MAX_LENGTH; i -= 2) {\n    if (str[i] == '-') {\n      i++;\n      continue;\n    }\n\n    temp[0] = str[i - 1];\n    temp[1] = str[i];\n\n    _data[_length] = strtoul(temp, NULL, 16);\n\n    _length++;\n  }\n\n  if (_length <= 2) {\n    _length = 2;\n  } else {\n    _length = 16;\n  }\n}\n\nconst char* BLEUuid::str() const\n{\n  return _str;\n}\n\nconst uint8_t* BLEUuid::data() const\n{\n  return _data;\n}\n\nuint8_t BLEUuid::length() const\n{\n  return _length;\n}\n\nconst char* BLEUuid::uuidToString(const uint8_t* data, uint8_t length)\n{\n  static char uuid[36 + 1];\n  char* c = uuid;\n\n  for (int i = length - 1; i >= 0; i--) {\n    uint8_t b = data[i];\n\n    utoa(b >> 4, c++, 16);\n    utoa(b & 0x0f, c++, 16);\n\n    if (i == 6 || i == 8 || i == 10 || i == 12) {\n      *c++ = '-';\n    }\n  }\n\n  *c = '\\0';\n\n  return uuid;\n}\n"
  },
  {
    "path": "src/utility/BLEUuid.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _BLE_UUID_H_\n#define _BLE_UUID_H_\n\n#include <Arduino.h>\n\n#define BLE_UUID_MAX_LENGTH 16\n\nclass BLEUuid\n{\npublic:\n  BLEUuid(const char * str);\n\n  const char* str() const;\n  const uint8_t * data() const;\n  uint8_t length() const;\n\n  static const char* uuidToString(const uint8_t* data, uint8_t length);\n\nprivate:\n  const char* _str;\n  uint8_t     _data[BLE_UUID_MAX_LENGTH];\n  uint8_t     _length;\n};\n\n#endif\n"
  },
  {
    "path": "src/utility/CordioHCICustomDriver.h",
    "content": "#if defined(CORE_CM4)\n\n#include \"CyH4TransportDriver.h\"\n\nble::vendor::cypress_ble::CyH4TransportDriver& ble_cordio_get_h4_transport_driver()\n{\n    static  ble::vendor::cypress_ble::CyH4TransportDriver s_transport_driver(\n        /* TX */ CYBSP_BT_UART_TX, /* RX */ CYBSP_BT_UART_RX,\n        /* cts */ CYBSP_BT_UART_CTS, /* rts */ CYBSP_BT_UART_RTS, NC, DEF_BT_BAUD_RATE,\n        CYBSP_BT_HOST_WAKE, CYBSP_BT_DEVICE_WAKE\n    );\n    return s_transport_driver;\n}\n\n#define CUSTOM_HCI_DRIVER\n\n#endif"
  },
  {
    "path": "src/utility/GAP.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"BLEUuid.h\"\n#include \"HCI.h\"\n\n#include \"GAP.h\"\n\n#define GAP_MAX_DISCOVERED_QUEUE_SIZE 32\n\n#define GAP_ADV_IND (0x00)\n#define GAP_ADV_SCAN_IND (0x02)\n#define GAP_ADV_NONCONN_IND (0x03)\n\nGAPClass::GAPClass() :\n  _advertising(false),\n  _scanning(false),\n  _advertisingInterval(160),\n  _connectable(true),\n  _discoverEventHandler(NULL)\n{\n}\n\nGAPClass::~GAPClass()\n{\n}\n\nbool GAPClass::advertising()\n{\n  return _advertising;\n}\n\nint GAPClass::advertise(uint8_t* advData, uint8_t advDataLen, uint8_t* scanData, uint8_t scanDataLen)\n{\n  uint8_t directBdaddr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n  uint8_t type = (_connectable) ? GAP_ADV_IND : (scanDataLen ? GAP_ADV_SCAN_IND : GAP_ADV_NONCONN_IND);\n\n  stopAdvertise();\n\n  if (HCI.leSetAdvertisingParameters(_advertisingInterval, _advertisingInterval, type, 0x00, 0x00, directBdaddr, 0x07, 0) != 0) {\n    return 0;\n  }\n\n  if (HCI.leSetAdvertisingData(advDataLen, advData) != 0) {\n    return 0;\n  }\n\n  if (HCI.leSetScanResponseData(scanDataLen, scanData) != 0) {\n    return 0;\n  }\n\n  if (HCI.leSetAdvertiseEnable(0x01) != 0) {\n    return 0;\n  }\n\n  _advertising = true;\n\n  return 1;\n}\n\nvoid GAPClass::stopAdvertise()\n{\n  _advertising = false;\n\n  HCI.leSetAdvertiseEnable(0x00);\n}\n\nint GAPClass::scan(bool withDuplicates)\n{\n  HCI.leSetScanEnable(false, true);\n\n  // active scan, 20 ms scan interval (N * 0.625), 20 ms scan window (N * 0.625), public own address type, no filter\n  /*\n    Warning (from BLUETOOTH SPECIFICATION 5.x):\n    - scan interval: mandatory range from 0x0012 to 0x1000; only even values are valid\n    - scan window: mandatory range from 0x0011 to 0x1000\n    - The scan window can only be less than or equal to the scan interval\n  */\n  if (HCI.leSetScanParameters(0x01, 0x0020, 0x0020, 0x00, 0x00) != 0) {\n    return false;\n  }\n\n  _scanning = true;\n\n  if (HCI.leSetScanEnable(true, !withDuplicates) != 0) {\n    return 0;\n  }\n\n  return 1;\n}\n\nint GAPClass::scanForName(String name, bool withDuplicates)\n{\n  _scanNameFilter    = name;\n  _scanUuidFilter    = \"\";\n  _scanAddressFilter = \"\";\n\n  return scan(withDuplicates);\n}\n\nint GAPClass::scanForUuid(String uuid, bool withDuplicates)\n{\n  _scanNameFilter    = \"\";\n  _scanUuidFilter    = uuid;\n  _scanAddressFilter = \"\";\n\n  return scan(withDuplicates);\n}\n\nint GAPClass::scanForAddress(String address, bool withDuplicates)\n{\n  _scanNameFilter    = \"\";\n  _scanUuidFilter    = \"\";\n  _scanAddressFilter = address;\n\n  return scan(withDuplicates);\n}\n\nvoid GAPClass::stopScan()\n{\n  HCI.leSetScanEnable(false, false);\n\n  _scanning = false;\n\n  for (unsigned int i = 0; i < _discoveredDevices.size(); i++) {\n    BLEDevice* device = _discoveredDevices.get(i);\n\n    delete device;\n  }\n\n  _discoveredDevices.clear();\n}\n\nBLEDevice GAPClass::available()\n{\n  for (unsigned int i = 0; i < _discoveredDevices.size(); i++) {\n    BLEDevice* device = _discoveredDevices.get(i);\n\n    if (device->discovered()) {\n      BLEDevice result = *device;\n\n      _discoveredDevices.remove(i);\n      delete device;\n\n      if (matchesScanFilter(result)) {\n        return result;\n      } else {\n        continue;\n      } \n    }\n  }\n\n  return BLEDevice();\n}\n\nvoid GAPClass::setAdvertisingInterval(uint16_t advertisingInterval)\n{\n  _advertisingInterval = advertisingInterval;\n}\n\nvoid GAPClass::setConnectable(bool connectable)\n{\n  _connectable = connectable;\n}\n\nvoid GAPClass::setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler)\n{\n  if (event == BLEDiscovered) {\n    _discoverEventHandler = eventHandler;\n  }\n}\n\nvoid GAPClass::handleLeAdvertisingReport(uint8_t type, uint8_t addressType, uint8_t address[6],\n                                          uint8_t eirLength, uint8_t eirData[], int8_t rssi)\n{\n  if (!_scanning) {\n    return;\n  }\n\n  if (_discoverEventHandler && type == 0x03) {\n    // call event handler and skip adding to discover list\n    BLEDevice device(addressType, address);\n\n    device.setAdvertisementData(type, eirLength, eirData, rssi);\n\n    if (matchesScanFilter(device)) {\n      _discoverEventHandler(device);\n    }\n    return;\n  }\n\n  BLEDevice* discoveredDevice = NULL;\n  int discoveredIndex = -1;\n\n  for (unsigned int i = 0; i < _discoveredDevices.size(); i++) {\n    BLEDevice* device = _discoveredDevices.get(i);\n\n    if (device->hasAddress(addressType, address)) {\n      discoveredDevice = device;\n      discoveredIndex = i;\n\n      break;\n    }\n  }\n\n  if (discoveredDevice == NULL) {\n    if (_discoveredDevices.size() >= GAP_MAX_DISCOVERED_QUEUE_SIZE) {\n      BLEDevice* device_first = _discoveredDevices.remove(0);\n      if (device_first != NULL) {\n        delete device_first;\n      }\n    }\n\n    discoveredDevice = new BLEDevice(addressType, address);\n\n    _discoveredDevices.add(discoveredDevice);\n    discoveredIndex = _discoveredDevices.size() - 1;\n  }\n\n  if (type != 0x04) {\n    discoveredDevice->setAdvertisementData(type, eirLength, eirData, rssi);\n  } else {\n    discoveredDevice->setScanResponseData(eirLength, eirData, rssi);\n  }\n\n  if (discoveredDevice->discovered() && _discoverEventHandler) {\n    // remove from list and report as discovered\n    BLEDevice device = *discoveredDevice;\n\n    _discoveredDevices.remove(discoveredIndex);\n    delete discoveredDevice;\n\n    if (matchesScanFilter(device)) {\n      _discoverEventHandler(device);\n    }\n  }\n}\n\nbool GAPClass::matchesScanFilter(const BLEDevice& device)\n{\n  if (_scanAddressFilter.length() > 0 && !(_scanAddressFilter.equalsIgnoreCase(device.address()))) {\n    return false; // drop doesn't match\n  } else if (_scanNameFilter.length() > 0 && _scanNameFilter != device.localName()) {\n    return false; // drop doesn't match\n  } else if (_scanUuidFilter.length() > 0 && !(_scanUuidFilter.equalsIgnoreCase(device.advertisedServiceUuid()))) {\n    return false; // drop doesn't match\n  }\n\n  return true;\n}\n\n#if !defined(FAKE_GAP)\nGAPClass GAPObj;\nGAPClass& GAP = GAPObj;\n#endif\n"
  },
  {
    "path": "src/utility/GAP.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _GAP_H_\n#define _GAP_H_\n\n#include \"utility/BLELinkedList.h\"\n\n#include \"BLEDevice.h\"\n\nclass GAPClass {\npublic:\n  GAPClass();\n  virtual ~GAPClass();\n\n  virtual bool advertising();\n  virtual int advertise(uint8_t* advData, uint8_t advDataLength, uint8_t* scanData, uint8_t scanDataLength);\n  virtual void stopAdvertise();\n\n  virtual int scan(bool withDuplicates);\n  virtual int scanForName(String name, bool withDuplicates);\n  virtual int scanForUuid(String uuid, bool withDuplicates);\n  virtual int scanForAddress(String address, bool withDuplicates);\n  virtual void stopScan();\n  virtual BLEDevice available();\n\n  virtual void setAdvertisingInterval(uint16_t advertisingInterval);\n  virtual void setConnectable(bool connectable);\n\n  virtual void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler);\n\nprotected:\n  friend class HCIClass;\n\n  virtual void handleLeAdvertisingReport(uint8_t type, uint8_t addressType, uint8_t address[6],\n                                  uint8_t eirLength, uint8_t eirData[], int8_t rssi);\n\nprivate:\n  virtual bool matchesScanFilter(const BLEDevice& device);\n\nprivate:\n  bool _advertising;\n  bool _scanning;\n\n  uint16_t _advertisingInterval;\n  bool _connectable;\n\n  BLEDeviceEventHandler _discoverEventHandler;\n  BLELinkedList<BLEDevice*> _discoveredDevices;\n\n  String _scanNameFilter;\n  String _scanUuidFilter;\n  String _scanAddressFilter;\n};\n\nextern GAPClass& GAP;\n\n#endif\n"
  },
  {
    "path": "src/utility/GATT.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include <Arduino.h>\n\n#include \"local/BLELocalCharacteristic.h\"\n#include \"local/BLELocalDescriptor.h\"\n#include \"local/BLELocalService.h\"\n\n#include \"BLEProperty.h\"\n\n#include \"GATT.h\"\n\nGATTClass::GATTClass() :\n  _genericAccessService(NULL),\n  _deviceNameCharacteristic(NULL),\n  _appearanceCharacteristic(NULL),\n  _genericAttributeService(NULL),\n  _servicesChangedCharacteristic(NULL)\n{\n}\n\nGATTClass::~GATTClass()\n{\n  end();\n}\n\nvoid GATTClass::begin()\n{\n  _genericAccessService = new BLELocalService(\"1800\");\n  _deviceNameCharacteristic = new BLELocalCharacteristic(\"2a00\", BLERead, 20);\n  _appearanceCharacteristic = new BLELocalCharacteristic(\"2a01\", BLERead, 2);\n  _genericAttributeService = new BLELocalService(\"1801\");\n  _servicesChangedCharacteristic = new BLELocalCharacteristic(\"2a05\", BLEIndicate, 4);\n\n  _genericAccessService->retain();\n  _deviceNameCharacteristic->retain();\n  _appearanceCharacteristic->retain();\n  _genericAttributeService->retain();\n  _servicesChangedCharacteristic->retain();\n\n  _genericAccessService->addCharacteristic(_deviceNameCharacteristic);\n  _genericAccessService->addCharacteristic(_appearanceCharacteristic);\n  _genericAttributeService->addCharacteristic(_servicesChangedCharacteristic);\n\n  setDeviceName(\"Arduino\");\n  setAppearance(0x000);\n\n  clearAttributes();\n\n  addService(_genericAccessService);\n  addService(_genericAttributeService);\n}\n\nvoid GATTClass::end()\n{\n  if (_genericAccessService && _genericAccessService->release() == 0) {\n    delete(_genericAccessService);\n    _genericAccessService = NULL;\n  }\n\n  if (_deviceNameCharacteristic && _deviceNameCharacteristic->release() == 0) {\n    delete(_deviceNameCharacteristic);\n    _deviceNameCharacteristic = NULL;\n  }\n\n  if (_appearanceCharacteristic && _appearanceCharacteristic->release() == 0) {\n    delete(_appearanceCharacteristic);\n    _appearanceCharacteristic = NULL;\n  }\n\n  if (_genericAttributeService && _genericAttributeService->release() == 0) {\n    delete(_genericAttributeService);\n    _genericAttributeService = NULL;\n  }\n\n  if (_servicesChangedCharacteristic && _servicesChangedCharacteristic->release() == 0) {\n    delete(_servicesChangedCharacteristic);\n    _servicesChangedCharacteristic = NULL;\n  }\n\n  clearAttributes();\n}\n\nvoid GATTClass::setDeviceName(const char* deviceName)\n{\n  _deviceNameCharacteristic->writeValue(deviceName);\n}\n\nvoid GATTClass::setAppearance(uint16_t appearance)\n{\n  _appearanceCharacteristic->writeValue((uint8_t*)&appearance, sizeof(appearance));\n}\n\nvoid GATTClass::addService(BLEService& service)\n{\n  BLELocalService* localService = service.local();\n\n  if (localService) {\n    addService(localService);\n  }\n}\n\nunsigned int GATTClass::attributeCount() const\n{\n  return _attributes.size();\n}\n\nBLELocalAttribute* GATTClass::attribute(unsigned int index) const\n{\n  return _attributes.get(index);\n}\n\nuint16_t GATTClass::serviceUuidForCharacteristic(BLELocalCharacteristic* characteristic) const\n{\n  uint16_t serviceUuid = 0x0000;\n\n  BLELocalService* lastService = NULL;\n\n  for (unsigned int i = 0; i < attributeCount(); i++) {\n    BLELocalAttribute* a = attribute(i);\n    uint16_t attributeType = a->type();\n\n    if (attributeType == BLETypeService) {\n      lastService = (BLELocalService*)a;\n    } else if (a == characteristic) {\n      break;\n    }\n  }\n\n  if (lastService) {\n    if (lastService->uuidLength() == 2) {\n      serviceUuid = *(uint16_t*)(lastService->uuidData());\n    } else {\n      serviceUuid = *(uint16_t*)(lastService->uuidData() + 10);\n    }\n  }\n\n  return serviceUuid;\n}\n\nvoid GATTClass::addService(BLELocalService* service)\n{\n  service->retain();\n  _attributes.add(service);\n  _services.add(service);\n\n  uint16_t startHandle = attributeCount();\n\n  for (unsigned int i = 0; i < service->characteristicCount(); i++) {\n    BLELocalCharacteristic* characteristic = service->characteristic(i);\n\n    characteristic->retain();\n    _attributes.add(characteristic);\n    characteristic->setHandle(attributeCount());\n    \n    // add the characteristic again to make space of the characteristic value handle\n    characteristic->retain();\n    _attributes.add(characteristic);\n\n    for (unsigned int j = 0; j < characteristic->descriptorCount(); j++) {\n      BLELocalDescriptor* descriptor = characteristic->descriptor(j);\n\n      descriptor->retain();\n      _attributes.add(descriptor);\n      descriptor->setHandle(attributeCount());\n    }\n  }\n\n  service->setHandles(startHandle, attributeCount());\n}\n\nvoid GATTClass::clearAttributes()\n{\n  for (unsigned int i = 0; i < attributeCount(); i++) {\n    BLELocalAttribute* a = attribute(i);\n\n    if (a->release() == 0) {\n      delete a;\n    }\n  }\n  _attributes.clear();\n\n  for (unsigned int i = 0; i < _services.size(); i++) {\n    _services.get(i)->clear();\n  }\n  _services.clear();\n\n}\n\n#if !defined(FAKE_GATT)\nGATTClass GATTObj;\nGATTClass& GATT = GATTObj;\n#endif\n"
  },
  {
    "path": "src/utility/GATT.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _GATT_H_\n#define _GATT_H_\n\n#include \"utility/BLELinkedList.h\"\n\n#include \"local/BLELocalAttribute.h\"\n#include \"local/BLELocalCharacteristic.h\"\n#include \"local/BLELocalService.h\"\n\n#include \"BLEService.h\"\n\nclass GATTClass {\npublic:\n  GATTClass();\n  virtual ~GATTClass();\n\n  virtual void begin();\n  virtual void end();\n\n  virtual void setDeviceName(const char* deviceName);\n  virtual void setAppearance(uint16_t appearance);\n\n  virtual void addService(BLEService& service);\n\nprotected:\n  friend class ATTClass;\n\n  virtual unsigned int attributeCount() const;\n  virtual BLELocalAttribute* attribute(unsigned int index) const;\n\nprotected:\n  friend class BLELocalCharacteristic;\n\n  virtual uint16_t serviceUuidForCharacteristic(BLELocalCharacteristic* characteristic) const;\n\nprivate:\n  virtual void addService(BLELocalService* service);\n\n  virtual void clearAttributes();\n\nprivate:\n  BLELinkedList<BLELocalAttribute*> _attributes;\n  BLELinkedList<BLELocalService*>   _services;\n\n  BLELocalService*              _genericAccessService;\n  BLELocalCharacteristic*       _deviceNameCharacteristic;\n  BLELocalCharacteristic*       _appearanceCharacteristic;\n  BLELocalService*              _genericAttributeService;\n  BLELocalCharacteristic*       _servicesChangedCharacteristic;\n};\n\nextern GATTClass& GATT;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCI.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"ATT.h\"\n#include \"GAP.h\"\n#include \"HCITransport.h\"\n#include \"L2CAPSignaling.h\"\n#include \"btct.h\"\n#include \"HCI.h\"\n#include \"bitDescriptions.h\"\n// #define _BLE_TRACE_\n\n\n#define HCI_COMMAND_PKT   0x01\n#define HCI_ACLDATA_PKT   0x02\n#define HCI_EVENT_PKT     0x04\n#define HCI_SECURITY_PKT  0x06\n\n#define EVT_DISCONN_COMPLETE  0x05\n#define EVT_ENCRYPTION_CHANGE 0x08\n#define EVT_CMD_COMPLETE      0x0e\n#define EVT_CMD_STATUS        0x0f\n#define EVT_NUM_COMP_PKTS     0x13\n#define EVT_RETURN_LINK_KEYS  0x15\n#define EVT_UNKNOWN           0x10\n#define EVT_LE_META_EVENT     0x3e\n\n#define EVT_LE_CONN_COMPLETE      0x01\n#define EVT_LE_ADVERTISING_REPORT 0x02\n\n\n// OGF_LINK_CTL\n#define OCF_DISCONNECT         0x0006\n\n// OGF_HOST_CTL\n#define OCF_SET_EVENT_MASK     0x0001\n#define OCF_RESET              0x0003\n\n// OGF_INFO_PARAM\n#define OCF_READ_LOCAL_VERSION 0x0001\n#define OCF_READ_BD_ADDR       0x0009\n\n// OGF_STATUS_PARAM\n#define OCF_READ_RSSI          0x0005\n\n// OGF_LE_CTL\n#define OCF_LE_READ_BUFFER_SIZE           0x0002\n#define OCF_LE_SET_RANDOM_ADDRESS         0x0005\n#define OCF_LE_SET_ADVERTISING_PARAMETERS 0x0006\n#define OCF_LE_SET_ADVERTISING_DATA       0x0008\n#define OCF_LE_SET_SCAN_RESPONSE_DATA     0x0009\n#define OCF_LE_SET_ADVERTISE_ENABLE       0x000a\n#define OCF_LE_SET_SCAN_PARAMETERS        0x000b\n#define OCF_LE_SET_SCAN_ENABLE            0x000c\n#define OCF_LE_CREATE_CONN                0x000d\n#define OCF_LE_CANCEL_CONN                0x000e\n#define OCF_LE_CONN_UPDATE                0x0013\n\n#define HCI_OE_USER_ENDED_CONNECTION 0x13\n\nString metaEventToString(LE_META_EVENT event)\n{\n  switch(event){\n    case CONN_COMPLETE: return F(\"CONN_COMPLETE\");\n    case ADVERTISING_REPORT: return F(\"ADVERTISING_REPORT\");\n    case LONG_TERM_KEY_REQUEST: return F(\"LE_LONG_TERM_KEY_REQUEST\");\n    case READ_LOCAL_P256_COMPLETE: return F(\"READ_LOCAL_P256_COMPLETE\");\n    case GENERATE_DH_KEY_COMPLETE: return F(\"GENERATE_DH_KEY_COMPLETE\");\n    case ENHANCED_CONN_COMPLETE: return F(\"ENHANCED_CONN_COMPLETE\");\n    default: return \"event unknown\";\n  }\n}\nString commandToString(LE_COMMAND command){\n  switch (command)\n  {\n    case ENCRYPT: return F(\"ENCRYPT\");\n    case LONG_TERM_KEY_REPLY: return F(\"LONG_TERM_KEY_REPLY\");\n    case READ_LOCAL_P256: return F(\"READ_LOCAL_P256\");\n    case GENERATE_DH_KEY_V1: return F(\"GENERATE_DH_KEY_V1\");\n    case GENERATE_DH_KEY_V2: return F(\"GENERATE_DH_KEY_V2\");\n    default: return \"UNKNOWN\";\n  }\n}\n\nHCIClass::HCIClass() :\n  _debug(NULL),\n  _recvIndex(0),\n  _pendingPkt(0),\n  _l2CapPduBufferSize(0)\n{\n}\n\nHCIClass::~HCIClass()\n{\n}\n\nint HCIClass::begin()\n{\n  _recvIndex = 0;\n\n  return HCITransport.begin();\n}\n\nvoid HCIClass::end()\n{\n  HCITransport.end();\n}\n\nvoid HCIClass::poll()\n{\n  poll(0);\n}\n\nvoid HCIClass::poll(unsigned long timeout)\n{\n#ifdef ARDUINO_AVR_UNO_WIFI_REV2\n  digitalWrite(NINA_RTS, LOW);\n#endif\n\n  if (timeout) {\n    HCITransport.wait(timeout);\n  }\n\n  HCITransport.lockForRead();\n  while (HCITransport.available()) {\n    byte b = HCITransport.read();\n\n    if (_recvIndex >= (int)sizeof(_recvBuffer)) {\n        _recvIndex = 0;\n        if (_debug) {\n            HCITransport.unlockForRead();\n            _debug->println(\"_recvBuffer overflow\");\n            HCITransport.lockForRead();\n        }\n    }\n\n    _recvBuffer[_recvIndex++] = b;\n\n    if (_recvBuffer[0] == HCI_ACLDATA_PKT) {\n      if (_recvIndex > 5 && _recvIndex >= (5 + (_recvBuffer[3] + (_recvBuffer[4] << 8)))) {\n        HCITransport.unlockForRead();\n        if (_debug) {\n          dumpPkt(\"HCI ACLDATA RX <- \", _recvIndex, _recvBuffer);\n        }\n#ifdef ARDUINO_AVR_UNO_WIFI_REV2\n        digitalWrite(NINA_RTS, HIGH);\n#endif\n        int pktLen = _recvIndex - 1;\n        _recvIndex = 0;\n\n        handleAclDataPkt(pktLen, &_recvBuffer[1]);\n\n#ifdef ARDUINO_AVR_UNO_WIFI_REV2\n        digitalWrite(NINA_RTS, LOW);\n#endif\n        HCITransport.lockForRead();\n      }\n    } else if (_recvBuffer[0] == HCI_EVENT_PKT) {\n      if (_recvIndex > 3 && _recvIndex >= (3 + _recvBuffer[2])) {\n        HCITransport.unlockForRead();\n        if (_debug) {\n          dumpPkt(\"HCI EVENT RX <- \", _recvIndex, _recvBuffer);\n        }\n#ifdef ARDUINO_AVR_UNO_WIFI_REV2\n        digitalWrite(NINA_RTS, HIGH);\n#endif\n        // received full event\n        int pktLen = _recvIndex - 1;\n        _recvIndex = 0;\n\n        handleEventPkt(pktLen, &_recvBuffer[1]);\n\n#ifdef ARDUINO_AVR_UNO_WIFI_REV2\n        digitalWrite(NINA_RTS, LOW);\n#endif\n        HCITransport.lockForRead();\n      }\n    } else {\n      _recvIndex = 0;\n\n      if (_debug) {\n        HCITransport.unlockForRead();\n        _debug->println(b, HEX);\n        HCITransport.lockForRead();\n      }\n    }\n  }\n\n#ifdef ARDUINO_AVR_UNO_WIFI_REV2\n  digitalWrite(NINA_RTS, HIGH);\n#endif\n  HCITransport.unlockForRead();\n}\n\nint HCIClass::reset()\n{\n  return sendCommand(OGF_HOST_CTL << 10 | OCF_RESET);\n}\n\nint HCIClass::readLocalVersion(uint8_t& hciVer, uint16_t& hciRev, uint8_t& lmpVer, uint16_t& manufacturer, uint16_t& lmpSubVer)\n{\n  int result = sendCommand(OGF_INFO_PARAM << 10 | OCF_READ_LOCAL_VERSION);\n\n  if (result == 0) {\n    struct __attribute__ ((packed)) HCILocalVersion {\n      uint8_t hciVer;\n      uint16_t hciRev;\n      uint8_t lmpVer;\n      uint16_t manufacturer;\n      uint16_t lmpSubVer;\n    } *localVersion = (HCILocalVersion*)_cmdResponse;\n\n    hciVer = localVersion->hciVer;\n    hciRev = localVersion->hciRev;\n    lmpVer = localVersion->lmpVer;\n    manufacturer = localVersion->manufacturer;\n    lmpSubVer = localVersion->lmpSubVer;\n  }\n\n  return result;\n}\n\nint HCIClass::readBdAddr(uint8_t addr[6])\n{\n  int result = sendCommand(OGF_INFO_PARAM << 10 | OCF_READ_BD_ADDR);\n\n  if (result == 0) {\n    memcpy(addr, _cmdResponse, 6);\n  }\n\n  return result;\n}\n\nint HCIClass::readBdAddr(){\n  uint8_t response[6];\n  int result = readBdAddr(response);\n  if(result==0){\n    for(int i=0; i<6; i++){\n      localAddr[5-i] = _cmdResponse[i];\n    }\n  }\n  return result;\n}\n\nint HCIClass::readRssi(uint16_t handle)\n{\n  int result = sendCommand(OGF_STATUS_PARAM << 10 | OCF_READ_RSSI, sizeof(handle), &handle);\n  int rssi = 127;\n\n  if (result == 0) {\n    struct __attribute__ ((packed)) HCIReadRssi {\n      uint16_t handle;\n        int8_t rssi;\n    } *readRssi = (HCIReadRssi*)_cmdResponse;\n\n    if (readRssi->handle == handle) {\n      rssi = readRssi->rssi;\n    }\n  }\n\n  return rssi;\n}\n\nint HCIClass::setEventMask(uint64_t eventMask)\n{\n  return sendCommand(OGF_HOST_CTL << 10 | OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask);\n}\n// Set LE Event mask\nint HCIClass::setLeEventMask(uint64_t leEventMask)\n{\n  return sendCommand(OGF_LE_CTL << 10 | 0x01, sizeof(leEventMask), &leEventMask);\n}\n\nint HCIClass::readLeBufferSize(uint16_t& pktLen, uint8_t& maxPkt)\n{\n  int result = sendCommand(OGF_LE_CTL << 10 | OCF_LE_READ_BUFFER_SIZE);\n\n  if (result == 0) {\n    struct __attribute__ ((packed)) HCILeBufferSize {\n      uint16_t pktLen;\n      uint8_t maxPkt;\n    } *leBufferSize = (HCILeBufferSize*)_cmdResponse;\n\n    pktLen = leBufferSize->pktLen;\n    _maxPkt = maxPkt = leBufferSize->maxPkt;\n\n#ifndef __AVR__\n    ATT.setMaxMtu(pktLen - 9); // max pkt len - ACL header size\n#endif\n  }\n\n  return result;\n}\n\nint HCIClass::leSetRandomAddress(uint8_t addr[6])\n{\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_RANDOM_ADDRESS, 6, addr);\n}\n\nint HCIClass::leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval,\n                                         uint8_t advType, uint8_t ownBdaddrType,\n                                         uint8_t directBdaddrType, uint8_t directBdaddr[6],\n                                         uint8_t chanMap,\n                                         uint8_t filter)\n{\n  struct __attribute__ ((packed)) HCILeAdvertisingParameters {\n    uint16_t minInterval;\n    uint16_t maxInterval;\n    uint8_t advType;\n    uint8_t ownBdaddrType;\n    uint8_t directBdaddrType;\n    uint8_t directBdaddr[6];\n    uint8_t chanMap;\n    uint8_t filter;\n  } leAdvertisingParamters;\n\n  leAdvertisingParamters.minInterval = minInterval;\n  leAdvertisingParamters.maxInterval = maxInterval;\n  leAdvertisingParamters.advType = advType;\n  leAdvertisingParamters.ownBdaddrType = ownBdaddrType;\n  leAdvertisingParamters.directBdaddrType = directBdaddrType;\n  memcpy(leAdvertisingParamters.directBdaddr, directBdaddr, 6);\n  leAdvertisingParamters.chanMap = chanMap;\n  leAdvertisingParamters.filter = filter;\n\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISING_PARAMETERS, sizeof(leAdvertisingParamters), &leAdvertisingParamters);\n}\n\nint HCIClass::leSetAdvertisingData(uint8_t length, uint8_t data[])\n{\n  struct __attribute__ ((packed)) HCILeAdvertisingData {\n    uint8_t length;\n    uint8_t data[31];\n  } leAdvertisingData;\n\n  memset(&leAdvertisingData, 0, sizeof(leAdvertisingData));\n  leAdvertisingData.length = length;\n  memcpy(leAdvertisingData.data, data, length);\n\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISING_DATA, sizeof(leAdvertisingData), &leAdvertisingData);\n}\n\nint HCIClass::leSetScanResponseData(uint8_t length, uint8_t data[])\n{\n  struct __attribute__ ((packed)) HCILeScanResponseData {\n    uint8_t length;\n    uint8_t data[31];\n  } leScanResponseData;\n\n  memset(&leScanResponseData, 0, sizeof(leScanResponseData));\n  leScanResponseData.length = length;\n  memcpy(leScanResponseData.data, data, length);\n\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_RESPONSE_DATA, sizeof(leScanResponseData), &leScanResponseData);\n}\n\nint HCIClass::leSetAdvertiseEnable(uint8_t enable)\n{\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable);\n}\n\nint HCIClass::leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window,\n                          uint8_t ownBdaddrType, uint8_t filter)\n{\n  struct __attribute__ ((packed)) HCILeSetScanParameters {\n    uint8_t type;\n    uint16_t interval;\n    uint16_t window;\n    uint8_t ownBdaddrType;\n    uint8_t filter;\n  } leScanParameters;\n\n  leScanParameters.type = type;\n  leScanParameters.interval = interval;\n  leScanParameters.window = window;\n  leScanParameters.ownBdaddrType = ownBdaddrType;\n  leScanParameters.filter = filter;\n\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_PARAMETERS, sizeof(leScanParameters), &leScanParameters);\n}\n\nint HCIClass::leSetScanEnable(uint8_t enabled, uint8_t duplicates)\n{\n  struct __attribute__ ((packed)) HCILeSetScanEnableData {\n    uint8_t enabled;\n    uint8_t duplicates;\n  } leScanEnableData;\n\n  leScanEnableData.enabled = enabled;\n  leScanEnableData.duplicates = duplicates;\n\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData);\n}\n\nint HCIClass::leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter,\n                            uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint8_t ownBdaddrType,\n                            uint16_t minInterval, uint16_t maxInterval, uint16_t latency,\n                            uint16_t supervisionTimeout, uint16_t minCeLength, uint16_t maxCeLength)\n{\n  struct __attribute__ ((packed)) HCILeCreateConnData {\n    uint16_t interval;\n    uint16_t window;\n    uint8_t initiatorFilter;\n    uint8_t peerBdaddrType;\n    uint8_t peerBdaddr[6];\n    uint8_t ownBdaddrType;\n    uint16_t minInterval;\n    uint16_t maxInterval;\n    uint16_t latency;\n    uint16_t supervisionTimeout;\n    uint16_t minCeLength;\n    uint16_t maxCeLength;\n  } leCreateConnData;\n\n  leCreateConnData.interval = interval;\n  leCreateConnData.window = window;\n  leCreateConnData.initiatorFilter = initiatorFilter;\n  leCreateConnData.peerBdaddrType = peerBdaddrType;\n  memcpy(leCreateConnData.peerBdaddr, peerBdaddr, sizeof(leCreateConnData.peerBdaddr));\n  leCreateConnData.ownBdaddrType = ownBdaddrType;\n  leCreateConnData.minInterval = minInterval;\n  leCreateConnData.maxInterval = maxInterval;\n  leCreateConnData.latency = latency;\n  leCreateConnData.supervisionTimeout = supervisionTimeout;\n  leCreateConnData.minCeLength = minCeLength;\n  leCreateConnData.maxCeLength = maxCeLength;\n\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData);\n}\n\nint HCIClass::leCancelConn()\n{\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CANCEL_CONN, 0, NULL);\n}\n\nint HCIClass::leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval,\n                          uint16_t latency, uint16_t supervisionTimeout)\n{\n  struct __attribute__ ((packed)) HCILeConnUpdateData {\n    uint16_t handle;\n    uint16_t minInterval;\n    uint16_t maxInterval;\n    uint16_t latency;\n    uint16_t supervisionTimeout;\n    uint16_t minCeLength;\n    uint16_t maxCeLength;\n  } leConnUpdateData;\n\n  leConnUpdateData.handle = handle;\n  leConnUpdateData.minInterval = minInterval;\n  leConnUpdateData.maxInterval = maxInterval;\n  leConnUpdateData.latency = latency;\n  leConnUpdateData.supervisionTimeout = supervisionTimeout;\n  leConnUpdateData.minCeLength = 0x0004;\n  leConnUpdateData.maxCeLength = 0x0006;\n\n  return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CONN_UPDATE, sizeof(leConnUpdateData), &leConnUpdateData);\n}\nvoid HCIClass::saveNewAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* localIrk){\n  (void)addressType;\n  (void)localIrk;\n  if(_storeIRK!=0){\n    _storeIRK(address, peerIrk);\n  }\n  // Again... this should work\n  // leAddResolvingAddress(addressType, address, peerIrk, localIrk);\n}\nvoid HCIClass::leAddResolvingAddress(uint8_t addressType, uint8_t* peerAddress, uint8_t* peerIrk, uint8_t* localIrk){\n  leStopResolvingAddresses();\n\n  struct __attribute__ ((packed)) AddDevice {\n    uint8_t peerAddressType;\n    uint8_t peerAddress[6];\n    uint8_t peerIRK[16];\n    uint8_t localIRK[16];\n  } addDevice;\n  addDevice.peerAddressType = addressType;\n  for(int i=0; i<6; i++) addDevice.peerAddress[5-i] = peerAddress[i];\n  for(int i=0; i<16; i++) {\n    addDevice.peerIRK[15-i]  = peerIrk[i];\n    addDevice.localIRK[15-i] = localIrk[i];\n  }\n#ifdef _BLE_TRACE_\n  Serial.print(\"ADDTYPE    :\");\n  btct.printBytes(&addDevice.peerAddressType,1);\n  Serial.print(\"adddddd    :\");\n  btct.printBytes(addDevice.peerAddress,6);\n  Serial.print(\"Peer IRK   :\");\n  btct.printBytes(addDevice.peerIRK,16);\n  Serial.print(\"localIRK   :\");\n  btct.printBytes(addDevice.localIRK,16);\n#endif\n  sendCommand(OGF_LE_CTL << 10 | 0x27, sizeof(addDevice), &addDevice);\n\n  leStartResolvingAddresses();\n}\nint HCIClass::leStopResolvingAddresses(){\n    uint8_t enable = 0;\n    return HCI.sendCommand(OGF_LE_CTL << 10 | 0x2D, 1,&enable); // Disable address resolution\n}\nint HCIClass::leStartResolvingAddresses(){\n  uint8_t enable = 1;\n  return HCI.sendCommand(OGF_LE_CTL << 10 | 0x2D, 1,&enable); // Disable address resolution\n}\nint HCIClass::leReadPeerResolvableAddress(uint8_t peerAddressType, uint8_t* peerIdentityAddress, uint8_t* peerResolvableAddress){\n  (void)peerResolvableAddress;\n  struct __attribute__ ((packed)) Request {\n    uint8_t addressType;\n    uint8_t identityAddress[6];\n  } request;\n  request.addressType = peerAddressType;\n  for(int i=0; i<6; i++) request.identityAddress[5-i] = peerIdentityAddress[i];\n\n\n  int res = sendCommand(OGF_LE_CTL << 10 | 0x2B, sizeof(request), &request);\n#ifdef _BLE_TRACE_\n  Serial.print(\"res: 0x\");\n  Serial.println(res, HEX);\n  if(res==0){\n    struct __attribute__ ((packed)) Response {\n      uint8_t status;\n      uint8_t peerResolvableAddress[6];\n    } *response = (Response*)_cmdResponse;\n    Serial.print(\"Address resolution status: 0x\");\n    Serial.println(response->status, HEX);\n    Serial.print(\"peer resolvable address: \");\n    btct.printBytes(response->peerResolvableAddress,6);\n  }\n  #endif\n  return res;\n}\n\nvoid HCIClass::writeLK(uint8_t peerAddress[], uint8_t LK[]){\n  struct __attribute__ ((packed)) StoreLK {\n    uint8_t nKeys;\n    uint8_t BD_ADDR[6];\n    uint8_t LTK[16];\n  } storeLK;\n  storeLK.nKeys = 1;\n  memcpy(storeLK.BD_ADDR, peerAddress, 6);\n  for(int i=0; i<16; i++) storeLK.LTK[15-i] = LK[i];\n  HCI.sendCommand(OGF_HOST_CTL << 10 | 0x11, sizeof(storeLK), &storeLK);\n}\nvoid HCIClass::readStoredLKs(){\n  uint8_t BD_ADDR[6];\n  readStoredLK(BD_ADDR, 1);\n}\nint HCIClass::readStoredLK(uint8_t BD_ADDR[], uint8_t read_all ){\n  struct __attribute__ ((packed)) Request {\n    uint8_t BD_ADDR[6];\n    uint8_t read_a;\n  } request = {{0},0};\n  for(int i=0; i<6; i++) request.BD_ADDR[5-i] = BD_ADDR[i];\n  request.read_a = read_all;\n  return sendCommand(OGF_HOST_CTL << 10 | 0xD, sizeof(request), &request);\n}\n\nint HCIClass::tryResolveAddress(uint8_t* BDAddr, uint8_t* address){\n  bool foundMatch = false;\n  if(HCI._getIRKs!=0){\n    uint8_t nIRKs = 0;\n    uint8_t** BDAddrType = new uint8_t*;\n    uint8_t*** BADDRs = new uint8_t**;\n    uint8_t*** IRKs = new uint8_t**;\n\n\n    if(!HCI._getIRKs(&nIRKs, BDAddrType, BADDRs, IRKs)){\n#ifdef _BLE_TRACE_\n      Serial.println(\"error getting IRKs.\");\n#endif\n    }\n    for(int i=0; i<nIRKs; i++){\n      if(!foundMatch){\n#ifdef _BLE_TRACE_\n        Serial.print(\"BDAddr type:      : 0x\");\n        Serial.println((*BDAddrType)[i],HEX);\n        Serial.print(\"BDAddr            : \");\n        btct.printBytes((*BADDRs)[i],6);\n        Serial.print(\"IRK               : \");\n        btct.printBytes((*IRKs)[i],16);\n#endif\n        uint8_t hashresult[3];\n        btct.ah((*IRKs)[i], BDAddr, hashresult);\n#ifdef _BLE_TRACE_\n        Serial.print(\"hash match        : \");\n        btct.printBytes(hashresult,3);\n        Serial.print(\"                  : \");\n        btct.printBytes(&BDAddr[3],3);\n#endif\n\n        for(int k=0; k<3; k++){\n          if(hashresult[k] == BDAddr[3 + k]){\n            foundMatch = true;\n          }else{\n            foundMatch = false;\n            break;\n          }\n        }\n        if(foundMatch){\n          memcpy(address, (*BADDRs)[i],6);\n        }\n      }\n      delete[] (*BADDRs)[i];\n      delete[] (*IRKs)[i];\n    }\n    delete[] (*BDAddrType);\n    delete BDAddrType;\n    delete[] (*BADDRs);\n    delete BADDRs;\n    delete[] (*IRKs);\n    delete IRKs;\n\n    if(foundMatch){\n      return 1;\n    }\n  }\n  return 0;\n}\n\nint HCIClass::sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data)\n{\n  while (_pendingPkt >= _maxPkt) {\n    poll();\n  }\n\n  struct __attribute__ ((packed)) HCIACLHdr {\n    uint8_t pktType;\n    uint16_t handle;\n    uint16_t dlen;\n    uint16_t plen;\n    uint16_t cid;\n  } aclHdr = { HCI_ACLDATA_PKT, handle, uint8_t(plen + 4), plen, cid };\n\n  uint8_t txBuffer[sizeof(aclHdr) + plen];\n  memcpy(txBuffer, &aclHdr, sizeof(aclHdr));\n  memcpy(&txBuffer[sizeof(aclHdr)], data, plen);\n\n  if (_debug) {\n    dumpPkt(\"HCI ACLDATA TX -> \", sizeof(aclHdr) + plen, txBuffer);\n  }\n#ifdef _BLE_TRACE_\n  Serial.print(\"Data tx -> \");\n  for(int i=0; i< sizeof(aclHdr) + plen;i++){\n    Serial.print(\" 0x\");\n    Serial.print(txBuffer[i],HEX);\n  }\n  Serial.println(\".\");\n#endif\n\n  _pendingPkt++;\n  HCITransport.write(txBuffer, sizeof(aclHdr) + plen);\n\n  return 0;\n}\n\nint HCIClass::disconnect(uint16_t handle)\n{\n    struct __attribute__ ((packed)) HCIDisconnectData {\n    uint16_t handle;\n    uint8_t reason;\n  } disconnectData = { handle, HCI_OE_USER_ENDED_CONNECTION };\n\n  return sendCommand(OGF_LINK_CTL << 10 | OCF_DISCONNECT, sizeof(disconnectData), &disconnectData);\n}\n\nvoid HCIClass::debug(Stream& stream)\n{\n  _debug = &stream;\n}\n\nvoid HCIClass::noDebug()\n{\n  _debug = NULL;\n}\n\nint HCIClass::sendCommand(uint16_t opcode, uint8_t plen, void* parameters)\n{\n  struct __attribute__ ((packed)) {\n    uint8_t pktType;\n    uint16_t opcode;\n    uint8_t plen;\n  } pktHdr = {HCI_COMMAND_PKT, opcode, plen};\n\n  uint8_t txBuffer[sizeof(pktHdr) + plen];\n  memcpy(txBuffer, &pktHdr, sizeof(pktHdr));\n  memcpy(&txBuffer[sizeof(pktHdr)], parameters, plen);\n\n  if (_debug) {\n    dumpPkt(\"HCI COMMAND TX -> \", sizeof(pktHdr) + plen, txBuffer);\n  }\n#ifdef _BLE_TRACE_\n  Serial.print(\"Command tx -> \");\n  for(int i=0; i< sizeof(pktHdr) + plen;i++){\n    Serial.print(\" 0x\");\n    Serial.print(txBuffer[i],HEX);\n  }\n  Serial.println(\"\");\n#endif\n  HCITransport.write(txBuffer, sizeof(pktHdr) + plen);\n\n  _cmdCompleteOpcode = 0xffff;\n  _cmdCompleteStatus = -1;\n\n  for (unsigned long start = millis(); _cmdCompleteOpcode != opcode && millis() < (start + 1000);) {\n    poll();\n  }\n\n  return _cmdCompleteStatus;\n}\n\nvoid HCIClass::handleAclDataPkt(uint8_t /*plen*/, uint8_t pdata[])\n{\n  struct __attribute__ ((packed)) HCIACLHdr {\n    uint16_t connectionHandleWithFlags;\n    uint16_t dlen; // dlen + 4 = plen (dlen is the size of the ACL SDU)\n  } *aclHeader = (HCIACLHdr*)pdata;\n\n  uint8_t pbFlag = (aclHeader->connectionHandleWithFlags & 0x3000) >> 12;\n  uint16_t connectionHandle = aclHeader->connectionHandleWithFlags & 0x0fff;\n\n  uint8_t *aclSdu = &pdata[sizeof(HCIACLHdr)];\n\n#ifdef _BLE_TRACE_\n  uint8_t bcFlag = (aclHeader->connectionHandleWithFlags & 0xc000) >> 14;\n  Serial.print(\"Acl packet bcFlag = \");\n  Serial.print(bcFlag, BIN);\n  Serial.print(\" pbFlag = \");\n  Serial.print(pbFlag, BIN);\n  Serial.print(\" connectionHandle = \");\n  Serial.print(connectionHandle, HEX);\n  Serial.print(\" dlen = \");\n  Serial.println(aclHeader->dlen, DEC);\n#endif\n\n  // Pointer to the L2CAP PDU (might be reconstructed from multiple fragments)\n  uint8_t *l2CapPdu;\n  uint8_t l2CapPduSize;\n\n  if (pbFlag == 0b10) {\n    // \"First automatically flushable packet\" = Start of our L2CAP PDU\n\n    l2CapPdu = aclSdu;\n    l2CapPduSize = aclHeader->dlen;\n  } else if (pbFlag == 0b01) {\n    // \"Continuing Fragment\" = Continued L2CAP PDU\n#ifdef _BLE_TRACE_\n    Serial.print(\"Continued packet. Appending to L2CAP PDU buffer (previously \");\n    Serial.print(_l2CapPduBufferSize, DEC);\n    Serial.println(\" bytes in buffer)\");\n#endif\n    // If we receive a fragment, we always need to append it to the L2CAP PDU buffer\n    memcpy(&_l2CapPduBuffer[_l2CapPduBufferSize], aclSdu, aclHeader->dlen);\n    _l2CapPduBufferSize += aclHeader->dlen;\n\n    l2CapPdu = _l2CapPduBuffer;\n    l2CapPduSize = _l2CapPduBufferSize;\n  } else {\n    // I don't think other values are allowed for BLE\n#ifdef _BLE_TRACE_\n    Serial.println(\"Invalid pbFlag, discarding packet\");\n#endif\n    return;\n  }\n\n  // We now have a valid L2CAP header in l2CapPdu and can parse the headers\n  struct __attribute__ ((packed)) HCIL2CapHdr {\n    uint16_t len; // size of the L2CAP SDU\n    uint16_t cid;\n  } *l2CapHeader = (HCIL2CapHdr*)l2CapPdu;\n\n#ifdef _BLE_TRACE_\n  Serial.print(\"Received \");\n  Serial.print(l2CapPduSize - 4, DEC);\n  Serial.print(\"B/\");\n  Serial.print(l2CapHeader->len, DEC);\n  Serial.print(\"B of the L2CAP SDU. CID = \");\n  Serial.println(l2CapHeader->cid, HEX);\n#endif\n\n  // -4 because the buffer is the L2CAP PDU (with L2CAP header). The len field is only the L2CAP SDU (without L2CAP header).\n  if (l2CapPduSize - 4 != l2CapHeader->len) {\n#ifdef _BLE_TRACE_\n    Serial.println(\"L2CAP SDU incomplete\");\n#endif\n\n    // If this is a first packet, we have not copied it into the buffer yet\n    if (pbFlag == 0b10) {\n#ifdef _BLE_TRACE_\n      Serial.println(\"Storing first packet to L2CAP PDU buffer\");\n      if (_l2CapPduBufferSize != 0) {\n        Serial.print(\"Warning: Discarding \");\n        Serial.print(_l2CapPduBufferSize, DEC);\n        Serial.println(\" bytes from buffer\");\n      }\n#endif\n\n      memcpy(_l2CapPduBuffer, l2CapPdu, l2CapPduSize);\n      _l2CapPduBufferSize = l2CapPduSize;\n    }\n\n    // We need to wait for the missing parts of the L2CAP SDU\n    return;\n  }\n\n#ifdef _BLE_TRACE_\n    Serial.println(\"L2CAP SDU complete\");\n#endif\n\n  if (l2CapHeader->cid == ATT_CID) {\n#ifdef _BLE_TRACE_\n    Serial.println(\"CID: ATT\");\n#endif\n    ATT.handleData(connectionHandle, l2CapHeader->len, &l2CapPdu[sizeof(HCIL2CapHdr)]);\n  } else if (l2CapHeader->cid == SIGNALING_CID) {\n#ifdef _BLE_TRACE_\n    Serial.println(\"CID: SIGNALING\");\n#endif\n    L2CAPSignaling.handleData(connectionHandle, l2CapHeader->len, &l2CapPdu[sizeof(HCIL2CapHdr)]);\n  } else if (l2CapHeader->cid == SECURITY_CID) {\n    // Security manager\n#ifdef _BLE_TRACE_\n    Serial.println(\"CID: SECURITY\");\n#endif\n    L2CAPSignaling.handleSecurityData(connectionHandle, l2CapHeader->len, &l2CapPdu[sizeof(HCIL2CapHdr)]);\n  } else {\n    struct __attribute__ ((packed)) {\n      uint8_t op;\n      uint8_t id;\n      uint16_t length;\n      uint16_t reason;\n      uint16_t localCid;\n      uint16_t remoteCid;\n    } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, l2CapHeader->cid, 0x0000 };\n#ifdef _BLE_TRACE_\n    Serial.println(\"Rejecting packet cid\");\n#endif\n\n    sendAclPkt(connectionHandle, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid);\n  }\n\n  // We have processed everything in the buffer. Discard the contents.\n  _l2CapPduBufferSize = 0;\n}\n\nvoid HCIClass::handleNumCompPkts(uint16_t /*handle*/, uint16_t numPkts)\n{\n  if (numPkts && _pendingPkt > numPkts) {\n    _pendingPkt -= numPkts;\n  } else {\n    _pendingPkt = 0;\n  }\n}\n\nvoid HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[])\n{\n  struct __attribute__ ((packed)) HCIEventHdr {\n    uint8_t evt;\n    uint8_t plen;\n  } *eventHdr = (HCIEventHdr*)pdata;\n#ifdef _BLE_TRACE_\n  Serial.print(\"HCI event: \");\n  Serial.println(eventHdr->evt, HEX);\n#endif\n\n  if (eventHdr->evt == EVT_DISCONN_COMPLETE)\n  {\n    struct __attribute__ ((packed)) DisconnComplete {\n      uint8_t status;\n      uint16_t handle;\n      uint8_t reason;\n    } *disconnComplete = (DisconnComplete*)&pdata[sizeof(HCIEventHdr)];\n\n    ATT.removeConnection(disconnComplete->handle, disconnComplete->reason);\n    L2CAPSignaling.removeConnection(disconnComplete->handle, disconnComplete->reason);\n\n    if (GAP.advertising())\n    {\n      HCI.leSetAdvertiseEnable(0x01);\n    }\n  }\n  else if (eventHdr->evt == EVT_ENCRYPTION_CHANGE)\n  {\n    struct __attribute__ ((packed)) EncryptionChange {\n      uint8_t status;\n      uint16_t connectionHandle;\n      uint8_t enabled;\n    } *encryptionChange = (EncryptionChange*)&pdata[sizeof(HCIEventHdr)];\n#ifdef _BLE_TRACE_\n    Serial.println(\"[Info] Encryption changed\");\n    Serial.print(\"status : \");\n    btct.printBytes(&encryptionChange->status,1);\n    Serial.print(\"handle : \");\n    btct.printBytes((uint8_t*)&encryptionChange->connectionHandle,2);\n    Serial.print(\"enabled: \");\n    btct.printBytes(&encryptionChange->enabled,1);\n#endif\n    if(encryptionChange->enabled>0){\n      // 0001 1110\n      if((ATT.getPeerEncryption(encryptionChange->connectionHandle)&PEER_ENCRYPTION::PAIRING_REQUEST)>0){\n        if(ATT.localKeyDistribution.EncKey()){\n#ifdef _BLE_TRACE_\n          Serial.println(\"Enc key set but should be ignored\");\n#endif\n        }else{\n#ifdef _BLE_TRACE_\n          Serial.println(\"No enc key distribution\");\n#endif\n        }\n        // From page 1681 bluetooth standard - order matters\n        if(ATT.localKeyDistribution.IdKey()){\n          /// We shall distribute IRK and address using identity information\n          {\n            uint8_t response[17];\n            response[0] = CONNECTION_IDENTITY_INFORMATION; // Identity information.\n            for(int i=0; i<16; i++) response[16-i] = ATT.localIRK[i];\n            HCI.sendAclPkt(encryptionChange->connectionHandle, SECURITY_CID, sizeof(response), response);\n#ifdef _BLE_TRACE_\n            Serial.println(\"Distribute ID Key\");\n#endif\n          }\n          {\n            uint8_t response[8];\n            response[0] = CONNECTION_IDENTITY_ADDRESS; // Identity address information\n            response[1] = 0x00; // Static local address\n            for(int i=0; i<6; i++) response[7-i] = HCI.localAddr[i];\n            HCI.sendAclPkt(encryptionChange->connectionHandle, SECURITY_CID, sizeof(response), response);\n          }\n        }\n        if(ATT.localKeyDistribution.SignKey()){\n          /// We shall distribut CSRK\n#ifdef _BLE_TRACE_\n          Serial.println(\"We shall distribute CSRK // not implemented\");\n#endif\n\n        }else{\n          // Serial.println(\"We don't want to distribute CSRK\");\n        }\n        if(ATT.localKeyDistribution.LinkKey()){\n#ifdef _BLE_TRACE_\n          Serial.println(\"We would like to use LTK to generate BR/EDR // not implemented\");\n#endif\n        }\n      }else{\n#ifdef _BLE_TRACE_\n        Serial.println(\"Reconnection, not pairing so no keys\");\n        Serial.println(ATT.getPeerEncryption(encryptionChange->connectionHandle),HEX);\n#endif\n      }\n\n      ATT.setPeerEncryption(encryptionChange->connectionHandle, PEER_ENCRYPTION::ENCRYPTED_AES);\n      if(ATT.writeBufferSize > 0){\n        ATT.processWriteBuffer();\n      }\n      if(ATT.holdBufferSize>0){\n#ifdef _BLE_TRACE_\n        Serial.print(\"Sending queued response size: \");\n        Serial.println(ATT.holdBufferSize);\n#endif\n        HCI.sendAclPkt(encryptionChange->connectionHandle, ATT_CID, ATT.holdBufferSize, ATT.holdBuffer);\n        ATT.holdBufferSize = 0;\n      }\n    }else{\n      ATT.setPeerEncryption(encryptionChange->connectionHandle, PEER_ENCRYPTION::NO_ENCRYPTION);\n    }\n  }\n  else if (eventHdr->evt == EVT_CMD_COMPLETE)\n  {\n    struct __attribute__ ((packed)) CmdComplete {\n      uint8_t ncmd;\n      uint16_t opcode;\n      uint8_t status;\n    } *cmdCompleteHeader = (CmdComplete*)&pdata[sizeof(HCIEventHdr)];\n#ifdef _BLE_TRACE_\n    Serial.print(\"E ncmd:   0x\");\n    Serial.println(cmdCompleteHeader->ncmd,HEX);\n    Serial.print(\"E opcode: 0x\");\n    Serial.println(cmdCompleteHeader->opcode, HEX);\n    Serial.print(\"E status: 0x\");\n    Serial.println(cmdCompleteHeader->status, HEX);\n#endif\n    _cmdCompleteOpcode = cmdCompleteHeader->opcode;\n    _cmdCompleteStatus = cmdCompleteHeader->status;\n    _cmdResponseLen = pdata[1] - sizeof(CmdComplete);\n    _cmdResponse = &pdata[sizeof(HCIEventHdr) + sizeof(CmdComplete)];\n\n  }\n  else if (eventHdr->evt == EVT_CMD_STATUS)\n  {\n    struct __attribute__ ((packed)) CmdStatus {\n      uint8_t status;\n      uint8_t ncmd;\n      uint16_t opcode;\n    } *cmdStatusHeader = (CmdStatus*)&pdata[sizeof(HCIEventHdr)];\n\n#ifdef _BLE_TRACE_\n    Serial.print(\"F n cmd:  0x\");\n    Serial.println(cmdStatusHeader->ncmd, HEX);\n    Serial.print(\"F status: 0x\");\n    Serial.println(cmdStatusHeader->status, HEX);\n    Serial.print(\"F opcode: 0x\");\n    Serial.println(cmdStatusHeader->opcode, HEX);\n#endif\n    _cmdCompleteOpcode = cmdStatusHeader->opcode;\n    _cmdCompleteStatus = cmdStatusHeader->status;\n    _cmdResponseLen = 0;\n  }\n  else if (eventHdr->evt == EVT_NUM_COMP_PKTS)\n  {\n    uint8_t numHandles = pdata[sizeof(HCIEventHdr)];\n    uint16_t* data = (uint16_t*)&pdata[sizeof(HCIEventHdr) + sizeof(numHandles)];\n\n    for (uint8_t i = 0; i < numHandles; i++) {\n      handleNumCompPkts(data[0], data[1]);\n#ifdef _BLE_TRACE_\n      Serial.print(\"Outstanding packets: \");\n      Serial.println(_pendingPkt);\n      Serial.print(\"Data[0]: 0x\");\n      Serial.println(data[0]);\n      Serial.print(\"Data[1]: 0x\");\n      Serial.println(data[1]);\n#endif\n      data += 2;\n    }\n  }\n  else if(eventHdr->evt == 0x10)\n  {\n#ifdef _BLE_TRACE_\n    struct __attribute__ ((packed)) CmdHardwareError {\n      uint8_t hardwareCode;\n    } *cmdHardwareError = (CmdHardwareError*)&pdata[sizeof(HCIEventHdr)];\n    Serial.print(\"Bluetooth hardware error.\");\n    Serial.print(\" Code: 0x\");\n    Serial.println(cmdHardwareError->hardwareCode, HEX);\n#endif\n  }\n  else if (eventHdr->evt == EVT_LE_META_EVENT)\n  {\n    struct __attribute__ ((packed)) LeMetaEventHeader {\n      uint8_t subevent;\n    } *leMetaHeader = (LeMetaEventHeader*)&pdata[sizeof(HCIEventHdr)];\n#ifdef _BLE_TRACE_\n    Serial.print(\"\\tSubEvent: 0x\");\n    Serial.println(leMetaHeader->subevent,HEX);\n#endif\n    switch((LE_META_EVENT)leMetaHeader->subevent){\n      case ENHANCED_CONN_COMPLETE:{\n        struct __attribute__ ((packed)) EvtLeConnectionComplete {\n          uint8_t status;\n          uint16_t handle;\n          uint8_t role;\n          uint8_t peerBdaddrType;\n          uint8_t peerBdaddr[6];\n          uint8_t localResolvablePrivateAddress[6];\n          uint8_t peerResolvablePrivateAddress[6];\n          uint16_t interval;\n          uint16_t latency;\n          uint16_t supervisionTimeout;\n          uint8_t masterClockAccuracy;\n        } *leConnectionComplete = (EvtLeConnectionComplete*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)];\n\n        if (leConnectionComplete->status == 0x00) {\n          ATT.addConnection(leConnectionComplete->handle,\n                            leConnectionComplete->role,\n                            leConnectionComplete->peerBdaddrType,\n                            leConnectionComplete->peerBdaddr,\n                            leConnectionComplete->interval,\n                            leConnectionComplete->latency,\n                            leConnectionComplete->supervisionTimeout,\n                            leConnectionComplete->masterClockAccuracy);\n\n          L2CAPSignaling.addConnection(leConnectionComplete->handle,\n                                leConnectionComplete->role,\n                                leConnectionComplete->peerBdaddrType,\n                                leConnectionComplete->peerBdaddr,\n                                leConnectionComplete->interval,\n                                leConnectionComplete->latency,\n                                leConnectionComplete->supervisionTimeout,\n                                leConnectionComplete->masterClockAccuracy);\n        }\n        // uint8_t address[6];\n        // uint8_t BDAddr[6];\n        // for(int i=0; i<6; i++) BDAddr[5-i] = leConnectionComplete->peerBdaddr[i];\n        // leReadPeerResolvableAddress(leConnectionComplete->peerBdaddrType,BDAddr,address);\n        // Serial.print(\"Resolving address: \");\n        // btct.printBytes(BDAddr, 6);\n        // Serial.print(\"BT answer         : \");\n        // btct.printBytes(address, 6);\n\n#ifdef _BLE_TRACE_\n        Serial.print(\"Resolved peer     : \");\n        btct.printBytes(leConnectionComplete->peerResolvablePrivateAddress,6);\n        Serial.print(\"Resolved local    : \");\n        btct.printBytes(leConnectionComplete->localResolvablePrivateAddress,6);\n#endif\n        break;\n      }\n      case CONN_COMPLETE:{\n        struct __attribute__ ((packed)) EvtLeConnectionComplete {\n          uint8_t status;\n          uint16_t handle;\n          uint8_t role;\n          uint8_t peerBdaddrType;\n          uint8_t peerBdaddr[6];\n          uint16_t interval;\n          uint16_t latency;\n          uint16_t supervisionTimeout;\n          uint8_t masterClockAccuracy;\n        } *leConnectionComplete = (EvtLeConnectionComplete*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)];\n\n        if (leConnectionComplete->status == 0x00) {\n          ATT.addConnection(leConnectionComplete->handle,\n                            leConnectionComplete->role,\n                            leConnectionComplete->peerBdaddrType,\n                            leConnectionComplete->peerBdaddr,\n                            leConnectionComplete->interval,\n                            leConnectionComplete->latency,\n                            leConnectionComplete->supervisionTimeout,\n                            leConnectionComplete->masterClockAccuracy);\n\n          L2CAPSignaling.addConnection(leConnectionComplete->handle,\n                                leConnectionComplete->role,\n                                leConnectionComplete->peerBdaddrType,\n                                leConnectionComplete->peerBdaddr,\n                                leConnectionComplete->interval,\n                                leConnectionComplete->latency,\n                                leConnectionComplete->supervisionTimeout,\n                                leConnectionComplete->masterClockAccuracy);\n        }\n        // leReadPeerResolvableAddress(leConnectionComplete->peerBdaddrType,BDAddr,address);\n        // Serial.print(\"Resolving address: \");\n        // btct.printBytes(BDAddr, 6);\n        // Serial.print(\"BT answer         : \");\n        // btct.printBytes(address, 6);\n        break;\n      }\n      case ADVERTISING_REPORT:{\n        struct __attribute__ ((packed)) EvtLeAdvertisingReport {\n          uint8_t status;\n          uint8_t type;\n          uint8_t peerBdaddrType;\n          uint8_t peerBdaddr[6];\n          uint8_t eirLength;\n          uint8_t eirData[31];\n        } *leAdvertisingReport = (EvtLeAdvertisingReport*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)];\n\n        if(leAdvertisingReport->eirLength > sizeof(leAdvertisingReport->eirData)){\n          return ;\n        }\n\n        if (leAdvertisingReport->status == 0x01) {\n          // last byte is RSSI\n          int8_t rssi = leAdvertisingReport->eirData[leAdvertisingReport->eirLength];\n\n          GAP.handleLeAdvertisingReport(leAdvertisingReport->type,\n                                        leAdvertisingReport->peerBdaddrType,\n                                        leAdvertisingReport->peerBdaddr,\n                                        leAdvertisingReport->eirLength,\n                                        leAdvertisingReport->eirData,\n                                        rssi);\n        }\n        break;\n      }\n      case LONG_TERM_KEY_REQUEST:{\n        struct __attribute__ ((packed)) LTKRequest\n        {\n          uint8_t subEventCode;\n          uint16_t connectionHandle;\n          uint8_t randomNumber[8];\n          uint8_t encryptedDiversifier[2];\n        } *ltkRequest = (LTKRequest*)&pdata[sizeof(HCIEventHdr)];\n#ifdef _BLE_TRACE_\n        Serial.println(\"LTK request received\");\n        Serial.print(\"Connection Handle: \");\n        btct.printBytes((uint8_t*)&ltkRequest->connectionHandle,2);\n        Serial.print(\"Random Number    : \");\n        btct.printBytes(ltkRequest->randomNumber,8);\n        Serial.print(\"EDIV           : \");\n        btct.printBytes(ltkRequest->encryptedDiversifier,2);\n#endif\n        // Load our LTK for this connection.\n        uint8_t peerAddr[7];\n        uint8_t resolvableAddr[6];\n        uint8_t foundLTK;\n        ATT.getPeerAddrWithType(ltkRequest->connectionHandle, peerAddr);\n\n        if((ATT.getPeerEncryption(ltkRequest->connectionHandle) & PEER_ENCRYPTION::PAIRING_REQUEST)>0){\n          // Pairing request - LTK is one in buffer already\n          foundLTK = 1;\n        }else{\n          if(ATT.getPeerResolvedAddress(ltkRequest->connectionHandle, resolvableAddr)){\n            foundLTK = getLTK(resolvableAddr, HCI.LTK);\n          }else{\n            foundLTK = getLTK(&peerAddr[1], HCI.LTK);\n          }\n        }\n        // } //2d\n        // Send our LTK back\n        if(foundLTK){\n          struct __attribute__ ((packed)) LTKReply\n          {\n            uint16_t connectionHandle;\n            uint8_t LTK[16];\n          } ltkReply = {0,0};\n          ltkReply.connectionHandle = ltkRequest->connectionHandle;\n          for(int i=0; i<16; i++) ltkReply.LTK[15-i] = HCI.LTK[i];\n          int result = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::LONG_TERM_KEY_REPLY,sizeof(ltkReply), &ltkReply);\n\n  #ifdef _BLE_TRACE_\n          Serial.println(\"Sending LTK as: \");\n          btct.printBytes(ltkReply.LTK,16);\n  #endif\n\n          if(result == 0){\n            struct __attribute__ ((packed)) LTKReplyResult\n            {\n              uint8_t status;\n              uint16_t connectionHandle;\n            } ltkReplyResult = {0,0};\n            memcpy(&ltkReplyResult, _cmdResponse, 3);\n\n  #ifdef _BLE_TRACE_\n            Serial.println(\"LTK send success\");\n            Serial.print(\"status     : \");\n            btct.printBytes(&ltkReplyResult.status,1);\n            Serial.print(\"Conn Handle: \");\n            btct.printBytes((uint8_t*)&ltkReplyResult.connectionHandle,2);\n  #endif\n          }else{\n  #ifdef _BLE_TRACE_\n            Serial.print(\"Failed to send LTK...: \");\n            btct.printBytes((uint8_t*)&result,2);\n  #endif\n          }\n        }else{\n          /// do LTK rejection\n#ifdef _BLE_TRACE_\n          Serial.println(\"LTK not found, rejecting\");\n#endif\n          sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::LONG_TERM_KEY_NEGATIVE_REPLY,2, &ltkRequest->connectionHandle);\n        }\n        break;\n      }\n      case REMOTE_CONN_PARAM_REQ:{\n        struct __attribute__ ((packed)) RemoteConnParamReq {\n          uint8_t subEventCode;\n          uint16_t connectionHandle;\n          uint16_t intervalMin;\n          uint16_t intervalMax;\n          uint16_t latency;\n          uint16_t timeOut;\n        } *remoteConnParamReq = (RemoteConnParamReq*)&pdata[sizeof(HCIEventHdr)];\n#ifdef _BLE_TRACE_\n        Serial.println(\"--- Remtoe conn param req\");\n        Serial.print(\"Handle      : \");\n        btct.printBytes((uint8_t*)&remoteConnParamReq->connectionHandle,2);\n        Serial.print(\"Interval min: \");\n        btct.printBytes((uint8_t*)&remoteConnParamReq->intervalMin,2);\n        Serial.print(\"Interval max: \");\n        btct.printBytes((uint8_t*)&remoteConnParamReq->intervalMax,2);\n        Serial.print(\"Latency     : \");\n        btct.printBytes((uint8_t*)&remoteConnParamReq->latency,2);\n        Serial.print(\"Timeout     : \");\n        btct.printBytes((uint8_t*)&remoteConnParamReq->timeOut,2);\n#endif\n\n        struct __attribute__ ((packed)) RemoteConnParamReqReply {\n          uint16_t connectionHandle;\n          uint16_t intervalMin;\n          uint16_t intervalMax;\n          uint16_t latency;\n          uint16_t timeOut;\n          uint16_t minLength;\n          uint16_t maxLength;\n        } remoteConnParamReqReply;\n        memcpy(&remoteConnParamReqReply, &remoteConnParamReq->connectionHandle, sizeof(RemoteConnParamReq)-1);\n\n        remoteConnParamReqReply.minLength = 0x000F;\n        remoteConnParamReqReply.maxLength = 0x0FFF;\n        sendCommand(OGF_LE_CTL << 10 | 0x20, sizeof(RemoteConnParamReqReply), &remoteConnParamReqReply);\n        break;\n      }\n      case READ_LOCAL_P256_COMPLETE:{\n        struct __attribute__ ((packed)) EvtReadLocalP256Complete{\n          uint8_t subEventCode;\n          uint8_t status;\n          uint8_t localPublicKey[64];\n        } *evtReadLocalP256Complete = (EvtReadLocalP256Complete*)&pdata[sizeof(HCIEventHdr)];\n        if(evtReadLocalP256Complete->status == 0x0){\n#ifdef _BLE_TRACE_\n          Serial.println(\"Key read success\");\n#endif\n          struct __attribute__ ((packed)) PairingPublicKey\n          {\n            uint8_t code;\n            uint8_t publicKey[64];\n          } pairingPublicKey = {CONNECTION_PAIRING_PUBLIC_KEY,0};\n          memcpy(pairingPublicKey.publicKey,evtReadLocalP256Complete->localPublicKey,64);\n          memcpy(localPublicKeyBuffer,      evtReadLocalP256Complete->localPublicKey,64);\n\n          // Send the local public key to the remote\n          uint16_t connectionHandle = ATT.getPeerEncrptingConnectionHandle();\n          if(connectionHandle>ATT_MAX_PEERS){\n#ifdef _BLE_TRACE_\n            Serial.println(\"failed to find connection handle\");\n#endif\n            break;\n          }\n          HCI.sendAclPkt(connectionHandle,SECURITY_CID,sizeof(PairingPublicKey),&pairingPublicKey);\n          uint8_t encryption = ATT.getPeerEncryption(connectionHandle) | PEER_ENCRYPTION::SENT_PUBKEY;\n          ATT.setPeerEncryption(connectionHandle, encryption);\n\n\n          uint8_t Z = 0;\n\n          HCI.leRand(Nb);\n          HCI.leRand(&Nb[8]);\n\n#ifdef _BLE_TRACE_\n          Serial.print(\"nb: \");\n          btct.printBytes(Nb, 16);\n#endif\n          struct __attribute__ ((packed)) F4Params\n          {\n            uint8_t U[32];\n            uint8_t V[32];\n            uint8_t Z;\n          } f4Params = {{0},{0},Z};\n          for(int i=0; i<32; i++){\n            f4Params.U[31-i] = pairingPublicKey.publicKey[i];\n            f4Params.V[31-i] = HCI.remotePublicKeyBuffer[i];\n          }\n\n          struct __attribute__ ((packed)) PairingConfirm\n          {\n            uint8_t code;\n            uint8_t cb[16];\n          } pairingConfirm = {CONNECTION_PAIRING_CONFIRM,0};\n\n          btct.AES_CMAC(Nb,(unsigned char *)&f4Params,sizeof(f4Params),pairingConfirm.cb);\n\n#ifdef _BLE_TRACE_\n          Serial.print(\"cb: \");\n          btct.printBytes(pairingConfirm.cb, 16);\n#endif\n\n          uint8_t cb_temp[sizeof(pairingConfirm.cb)];\n          for(unsigned int i=0; i<sizeof(pairingConfirm.cb);i++){\n            cb_temp[sizeof(pairingConfirm.cb)-1-i] = pairingConfirm.cb[i];\n          }\n          /// cb wa back to front.\n          memcpy(pairingConfirm.cb,cb_temp,sizeof(pairingConfirm.cb));\n\n          // Send Pairing confirm response\n          HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(pairingConfirm), &pairingConfirm);\n\n          HCI.sendCommand( (OGF_LE_CTL << 10) | LE_COMMAND::GENERATE_DH_KEY_V1, sizeof(HCI.remotePublicKeyBuffer), HCI.remotePublicKeyBuffer);\n        }else{\n#ifdef _BLE_TRACE_\n          Serial.print(\"Key read error: 0x\");\n          Serial.println(evtReadLocalP256Complete->status,HEX);\n          for(int i=0; i<64; i++){\n            Serial.print(\" 0x\");\n            Serial.print(evtReadLocalP256Complete->localPublicKey[i],HEX);\n          }\n          Serial.println(\".\");\n#endif\n        }\n        break;\n      }\n      case GENERATE_DH_KEY_COMPLETE:{\n        struct __attribute__ ((packed)) EvtLeDHKeyComplete{\n          uint8_t subEventCode;\n          uint8_t status;\n          uint8_t DHKey[32];\n        } *evtLeDHKeyComplete = (EvtLeDHKeyComplete*)&pdata[sizeof(HCIEventHdr)];\n        if(evtLeDHKeyComplete->status == 0x0){\n#ifdef _BLE_TRACE_\n          Serial.println(\"DH key generated\");\n#endif\n          uint16_t connectionHandle = ATT.getPeerEncrptingConnectionHandle();\n          if(connectionHandle>ATT_MAX_PEERS){\n#ifdef _BLE_TRACE_\n            Serial.println(\"Failed to find connection handle DH key check\");\n#endif\n            break;\n          }\n\n\n          for(int i=0; i<32; i++) DHKey[31-i] = evtLeDHKeyComplete->DHKey[i];\n\n#ifdef _BLE_TRACE_\n          Serial.println(\"Stored our DHKey:\");\n          btct.printBytes(DHKey,32);\n#endif\n          uint8_t encryption = ATT.getPeerEncryption(connectionHandle) | PEER_ENCRYPTION::DH_KEY_CALULATED;\n          ATT.setPeerEncryption(connectionHandle, encryption);\n\n          if((encryption & PEER_ENCRYPTION::RECEIVED_DH_CHECK) > 0){\n#ifdef _BLE_TRACE_\n            Serial.println(\"Received DHKey check already so calculate f5, f6 now.\");\n#endif\n            L2CAPSignaling.smCalculateLTKandConfirm(connectionHandle, HCI.remoteDHKeyCheckBuffer);\n\n          }else{\n#ifdef _BLE_TRACE_\n            Serial.println(\"Waiting on other DHKey check before calculating.\");\n#endif\n          }\n        }else{\n#ifdef _BLE_TRACE_\n          Serial.print(\"Key generation error: 0x\");\n          Serial.println(evtLeDHKeyComplete->status, HEX);\n#endif\n        }\n        break;\n      }\n      default:\n      {\n#ifdef _BLE_TRACE_\n        Serial.println(\"[Info] Unhandled meta event\");\n#endif\n      }\n    }\n  }else{\n#ifdef _BLE_TRACE_\n    Serial.println(\"[Info] Unhandled event\");\n#endif\n  }\n}\nint HCIClass::leEncrypt(uint8_t* key, uint8_t* plaintext, uint8_t* status, uint8_t* ciphertext){\n  (void)status;\n  struct __attribute__ ((packed)) LeEncryptCommand\n  {\n    uint8_t key[16];\n    uint8_t plaintext[16];\n  } leEncryptCommand = {{0},{0}};\n  for(int i=0; i<16; i++){\n    leEncryptCommand.key[15-i] = key[i];\n    leEncryptCommand.plaintext[15-i] = plaintext[i];\n  }\n\n  int res = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::ENCRYPT, 32, &leEncryptCommand);\n  if(res == 0){\n#ifdef _BLE_TRACE_\n    Serial.print(\"Copying from command Response length: \");\n    Serial.println(_cmdResponseLen);\n    Serial.println(\".\");\n    for(int i=0; i<20; i++){\n        Serial.print(\" 0x\");\n        Serial.print(_cmdResponse[i],HEX);\n    }\n    Serial.println(\".\");\n#endif\n    for(int i=0; i<16; i++){\n      ciphertext[15-i] = _cmdResponse[i];\n    }\n    return 1;\n  }\n#ifdef _BLE_TRACE_\n  Serial.print(\"Error with AES: 0x\");\n  Serial.println(res, HEX);\n#endif\n  return res;\n}\nint HCIClass::leRand(uint8_t rand[]){\n  int res = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::RANDOM);\n  if(res == 0){\n    memcpy(rand,_cmdResponse, 8); /// backwards but it's a random number\n  }\n  return res;\n}\nint HCIClass::getLTK(uint8_t* address, uint8_t* LTK){\n  if(_getLTK!=0){\n    return _getLTK(address, LTK);\n  }else{\n    return 0;\n  }\n}\nint HCIClass::storeIRK(uint8_t* address, uint8_t* IRK){\n  if(_storeIRK!=0){\n    return _storeIRK(address, IRK);\n  }else{\n    return 0;\n  }\n}\nint HCIClass::storeLTK(uint8_t* address, uint8_t* LTK){\n  if(_storeLTK!=0){\n    return _storeLTK(address, LTK);\n  }else{\n    return 0;\n  }\n}\nuint8_t HCIClass::localIOCap(){\n  if(_displayCode!=0){\n    /// We have a display\n    if(_binaryConfirmPairing!=0){\n      return IOCAP_DISPLAY_YES_NO;\n    }else{\n      return IOCAP_DISPLAY_ONLY;\n    }\n  }else{\n    // We have no display\n    return IOCAP_NO_INPUT_NO_OUTPUT;\n  }\n}\n\n/// Stub function to generate parameters for local authreq\nAuthReq HCIClass::localAuthreq(){\n  // If get, set, IRK, LTK all set then we can bond.\n  AuthReq local = AuthReq();\n  if(_storeIRK!=0 && _storeLTK!=0 && _getLTK!=0 && _getIRKs!=0){\n    local.setBonding(true);\n  }\n  local.setSC(true);\n  local.setMITM(true);\n  local.setCT2(true);\n  return LOCAL_AUTHREQ;\n}\n\nvoid HCIClass::dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[])\n{\n  if (_debug) {\n    _debug->print(prefix);\n\n    for (uint8_t i = 0; i < plen; i++) {\n      byte b = pdata[i];\n\n      if (b < 16) {\n        _debug->print(\"0\");\n      }\n\n      _debug->print(b, HEX);\n    }\n\n    _debug->println();\n    _debug->flush();\n  }\n}\n\n#if !defined(FAKE_HCI)\nHCIClass HCIObj;\nHCIClass& HCI = HCIObj;\n#endif\n"
  },
  {
    "path": "src/utility/HCI.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _HCI_H_\n#define _HCI_H_\n\n#include <Arduino.h>\n#include \"bitDescriptions.h\"\n\n#include \"L2CAPSignaling.h\"\n\n#define OGF_LINK_CTL           0x01\n#define OGF_HOST_CTL           0x03\n#define OGF_INFO_PARAM         0x04\n#define OGF_STATUS_PARAM       0x05\n#define OGF_LE_CTL             0x08\n\nenum LE_COMMAND {\n  ENCRYPT                      = 0x0017,\n  RANDOM                       = 0x0018,\n  LONG_TERM_KEY_REPLY          = 0x001A,\n  LONG_TERM_KEY_NEGATIVE_REPLY = 0x001B,\n  READ_LOCAL_P256              = 0x0025,\n  GENERATE_DH_KEY_V1           = 0x0026,\n  GENERATE_DH_KEY_V2           = 0x005E\n};\nenum LE_META_EVENT {\n  CONN_COMPLETE             = 0x01,\n  ADVERTISING_REPORT        = 0x02,\n  LONG_TERM_KEY_REQUEST     = 0x05,\n  REMOTE_CONN_PARAM_REQ     = 0x06,\n  READ_LOCAL_P256_COMPLETE  = 0x08,\n  GENERATE_DH_KEY_COMPLETE  = 0x09,\n  ENHANCED_CONN_COMPLETE    = 0x0A,\n};\nString metaEventToString(LE_META_EVENT event);\nString commandToString(LE_COMMAND command);\n\nclass HCIClass {\npublic:\n  HCIClass();\n  virtual ~HCIClass();\n\n  virtual int begin();\n  virtual void end();\n\n  virtual void poll();\n  virtual void poll(unsigned long timeout);\n\n  virtual int reset();\n  virtual int readLocalVersion(uint8_t& hciVer, uint16_t& hciRev, uint8_t& lmpVer,\n                       uint16_t& manufacturer, uint16_t& lmpSubVer);\n\n  virtual int readBdAddr(uint8_t addr[6]);\n  virtual int readBdAddr();\n\n  virtual int readRssi(uint16_t handle);\n\n  virtual int setEventMask(uint64_t eventMask);\n  virtual int setLeEventMask(uint64_t leEventMask);\n  virtual int readLeBufferSize(uint16_t& pktLen, uint8_t& maxPkt);\n  virtual int leSetRandomAddress(uint8_t addr[6]);\n  virtual int leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval,\n                                 uint8_t advType, uint8_t ownBdaddrType,\n                                 uint8_t directBdaddrType, uint8_t directBdaddr[6],\n                                 uint8_t chanMap,\n                                 uint8_t filter);\n  virtual int leSetAdvertisingData(uint8_t length, uint8_t data[]);\n  virtual int leSetScanResponseData(uint8_t length, uint8_t data[]);\n  virtual int leSetAdvertiseEnable(uint8_t enable);\n  virtual int leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window, \n                          uint8_t ownBdaddrType, uint8_t filter);\n  virtual int leSetScanEnable(uint8_t enabled, uint8_t duplicates);\n  virtual int leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter,\n                  uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint8_t ownBdaddrType,\n                  uint16_t minInterval, uint16_t maxInterval, uint16_t latency,\n                  uint16_t supervisionTimeout, uint16_t minCeLength, uint16_t maxCeLength);\n  virtual int leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval, \n                  uint16_t latency, uint16_t supervisionTimeout);\n  virtual int leCancelConn();\n  virtual int leEncrypt(uint8_t* Key, uint8_t* plaintext, uint8_t* status, uint8_t* ciphertext);\n  // Generate a 64 bit random number\n  virtual int leRand(uint8_t rand[]);\n  virtual AuthReq localAuthreq();\n  virtual uint8_t localIOCap();\n\n  virtual void saveNewAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk);\n  virtual void leAddResolvingAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk);\n  virtual int leStopResolvingAddresses();\n  virtual int leStartResolvingAddresses();\n  virtual int leReadPeerResolvableAddress(uint8_t peerAddressType, uint8_t* peerIdentityAddress, uint8_t* peerResolvableAddress);\n\n  virtual void readStoredLKs();\n  virtual int readStoredLK(uint8_t BD_ADDR[], uint8_t read_all = 0);\n  virtual void writeLK(uint8_t peerAddress[], uint8_t LK[]);\n  virtual int tryResolveAddress(uint8_t* BDAddr, uint8_t* address);\n\n  virtual int sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data);\n\n  virtual int disconnect(uint16_t handle);\n\n  virtual void debug(Stream& stream);\n  virtual void noDebug();\n\n  // TODO: Send command be private again & use ATT implementation of send command within ATT.\n  virtual int sendCommand(uint16_t opcode, uint8_t plen = 0, void* parameters = NULL);\n  uint8_t remotePublicKeyBuffer[64];\n  uint8_t localPublicKeyBuffer[64];\n  uint8_t remoteDHKeyCheckBuffer[16];\n  uint8_t Na[16];\n  uint8_t Nb[16];\n  uint8_t DHKey[32];\n  uint8_t localAddr[6];\n  uint8_t LTK[16];\n  virtual int getLTK(uint8_t* address, uint8_t* LTK);\n  virtual int storeLTK(uint8_t* address, uint8_t* LTK);\n  virtual int storeIRK(uint8_t* address, uint8_t* IRK);\n  int (*_storeIRK)(uint8_t* address, uint8_t* peerIrk) = 0;\n  int (*_getIRKs)(uint8_t* nIRKs,uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs) = 0;\n  int (*_storeLTK)(uint8_t*, uint8_t*) = 0;\n  int (*_getLTK)(uint8_t*, uint8_t*) = 0;\n  void (*_displayCode)(uint32_t confirmationCode) = 0;\n  bool (*_binaryConfirmPairing)() = 0;\n\nprivate:\n\n  virtual void handleAclDataPkt(uint8_t plen, uint8_t pdata[]);\n  virtual void handleNumCompPkts(uint16_t handle, uint16_t numPkts);\n  virtual void handleEventPkt(uint8_t plen, uint8_t pdata[]);\n\n  virtual void dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]);\n\n  Stream* _debug;\n\n  int _recvIndex;\n  uint8_t _recvBuffer[3 + 255];\n\n  uint16_t _cmdCompleteOpcode;\n  int _cmdCompleteStatus;\n  uint8_t _cmdResponseLen;\n  uint8_t* _cmdResponse;\n\n  uint8_t _maxPkt;\n  uint8_t _pendingPkt;\n\n  uint8_t _l2CapPduBuffer[255];\n  uint8_t _l2CapPduBufferSize;\n};\n\nextern HCIClass& HCI;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCICordioTransport.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#if defined(ARDUINO_ARCH_MBED) && !defined(TARGET_NANO_RP2040_CONNECT) // && !defined(CORE_CM4)\n#include <Arduino.h>\n#include <mbed.h>\n\n#include <driver/CordioHCITransportDriver.h>\n#include <driver/CordioHCIDriver.h>\n\n#if defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_GIGA) || defined(ARDUINO_OPTA)\n#include \"ble/BLE.h\"\n#include <events/mbed_events.h>\n#endif\n\n// Parts of this file are based on: https://github.com/ARMmbed/mbed-os-cordio-hci-passthrough/pull/2\n// With permission from the Arm Mbed team to re-license\n\n#if CORDIO_ZERO_COPY_HCI\n#include <wsf_types.h>\n#include <wsf_buf.h>\n#include <wsf_msg.h>\n#include <wsf_os.h>\n#include <wsf_buf.h>\n#include <wsf_timer.h>\n\n/* avoid many small allocs (and WSF doesn't have smaller buffers) */\n#define MIN_WSF_ALLOC (16)\n#endif //CORDIO_ZERO_COPY_HCI\n\n#include \"HCICordioTransport.h\"\n\n#if (MBED_VERSION > MBED_ENCODE_VERSION(6, 2, 0))\n#define BLE_NAMESPACE ble \n#else\n#define BLE_NAMESPACE ble::vendor::cordio\n#endif\n\n#include \"CordioHCICustomDriver.h\"\n\nextern BLE_NAMESPACE::CordioHCIDriver& ble_cordio_get_hci_driver();\nextern \"C\" void hciTrSerialRxIncoming(uint8_t *pBuf, uint8_t len);\n\nnamespace BLE_NAMESPACE {\n  struct CordioHCIHook {\n    static CordioHCIDriver& getDriver() {\n      return ble_cordio_get_hci_driver();\n    }\n\n    static CordioHCITransportDriver& getTransportDriver() {\n      return getDriver()._transport_driver;\n    }\n\n    static void setDataReceivedHandler(void (*handler)(uint8_t*, uint8_t)) {\n      getTransportDriver().set_data_received_handler(handler);\n    }\n  };\n}\n\nusing BLE_NAMESPACE::CordioHCIHook;\n\n#if CORDIO_ZERO_COPY_HCI\nextern uint8_t *SystemHeapStart;\nextern uint32_t SystemHeapSize;\n\nvoid init_wsf(BLE_NAMESPACE::buf_pool_desc_t& buf_pool_desc) {\n    static bool init = false;\n\n    if (init) {\n      return;\n    }\n    init = true;\n\n    // use the buffer for the WSF heap\n    SystemHeapStart = buf_pool_desc.buffer_memory;\n    SystemHeapSize = buf_pool_desc.buffer_size;\n\n    // Initialize buffers with the ones provided by the HCI driver\n    uint16_t bytes_used = WsfBufInit(\n        buf_pool_desc.pool_count,\n        (wsfBufPoolDesc_t*)buf_pool_desc.pool_description\n    );\n\n    // Raise assert if not enough memory was allocated\n    MBED_ASSERT(bytes_used != 0);\n\n    SystemHeapStart += bytes_used;\n    SystemHeapSize -= bytes_used;\n\n    WsfTimerInit();\n}\n\n\nextern \"C\" void wsf_mbed_ble_signal_event(void)\n{\n    // do nothing\n}\n#endif //CORDIO_ZERO_COPY_HCI\n\nstatic void bleLoop()\n{\n#if CORDIO_ZERO_COPY_HCI\n    uint64_t last_update_us = 0;\n    mbed::LowPowerTimer timer;\n\n    timer.start();\n\n    while (true) {\n        last_update_us += (uint64_t) timer.read_high_resolution_us();\n        timer.reset();\n\n        uint64_t last_update_ms = (last_update_us / 1000);\n        wsfTimerTicks_t wsf_ticks = (last_update_ms / WSF_MS_PER_TICK);\n\n        if (wsf_ticks > 0) {\n            WsfTimerUpdate(wsf_ticks);\n            last_update_us -= (last_update_ms * 1000);\n        }\n\n        wsfOsDispatcher();\n\n        bool sleep = false;\n        {\n            /* call needs interrupts disabled */\n            mbed::CriticalSectionLock critical_section;\n            if (wsfOsReadyToSleep()) {\n                sleep = true;\n            }\n        }\n\n        uint64_t time_spent = (uint64_t) timer.read_high_resolution_us();\n\n        /* don't bother sleeping if we're already past tick */\n        if (sleep && (WSF_MS_PER_TICK * 1000 > time_spent)) {\n            /* sleep to maintain constant tick rate */\n            uint64_t wait_time_us = WSF_MS_PER_TICK * 1000 - time_spent;\n            uint64_t wait_time_ms = wait_time_us / 1000;\n\n            wait_time_us = wait_time_us % 1000;\n\n            if (wait_time_ms) {\n              rtos::ThisThread::sleep_for(wait_time_ms);\n            }\n\n            if (wait_time_us) {\n              wait_us(wait_time_us);\n            }\n        }\n    }\n#else\n    while(true) {\n        rtos::ThisThread::sleep_for(osWaitForever);\n    }\n#endif // CORDIO_ZERO_COPY_HCI\n}\n\nstatic rtos::EventFlags bleEventFlags; \nstatic rtos::Thread* bleLoopThread = NULL;\n\n\nHCICordioTransportClass::HCICordioTransportClass() :\n  _begun(false)\n{\n}\n\nHCICordioTransportClass::~HCICordioTransportClass()\n{\n}\n\n#if (defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_GIGA) || defined(ARDUINO_OPTA)) && !defined(CUSTOM_HCI_DRIVER)\nevents::EventQueue eventQueue(10 * EVENTS_EVENT_SIZE);\nvoid scheduleMbedBleEvents(BLE::OnEventsToProcessCallbackContext *context) {\n  eventQueue.call(mbed::Callback<void()>(&context->ble, &BLE::processEvents));\n}\n\nvoid completeCallback(BLE::InitializationCompleteCallbackContext *context) {\n  eventQueue.break_dispatch();\n}\n#endif\n\nint HCICordioTransportClass::begin()\n{\n  _rxBuf.clear();\n\n#if CORDIO_ZERO_COPY_HCI\n  BLE_NAMESPACE::buf_pool_desc_t bufPoolDesc = CordioHCIHook::getDriver().get_buffer_pool_description();\n  init_wsf(bufPoolDesc);\n#endif\n\n#if (defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_GIGA) || defined(ARDUINO_OPTA)) && !defined(CUSTOM_HCI_DRIVER)\n\n  BLE &ble = BLE::Instance();\n  ble.onEventsToProcess(scheduleMbedBleEvents);\n\n  ble.init(completeCallback);\n  eventQueue.dispatch(10000);\n\n  if (!ble.hasInitialized()){\n    return 0;\n  } \n#else \n  CordioHCIHook::getDriver().initialize();\n#endif\n\n  if (bleLoopThread == NULL) {\n    bleLoopThread = new rtos::Thread();\n    bleLoopThread->start(bleLoop);\n  }\n\n  CordioHCIHook::setDataReceivedHandler(HCICordioTransportClass::onDataReceived);\n\n  _begun = true;\n\n  return 1;\n}\n\nvoid HCICordioTransportClass::end()\n{\n  if (bleLoopThread != NULL) {\n    bleLoopThread->terminate();\n    delete bleLoopThread;\n    bleLoopThread = NULL;\n  }\n  // Reset the callback with the mbed-os default handler to properly handle the following CYW43xxx chip initializations and begins\n  CordioHCIHook::setDataReceivedHandler(hciTrSerialRxIncoming);\n\n#if (defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_GIGA) || defined(ARDUINO_OPTA)) && !defined(CUSTOM_HCI_DRIVER)\n  BLE &ble = BLE::Instance();\n  ble.shutdown();\n#endif\n\n#if !defined(TARGET_STM32H7)\n  CordioHCIHook::getDriver().terminate();\n#endif\n\n  _begun = false;\n}\n\nvoid HCICordioTransportClass::wait(unsigned long timeout)\n{\n  {\n    mbed::CriticalSectionLock critical_section;\n    if (available()) {\n      return;\n    }\n  }\n\n  // wait for handleRxData to signal\n  bleEventFlags.wait_all(0x01, timeout, true);\n}\n\nint HCICordioTransportClass::available()\n{\n  return _rxBuf.available();\n}\n\nint HCICordioTransportClass::peek()\n{\n  return _rxBuf.peek();\n}\n\nint HCICordioTransportClass::read()\n{\n  return _rxBuf.read_char();\n}\n\nvoid HCICordioTransportClass::lockForRead() {\n  mbed::CriticalSectionLock::enable();\n}\n\nvoid HCICordioTransportClass::unlockForRead() {\n  mbed::CriticalSectionLock::disable();\n}\n\nsize_t HCICordioTransportClass::write(const uint8_t* data, size_t length)\n{\n  if (!_begun) {\n    return 0;\n  }\n\n  uint8_t packetLength = length - 1;\n  uint8_t packetType   = data[0];\n\n#if CORDIO_ZERO_COPY_HCI\n  uint8_t* packet = (uint8_t*)WsfMsgAlloc(max(packetLength, MIN_WSF_ALLOC));\n\n  memcpy(packet, &data[1], packetLength);\n\n  return CordioHCIHook::getTransportDriver().write(packetType, packetLength, packet);\n#else\n  return CordioHCIHook::getTransportDriver().write(packetType, packetLength, (uint8_t*)&data[1]);\n#endif\n}\n\nvoid HCICordioTransportClass::handleRxData(uint8_t* data, uint8_t len)\n{\n  {\n    #if defined(ARDUINO_ARCH_NRF52840)\n    mbed::CriticalSectionLock critical_section;\n    #endif\n    if (_rxBuf.availableForStore() < len) {\n      // drop!\n      return;\n    }\n\n    for (int i = 0; i < len; i++) {\n      _rxBuf.store_char(data[i]);\n    }\n  }\n  bleEventFlags.set(0x01);\n}\n\nHCICordioTransportClass HCICordioTransport;\nHCITransportInterface& HCITransport = HCICordioTransport;\n\nvoid HCICordioTransportClass::onDataReceived(uint8_t* data, uint8_t len)\n{\n  HCICordioTransport.handleRxData(data, len);\n}\n\n#endif\n"
  },
  {
    "path": "src/utility/HCICordioTransport.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2019 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _HCI_CORDIO_TRANSPORT_H_\n#define _HCI_CORDIO_TRANSPORT_H_\n\n#include <string.h>\n\n#include \"api/RingBuffer.h\"\n\n#include \"HCITransport.h\"\n\nclass HCICordioTransportClass : public HCITransportInterface {\npublic:\n  HCICordioTransportClass();\n  virtual ~HCICordioTransportClass();\n\n  virtual int begin();\n  virtual void end();\n\n  virtual void wait(unsigned long timeout);\n\n  virtual int available();\n  virtual int peek();\n  virtual int read();\n\n  virtual void lockForRead() override;\n  virtual void unlockForRead() override;\n\n  virtual size_t write(const uint8_t* data, size_t length);\n\nprivate:\n  static void onDataReceived(uint8_t* data, uint8_t len);\n  void handleRxData(uint8_t* data, uint8_t len);\n\nprivate:\n  bool _begun;\n  RingBufferN<256> _rxBuf;\n};\n\n#endif\n"
  },
  {
    "path": "src/utility/HCINinaSpiTransport.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n\n  Copyright (c) 2024 Arduino SA\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n*/\n\n#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(TARGET_NANO_RP2040_CONNECT)\n#include \"HCINinaSpiTransport.h\"\n#include <Arduino_SpiNINA.h>\n\nenum {\n  BLE_BEGIN \t\t\t= 0x4A,\n  BLE_END \t\t\t\t= 0x4B,\n  BLE_AVAILABLE\t\t= 0x4C,\n  BLE_PEEK \t\t\t\t= 0x4D,\n  BLE_READ \t\t\t\t= 0x4E,\n  BLE_WRITE \t\t\t= 0x4F,\n};\n\nint BleDrv::bleBegin() {\n    WAIT_FOR_SLAVE_SELECT();\n\n    SpiDrv::sendCmd(BLE_BEGIN, PARAM_NUMS_0);\n\n    SpiDrv::spiSlaveDeselect();\n    //Wait the reply elaboration\n    SpiDrv::waitForSlaveReady();\n    SpiDrv::spiSlaveSelect();\n\n    uint8_t len = 1;\n    uint8_t result = 0;\n    SpiDrv::waitResponseCmd(BLE_BEGIN, PARAM_NUMS_1, (uint8_t*)&result, &len);\n    SpiDrv::spiSlaveDeselect();\n\n    return result == 0;\n}\n\nvoid BleDrv::bleEnd() {\n    WAIT_FOR_SLAVE_SELECT();\n\n    SpiDrv::sendCmd(BLE_END, PARAM_NUMS_0);\n\n    SpiDrv::spiSlaveDeselect();\n    //Wait the reply elaboration\n    SpiDrv::waitForSlaveReady();\n    SpiDrv::spiSlaveSelect();\n\n    uint8_t len = 1;\n    uint8_t result = 0;\n    SpiDrv::waitResponseCmd(BLE_END, PARAM_NUMS_1, (uint8_t*)&result, &len);\n    SpiDrv::spiSlaveDeselect();\n}\n\nint BleDrv::bleAvailable() {\n    WAIT_FOR_SLAVE_SELECT();\n    uint16_t result = 0;\n\n    SpiDrv::sendCmd(BLE_AVAILABLE, PARAM_NUMS_0);\n\n    SpiDrv::spiSlaveDeselect();\n    //Wait the reply elaboration\n    SpiDrv::waitForSlaveReady();\n    SpiDrv::spiSlaveSelect();\n\n    uint8_t len = 2;\n    SpiDrv::waitResponseCmd(BLE_AVAILABLE, PARAM_NUMS_1, (uint8_t*)&result, &len);\n    SpiDrv::spiSlaveDeselect();\n\n    return result;\n}\n\nint BleDrv::bleRead(uint8_t data[], size_t length) {\n    WAIT_FOR_SLAVE_SELECT();\n\n    SpiDrv::sendCmd(BLE_READ, PARAM_NUMS_1);\n\n    int commandSize = 7; // 4 for the normal command length + 3 for the parameter\n    uint16_t param = length; // TODO check length doesn't exceed 2^16\n    SpiDrv::sendParam((uint8_t*)&param, sizeof(param), LAST_PARAM);\n\n    // pad to multiple of 4\n    while (commandSize % 4 != 0) {\n        SpiDrv::readChar();\n        commandSize++;\n    }\n\n    SpiDrv::spiSlaveDeselect();\n    //Wait the reply elaboration\n    SpiDrv::waitForSlaveReady();\n    SpiDrv::spiSlaveSelect();\n\n    uint16_t res_len = 0;\n    SpiDrv::waitResponseData16(BLE_READ, data, (uint16_t*)&res_len);\n\n    SpiDrv::spiSlaveDeselect();\n\n    return res_len;\n}\n\nint BleDrv::blePeek(uint8_t data[], size_t length) {\n    WAIT_FOR_SLAVE_SELECT();\n\n    SpiDrv::sendCmd(BLE_PEEK, PARAM_NUMS_1);\n\n    int commandSize = 7; // 4 for the normal command length + 3 for the parameter\n    uint16_t param = length; // TODO check length doesn't exceed 2^16\n    SpiDrv::sendParam((uint8_t*)&param, sizeof(param), LAST_PARAM);\n\n    // pad to multiple of 4\n    while (commandSize % 4 != 0) {\n        SpiDrv::readChar();\n        commandSize++;\n    }\n\n    SpiDrv::spiSlaveDeselect();\n    //Wait the reply elaboration\n    SpiDrv::waitForSlaveReady();\n    SpiDrv::spiSlaveSelect();\n\n    uint16_t res_len = 0;\n    SpiDrv::waitResponseData16(BLE_READ, data, (uint16_t*)&res_len);\n\n    SpiDrv::spiSlaveDeselect();\n\n    return res_len;\n}\n\nsize_t BleDrv::bleWrite(const uint8_t* data, size_t len) {\n    WAIT_FOR_SLAVE_SELECT();\n\n    int commandSize = 4;\n    SpiDrv::sendCmd(BLE_WRITE, PARAM_NUMS_1);\n\n    SpiDrv::sendBuffer((uint8_t*)data, len, LAST_PARAM);\n    commandSize += len+2;\n\n    // pad to multiple of 4\n    while (commandSize % 4 != 0) {\n        SpiDrv::readChar();\n        commandSize++;\n    }\n\n    SpiDrv::spiSlaveDeselect();\n    //Wait the reply elaboration\n    SpiDrv::waitForSlaveReady();\n    SpiDrv::spiSlaveSelect();\n\n    uint8_t res_len = 1;\n    uint16_t res = 0;\n    SpiDrv::waitResponseCmd(BLE_WRITE, PARAM_NUMS_1, (uint8_t*)&res, &res_len);\n    SpiDrv::spiSlaveDeselect();\n\n    return res;\n}\n\nint HCINinaSpiTransportClass::begin()\n{\n  SpiDrv::begin();\n  return BleDrv::bleBegin();\n}\n\nvoid HCINinaSpiTransportClass::end()\n{\n  BleDrv::bleEnd();\n}\n\nvoid HCINinaSpiTransportClass::wait(unsigned long timeout)\n{\n  for (unsigned long start = millis(); (millis() - start) < timeout;) {\n    if (available()) {\n      break;\n    }\n  }\n}\n\nint HCINinaSpiTransportClass::available()\n{\n  return BleDrv::bleAvailable();\n}\n\nint HCINinaSpiTransportClass::peek()\n{\n  int res=-1;\n  BleDrv::blePeek((uint8_t*)&res, 1); // read a single byte, if nothing is returned we return -1\n\n  return res;\n}\n\nint HCINinaSpiTransportClass::read()\n{\n  int res=-1;\n  BleDrv::bleRead((uint8_t*)&res, 1); // read a single byte, if nothing is returned we return -1\n\n  return res;\n}\n\nsize_t HCINinaSpiTransportClass::write(const uint8_t* data, size_t length)\n{\n  return BleDrv::bleWrite(data, length);\n}\n\nHCINinaSpiTransportClass HCINinaSpiTransport;\nHCITransportInterface& HCITransport = HCINinaSpiTransport;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCINinaSpiTransport.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n\n  Copyright (c) 2024 Arduino SA\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n*/\n\n#ifndef _HCI_NINA_SPI_TRANSPORT_H_\n#define _HCI_NINA_SPI_TRANSPORT_H_\n\n#include \"HCITransport.h\"\n\nclass BleDrv\n{\npublic:\n    static int bleBegin();\n    static void bleEnd();\n    static int bleAvailable();\n    static int bleRead(uint8_t data[], size_t length);\n    static int blePeek(uint8_t data[], size_t length);\n    static size_t bleWrite(const uint8_t* data, size_t length);\n};\n\nclass HCINinaSpiTransportClass : public HCITransportInterface {\npublic:\n  HCINinaSpiTransportClass() {}\n\n  virtual int begin();\n  virtual void end();\n\n  virtual void wait(unsigned long timeout);\n\n  virtual int available();\n  virtual int peek();\n  virtual int read();\n\n  virtual size_t write(const uint8_t* data, size_t length);\n};\n\n#endif\n"
  },
  {
    "path": "src/utility/HCISilabsTransport.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2024 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#if defined(ARDUINO_SILABS)\n\n#include \"HCISilabsTransport.h\"\n#include \"sl_string.h\"\n\nextern \"C\" {\n#include \"sl_btctrl_linklayer.h\"\n#include \"sl_hci_common_transport.h\"\n}\n\nextern \"C\" int strcasecmp(char const *a, char const *b) {\n  return sl_strcasecmp(a, b);\n}\n\nstatic RingBufferN<512> buf;\n\nHCISilabsTransportClass::HCISilabsTransportClass()\n{\n}\n\nHCISilabsTransportClass::~HCISilabsTransportClass()\n{\n}\n\nint HCISilabsTransportClass::begin()\n{\n  if(!sl_btctrl_is_initialized()) {\n    sl_bt_controller_init(); \n  }\n\n  /* Initialize adv & scan components */\n  sl_btctrl_init_adv();\n  sl_btctrl_init_scan();\n  sl_btctrl_init_conn(); \n  sl_btctrl_init_adv_ext();\n  sl_btctrl_init_scan_ext();\n\n  /* Initialize HCI controller */\n  sl_bthci_init_upper(); \n  sl_btctrl_hci_parser_init_default();\n  sl_btctrl_hci_parser_init_conn();\n  sl_btctrl_hci_parser_init_adv();\n  sl_btctrl_hci_parser_init_phy();\n\n  return 1;\n}\n\nvoid HCISilabsTransportClass::end()\n{\n  sl_bt_controller_deinit();\n}\n\nvoid HCISilabsTransportClass::wait(unsigned long timeout)\n{\n  for (unsigned long start = millis(); (millis() - start) < timeout;) {\n    if (available()) {\n      break;\n    }\n  }\n}\n\nint HCISilabsTransportClass::available()\n{\n  return buf.available();\n}\n\nint HCISilabsTransportClass::peek()\n{\n  return buf.peek();\n}\n\nint HCISilabsTransportClass::read()\n{\n  return buf.read_char();\n}\n\nsize_t HCISilabsTransportClass::write(const uint8_t* data, size_t len)\n{\n  int ret = 0;\n  ret = hci_common_transport_receive((uint8_t *)data, len, true);\n\n  if (ret == 0) return len;\n\n  return 0;\n}\n\nextern \"C\" {\n  /**\n   * @brief Transmit HCI message using the currently used transport layer.\n   * The HCI calls this function to transmit a full HCI message.\n   * @param[in] data Packet type followed by HCI packet data.\n   * @param[in] len Length of the `data` parameter\n   * @return 0 - on success, or non-zero on failure.\n   */\n  uint32_t hci_common_transport_transmit(uint8_t *data, int16_t len)\n  {\n    for (int i = 0; i < len; i++) {\n      buf.store_char(data[i]);\n      if (buf.isFull()) return SL_STATUS_FAIL;\n    }\n    \n    sl_btctrl_hci_transmit_complete(0);\n    return 0;\n  }\n}\n\nHCISilabsTransportClass HCISilabsTransport;\n\nHCITransportInterface& HCITransport = HCISilabsTransport;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCISilabsTransport.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _HCI_SILABS_TRANSPORT_H_\n#define _HCI_SILABS_TRANSPORT_H_\n\n#include \"HCITransport.h\"\n\nclass HCISilabsTransportClass : public HCITransportInterface {\npublic:\n  HCISilabsTransportClass();\n  virtual ~HCISilabsTransportClass();\n\n  virtual int begin();\n  virtual void end();\n\n  virtual void wait(unsigned long timeout);\n\n  virtual int available();\n  virtual int peek();\n  virtual int read();\n\n  virtual size_t write(const uint8_t* data, size_t length);\n};\n\n#endif"
  },
  {
    "path": "src/utility/HCITransport.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _HCI_TRANSPORT_INTERFACE_H_\n#define _HCI_TRANSPORT_INTERFACE_H_\n\n#include <Arduino.h>\n\nclass HCITransportInterface {\npublic:\n  virtual int begin() = 0;\n  virtual void end() = 0;\n\n  virtual void wait(unsigned long timeout) = 0;\n\n  virtual int available() = 0;\n  virtual int peek() = 0;\n  virtual int read() = 0;\n\n  // Some transports require a lock to use available/peek/read\n  // These methods allow to keep the lock while reading an unknown number of bytes\n  // These methods might disable interrupts. Only keep the lock as long as necessary.\n  virtual void lockForRead() {}\n  virtual void unlockForRead() {}\n\n  virtual size_t write(const uint8_t* data, size_t length) = 0;\n};\n\nextern HCITransportInterface& HCITransport;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCIUartTransport.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#if defined(ARDUINO_PORTENTA_C33) && !defined(__ZEPHYR__)\n\n#include \"HCIUartTransport.h\"\n\n#if defined(ARDUINO_PORTENTA_C33)\n#define SerialHCI Serial5\n#else\n#error \"Unsupported board selected!\"\n#endif\n\nHCIUartTransportClass::HCIUartTransportClass(HardwareSerial& uart, unsigned long baudrate) :\n  _uart(&uart),\n  _baudrate(baudrate)\n{\n}\n\nHCIUartTransportClass::~HCIUartTransportClass()\n{\n}\n\nint HCIUartTransportClass::begin()\n{\n  _uart->begin(_baudrate);\n\n  return 1;\n}\n\nvoid HCIUartTransportClass::end()\n{\n  _uart->end();\n}\n\nvoid HCIUartTransportClass::wait(unsigned long timeout)\n{\n  for (unsigned long start = millis(); (millis() - start) < timeout;) {\n    if (available()) {\n      break;\n    }\n  }\n}\n\nint HCIUartTransportClass::available()\n{\n  return _uart->available();\n}\n\nint HCIUartTransportClass::peek()\n{\n  return _uart->peek();\n}\n\nint HCIUartTransportClass::read()\n{\n  return _uart->read();\n}\n\nsize_t HCIUartTransportClass::write(const uint8_t* data, size_t length)\n{\n#ifdef ARDUINO_AVR_UNO_WIFI_REV2\n  // wait while the CTS pin is low\n  while (digitalRead(NINA_CTS) == HIGH);\n#endif\n\n  size_t result = _uart->write(data, length);\n\n  _uart->flush();\n\n  return result;\n}\n\nHCIUartTransportClass HCIUartTransport(SerialHCI, 912600);\nHCITransportInterface& HCITransport = HCIUartTransport;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCIUartTransport.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _HCI_UART_TRANSPORT_H_\n#define _HCI_UART_TRANSPORT_H_\n\n#include \"HCITransport.h\"\n\nclass HCIUartTransportClass : public HCITransportInterface {\npublic:\n  HCIUartTransportClass(HardwareSerial& uart, unsigned long baudrate);\n  virtual ~HCIUartTransportClass();\n\n  virtual int begin();\n  virtual void end();\n\n  virtual void wait(unsigned long timeout);\n\n  virtual int available();\n  virtual int peek();\n  virtual int read();\n\n  virtual size_t write(const uint8_t* data, size_t length);\n\nprivate:\n  HardwareSerial* _uart;\n  unsigned long _baudrate;\n};\n\n#endif\n"
  },
  {
    "path": "src/utility/HCIVirtualTransport.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#if defined(ESP32)\n\n#include \"HCIVirtualTransport.h\"\n\nStreamBufferHandle_t rec_buffer;\nStreamBufferHandle_t send_buffer;\nTaskHandle_t bleHandle;\n\n\nstatic void notify_host_send_available(void)\n{\n}\n\nstatic int notify_host_recv(uint8_t *data, uint16_t length)\n{\n  xStreamBufferSend(rec_buffer,data,length,portMAX_DELAY);  // !!!potentially waiting forever\n  return 0;\n}\n\nstatic esp_vhci_host_callback_t vhci_host_cb = {\n  notify_host_send_available,\n  notify_host_recv\n};\n\nvoid bleTask(void *pvParameters)\n{\n  esp_vhci_host_register_callback(&vhci_host_cb);\n  size_t length;\n  uint8_t mybuf[258];\n\n  while(true){\n    length = xStreamBufferReceive(send_buffer,mybuf,258,portMAX_DELAY);\n    while (!esp_vhci_host_check_send_available()) {}\n    esp_vhci_host_send_packet(mybuf, length);\n  }\n}\n\n\nHCIVirtualTransportClass::HCIVirtualTransportClass()\n{\n}\n\nHCIVirtualTransportClass::~HCIVirtualTransportClass()\n{\n}\n\nint HCIVirtualTransportClass::begin()\n{\n  btStarted(); // this somehow stops the arduino ide from initializing bluedroid\n\n  rec_buffer = xStreamBufferCreate(258, 1);\n  send_buffer = xStreamBufferCreate(258, 1);\n\n  esp_err_t ret = nvs_flash_init();\n  if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n    ESP_ERROR_CHECK(nvs_flash_erase());\n    ret = nvs_flash_init();\n  }\n  esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();\n  \n#if CONFIG_IDF_TARGET_ESP32\n  bt_cfg.mode = ESP_BT_MODE_BLE; //original esp32 chip\n#else\n#if !(CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2)\n  bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE; //different api for newer models\n#endif\n#endif\n\n  esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);\n  esp_bt_controller_init(&bt_cfg);\n  esp_bt_controller_enable(ESP_BT_MODE_BLE);\n  xTaskCreatePinnedToCore(&bleTask, \"bleTask\", 2048, NULL, 5, &bleHandle, 0);\n  return 1;\n}\n\nvoid HCIVirtualTransportClass::end()\n{\n  vStreamBufferDelete(rec_buffer);\n  vStreamBufferDelete(send_buffer);\n  esp_bt_controller_disable();\n  esp_bt_controller_deinit();\n  vTaskDelete(bleHandle);\n}\n\nvoid HCIVirtualTransportClass::wait(unsigned long timeout)\n{\n  for (unsigned long start = (esp_timer_get_time() / 1000ULL); ((esp_timer_get_time() / 1000ULL) - start) < timeout;) {\n    if (available()) {\n      break;\n    }\n  }\n}\n\nint HCIVirtualTransportClass::available()\n{\n  size_t bytes\t= xStreamBufferBytesAvailable(rec_buffer);\n  return bytes;\n}\n\n// never called\nint HCIVirtualTransportClass::peek()\n{\n  return -1;\n}\n\nint HCIVirtualTransportClass::read()\n{\n  uint8_t c;\n  if(xStreamBufferReceive(rec_buffer, &c, 1, portMAX_DELAY)) {\n    return c;\n  }\n  return -1;\n}\n\nsize_t HCIVirtualTransportClass::write(const uint8_t* data, size_t length)\n{\n  size_t result = xStreamBufferSend(send_buffer,data,length,portMAX_DELAY);\n  return result;\n}\n\nHCIVirtualTransportClass HCIVirtualTransport;\n\nHCITransportInterface& HCITransport = HCIVirtualTransport;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCIVirtualTransport.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"HCITransport.h\"\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/stream_buffer.h\"\n\n#include \"esp_bt.h\"\n#include \"nvs_flash.h\"\n\n#include \"esp32-hal-bt.h\" // this is needed to disable bluedroid\n\n\nclass HCIVirtualTransportClass : public HCITransportInterface {\npublic:\n  HCIVirtualTransportClass();\n  virtual ~HCIVirtualTransportClass();\n\n  virtual int begin();\n  virtual void end();\n\n  virtual void wait(unsigned long timeout);\n\n  virtual int available();\n  virtual int peek();\n  virtual int read();\n\n  virtual size_t write(const uint8_t* data, size_t length);\n};"
  },
  {
    "path": "src/utility/HCIVirtualTransportAT.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#if defined(ARDUINO_UNOR4_WIFI)\n\n#include \"HCIVirtualTransportAT.h\"\n\nextern ModemClass modem;\n\nHCIVirtualTransportATClass::HCIVirtualTransportATClass()\n{\n}\n\nHCIVirtualTransportATClass::~HCIVirtualTransportATClass()\n{\n}\n\nstatic RingBufferN<258> buf;\n\nint HCIVirtualTransportATClass::begin()\n{\n  // TODO: add this helper\n  //modem.debug(Serial);\n  buf.clear();\n  //modem.debug(true);\n  std::string res = \"\";\n  modem.begin();\n  if (modem.write(std::string(PROMPT(_HCI_BEGIN)), res, CMD(_HCI_BEGIN))) {\n      return 1;\n  }\n  return 0;\n}\n\nvoid HCIVirtualTransportATClass::end()\n{\n}\n\nvoid HCIVirtualTransportATClass::wait(unsigned long timeout)\n{\n  std::string res = \"\";\n  modem.write(std::string(PROMPT(_HCI_WAIT)), res, \"%d\\n\\r\", CMD_WRITE(_HCI_WAIT), timeout);\n}\n\nint HCIVirtualTransportATClass::available()\n{\n  std::string res = \"\";\n  if (buf.available()) {\n    return buf.available();\n  }\n  if (modem.write(std::string(PROMPT(_HCI_AVAILABLE)), res, CMD_READ(_HCI_AVAILABLE))) {\n    return atoi(res.c_str());\n  }\n\n  return 0;\n}\n\n// never called\nint HCIVirtualTransportATClass::peek()\n{\n  return -1;\n}\n\nint HCIVirtualTransportATClass::read()\n{\n  uint8_t c;\n  std::string res = \"\";\n  if (buf.available()) {\n    return buf.read_char();\n  }\n  modem.avoid_trim_results();\n  modem.read_using_size();\n  if (modem.write(std::string(PROMPT(_HCI_READ)), res, CMD(_HCI_READ))) {\n    for(int i = 0; i < res.size(); i++) {\n      buf.store_char((uint8_t)res[i]);\n    }\n    return buf.read_char();\n  }\n\n  return -1;\n}\n\nsize_t HCIVirtualTransportATClass::write(const uint8_t* data, size_t length)\n{\n  std::string res = \"\";\n  modem.write_nowait(std::string(PROMPT(_HCI_WRITE)), res, \"%s%d\\r\\n\" , CMD_WRITE(_HCI_WRITE), length);\n  if(modem.passthrough(data, length)) {\n    return length;\n  }\n  return 0;\n}\n\nHCIVirtualTransportATClass HCIVirtualTransportAT;\n\nHCITransportInterface& HCITransport = HCIVirtualTransportAT;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCIVirtualTransportAT.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"HCITransport.h\"\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"WiFiS3.h\"\n\nclass HCIVirtualTransportATClass : public HCITransportInterface {\npublic:\n  HCIVirtualTransportATClass();\n  virtual ~HCIVirtualTransportATClass();\n\n  virtual int begin();\n  virtual void end();\n\n  virtual void wait(unsigned long timeout);\n\n  virtual int available();\n  virtual int peek();\n  virtual int read();\n\n  virtual size_t write(const uint8_t* data, size_t length);\n};"
  },
  {
    "path": "src/utility/HCIVirtualTransportRPC.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018-2025 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#if defined(ARDUINO_UNO_Q)\n\n#include \"HCIVirtualTransportRPC.h\"\n\n#include <Arduino_RouterBridge.h>\n\nusing RouterBridge::HCI;\n\nHCIVirtualTransportRPCClass::HCIVirtualTransportRPCClass() : initialized(false) {\n}\n\nHCIVirtualTransportRPCClass::~HCIVirtualTransportRPCClass() {\n}\n\nint HCIVirtualTransportRPCClass::begin() {\n  // Initialize the Bridge if not already started\n  if (!Bridge) {\n    if (!Bridge.begin()) {\n      return 0;\n    }\n  }\n\n  // Open HCI device through Bridge RPC\n  if (!HCI.begin(\"hci0\")) {\n    return 0;\n  }\n\n  rxbuf.clear();\n  initialized = true;\n\n  return 1;\n}\n\nvoid HCIVirtualTransportRPCClass::end() {\n  if (initialized) {\n    HCI.end();\n    initialized = false;\n  }\n}\n\nvoid HCIVirtualTransportRPCClass::wait(unsigned long timeout) {\n  delay(timeout);\n}\n\nint HCIVirtualTransportRPCClass::available() {\n  if (!initialized) {\n    return 0;\n  }\n\n  // Return buffered data if available\n  if (rxbuf.available()) {\n    return rxbuf.available();\n  }\n\n  // Check if data is available from Bridge HCI and buffer it\n  if (HCI.available()) {\n    uint8_t packet[258];\n    int received = HCI.recv(packet, sizeof(packet));\n\n    if (received > 0) {\n      // Store received data in ring buffer\n      for (int i = 0; i < received; i++) {\n        rxbuf.store_char(packet[i]);\n      }\n    }\n  }\n\n  return rxbuf.available();\n}\n\nint HCIVirtualTransportRPCClass::peek() {\n  return -1;\n}\n\nint HCIVirtualTransportRPCClass::read() {\n  if (rxbuf.available()) {\n    return rxbuf.read_char();\n  }\n\n  return -1;\n}\n\nsize_t HCIVirtualTransportRPCClass::write(const uint8_t* data, size_t length) {\n  if (!initialized) {\n    return 0;\n  }\n\n  int sent = HCI.send(data, length);\n  if (sent < 0) {\n    return 0;\n  }\n\n  return sent;\n}\n\nHCIVirtualTransportRPCClass HCIVirtualTransportRPC;\nHCITransportInterface& HCITransport = HCIVirtualTransportRPC;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCIVirtualTransportRPC.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018-2025 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _HCI_VIRTUAL_TRANSPORT_RPC_H_\n#define _HCI_VIRTUAL_TRANSPORT_RPC_H_\n\n#include \"HCITransport.h\"\n#include \"api/RingBuffer.h\"\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\nclass HCIVirtualTransportRPCClass : public HCITransportInterface {\n  public:\n    HCIVirtualTransportRPCClass();\n    virtual ~HCIVirtualTransportRPCClass();\n\n    virtual int begin();\n    virtual void end();\n\n    virtual void wait(unsigned long timeout);\n\n    virtual int available();\n    virtual int peek();\n    virtual int read();\n\n    virtual size_t write(const uint8_t* data, size_t length);\n\n  private:\n    RingBufferN<258> rxbuf;\n    bool initialized;\n};\n\nextern HCIVirtualTransportRPCClass HCIVirtualTransportRPC;\n\n#endif\n"
  },
  {
    "path": "src/utility/HCIVirtualTransportZephyr.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018-2025 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#if defined(__ZEPHYR__) && !defined(ARDUINO_UNO_Q)\n\n#include \"HCIVirtualTransportZephyr.h\"\n#include \"HCI.h\"\n\n#include <zephyr/bluetooth/buf.h>\n#include <zephyr/bluetooth/hci.h>\n#include <zephyr/bluetooth/hci_raw.h>\n#include <zephyr/bluetooth/controller.h>\n#include <zephyr/drivers/uart.h>\n#include <zephyr/drivers/hwinfo.h>\n\nstatic K_FIFO_DEFINE(rx_queue);\nstruct k_fifo* __rx_queue = &rx_queue;\nextern \"C\" int bt_h4_vnd_setup(const struct device *dev);\n\n#if CONFIG_CYW4343W_MURATA_1DX\n// External firmware defines.\nextern const uint8_t brcm_patchram_buf[];\nextern const int brcm_patch_ram_length;\n\nenum {\n  HCI_VND_OP_FW_DOWNLOAD  = 0xFC2E,\n  HCI_VND_OP_WRITE_RAM    = 0xFC4C,\n  HCI_VND_OP_LAUNCH_RAM   = 0xFC4E,\n  HCI_VND_OP_SET_BAUDRATE = 0xFC18,\n};\n\nstatic int cyw4343_set_baudrate(const struct device *uart, uint32_t baudrate) {\n    struct __attribute__ ((packed)) {\n      uint16_t zero;\n      uint32_t baud;\n    } param = { 0, baudrate };\n\n\tstruct uart_config uart_cfg;\n\tif (uart_config_get(uart, &uart_cfg)) {\n\t\treturn -1;\n\t}\n\n    if (HCI.sendCommand(HCI_VND_OP_SET_BAUDRATE, sizeof(param), (void *) &param)) {\n      return -1;\n    }\n\n    uart_cfg.baudrate = baudrate;\n    if (uart_configure(uart, &uart_cfg)) {\n        return -1;\n    }\n\n    uart_irq_rx_enable(uart);\n    return 0;\n}\n\nstatic int cyw4343_download_firmware(const struct device *uart) {\n  #define MURATA_NODE DT_CHILD(DT_CHOSEN(zephyr_bt_hci), murata_1dx)\n  uint32_t operational_speed = DT_PROP_OR(MURATA_NODE, hci_operation_speed, 115200);\n  uint32_t fw_download_speed = DT_PROP_OR(MURATA_NODE, fw_download_speed, 115200);\n\n  // Reset controller\n  if (HCI.sendCommand(0x0C03, 0, NULL)) {\n    return -1;\n  }\n\n  // Switch to fast baudrate\n  if ((operational_speed != fw_download_speed) && \n      cyw4343_set_baudrate(uart, fw_download_speed)) {\n      return -1;\n  }\n\n  // Start firmware downloader.\n  if (HCI.sendCommand(HCI_VND_OP_FW_DOWNLOAD, 0, NULL)) {\n    return -1;\n  }\n\n  // Load the firmware image.\n  for (int offset=0; offset < brcm_patch_ram_length;) {\n    uint8_t  length = brcm_patchram_buf[offset + 2];\n    uint16_t opcode = (brcm_patchram_buf[offset + 0]) |\n                      (brcm_patchram_buf[offset + 1] << 8);\n\n    // Opcode should be write RAM or launch RAM.\n    if (opcode != HCI_VND_OP_WRITE_RAM && opcode != HCI_VND_OP_LAUNCH_RAM) {\n      return -1;\n    }\n\n    if (HCI.sendCommand(opcode, length, (void *) &brcm_patchram_buf[offset + 3])) {\n      return -1;\n    }\n\n    offset += length + 3;\n  }\n\n  // Delay after firmware loading.\n  delay(250);\n\n  // Switch back to the default baudrate.\n  if ((operational_speed != fw_download_speed) && \n      cyw4343_set_baudrate(uart, operational_speed)) {\n      return -1;\n  }\n\n  return 0;\n}\n#endif\n\nHCIVirtualTransportZephyrClass::HCIVirtualTransportZephyrClass() {\n\n}\n\nHCIVirtualTransportZephyrClass::~HCIVirtualTransportZephyrClass() {\n\n}\n\nint HCIVirtualTransportZephyrClass::begin() {\n  k_fifo_init(&rx_queue);\n  bt_enable_raw(__rx_queue);\n\n#if CONFIG_BT_HCI_SETUP\n  const struct device *uart = DEVICE_DT_GET(DT_PARENT(DT_CHOSEN(zephyr_bt_hci)));\n  if (!uart) {\n    return 0;\n  }\n\n  if (bt_h4_vnd_setup(uart)) {\n    return 0;\n  }\n\n#if CONFIG_CYW4343W_MURATA_1DX\n  if (cyw4343_download_firmware(uart)) {\n    return 0;\n  }\n#endif /* CONFIG_CYW4343W_MURATA_1DX */\n#endif /* CONFIG_BT_HCI_SETUP */\n\n#if CONFIG_BT_LL_SW_SPLIT\n  // Use unique device id for BD addr.\n  uint8_t bd_addr[6] = { 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA };\n\n#if CONFIG_HWINFO\n  hwinfo_get_device_id(bd_addr, sizeof(bd_addr));\n#endif  /* CONFIG_HWINFO */\n\n  // Set public address for controller.\n  bt_ctlr_set_public_addr(bd_addr);\n#endif  /* CONFIG_BT_LL_SW_SPLIT */\n\n  rxbuf.clear();\n\n  return 1;\n}\n\nvoid HCIVirtualTransportZephyrClass::end() {\n\n}\n\nvoid HCIVirtualTransportZephyrClass::wait(unsigned long timeout) {\n  delay(timeout);\n}\n\nint HCIVirtualTransportZephyrClass::available() {\n  static struct net_buf *buf = NULL;\n\n  if (rxbuf.available()) {\n    return rxbuf.available();\n  }\n\n  buf = (struct net_buf *) k_fifo_get(__rx_queue, K_MSEC(10));\n  if (!buf) {\n    return 0;\n  }\n\n  for (int i=0; i<buf->len; i++) {\n    rxbuf.store_char((uint8_t)buf->data[i]);\n  }\n\n  net_buf_pull(buf, buf->len);\n  if (!buf->len) {\n    net_buf_unref(buf);\n    buf = NULL;\n  }\n\n  return rxbuf.available();\n}\n\nint HCIVirtualTransportZephyrClass::peek() {\n  return -1;\n}\n\nint HCIVirtualTransportZephyrClass::read() {\n  if (rxbuf.available()) {\n    return rxbuf.read_char();\n  }\n\n  return -1;\n}\n\nsize_t HCIVirtualTransportZephyrClass::write(const uint8_t* data, size_t length) {\n  enum bt_buf_type type = bt_buf_type_from_h4(data[0], BT_BUF_OUT);\n  struct net_buf *buf = bt_buf_get_tx(type, K_FOREVER, &data[1], length - 1);\n\n  if (buf) {\n    auto err = bt_send(buf);\n    if (err) {\n    \tnet_buf_unref(buf);\n    }\n    return length;\n  }\n  return 0;\n}\n\nHCIVirtualTransportZephyrClass HCIVirtualTransportZephyr;\nHCITransportInterface& HCITransport = HCIVirtualTransportZephyr;\n#endif\n"
  },
  {
    "path": "src/utility/HCIVirtualTransportZephyr.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018-2025 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"HCITransport.h\"\n#include \"api/RingBuffer.h\"\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\nclass HCIVirtualTransportZephyrClass : public HCITransportInterface {\n  public:\n    HCIVirtualTransportZephyrClass();\n    virtual ~HCIVirtualTransportZephyrClass();\n  \n    virtual int begin();\n    virtual void end();\n  \n    virtual void wait(unsigned long timeout);\n  \n    virtual int available();\n    virtual int peek();\n    virtual int read();\n  \n    virtual size_t write(const uint8_t* data, size_t length);\n  \n  private:\n    RingBufferN<258> rxbuf;\n};\n"
  },
  {
    "path": "src/utility/L2CAPSignaling.cpp",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#include \"HCI.h\"\n#include \"ATT.h\"\n#include \"btct.h\"\n#include \"L2CAPSignaling.h\"\n#include \"keyDistribution.h\"\n#include \"bitDescriptions.h\"\n#define CONNECTION_PARAMETER_UPDATE_REQUEST  0x12\n#define CONNECTION_PARAMETER_UPDATE_RESPONSE 0x13\n\n//#define _BLE_TRACE_\n\nL2CAPSignalingClass::L2CAPSignalingClass() :\n  _minInterval(0),\n  _maxInterval(0),\n  _supervisionTimeout(0),\n  _pairing_enabled(1)\n{\n}\n\nL2CAPSignalingClass::~L2CAPSignalingClass()\n{\n}\n\nvoid L2CAPSignalingClass::addConnection(uint16_t handle, uint8_t role, uint8_t /*peerBdaddrType*/,\n                                        uint8_t /*peerBdaddr*/[6], uint16_t interval,\n                                        uint16_t /*latency*/, uint16_t supervisionTimeout,\n                                        uint8_t /*masterClockAccuracy*/)\n{\n  if (role != 1) {\n    // ignore\n    return;\n  }\n\n  bool updateParameters = false;\n  uint16_t updatedMinInterval = interval;\n  uint16_t updatedMaxInterval = interval;\n  uint16_t updatedSupervisionTimeout = supervisionTimeout;\n\n  if (_minInterval && _maxInterval) {\n    if (interval < _minInterval || interval > _maxInterval) {\n      updatedMinInterval = _minInterval;\n      updatedMaxInterval = _maxInterval;\n      updateParameters = true;\n    }\n  }\n\n  if (_supervisionTimeout && supervisionTimeout != _supervisionTimeout) {\n    updatedSupervisionTimeout = _supervisionTimeout;\n    updateParameters = true;\n  }\n\n  if (updateParameters) {\n    struct __attribute__ ((packed)) L2CAPConnectionParameterUpdateRequest {\n      uint8_t code;\n      uint8_t identifier;\n      uint16_t length;\n      uint16_t minInterval;\n      uint16_t maxInterval;\n      uint16_t latency;\n      uint16_t supervisionTimeout;\n    } request = { CONNECTION_PARAMETER_UPDATE_REQUEST, 0x01, 8,\n                  updatedMinInterval, updatedMaxInterval, 0x0000, updatedSupervisionTimeout };\n\n    HCI.sendAclPkt(handle, SIGNALING_CID, sizeof(request), &request);\n  }\n}\n\nvoid L2CAPSignalingClass::handleData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  struct __attribute__ ((packed)) L2CAPSignalingHdr {\n    uint8_t code;\n    uint8_t identifier;\n    uint16_t length;\n  } *l2capSignalingHdr = (L2CAPSignalingHdr*)data;\n\n  if (dlen < sizeof(L2CAPSignalingHdr)) {\n    // too short, ignore\n    return;\n  }\n\n  if (dlen != (sizeof(L2CAPSignalingHdr) + l2capSignalingHdr->length)) {\n    // invalid length, ignore\n    return;\n  }\n\n  uint8_t code = l2capSignalingHdr->code;\n  uint8_t identifier = l2capSignalingHdr->identifier;\n  uint16_t length = l2capSignalingHdr->length;\n  data = &data[sizeof(L2CAPSignalingHdr)];\n\n  if (code == CONNECTION_PARAMETER_UPDATE_REQUEST) {\n    connectionParameterUpdateRequest(connectionHandle, identifier, length, data);\n  } else if (code == CONNECTION_PARAMETER_UPDATE_RESPONSE) {\n    connectionParameterUpdateResponse(connectionHandle, identifier, length, data);\n  }\n}\nvoid L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[])\n{\n  struct __attribute__ ((packed)) L2CAPSignalingHdr {\n    uint8_t code;\n    uint8_t data[64];\n  } *l2capSignalingHdr = (L2CAPSignalingHdr*)data;\n#ifdef _BLE_TRACE_\n  Serial.print(\"dlen: \");\n  Serial.println(dlen);\n#else\n  (void)dlen;\n#endif\n  uint8_t code = l2capSignalingHdr->code;\n\n#ifdef _BLE_TRACE_\n  Serial.print(\"handleSecurityData: code: 0x\");\n  Serial.println(code, HEX);\n  Serial.print(\"rx security:\");\n  btct.printBytes(data,dlen);\n#endif\n  if (code == CONNECTION_PAIRING_REQUEST) {\n\t  \n    if (isPairingEnabled()){\n      if (_pairing_enabled >= 2) _pairing_enabled = 0;  // 2 = pair once only\n      \n      // 0x1\n      struct __attribute__ ((packed)) PairingRequest {\n        uint8_t ioCapability;\n        uint8_t oobDataFlag;\n        uint8_t authReq;\n        uint8_t maxEncSize;\n        uint8_t initiatorKeyDistribution;\n        uint8_t responderKeyDistribution;\n      } *pairingRequest = (PairingRequest*)l2capSignalingHdr->data;\n\n      KeyDistribution responseKD = KeyDistribution();\n      responseKD.setIdKey(true);\n\n      ATT.remoteKeyDistribution = responseKD;// KeyDistribution(pairingRequest->initiatorKeyDistribution);\n      ATT.localKeyDistribution = responseKD; //KeyDistribution(pairingRequest->responderKeyDistribution);\n      // KeyDistribution rkd(pairingRequest->responderKeyDistribution);\n      AuthReq req(pairingRequest->authReq);\n#ifdef _BLE_TRACE_\n      Serial.print(\"Req has properties: \");\n      Serial.print(req.Bonding()?\"bonding, \":\"no bonding, \");\n      Serial.print(req.CT2()?\"CT2, \":\"no CT2, \");\n      Serial.print(req.KeyPress()?\"KeyPress, \":\"no KeyPress, \");\n      Serial.print(req.MITM()?\"MITM, \":\"no MITM, \");\n      Serial.print(req.SC()?\"SC, \":\"no SC, \");\n#endif\n    \n      uint8_t peerIOCap[3];\n      peerIOCap[0] = pairingRequest->authReq;\n      peerIOCap[1] = pairingRequest->oobDataFlag;\n      peerIOCap[2] = pairingRequest->ioCapability;\n      ATT.setPeerIOCap(connectionHandle, peerIOCap);\n      ATT.setPeerEncryption(connectionHandle, ATT.getPeerEncryption(connectionHandle) | PEER_ENCRYPTION::PAIRING_REQUEST);\n#ifdef _BLE_TRACE_\n      Serial.print(\"Peer encryption : 0b\");\n      Serial.println(ATT.getPeerEncryption(connectionHandle), BIN);\n#endif\n      struct __attribute__ ((packed)) PairingResponse {\n        uint8_t code;\n        uint8_t ioCapability;\n        uint8_t oobDataFlag;\n        uint8_t authReq;\n        uint8_t maxEncSize;\n        uint8_t initiatorKeyDistribution;\n        uint8_t responderKeyDistribution;\n      } response = { CONNECTION_PAIRING_RESPONSE, HCI.localIOCap(), 0, HCI.localAuthreq().getOctet(), 0x10, responseKD.getOctet(), responseKD.getOctet()};\n     \n      HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(response), &response);\n      \n    } else {\n      // Pairing not enabled\n      uint8_t ret[2] = {CONNECTION_PAIRING_FAILED, 0x05}; // reqect pairing\n      HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(ret), ret);\n      ATT.setPeerEncryption(connectionHandle, NO_ENCRYPTION);\n    }\n  }\n  else if (code == CONNECTION_PAIRING_RANDOM)\n  {\n    struct __attribute__ ((packed)) PairingRandom {\n      uint8_t Na[16];\n    } *pairingRandom = (PairingRandom*)l2capSignalingHdr->data;\n    for(int i=0; i<16; i++){\n      HCI.Na[15-i] = pairingRandom->Na[i];\n    }\n#ifdef _BLE_TRACE_\n    Serial.println(\"[Info] Pairing random.\");\n#endif\n    struct __attribute__ ((packed)) PairingResponse {\n      uint8_t code;\n      uint8_t Nb[16];\n    } response = { CONNECTION_PAIRING_RANDOM, 0};\n    for(int i=0; i< 16; i++) response.Nb[15-i] = HCI.Nb[i];\n\n    HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(response), &response);\n\n    // We now have all needed for compare value\n    uint8_t g2Result[4];\n    uint8_t U[32];\n    uint8_t V[32];\n    \n    for(int i=0; i<32; i++){\n      U[31-i] = HCI.remotePublicKeyBuffer[i];\n      V[31-i] = HCI.localPublicKeyBuffer[i];\n    }\n\n    btct.g2(U,V,HCI.Na,HCI.Nb, g2Result);\n    uint32_t result = 0;\n    for(int i=0; i<4; i++) result += g2Result[3-i] << 8*i;\n\n#ifdef _BLE_TRACE_\n    Serial.print(\"U      : \");\n    btct.printBytes(U,32);\n    Serial.print(\"V      : \");\n    btct.printBytes(V,32);\n    Serial.print(\"X      : \");\n    btct.printBytes(HCI.Na,16);\n    Serial.print(\"Y      : \");\n    btct.printBytes(HCI.Nb,16);\n    Serial.print(\"g2res  : \");\n    btct.printBytes(g2Result,4);\n    Serial.print(\"Result : \");\n    Serial.println(result);\n#endif\n\n    if(HCI._displayCode!=0){\n      HCI._displayCode(result%1000000);\n    }\n    if(HCI._binaryConfirmPairing!=0){\n      if(!HCI._binaryConfirmPairing()){\n#ifdef _BLE_TRACE_\n        Serial.println(\"User rejection\");\n#endif\n        uint8_t rejection[2];\n        rejection[0] = CONNECTION_PAIRING_FAILED;\n        rejection[1] = 0x0C; // Numeric comparison failed\n        HCI.sendAclPkt(connectionHandle, SECURITY_CID, 2, rejection);\n        ATT.setPeerEncryption(connectionHandle, PEER_ENCRYPTION::NO_ENCRYPTION);\n      }else{\n#ifdef _BLE_TRACE_\n        Serial.println(\"User did confirm\");\n#endif\n      }\n    }\n  }\n  else if (code == CONNECTION_PAIRING_RESPONSE)\n  {\n  }\n  else if(code == CONNECTION_PAIRING_FAILED)\n  {\n#ifdef _BLE_TRACE_\n    struct __attribute__ ((packed)) PairingFailed\n    {\n      uint8_t code;\n      uint8_t reason;\n    } *pairingFailed = (PairingFailed*)data;\n    Serial.print(\"Pairing failed with code: 0x\");\n    Serial.println(pairingFailed->reason,HEX);\n#endif\n    ATT.setPeerEncryption(connectionHandle, PEER_ENCRYPTION::NO_ENCRYPTION);\n  }\n  else if (code == CONNECTION_IDENTITY_INFORMATION){\n    struct __attribute__ ((packed)) IdentityInformation {\n      uint8_t code;\n      uint8_t PeerIRK[16];\n    } *identityInformation = (IdentityInformation*)data;\n    for(int i=0; i<16; i++) ATT.peerIRK[15-i] = identityInformation->PeerIRK[i];\n#ifdef _BLE_TRACE_\n    Serial.println(\"Saved peer IRK\");\n#endif\n  }\n  else if (code == CONNECTION_IDENTITY_ADDRESS){\n    struct __attribute__ ((packed)) IdentityAddress {\n      uint8_t code;\n      uint8_t addressType;\n      uint8_t address[6];\n    } *identityAddress = (IdentityAddress*)data;\n    // we can save this information now.\n    uint8_t peerAddress[6];\n    for(int i=0; i<6; i++) peerAddress[5-i] = identityAddress->address[i];\n\n    HCI.saveNewAddress(identityAddress->addressType, peerAddress, ATT.peerIRK, ATT.localIRK);\n    if(HCI._storeLTK!=0){\n      HCI._storeLTK(peerAddress, HCI.LTK);\n    }\n  }\n  else if (code == CONNECTION_PAIRING_PUBLIC_KEY){\n    /// Received a public key\n    struct __attribute__ ((packed)) ConnectionPairingPublicKey {\n      uint8_t x[32];\n      uint8_t y[32];\n    } *connectionPairingPublicKey = (ConnectionPairingPublicKey*)l2capSignalingHdr->data;\n    struct __attribute__ ((packed)) GenerateDHKeyCommand {\n      uint8_t x[32];\n      uint8_t y[32];\n    } generateDHKeyCommand = {\n      {0x00},\n      {0x00},\n    };\n    memcpy(generateDHKeyCommand.x,connectionPairingPublicKey->x,32);\n    memcpy(generateDHKeyCommand.y,connectionPairingPublicKey->y,32);\n\n    if(ATT.setPeerEncryption(connectionHandle, ATT.getPeerEncryption(connectionHandle) | PEER_ENCRYPTION::REQUESTED_ENCRYPTION)){\n#ifdef _BLE_TRACE_\n      Serial.println(\"[Info] Pairing public key\");\n      Serial.println(\"Requested encryption stored.\");\n#endif\n    }else{\n#ifdef _BLE_TRACE_\n      Serial.println(\"[Info] Pairing public key\");\n      Serial.print(\"Failed to store encryption request with handle: 0x\");\n      Serial.println(connectionHandle,HEX);\n#endif\n    }\n    \n    memcpy(HCI.remotePublicKeyBuffer,&generateDHKeyCommand,sizeof(generateDHKeyCommand));\n    HCI.sendCommand( (OGF_LE_CTL << 10 )| LE_COMMAND::READ_LOCAL_P256, 0);\n  }\n  else if(code == CONNECTION_PAIRING_DHKEY_CHECK)\n  {\n    uint8_t RemoteDHKeyCheck[16];\n    for(int i=0; i<16; i++) RemoteDHKeyCheck[15-i] = l2capSignalingHdr->data[i];\n    \n\n#ifdef _BLE_TRACE_\n    Serial.println(\"[Info] DH Key check\");\n    Serial.print(\"Remote DHKey Check: \");\n    btct.printBytes(RemoteDHKeyCheck, 16);\n#endif\n\n    \n    \n    uint8_t encryptionState = ATT.getPeerEncryption(connectionHandle) | PEER_ENCRYPTION::RECEIVED_DH_CHECK;\n    ATT.setPeerEncryption(connectionHandle, encryptionState);\n    if((encryptionState & PEER_ENCRYPTION::DH_KEY_CALULATED) == 0){\n#ifdef _BLE_TRACE_\n      Serial.println(\"DHKey not yet ready, will calculate f5, f6 later\");\n#endif\n      // store RemoteDHKeyCheck for later check\n      memcpy(HCI.remoteDHKeyCheckBuffer,RemoteDHKeyCheck,16);\n\n    } else {\n      // We've already calculated the DHKey so we can calculate our check and send it.\n      smCalculateLTKandConfirm(connectionHandle, RemoteDHKeyCheck);\n      \n    }\n  }\n}\n\nvoid L2CAPSignalingClass::smCalculateLTKandConfirm(uint16_t handle, uint8_t expectedEa[])\n{ // Authentication stage 2: LTK Calculation\n  \n  uint8_t localAddress[7];\n  uint8_t remoteAddress[7];\n  ATT.getPeerAddrWithType(handle, remoteAddress);\n  \n  HCI.readBdAddr();\n  memcpy(&localAddress[1],HCI.localAddr,6);\n  localAddress[0] = 0; // IOT 33 uses a static address // TODO: confirm for Nano BLE\n\n  // Compute the LTK and MacKey\n  uint8_t MacKey[16];\n  btct.f5(HCI.DHKey, HCI.Na, HCI.Nb, remoteAddress, localAddress, MacKey, HCI.LTK);\n\n  // Compute Ea and Eb\n  uint8_t Ea[16];\n  uint8_t Eb[16];\n  uint8_t R[16];\n  uint8_t MasterIOCap[3];\n  uint8_t SlaveIOCap[3] = {HCI.localAuthreq().getOctet(), 0x0, HCI.localIOCap()};\n  \n  ATT.getPeerIOCap(handle, MasterIOCap);\n  for(int i=0; i<16; i++) R[i] = 0;\n  \n  btct.f6(MacKey, HCI.Na,HCI.Nb,R, MasterIOCap, remoteAddress, localAddress, Ea);\n  btct.f6(MacKey, HCI.Nb,HCI.Na,R, SlaveIOCap, localAddress, remoteAddress, Eb);\n\n#ifdef _BLE_TRACE_\n  Serial.println(\"Calculate and confirm LTK via f5, f6:\");\n  Serial.print(\"DHKey      : \");  btct.printBytes(HCI.DHKey,32);\n  Serial.print(\"Na         : \");  btct.printBytes(HCI.Na,16);\n  Serial.print(\"Nb         : \");  btct.printBytes(HCI.Nb,16);\n  Serial.print(\"MacKey     : \");  btct.printBytes(MacKey,16);\n  Serial.print(\"LTK        : \");  btct.printBytes(HCI.LTK,16);\n  Serial.print(\"Expected Ea: \");  btct.printBytes(expectedEa, 16);\n  Serial.print(\"Ea         : \");  btct.printBytes(Ea, 16);\n  Serial.print(\"Eb         : \");  btct.printBytes(Eb,16);\n  Serial.print(\"Local Addr : \");  btct.printBytes(localAddress, 7);\n  Serial.print(\"LocalIOCap : \");  btct.printBytes(SlaveIOCap, 3);\n  Serial.print(\"MasterAddr : \");  btct.printBytes(remoteAddress, 7);\n  Serial.print(\"MasterIOCAP: \");  btct.printBytes(MasterIOCap, 3);\n#endif\n      \n  // Check if Ea = expectedEa\n  if (memcmp(Ea, expectedEa, 16) == 0){\n    // Check ok\n    // Send our confirmation value to complete authentication stage 2\n    uint8_t ret[17];\n    ret[0] = CONNECTION_PAIRING_DHKEY_CHECK;\n    for(uint32_t i=0; i<sizeof(Eb); i++){\n      ret[sizeof(Eb)-i] = Eb[i];\n    }\n    HCI.sendAclPkt(handle, SECURITY_CID, sizeof(ret), ret );\n    uint8_t encryption = ATT.getPeerEncryption(handle) | PEER_ENCRYPTION::SENT_DH_CHECK;\n    ATT.setPeerEncryption(handle, encryption);\n#ifdef _BLE_TRACE_\n    Serial.println(\"DHKey check ok - send Eb back\");\n#endif\n\n  } else {\n    // Check failed, abort pairing\n    uint8_t ret[2] = {CONNECTION_PAIRING_FAILED, 0x0B}; // 0x0B = DHKey Check Failed\n    HCI.sendAclPkt(handle, SECURITY_CID, sizeof(ret), ret);\n    ATT.setPeerEncryption(handle, NO_ENCRYPTION);\n#ifdef _BLE_TRACE_\n    Serial.println(\"Error: DHKey check failed - Aborting\");\n#endif\n  }\n}\n\nvoid L2CAPSignalingClass::removeConnection(uint8_t /*handle*/, uint16_t /*reason*/)\n{\n}\n\nvoid L2CAPSignalingClass::setConnectionInterval(uint16_t minInterval, uint16_t maxInterval)\n{\n  _minInterval = minInterval;\n  _maxInterval = maxInterval;\n}\n\nvoid L2CAPSignalingClass::setSupervisionTimeout(uint16_t supervisionTimeout)\n{\n  _supervisionTimeout = supervisionTimeout;\n}\n\nvoid L2CAPSignalingClass::setPairingEnabled(uint8_t enabled)\n{\n  _pairing_enabled = enabled;\n}\nbool L2CAPSignalingClass::isPairingEnabled()\n{\n  return _pairing_enabled > 0;\n}\n\nvoid L2CAPSignalingClass::connectionParameterUpdateRequest(uint16_t handle, uint8_t identifier, uint8_t dlen, uint8_t data[])\n{\n  struct __attribute__ ((packed)) L2CAPConnectionParameterUpdateRequest {\n    uint16_t minInterval;\n    uint16_t maxInterval;\n    uint16_t latency;\n    uint16_t supervisionTimeout;\n  } *request = (L2CAPConnectionParameterUpdateRequest*)data;\n\n  if (dlen < sizeof(L2CAPConnectionParameterUpdateRequest)) {\n    // too short, ignore\n    return;\n  }\n\n  struct __attribute__ ((packed)) L2CAPConnectionParameterUpdateResponse {\n    uint8_t code;\n    uint8_t identifier;\n    uint16_t length;\n    uint16_t value;\n  } response = { CONNECTION_PARAMETER_UPDATE_RESPONSE, identifier, 2, 0x0000 };\n\n  if (_minInterval && _maxInterval) {\n    if (request->minInterval < _minInterval || request->maxInterval > _maxInterval) {\n      response.value = 0x0001; // reject\n    }\n  }\n\n  if  (_supervisionTimeout) {\n    if (request->supervisionTimeout != _supervisionTimeout) {\n      response.value = 0x0001; // reject\n    }\n  }\n\n  HCI.sendAclPkt(handle, SIGNALING_CID, sizeof(response), &response);\n\n  if (response.value == 0x0000) {\n    HCI.leConnUpdate(handle, request->minInterval, request->maxInterval, request->latency, request->supervisionTimeout);\n  }\n}\n\nvoid L2CAPSignalingClass::connectionParameterUpdateResponse(uint16_t /*handle*/, uint8_t /*identifier*/, uint8_t /*dlen*/, uint8_t /*data*/[])\n{\n}\n\n#if !defined(FAKE_L2CAP)\nL2CAPSignalingClass L2CAPSignalingObj;\nL2CAPSignalingClass& L2CAPSignaling = L2CAPSignalingObj;\n#endif\n"
  },
  {
    "path": "src/utility/L2CAPSignaling.h",
    "content": "/*\n  This file is part of the ArduinoBLE library.\n  Copyright (c) 2018 Arduino SA. All rights reserved.\n\n  This library is free software; you can redistribute it and/or\n  modify it under the terms of the GNU Lesser General Public\n  License as published by the Free Software Foundation; either\n  version 2.1 of the License, or (at your option) any later version.\n\n  This library is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n  Lesser General Public License for more details.\n\n  You should have received a copy of the GNU Lesser General Public\n  License along with this library; if not, write to the Free Software\n  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n*/\n\n#ifndef _L2CAP_SIGNALING_H_\n#define _L2CAP_SIGNALING_H_\n\n#include <Arduino.h>\n\n#define SIGNALING_CID 0x0005\n#define SECURITY_CID 0x0006\n\n\n#define CONNECTION_PAIRING_REQUEST        0x01\n#define CONNECTION_PAIRING_RESPONSE       0x02\n#define CONNECTION_PAIRING_CONFIRM        0x03\n#define CONNECTION_PAIRING_RANDOM         0x04\n#define CONNECTION_PAIRING_FAILED         0x05\n#define CONNECTION_ENCRYPTION_INFORMATION 0x06\n#define CONNECTION_MASTER_IDENTIFICATION  0x07\n#define CONNECTION_IDENTITY_INFORMATION   0x08\n#define CONNECTION_IDENTITY_ADDRESS       0x09\n#define CONNECTION_SIGNING_INFORMATION    0x0A\n#define CONNECTION_SECURITY_REQUEST       0x0B\n#define CONNECTION_PAIRING_PUBLIC_KEY     0x0C\n#define CONNECTION_PAIRING_DHKEY_CHECK    0x0D\n#define CONNECTION_PAIRING_KEYPRESS       0x0E\n\n#define IOCAP_DISPLAY_ONLY         0x00\n#define IOCAP_DISPLAY_YES_NO       0x01\n#define IOCAP_KEYBOARD_ONLY        0x02\n#define IOCAP_NO_INPUT_NO_OUTPUT   0x03\n#define IOCAP_KEYBOARD_DISPLAY     0x04\n\n\n#define LOCAL_AUTHREQ 0b00101101\n// #define LOCAL_IOCAP   IOCAP_DISPLAY_ONLY // will use JustWorks pairing\n\nclass L2CAPSignalingClass {\npublic:\n  L2CAPSignalingClass();\n  virtual ~L2CAPSignalingClass();\n\n  virtual void addConnection(uint16_t handle, uint8_t role, uint8_t peerBdaddrType,\n                    uint8_t peerBdaddr[6], uint16_t interval,\n                    uint16_t latency, uint16_t supervisionTimeout,\n                    uint8_t masterClockAccuracy);\n\n  virtual void handleData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n\n  virtual void handleSecurityData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]);\n\n  virtual void removeConnection(uint8_t handle, uint16_t reason);\n\n  virtual void setConnectionInterval(uint16_t minInterval, uint16_t maxInterval);\n\n  virtual void setSupervisionTimeout(uint16_t supervisionTimeout);\n  \n  virtual void setPairingEnabled(uint8_t enabled);\n  virtual bool isPairingEnabled();\n\n\n\n  virtual void smCalculateLTKandConfirm(uint16_t handle, uint8_t expectedEa[]);\n\n\nprivate:\n  virtual void connectionParameterUpdateRequest(uint16_t handle, uint8_t identifier, uint8_t dlen, uint8_t data[]);\n  virtual void connectionParameterUpdateResponse(uint16_t handle, uint8_t identifier, uint8_t dlen, uint8_t data[]);\n\n\nprivate:\n  uint16_t _minInterval;\n  uint16_t _maxInterval;\n  uint16_t _supervisionTimeout;\n  uint8_t _pairing_enabled;\n};\n\nextern L2CAPSignalingClass& L2CAPSignaling;\n\n#endif\n"
  },
  {
    "path": "src/utility/bitDescriptions.cpp",
    "content": "#include \"bitDescriptions.h\"\n\n\n#define BONDING_BIT  0b00000001\n#define MITM_BIT     0b00000100\n#define SC_BIT       0b00001000\n#define KEYPRESS_BIT 0b00010000\n#define CT2_BIT      0b00100000\n\n\nAuthReq::AuthReq(){}\nAuthReq::AuthReq(uint8_t octet):_octet(octet){}\nbool AuthReq::Bonding(){ return (_octet & BONDING_BIT)>0;}\nbool AuthReq::MITM(){ return (_octet & MITM_BIT)>0;}\nbool AuthReq::SC(){ return (_octet & SC_BIT)>0;}\nbool AuthReq::KeyPress(){ return (_octet & KEYPRESS_BIT)>0;}\nbool AuthReq::CT2(){ return (_octet & CT2_BIT)>0;}\n\n\nvoid AuthReq::setBonding(bool state) { _octet= state? _octet|BONDING_BIT  : _octet&~BONDING_BIT;}\nvoid AuthReq::setMITM(bool state)  { _octet= state? _octet|MITM_BIT   : _octet&~MITM_BIT;}\nvoid AuthReq::setSC(bool state){ _octet= state? _octet|SC_BIT : _octet&~SC_BIT;}\nvoid AuthReq::setKeyPress(bool state){ _octet= state? _octet|KEYPRESS_BIT : _octet&~KEYPRESS_BIT;}\nvoid AuthReq::setCT2(bool state){ _octet= state? _octet|CT2_BIT : _octet&~CT2_BIT;}\n\nuint8_t _octet;\n\n\nvoid AuthReq::setOctet( uint8_t octet){_octet = octet;}\nuint8_t AuthReq::getOctet() {return _octet;}\n"
  },
  {
    "path": "src/utility/bitDescriptions.h",
    "content": "#ifndef _BIT_DESCRIPTIONS_H_\n#define _BIT_DESCRIPTIONS_H_\n#include <Arduino.h>\n\nclass AuthReq{\npublic:\n    AuthReq();\n    AuthReq(uint8_t octet);\n    void setOctet( uint8_t octet);\n    uint8_t getOctet();\n\n\n    // The Bonding_Flags field is a 2-bit field that indicates the type of bonding being requested by the initiating device\n    bool Bonding();\n    // The MITM field is a 1-bit flag that is set to one if the device is requesting MITM protection\n    bool MITM();\n    // The SC field is a 1 bit flag. If LE Secure Connections pairing is supported by the device, then the SC field shall be set to 1, otherwise it shall be set to 0.\n    bool SC();\n    // The keypress field is a 1-bit flag that is used only in the Passkey Entry protocol and shall be ignored in other protocols.\n    bool KeyPress();\n    // The CT2 field is a 1-bit flag that shall be set to 1 upon transmission to indicate support for the h7 function.\n    bool CT2();\n\n    void setBonding(bool state);\n    void setMITM(bool state);\n    void setSC(bool state);\n    void setKeyPress(bool state);\n    void setCT2(bool state);\nprivate:\n    uint8_t _octet;\n};\n\nenum IOCap {\n    DisplayOnly,\n    DisplayYesNo,\n    KeyboardOnly,\n    NoInputNoOutput,\n    KeyboardDisplay\n};\n\n#endif"
  },
  {
    "path": "src/utility/btct.cpp",
    "content": "#include \"btct.h\"\n#include <Arduino.h>\n#include \"HCI.h\"\n#include \"ArduinoBLE.h\"\nBluetoothCryptoToolbox::BluetoothCryptoToolbox(){}\n//    In step 1, AES-128 with key K is applied to an all-zero input block.\n//    In step 2, K1 is derived through the following operation:\n//    If the most significant bit of L is equal to 0, K1 is the left-shift\n//    of L by 1 bit.\n//    Otherwise, K1 is the exclusive-OR of const_Rb and the left-shift of L\n//    by 1 bit.\n//    In step 3, K2 is derived through the following operation:\n//    If the most significant bit of K1 is equal to 0, K2 is the left-shift\n//    of K1 by 1 bit.\n//    Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of\n//    K1 by 1 bit.\n//    In step 4, (K1,K2) := Generate_Subkey(K) is returned.\nunsigned char const_Rb[16] = {\n      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87\n  };\n\n#define DHKEY_LENGTH 32\n#define N_LEN 16\n#define ADDR_LEN 6\n#define LEN_LTK 16\n#define LEN_MAC_KEY 16\n\nvoid BluetoothCryptoToolbox::printBytes(uint8_t bytes[], uint8_t length){\n#ifdef _BLE_TRACE_\n    for(int i=0; i<length; i++){\n        if(i>0){\n            Serial.print(\", 0x\");\n        }else{\n            Serial.print(\"0x\");\n        }\n        Serial.print(bytes[i],HEX);\n    }\n    Serial.print('\\n');\n#else\n    (void)bytes;\n    (void)length;\n#endif\n}\n\n\nint BluetoothCryptoToolbox::f5(uint8_t DHKey[],uint8_t N_master[], uint8_t N_slave[],\n            uint8_t BD_ADDR_master[], uint8_t BD_ADDR_slave[], uint8_t MacKey[], uint8_t LTK[])\n{\n    uint8_t SALT[16] = {0x6C, 0x88, 0x83, 0x91, 0xAA, 0xF5, 0xA5, 0x38, 0x60, 0x37, 0x0B, 0xDB, 0x5A, 0x60, 0x83, 0xBE};\n    uint8_t keyID[4] = {0x62, 0x74, 0x6c, 0x65};\n    uint8_t length[2];\n    length[0] = 0x01;\n    length[1] = 0x00;\n#ifdef _BLE_TRACE_\n    Serial.print(\"Starting f5 calculation\");\n    Serial.print(\"Using DHKey:  \");\n    printBytes(DHKey, DHKEY_LENGTH);\n    Serial.print(\"Using N_Master: \");\n    printBytes(N_master, N_LEN);\n    Serial.print(\"Using N_Slave:  \");\n    printBytes(N_slave, N_LEN);\n\n    Serial.println(\"Using BD_ADDR_MASTER: \");\n    printBytes(BD_ADDR_master, ADDR_LEN);\n    Serial.println(\"Using BD_ADDR_SLAVE:  \");\n    printBytes(BD_ADDR_slave, ADDR_LEN);\n#endif\n\n    uint8_t T[16];\n\n    struct __attribute__ ((packed)) CmacInput\n    {\n        uint8_t counter;\n        uint8_t keyID[4];\n        uint8_t N1[16];\n        uint8_t N2[16];\n        uint8_t A1[7];\n        uint8_t A2[7];\n        uint8_t length[2];\n    } cmacInput = {0,{0},{0},{0},{0},{0},{0}};\n    cmacInput.counter = 0;\n    memcpy(cmacInput.keyID, keyID, 4);\n    memcpy(cmacInput.N1,N_master,16);\n    memcpy(cmacInput.N2,N_slave,16);\n    memcpy(cmacInput.A1,BD_ADDR_master,7);\n    memcpy(cmacInput.A2,BD_ADDR_slave,7);\n    memcpy(cmacInput.length,length,2);\n    AES_CMAC(SALT, DHKey, 32, T);\n\n    AES_CMAC(T, (uint8_t*)&cmacInput,sizeof(cmacInput), MacKey);\n    cmacInput.counter=1;\n    AES_CMAC(T, (uint8_t*)&cmacInput, sizeof(cmacInput), LTK);\n\n    return 1;\n}\nint BluetoothCryptoToolbox::f6(uint8_t W[], uint8_t N1[],uint8_t N2[],uint8_t R[], uint8_t IOCap[], uint8_t A1[], uint8_t A2[], uint8_t Ex[])\n{\n    struct __attribute__ ((packed)) F6Input\n    {\n        uint8_t N1[16];\n        uint8_t N2[16];\n        uint8_t R[16];\n        uint8_t IOCap[3];\n        uint8_t A1[7];\n        uint8_t A2[7];\n    } f6Input = {{0},{0},{0},{0},{0},{0}};\n\n    memcpy(f6Input.N1, N1, 16);\n    memcpy(f6Input.N2, N2, 16);\n    memcpy(f6Input.R, R, 16);\n    memcpy(f6Input.IOCap, IOCap, 3);\n    memcpy(f6Input.A1, A1, 7);\n    memcpy(f6Input.A2, A2, 7);\n\n\n    AES_CMAC(W, (uint8_t*)&f6Input, sizeof(f6Input),Ex);\n    return 1;\n}\n// AES_CMAC from RFC\nint BluetoothCryptoToolbox::ah(uint8_t k[16], uint8_t r[3], uint8_t* result)\n{\n    uint8_t r_[16];\n    int i=0;\n    for(i=0; i<16; i++) r_[i] = 0;\n    for(i=0; i<3; i++)  r_[i+13] = r[i];\n    uint8_t intermediate[16];\n    AES_128(k,r_,intermediate);\n    for(i=0; i<3; i++){\n        result[i] = intermediate[i+13];\n    }\n    return 1;\n}\nvoid BluetoothCryptoToolbox::testAh()\n{\n    uint8_t irk[16] = {0xec,0x02,0x34,0xa3,0x57,0xc8,0xad,0x05,0x34,0x10,0x10,0xa6,0x0a,0x39,0x7d,0x9b};\n    uint8_t expected_final[3] = {0x0d,0xfb,0xaa};\n    uint8_t ourResult[3];\n    ah(irk, expected_final, ourResult);\n\n#ifdef _BLE_TRACE_\n    Serial.print(\"Expected   : \");\n    printBytes(&expected_final[3], 3);\n    Serial.print(\"Actual     : \");\n    printBytes(ourResult, 3);\n#endif\n}\n\nint BluetoothCryptoToolbox::g2(uint8_t U[], uint8_t V[], uint8_t X[], uint8_t Y[], uint8_t out[4])\n{\n    struct __attribute__ ((packed)) CmacInput {\n        uint8_t U[32];\n        uint8_t V[32];\n        uint8_t Y[16];\n    } cmacInput= {{0},{0},{0}};\n    memcpy(cmacInput.U,U,32);\n    memcpy(cmacInput.V,V,32);\n    memcpy(cmacInput.Y,Y,16);\n    uint8_t intermediate[16];\n    AES_CMAC(X,(uint8_t*)&cmacInput,sizeof(CmacInput),intermediate);\n    memcpy(out,&intermediate[12],4);\n    return 1;\n}\nvoid BluetoothCryptoToolbox::testg2(){\n    uint8_t U[32] = {0x20,0xb0,0x03,0xd2,0xf2,0x97,0xbe,0x2c,0x5e,0x2c,0x83,0xa7,0xe9,0xf9,0xa5,0xb9,0xef,0xf4,0x91,0x11,0xac,0xf4,0xfd,0xdb,0xcc,0x03,0x01,0x48,0x0e,0x35,0x9d,0xe6};\n    uint8_t V[32] = {0x55,0x18,0x8b,0x3d,0x32,0xf6,0xbb,0x9a,0x90,0x0a,0xfc,0xfb,0xee,0xd4,0xe7,0x2a,0x59,0xcb,0x9a,0xc2,0xf1,0x9d,0x7c,0xfb,0x6b,0x4f,0xdd,0x49,0xf4,0x7f,0xc5,0xfd};\n    uint8_t X[16] = {0xd5,0xcb,0x84,0x54,0xd1,0x77,0x73,0x3e,0xff,0xff,0xb2,0xec,0x71,0x2b,0xae,0xab};\n    uint8_t Y[16] = {0xa6,0xe8,0xe7,0xcc,0x25,0xa7,0x5f,0x6e,0x21,0x65,0x83,0xf7,0xff,0x3d,0xc4,0xcf};\n    uint8_t out[4];\n\n    g2(U,V,X,Y,out);\n    uint32_t result = 0;\n    for(int i=0; i<4; i++) result += out[i] << 8*i;\n\n#ifdef _BLE_TRACE_\n    Serial.println(\"Expected :     0\");\n    Serial.print(\"Result   : \");\n    Serial.println(result);\n    Serial.println();\n#endif\n}\n\nvoid BluetoothCryptoToolbox::AES_CMAC ( unsigned char *key, unsigned char *input, int length,\n                  unsigned char *mac )\n{\n    unsigned char       X[16],Y[16], M_last[16], padded[16];\n    unsigned char       K1[16], K2[16];\n    int         n, i, flag;\n    generateSubkey(key,K1,K2);\n\n    n = (length+15) / 16;       /* n is number of rounds */\n\n    if ( n == 0 ) {\n        n = 1;\n        flag = 0;\n    } else {\n        if ( (length%16) == 0 ) { /* last block is a complete block */\n            flag = 1;\n        } else { /* last block is not complete block */\n            flag = 0;\n        }\n    }\n\n    if ( flag ) { /* last block is complete block */\n        xor_128(&input[16*(n-1)],K1,M_last);\n    } else {\n        padding(&input[16*(n-1)],padded,length%16);\n        xor_128(padded,K2,M_last);\n    }\n\n    for ( i=0; i<16; i++ ) X[i] = 0;\n    for ( i=0; i<n-1; i++ ) {\n        xor_128(X,&input[16*i],Y); /* Y := Mi (+) X  */\n        AES_128(key,Y,X);      /* X := AES-128(KEY, Y); */\n    }\n\n    xor_128(X,M_last,Y);\n    AES_128(key,Y,X);\n\n    for ( i=0; i<16; i++ ) {\n        mac[i] = X[i];\n    }\n}\n// Paddinng function from RFC\nvoid BluetoothCryptoToolbox::padding( unsigned char *lastb, unsigned char *pad, int length )\n{\n    int j;\n    /* original last block */\n    for ( j=0; j<16; j++ ) {\n        if ( j < length ) {\n            pad[j] = lastb[j];\n        } else if ( j == length ) {\n            pad[j] = 0x80;\n        } else {\n            pad[j] = 0x00;\n        }\n    }\n}\n// Generate subkey from RFC\nvoid BluetoothCryptoToolbox::generateSubkey(uint8_t* key, uint8_t* K1, uint8_t* K2){\n    unsigned char L[16];\n    unsigned char Z[16];\n    unsigned char tmp[16];\n    int i;\n\n    for ( i=0; i<16; i++ ) Z[i] = 0;\n\n    AES_128(key,Z,L);\n\n    if ( (L[0] & 0x80) == 0 ) { /* If MSB(L) = 0, then K1 = L << 1 */\n        leftshift_onebit(L,K1);\n    } else {    /* Else K1 = ( L << 1 ) (+) Rb */\n\n        leftshift_onebit(L,tmp);\n        xor_128(tmp,const_Rb,K1);\n    }\n\n    if ( (K1[0] & 0x80) == 0 ) {\n        leftshift_onebit(K1,K2);\n    } else {\n        leftshift_onebit(K1,tmp);\n        xor_128(tmp,const_Rb,K2);\n    }\n    return;\n}\n// Use BLE AES function - restart bluetooth if crash\nint BluetoothCryptoToolbox::AES_128(uint8_t* key, uint8_t* data_in, uint8_t* data_out){\n    uint8_t status = 0;\n    int n = 0;\n    int tries = 30;\n    while(HCI.leEncrypt(key,data_in, &status, data_out)!=1&&n<tries){\n#ifdef _BLE_TRACE_\n        Serial.print(\"AES failed... retrying: \");\n        Serial.println(n);\n#endif\n        BLE.end();\n        delay(200);\n        BLE.begin();\n        n++;\n        delay(100*n);\n    }\n    if(n==tries){\n#ifdef _BLE_TRACE_\n        Serial.println(\"something went wrong with AES.\");\n#endif\n        return 0;\n    }\n    return 1;\n}\n// Tests AES CMAC\n#ifdef _BLE_TRACE_\nvoid BluetoothCryptoToolbox::test(){\n    unsigned char L[16];\n    unsigned char Z[16];\n    unsigned char tmp[16];\n    int i;\n\n    for ( i=0; i<16; i++ ) Z[i] = 0x00;\n    uint8_t k[16]            = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};\n\n    Serial.println(\"AES Plaintext:\");\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(Z[i],HEX);\n    }\n    Serial.println(\".\");\n    uint8_t expected_aes[16] = {0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3, 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f};\n\n    AES_128(k, Z, L);\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(L[i],HEX);\n    }\n    Serial.println(\".\");\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(expected_aes[i],HEX);\n    }\n    Serial.println(\".\");\n\n    uint8_t k1[16];\n    uint8_t k2[16];\n    generateSubkey(k,k1,k2);\n    uint8_t expected_k1[16]  = {0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66, 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde};\n    uint8_t expected_k2[16]  = {0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc, 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b};\n\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(k2[i],HEX);\n    }\n    Serial.println(\".\");\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(expected_k2[i],HEX);\n    }\n    Serial.println(\".\");\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(k1[i],HEX);\n    }\n    Serial.println(\".\");\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(expected_k1[i],HEX);\n    }\n    Serial.println(\".\");\n\n    uint8_t m[40] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11};\n    uint8_t mac[16];\n    uint8_t expected_mac[16] = {0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27};\n    AES_CMAC(k,m,40,mac);\n\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(mac[i],HEX);\n    }\n    Serial.println(\".\");\n    for(int i=0; i<16; i++){\n        Serial.print(\" 0x\");\n        Serial.print(expected_mac[i],HEX);\n    }\n    Serial.println(\".\");\n}\n#endif //_BLE_TRACE_\n// From RFC\nvoid BluetoothCryptoToolbox::leftshift_onebit(unsigned char *input,unsigned char *output)\n{\n    int i;\n    unsigned char overflow = 0;\n\n    for ( i=15; i>=0; i-- ) {\n        output[i] = input[i] << 1;\n        output[i] |= overflow;\n        overflow = (input[i] & 0x80)?1:0;\n    }\n    return;\n}\n// From RFC\nvoid BluetoothCryptoToolbox::xor_128(unsigned char *a, unsigned char *b, unsigned char *out)\n{\n    int i;\n    for (i=0;i<16; i++)\n    {\n        out[i] = a[i] ^ b[i];\n    }\n}\nBluetoothCryptoToolbox btct;\n"
  },
  {
    "path": "src/utility/btct.h",
    "content": "#ifndef _BTCT_H_\n#define _BTCT_H_\n#include <Arduino.h>\n\n// Implementation of functions defined in BTLE standard\nclass BluetoothCryptoToolbox{\npublic:\n    BluetoothCryptoToolbox();\n    void printBytes(uint8_t bytes[], uint8_t length);\n    void generateSubkey(uint8_t* K, uint8_t* K1, uint8_t* K2);\n    void AES_CMAC ( unsigned char *key, unsigned char *input, int length,\n                  unsigned char *mac );\n    int f5(uint8_t DHKey[],uint8_t N_master[], uint8_t N_slave[],\n            uint8_t BD_ADDR_master[], uint8_t BD_ADDR_slave[], uint8_t MacKey[], uint8_t LTK[]);\n    int f6(uint8_t W[], uint8_t N1[],uint8_t N2[],uint8_t R[], uint8_t IOCap[], uint8_t A1[], uint8_t A2[], uint8_t Ex[]);\n    int g2(uint8_t U[], uint8_t V[], uint8_t X[], uint8_t Y[], uint8_t out[4]);\n    int ah(uint8_t k[16], uint8_t r[3], uint8_t result[3]);\n    void test();\n    void testF5();\n    void testF6();\n    void testAh();\n    void testg2();\nprivate:\n    int AES_128(uint8_t key[], uint8_t data_in[], uint8_t data_out[]);\n    void leftshift_onebit(unsigned char *input,unsigned char *output);\n    void xor_128(unsigned char *a, unsigned char *b, unsigned char *out);\n    void padding ( unsigned char *lastb, unsigned char *pad, int length );\n};\nextern BluetoothCryptoToolbox btct;\n#endif"
  },
  {
    "path": "src/utility/keyDistribution.cpp",
    "content": "#include \"keyDistribution.h\"\n\nKeyDistribution::KeyDistribution():_octet(0){}\nKeyDistribution::KeyDistribution(uint8_t octet):_octet(octet){}\n\n#define ENCKEY  0b00000001\n#define IDKEY   0b00000010\n#define SIGNKEY 0b00000100\n#define LINKKEY 0b00001000\nvoid KeyDistribution::setOctet( uint8_t octet){_octet = octet;}\nuint8_t KeyDistribution::getOctet() {return _octet;}\n// Ignored when SMP is on LE transport\nbool KeyDistribution::EncKey(){ return (_octet & ENCKEY)>0;}\n// Device shall distribute IRK using Identity information command followed by its address using Identity address information\nbool KeyDistribution::IdKey(){ return  (_octet & IDKEY)>0;}\n// Device shall distribute CSRK using signing information command\nbool KeyDistribution::SignKey(){ return (_octet & SIGNKEY)>0;}\n// Device would like to derive BR/EDR from LTK\nbool KeyDistribution::LinkKey(){ return (_octet & LINKKEY)>0;}\n\nvoid KeyDistribution::setEncKey(bool state) { _octet= state? _octet|ENCKEY  : _octet&~ENCKEY;}\nvoid KeyDistribution::setIdKey(bool state)  { _octet= state? _octet|IDKEY   : _octet&~IDKEY;}\nvoid KeyDistribution::setSignKey(bool state){ _octet= state? _octet|SIGNKEY : _octet&~SIGNKEY;}\nvoid KeyDistribution::setLinkKey(bool state){ _octet= state? _octet|LINKKEY : _octet&~LINKKEY;}"
  },
  {
    "path": "src/utility/keyDistribution.h",
    "content": "#ifndef _KEY_DISTRIBUTION_H_\n#define _KEY_DISTRIBUTION_H_\n#include <Arduino.h>\n\nclass KeyDistribution{\npublic:\n    KeyDistribution();\n    KeyDistribution(uint8_t octet);\n    void setOctet( uint8_t octet);\n    uint8_t getOctet();\n    // Ignored when SMP is on LE transport\n    bool EncKey();\n    // Device shall distribute IRK using Identity information command followed by its address using Identity address information\n    bool IdKey();\n    // Device shall distribute CSRK using signing information command\n    bool SignKey();\n    // Device would like to derive BR/EDR from LTK\n    bool LinkKey();\n\n    void setEncKey(bool state);\n    void setIdKey(bool state);\n    void setSignKey(bool state);\n    void setLinkKey(bool state);\nprivate:\n    uint8_t _octet;\n    // 1.   IRK by the slave2.   BD ADDR by the slave3.   CSRK by the slave4.   IRK by the master5.   BD_ADDR by the master6.   CSRK by the master\n};\n\n#endif"
  }
]